Симеон обнови решението на 07.11.2013 02:11 (преди над 4 години)
+package main
+
+import (
+ "fmt"
+ "strings"
+)
+
+type Stringer interface {
+ String() string
+}
+
+type Image struct {
+ Pixels []Pixel
+ Header Header
+}
+
+type Header struct {
+ Format string
+ LineWidth int
+}
+
+type Pixel struct {
+ PixelColor Color
+}
+
+type Color struct {
+ Red, Green, Blue byte
+}
+
+func (pixel *Pixel) Color() Color {
+ return pixel.PixelColor
+}
+
+func (color Color) String() string {
+ return fmt.Sprintf("Red: %v, Green: %v, Blue: %v", color.Red, color.Green, color.Blue)
+}
+
+// Правим проверката дали X надвишава броя колони. Ако е така, става паника.
+func (image Image) InspectPixel(x, y int) Pixel {
+ if x >= image.Header.LineWidth {
+ panic("Invalid dimensions!")
+ }
+ return image.Pixels[y*image.Header.LineWidth+x]
+}
+
+// Тук става малко по-интересно
+func ParseImage(data []byte, header Header) *Image {
+ image := new(Image)
+ var r, g, b, a float32
+ formatLength := len(strings.Split(header.Format, ""))
+
+ if formatLength == 0 {
+ panic("Please enter a format!")
+ }
+
+ r, g, b, a = 0.0, 0.0, 0.0, 255.0
+ image.Header = header
+
+ // Идеята е, че разделяме пикселите на групички, номерирани със step. Броя на цветовете на всяка стъпка зависи от броя на символите въф формата на картинката. Ако форматът е RGB, тогава броя цветове в съответната стъпка е 3.
+ for step := 0; step < len(data)/formatLength; step++ {
+ for index, value := range strings.Split(header.Format, "") {
+ byteIndex := step*formatLength + index
+
+ // Итерираме през възможните буквички и записваме в r, g, b, a съответния цвят. В случая се оказва, че формати като GRAB, BRA и BAR също са валидни, което май не вреди... Кастваме цветовете към float32, защото ще ни трябват малко по-късно за сметки.
+ switch value {
+ case "R":
+ r = float32(data[byteIndex])
+ case "G":
+ g = float32(data[byteIndex])
+ case "B":
+ b = float32(data[byteIndex])
+ case "A":
+ a = float32(data[byteIndex])
+ default:
+ panic("Wrong header format. Please use a format with the letters R,G,B,A!")
+ }
+ }
+
+ // Очевидно всеки цвят се пресмята по формулата Color * Alpha / 255. Готовият резултат кастваме обратно към byte и си създаваме пиксела, който после добавяме в слайса с пиксели.
+ pixel := Pixel{PixelColor: Color{Red: byte(r * a / 255), Green: byte(g * a / 255), Blue: byte(b * a / 255)}}
+
+ image.Pixels = append(image.Pixels, pixel)
+ }
+
+ return image
+}
+
+func main() {
+ // В този случай имаме 3 реда и 2 колони, като цветовете на пикселите са по формата RG. Синият цвят по подразбиране се сетва на 0. Казваме да върне долния десен пиксел. (R: 17, G: 67, B: 0)
+ data := []byte{0, 12, 244, 13, 26, 52, 31, 33, 41, 33, 17, 67}
+ header := Header{"RG", 2}
+ pixel := ParseImage(data, header).InspectPixel(1, 2)
+ fmt.Println(pixel.Color())
+}