1package psd
2
3import (
4	"image"
5	"image/color"
6
7	psdColor "github.com/oov/psd/color"
8)
9
10type picker interface {
11	image.Image
12	setSource(rect image.Rectangle, src ...[]byte)
13}
14
15func findPicker(depth int, colorMode ColorMode, hasAlpha bool) picker {
16	switch colorMode {
17	case ColorModeBitmap, ColorModeGrayscale:
18		return findNGrayPicker(depth, hasAlpha)
19	case ColorModeRGB:
20		return findNRGBAPicker(depth, hasAlpha)
21	case ColorModeCMYK:
22		return findNCMYKAPicker(depth, hasAlpha)
23	}
24	return nil
25}
26
27func findGrayPicker(depth int) picker {
28	switch depth {
29	case 1:
30		return &pickerGray1{}
31	case 8:
32		return &pickerGray8{}
33	case 16:
34		return &pickerGray16{}
35	case 32:
36		return &pickerGray32{}
37	}
38	return nil
39}
40
41func findNGrayPicker(depth int, hasAlpha bool) picker {
42	switch depth {
43	case 8:
44		if hasAlpha {
45			return &pickerNGrayA8{}
46		}
47		return &pickerNGray8{}
48	case 16:
49		if hasAlpha {
50			return &pickerNGrayA16{}
51		}
52		return &pickerNGray16{}
53	case 32:
54		if hasAlpha {
55			return &pickerNGrayA32{}
56		}
57		return &pickerNGray32{}
58	}
59	return nil
60}
61
62func findNRGBAPicker(depth int, hasAlpha bool) picker {
63	switch depth {
64	case 8:
65		if hasAlpha {
66			return &pickerNRGBA8{}
67		}
68		return &pickerNRGB8{}
69	case 16:
70		if hasAlpha {
71			return &pickerNRGBA16{}
72		}
73		return &pickerNRGB16{}
74	case 32:
75		if hasAlpha {
76			return &pickerNRGBA32{}
77		}
78		return &pickerNRGB32{}
79	}
80	return nil
81}
82
83func findNCMYKAPicker(depth int, hasAlpha bool) picker {
84	switch depth {
85	case 8:
86		if hasAlpha {
87			return &pickerNCMYKA8{}
88		}
89		return &pickerNCMYK8{}
90	case 16:
91		if hasAlpha {
92			return &pickerNCMYKA16{}
93		}
94		return &pickerNCMYK16{}
95	}
96	return nil
97}
98
99type pickerPalette struct {
100	Rect    image.Rectangle
101	Src     []byte
102	Palette color.Palette
103}
104
105func (p *pickerPalette) setSource(rect image.Rectangle, src ...[]byte) { p.Rect, p.Src = rect, src[0] }
106func (p *pickerPalette) ColorModel() color.Model                       { return p.Palette }
107func (p *pickerPalette) Bounds() image.Rectangle                       { return p.Rect }
108func (p *pickerPalette) At(x, y int) color.Color {
109	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
110	return p.Palette[p.Src[pos]]
111}
112
113type pickerGray1 struct {
114	Rect image.Rectangle
115	Y    []byte
116}
117
118func (p *pickerGray1) setSource(rect image.Rectangle, src ...[]byte) { p.Rect, p.Y = rect, src[0] }
119func (p *pickerGray1) ColorModel() color.Model                       { return psdColor.Gray1Model }
120func (p *pickerGray1) Bounds() image.Rectangle                       { return p.Rect }
121func (p *pickerGray1) At(x, y int) color.Color {
122	xx := x - p.Rect.Min.X
123	pos := (p.Rect.Dx()+7)>>3*(y-p.Rect.Min.Y) + xx>>3
124	return psdColor.Gray1{Y: p.Y[pos]&(1<<uint(^xx&7)) == 0}
125}
126
127type pickerGray8 struct {
128	Rect image.Rectangle
129	Y    []byte
130}
131
132func (p *pickerGray8) setSource(rect image.Rectangle, src ...[]byte) { p.Rect, p.Y = rect, src[0] }
133func (p *pickerGray8) ColorModel() color.Model                       { return color.GrayModel }
134func (p *pickerGray8) Bounds() image.Rectangle                       { return p.Rect }
135func (p *pickerGray8) At(x, y int) color.Color {
136	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
137	return color.Gray{Y: p.Y[pos]}
138}
139
140type pickerNGray8 struct {
141	Rect image.Rectangle
142	Y    []byte
143}
144
145func (p *pickerNGray8) setSource(rect image.Rectangle, src ...[]byte) {
146	p.Rect, p.Y = rect, src[0]
147}
148func (p *pickerNGray8) ColorModel() color.Model { return psdColor.NGrayAModel }
149func (p *pickerNGray8) Bounds() image.Rectangle { return p.Rect }
150func (p *pickerNGray8) At(x, y int) color.Color {
151	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
152	return psdColor.NGrayA{Y: p.Y[pos], A: 0xff}
153}
154
155type pickerNGrayA8 struct {
156	Rect image.Rectangle
157	Y, A []byte
158}
159
160func (p *pickerNGrayA8) setSource(rect image.Rectangle, src ...[]byte) {
161	p.Rect, p.Y, p.A = rect, src[0], src[1]
162}
163func (p *pickerNGrayA8) ColorModel() color.Model { return psdColor.NGrayAModel }
164func (p *pickerNGrayA8) Bounds() image.Rectangle { return p.Rect }
165func (p *pickerNGrayA8) At(x, y int) color.Color {
166	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
167	return psdColor.NGrayA{Y: p.Y[pos], A: p.A[pos]}
168}
169
170type pickerGray16 struct {
171	Rect image.Rectangle
172	Y    []byte
173}
174
175func (p *pickerGray16) setSource(rect image.Rectangle, src ...[]byte) { p.Rect, p.Y = rect, src[0] }
176func (p *pickerGray16) ColorModel() color.Model                       { return color.Gray16Model }
177func (p *pickerGray16) Bounds() image.Rectangle                       { return p.Rect }
178func (p *pickerGray16) At(x, y int) color.Color {
179	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
180	return color.Gray16{Y: readUint16(p.Y, pos)}
181}
182
183type pickerNGray16 struct {
184	Rect image.Rectangle
185	Y    []byte
186}
187
188func (p *pickerNGray16) setSource(rect image.Rectangle, src ...[]byte) {
189	p.Rect, p.Y = rect, src[0]
190}
191func (p *pickerNGray16) ColorModel() color.Model { return psdColor.NGrayA32Model }
192func (p *pickerNGray16) Bounds() image.Rectangle { return p.Rect }
193func (p *pickerNGray16) At(x, y int) color.Color {
194	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
195	return psdColor.NGrayA32{Y: readUint16(p.Y, pos), A: 0xffff}
196}
197
198type pickerNGrayA16 struct {
199	Rect image.Rectangle
200	Y, A []byte
201}
202
203func (p *pickerNGrayA16) setSource(rect image.Rectangle, src ...[]byte) {
204	p.Rect, p.Y, p.A = rect, src[0], src[1]
205}
206func (p *pickerNGrayA16) ColorModel() color.Model { return psdColor.NGrayA32Model }
207func (p *pickerNGrayA16) Bounds() image.Rectangle { return p.Rect }
208func (p *pickerNGrayA16) At(x, y int) color.Color {
209	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
210	return psdColor.NGrayA32{Y: readUint16(p.Y, pos), A: readUint16(p.A, pos)}
211}
212
213type pickerGray32 struct {
214	Rect image.Rectangle
215	Y    []byte
216}
217
218func (p *pickerGray32) setSource(rect image.Rectangle, src ...[]byte) { p.Rect, p.Y = rect, src[0] }
219func (p *pickerGray32) ColorModel() color.Model                       { return psdColor.Gray32Model }
220func (p *pickerGray32) Bounds() image.Rectangle                       { return p.Rect }
221func (p *pickerGray32) At(x, y int) color.Color {
222	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 2
223	return psdColor.Gray32{Y: readFloat32(p.Y, pos)}
224}
225
226type pickerNGray32 struct {
227	Rect image.Rectangle
228	Y    []byte
229}
230
231func (p *pickerNGray32) setSource(rect image.Rectangle, src ...[]byte) {
232	p.Rect, p.Y = rect, src[0]
233}
234func (p *pickerNGray32) ColorModel() color.Model { return psdColor.NGrayA64Model }
235func (p *pickerNGray32) Bounds() image.Rectangle { return p.Rect }
236func (p *pickerNGray32) At(x, y int) color.Color {
237	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 2
238	return psdColor.NGrayA64{Y: readFloat32(p.Y, pos), A: 1}
239}
240
241type pickerNGrayA32 struct {
242	Rect image.Rectangle
243	Y, A []byte
244}
245
246func (p *pickerNGrayA32) setSource(rect image.Rectangle, src ...[]byte) {
247	p.Rect, p.Y, p.A = rect, src[0], src[1]
248}
249func (p *pickerNGrayA32) ColorModel() color.Model { return psdColor.NGrayA64Model }
250func (p *pickerNGrayA32) Bounds() image.Rectangle { return p.Rect }
251func (p *pickerNGrayA32) At(x, y int) color.Color {
252	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 2
253	return psdColor.NGrayA64{
254		Y: readFloat32(p.Y, pos),
255		A: readFloat32(p.A, pos),
256	}
257}
258
259type pickerNRGB8 struct {
260	Rect    image.Rectangle
261	R, G, B []byte
262}
263
264func (p *pickerNRGB8) setSource(rect image.Rectangle, src ...[]byte) {
265	p.Rect, p.R, p.G, p.B = rect, src[0], src[1], src[2]
266}
267func (p *pickerNRGB8) ColorModel() color.Model { return color.NRGBAModel }
268func (p *pickerNRGB8) Bounds() image.Rectangle { return p.Rect }
269func (p *pickerNRGB8) At(x, y int) color.Color {
270	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
271	return color.NRGBA{
272		R: p.R[pos],
273		G: p.G[pos],
274		B: p.B[pos],
275		A: 0xff,
276	}
277}
278
279type pickerNRGBA8 struct {
280	Rect       image.Rectangle
281	R, G, B, A []byte
282}
283
284func (p *pickerNRGBA8) setSource(rect image.Rectangle, src ...[]byte) {
285	p.Rect, p.R, p.G, p.B, p.A = rect, src[0], src[1], src[2], src[3]
286}
287func (p *pickerNRGBA8) ColorModel() color.Model { return color.NRGBAModel }
288func (p *pickerNRGBA8) Bounds() image.Rectangle { return p.Rect }
289func (p *pickerNRGBA8) At(x, y int) color.Color {
290	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
291	return color.NRGBA{p.R[pos], p.G[pos], p.B[pos], p.A[pos]}
292}
293
294type pickerNRGB16 struct {
295	Rect    image.Rectangle
296	R, G, B []byte
297}
298
299func (p *pickerNRGB16) setSource(rect image.Rectangle, src ...[]byte) {
300	p.Rect, p.R, p.G, p.B = rect, src[0], src[1], src[2]
301}
302func (p *pickerNRGB16) ColorModel() color.Model { return color.NRGBA64Model }
303func (p *pickerNRGB16) Bounds() image.Rectangle { return p.Rect }
304func (p *pickerNRGB16) At(x, y int) color.Color {
305	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
306	return color.NRGBA64{
307		R: readUint16(p.R, pos),
308		G: readUint16(p.G, pos),
309		B: readUint16(p.B, pos),
310		A: 0xffff,
311	}
312}
313
314type pickerNRGBA16 struct {
315	Rect       image.Rectangle
316	R, G, B, A []byte
317}
318
319func (p *pickerNRGBA16) setSource(rect image.Rectangle, src ...[]byte) {
320	p.Rect, p.R, p.G, p.B, p.A = rect, src[0], src[1], src[2], src[3]
321}
322func (p *pickerNRGBA16) ColorModel() color.Model { return color.NRGBA64Model }
323func (p *pickerNRGBA16) Bounds() image.Rectangle { return p.Rect }
324func (p *pickerNRGBA16) At(x, y int) color.Color {
325	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
326	return color.NRGBA64{
327		R: readUint16(p.R, pos),
328		G: readUint16(p.G, pos),
329		B: readUint16(p.B, pos),
330		A: readUint16(p.A, pos),
331	}
332}
333
334type pickerNRGB32 struct {
335	Rect    image.Rectangle
336	R, G, B []byte
337}
338
339func (p *pickerNRGB32) setSource(rect image.Rectangle, src ...[]byte) {
340	p.Rect, p.R, p.G, p.B = rect, src[0], src[1], src[2]
341}
342func (p *pickerNRGB32) ColorModel() color.Model { return psdColor.NRGBA128Model }
343func (p *pickerNRGB32) Bounds() image.Rectangle { return p.Rect }
344func (p *pickerNRGB32) At(x, y int) color.Color {
345	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 2
346	return psdColor.NRGBA128{
347		R: readFloat32(p.R, pos),
348		G: readFloat32(p.G, pos),
349		B: readFloat32(p.B, pos),
350		A: 1.0,
351	}
352}
353
354type pickerNRGBA32 struct {
355	Rect       image.Rectangle
356	R, G, B, A []byte
357}
358
359func (p *pickerNRGBA32) setSource(rect image.Rectangle, src ...[]byte) {
360	p.Rect, p.R, p.G, p.B, p.A = rect, src[0], src[1], src[2], src[3]
361}
362func (p *pickerNRGBA32) ColorModel() color.Model { return psdColor.NRGBA128Model }
363func (p *pickerNRGBA32) Bounds() image.Rectangle { return p.Rect }
364func (p *pickerNRGBA32) At(x, y int) color.Color {
365	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 2
366	return psdColor.NRGBA128{
367		R: readFloat32(p.R, pos),
368		G: readFloat32(p.G, pos),
369		B: readFloat32(p.B, pos),
370		A: readFloat32(p.A, pos),
371	}
372}
373
374type pickerNCMYK8 struct {
375	Rect       image.Rectangle
376	C, M, Y, K []byte
377}
378
379func (p *pickerNCMYK8) setSource(rect image.Rectangle, src ...[]byte) {
380	p.Rect, p.C, p.M, p.Y, p.K = rect, src[0], src[1], src[2], src[3]
381}
382func (p *pickerNCMYK8) ColorModel() color.Model { return psdColor.NCMYKAModel }
383func (p *pickerNCMYK8) Bounds() image.Rectangle { return p.Rect }
384func (p *pickerNCMYK8) At(x, y int) color.Color {
385	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
386	return psdColor.NCMYKA{
387		C: p.C[pos],
388		M: p.M[pos],
389		Y: p.Y[pos],
390		K: p.K[pos],
391		A: 0xff,
392	}
393}
394
395type pickerNCMYKA8 struct {
396	Rect          image.Rectangle
397	C, M, Y, K, A []byte
398}
399
400func (p *pickerNCMYKA8) setSource(rect image.Rectangle, src ...[]byte) {
401	p.Rect, p.C, p.M, p.Y, p.K, p.A = rect, src[0], src[1], src[2], src[3], src[4]
402}
403func (p *pickerNCMYKA8) ColorModel() color.Model { return psdColor.NCMYKAModel }
404func (p *pickerNCMYKA8) Bounds() image.Rectangle { return p.Rect }
405func (p *pickerNCMYKA8) At(x, y int) color.Color {
406	pos := (y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X
407	return psdColor.NCMYKA{
408		C: p.C[pos],
409		M: p.M[pos],
410		Y: p.Y[pos],
411		K: p.K[pos],
412		A: p.A[pos],
413	}
414}
415
416type pickerNCMYK16 struct {
417	Rect       image.Rectangle
418	C, M, Y, K []byte
419}
420
421func (p *pickerNCMYK16) setSource(rect image.Rectangle, src ...[]byte) {
422	p.Rect, p.C, p.M, p.Y, p.K = rect, src[0], src[1], src[2], src[3]
423}
424func (p *pickerNCMYK16) ColorModel() color.Model { return psdColor.NCMYKA80Model }
425func (p *pickerNCMYK16) Bounds() image.Rectangle { return p.Rect }
426func (p *pickerNCMYK16) At(x, y int) color.Color {
427	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
428	return psdColor.NCMYKA80{
429		C: readUint16(p.C, pos),
430		M: readUint16(p.M, pos),
431		Y: readUint16(p.Y, pos),
432		K: readUint16(p.K, pos),
433		A: 0xffff,
434	}
435}
436
437type pickerNCMYKA16 struct {
438	Rect          image.Rectangle
439	C, M, Y, K, A []byte
440}
441
442func (p *pickerNCMYKA16) setSource(rect image.Rectangle, src ...[]byte) {
443	p.Rect, p.C, p.M, p.Y, p.K, p.A = rect, src[0], src[1], src[2], src[3], src[4]
444}
445func (p *pickerNCMYKA16) ColorModel() color.Model { return psdColor.NCMYKA80Model }
446func (p *pickerNCMYKA16) Bounds() image.Rectangle { return p.Rect }
447func (p *pickerNCMYKA16) At(x, y int) color.Color {
448	pos := ((y-p.Rect.Min.Y)*p.Rect.Dx() + x - p.Rect.Min.X) << 1
449	return psdColor.NCMYKA80{
450		C: readUint16(p.C, pos),
451		M: readUint16(p.M, pos),
452		Y: readUint16(p.Y, pos),
453		K: readUint16(p.K, pos),
454		A: readUint16(p.A, pos),
455	}
456}
457