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}