1package imaging
  2
  3import (
  4	"image"
  5	"image/color"
  6)
  7
  8type scanner struct {
  9	image   image.Image
 10	w, h    int
 11	palette []color.NRGBA
 12}
 13
 14func newScanner(img image.Image) *scanner {
 15	s := &scanner{
 16		image: img,
 17		w:     img.Bounds().Dx(),
 18		h:     img.Bounds().Dy(),
 19	}
 20	if img, ok := img.(*image.Paletted); ok {
 21		s.palette = make([]color.NRGBA, len(img.Palette))
 22		for i := 0; i < len(img.Palette); i++ {
 23			s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA)
 24		}
 25	}
 26	return s
 27}
 28
 29// scan scans the given rectangular region of the image into dst.
 30func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
 31	switch img := s.image.(type) {
 32	case *image.NRGBA:
 33		size := (x2 - x1) * 4
 34		j := 0
 35		i := y1*img.Stride + x1*4
 36		if size == 4 {
 37			for y := y1; y < y2; y++ {
 38				d := dst[j : j+4 : j+4]
 39				s := img.Pix[i : i+4 : i+4]
 40				d[0] = s[0]
 41				d[1] = s[1]
 42				d[2] = s[2]
 43				d[3] = s[3]
 44				j += size
 45				i += img.Stride
 46			}
 47		} else {
 48			for y := y1; y < y2; y++ {
 49				copy(dst[j:j+size], img.Pix[i:i+size])
 50				j += size
 51				i += img.Stride
 52			}
 53		}
 54
 55	case *image.NRGBA64:
 56		j := 0
 57		for y := y1; y < y2; y++ {
 58			i := y*img.Stride + x1*8
 59			for x := x1; x < x2; x++ {
 60				s := img.Pix[i : i+8 : i+8]
 61				d := dst[j : j+4 : j+4]
 62				d[0] = s[0]
 63				d[1] = s[2]
 64				d[2] = s[4]
 65				d[3] = s[6]
 66				j += 4
 67				i += 8
 68			}
 69		}
 70
 71	case *image.RGBA:
 72		j := 0
 73		for y := y1; y < y2; y++ {
 74			i := y*img.Stride + x1*4
 75			for x := x1; x < x2; x++ {
 76				d := dst[j : j+4 : j+4]
 77				a := img.Pix[i+3]
 78				switch a {
 79				case 0:
 80					d[0] = 0
 81					d[1] = 0
 82					d[2] = 0
 83					d[3] = a
 84				case 0xff:
 85					s := img.Pix[i : i+4 : i+4]
 86					d[0] = s[0]
 87					d[1] = s[1]
 88					d[2] = s[2]
 89					d[3] = a
 90				default:
 91					s := img.Pix[i : i+4 : i+4]
 92					r16 := uint16(s[0])
 93					g16 := uint16(s[1])
 94					b16 := uint16(s[2])
 95					a16 := uint16(a)
 96					d[0] = uint8(r16 * 0xff / a16)
 97					d[1] = uint8(g16 * 0xff / a16)
 98					d[2] = uint8(b16 * 0xff / a16)
 99					d[3] = a
100				}
101				j += 4
102				i += 4
103			}
104		}
105
106	case *image.RGBA64:
107		j := 0
108		for y := y1; y < y2; y++ {
109			i := y*img.Stride + x1*8
110			for x := x1; x < x2; x++ {
111				s := img.Pix[i : i+8 : i+8]
112				d := dst[j : j+4 : j+4]
113				a := s[6]
114				switch a {
115				case 0:
116					d[0] = 0
117					d[1] = 0
118					d[2] = 0
119				case 0xff:
120					d[0] = s[0]
121					d[1] = s[2]
122					d[2] = s[4]
123				default:
124					r32 := uint32(s[0])<<8 | uint32(s[1])
125					g32 := uint32(s[2])<<8 | uint32(s[3])
126					b32 := uint32(s[4])<<8 | uint32(s[5])
127					a32 := uint32(s[6])<<8 | uint32(s[7])
128					d[0] = uint8((r32 * 0xffff / a32) >> 8)
129					d[1] = uint8((g32 * 0xffff / a32) >> 8)
130					d[2] = uint8((b32 * 0xffff / a32) >> 8)
131				}
132				d[3] = a
133				j += 4
134				i += 8
135			}
136		}
137
138	case *image.Gray:
139		j := 0
140		for y := y1; y < y2; y++ {
141			i := y*img.Stride + x1
142			for x := x1; x < x2; x++ {
143				c := img.Pix[i]
144				d := dst[j : j+4 : j+4]
145				d[0] = c
146				d[1] = c
147				d[2] = c
148				d[3] = 0xff
149				j += 4
150				i++
151			}
152		}
153
154	case *image.Gray16:
155		j := 0
156		for y := y1; y < y2; y++ {
157			i := y*img.Stride + x1*2
158			for x := x1; x < x2; x++ {
159				c := img.Pix[i]
160				d := dst[j : j+4 : j+4]
161				d[0] = c
162				d[1] = c
163				d[2] = c
164				d[3] = 0xff
165				j += 4
166				i += 2
167			}
168		}
169
170	case *image.YCbCr:
171		j := 0
172		x1 += img.Rect.Min.X
173		x2 += img.Rect.Min.X
174		y1 += img.Rect.Min.Y
175		y2 += img.Rect.Min.Y
176
177		hy := img.Rect.Min.Y / 2
178		hx := img.Rect.Min.X / 2
179		for y := y1; y < y2; y++ {
180			iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X)
181
182			var yBase int
183			switch img.SubsampleRatio {
184			case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio422:
185				yBase = (y - img.Rect.Min.Y) * img.CStride
186			case image.YCbCrSubsampleRatio420, image.YCbCrSubsampleRatio440:
187				yBase = (y/2 - hy) * img.CStride
188			}
189
190			for x := x1; x < x2; x++ {
191				var ic int
192				switch img.SubsampleRatio {
193				case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio440:
194					ic = yBase + (x - img.Rect.Min.X)
195				case image.YCbCrSubsampleRatio422, image.YCbCrSubsampleRatio420:
196					ic = yBase + (x/2 - hx)
197				default:
198					ic = img.COffset(x, y)
199				}
200
201				yy1 := int32(img.Y[iy]) * 0x10101
202				cb1 := int32(img.Cb[ic]) - 128
203				cr1 := int32(img.Cr[ic]) - 128
204
205				r := yy1 + 91881*cr1
206				if uint32(r)&0xff000000 == 0 {
207					r >>= 16
208				} else {
209					r = ^(r >> 31)
210				}
211
212				g := yy1 - 22554*cb1 - 46802*cr1
213				if uint32(g)&0xff000000 == 0 {
214					g >>= 16
215				} else {
216					g = ^(g >> 31)
217				}
218
219				b := yy1 + 116130*cb1
220				if uint32(b)&0xff000000 == 0 {
221					b >>= 16
222				} else {
223					b = ^(b >> 31)
224				}
225
226				d := dst[j : j+4 : j+4]
227				d[0] = uint8(r)
228				d[1] = uint8(g)
229				d[2] = uint8(b)
230				d[3] = 0xff
231
232				iy++
233				j += 4
234			}
235		}
236
237	case *image.Paletted:
238		j := 0
239		for y := y1; y < y2; y++ {
240			i := y*img.Stride + x1
241			for x := x1; x < x2; x++ {
242				c := s.palette[img.Pix[i]]
243				d := dst[j : j+4 : j+4]
244				d[0] = c.R
245				d[1] = c.G
246				d[2] = c.B
247				d[3] = c.A
248				j += 4
249				i++
250			}
251		}
252
253	default:
254		j := 0
255		b := s.image.Bounds()
256		x1 += b.Min.X
257		x2 += b.Min.X
258		y1 += b.Min.Y
259		y2 += b.Min.Y
260		for y := y1; y < y2; y++ {
261			for x := x1; x < x2; x++ {
262				r16, g16, b16, a16 := s.image.At(x, y).RGBA()
263				d := dst[j : j+4 : j+4]
264				switch a16 {
265				case 0xffff:
266					d[0] = uint8(r16 >> 8)
267					d[1] = uint8(g16 >> 8)
268					d[2] = uint8(b16 >> 8)
269					d[3] = 0xff
270				case 0:
271					d[0] = 0
272					d[1] = 0
273					d[2] = 0
274					d[3] = 0
275				default:
276					d[0] = uint8(((r16 * 0xffff) / a16) >> 8)
277					d[1] = uint8(((g16 * 0xffff) / a16) >> 8)
278					d[2] = uint8(((b16 * 0xffff) / a16) >> 8)
279					d[3] = uint8(a16 >> 8)
280				}
281				j += 4
282			}
283		}
284	}
285}