1
2
3
4
5
6
7
8
9 package draw
10
11 import (
12 "image"
13 "image/color"
14 "image/internal/imageutil"
15 )
16
17
18 const m = 1<<16 - 1
19
20
21 type Image interface {
22 image.Image
23 Set(x, y int, c color.Color)
24 }
25
26
27
28
29
30 type RGBA64Image interface {
31 image.RGBA64Image
32 Set(x, y int, c color.Color)
33 SetRGBA64(x, y int, c color.RGBA64)
34 }
35
36
37 type Quantizer interface {
38
39
40 Quantize(p color.Palette, m image.Image) color.Palette
41 }
42
43
44 type Op int
45
46 const (
47
48 Over Op = iota
49
50 Src
51 )
52
53
54
55 func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
56 DrawMask(dst, r, src, sp, nil, image.Point{}, op)
57 }
58
59
60 type Drawer interface {
61
62
63 Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
64 }
65
66
67
68 var FloydSteinberg Drawer = floydSteinberg{}
69
70 type floydSteinberg struct{}
71
72 func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
73 clip(dst, &r, src, &sp, nil, nil)
74 if r.Empty() {
75 return
76 }
77 drawPaletted(dst, r, src, sp, true)
78 }
79
80
81
82
83 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
84 orig := r.Min
85 *r = r.Intersect(dst.Bounds())
86 *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
87 if mask != nil {
88 *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
89 }
90 dx := r.Min.X - orig.X
91 dy := r.Min.Y - orig.Y
92 if dx == 0 && dy == 0 {
93 return
94 }
95 sp.X += dx
96 sp.Y += dy
97 if mp != nil {
98 mp.X += dx
99 mp.Y += dy
100 }
101 }
102
103 func processBackward(dst image.Image, r image.Rectangle, src image.Image, sp image.Point) bool {
104 return dst == src &&
105 r.Overlaps(r.Add(sp.Sub(r.Min))) &&
106 (sp.Y < r.Min.Y || (sp.Y == r.Min.Y && sp.X < r.Min.X))
107 }
108
109
110 func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
111 DrawMask(dst, r, src, sp, nil, image.Point{}, op)
112 }
113
114
115
116 func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
117 clip(dst, &r, src, &sp, mask, &mp)
118 if r.Empty() {
119 return
120 }
121
122
123 switch dst0 := dst.(type) {
124 case *image.RGBA:
125 if op == Over {
126 if mask == nil {
127 switch src0 := src.(type) {
128 case *image.Uniform:
129 sr, sg, sb, sa := src0.RGBA()
130 if sa == 0xffff {
131 drawFillSrc(dst0, r, sr, sg, sb, sa)
132 } else {
133 drawFillOver(dst0, r, sr, sg, sb, sa)
134 }
135 return
136 case *image.RGBA:
137 drawCopyOver(dst0, r, src0, sp)
138 return
139 case *image.NRGBA:
140 drawNRGBAOver(dst0, r, src0, sp)
141 return
142 case *image.YCbCr:
143
144
145
146
147 if imageutil.DrawYCbCr(dst0, r, src0, sp) {
148 return
149 }
150 case *image.Gray:
151 drawGray(dst0, r, src0, sp)
152 return
153 case *image.CMYK:
154 drawCMYK(dst0, r, src0, sp)
155 return
156 }
157 } else if mask0, ok := mask.(*image.Alpha); ok {
158 switch src0 := src.(type) {
159 case *image.Uniform:
160 drawGlyphOver(dst0, r, src0, mask0, mp)
161 return
162 }
163 }
164 } else {
165 if mask == nil {
166 switch src0 := src.(type) {
167 case *image.Uniform:
168 sr, sg, sb, sa := src0.RGBA()
169 drawFillSrc(dst0, r, sr, sg, sb, sa)
170 return
171 case *image.RGBA:
172 drawCopySrc(dst0, r, src0, sp)
173 return
174 case *image.NRGBA:
175 drawNRGBASrc(dst0, r, src0, sp)
176 return
177 case *image.YCbCr:
178 if imageutil.DrawYCbCr(dst0, r, src0, sp) {
179 return
180 }
181 case *image.Gray:
182 drawGray(dst0, r, src0, sp)
183 return
184 case *image.CMYK:
185 drawCMYK(dst0, r, src0, sp)
186 return
187 }
188 }
189 }
190 drawRGBA(dst0, r, src, sp, mask, mp, op)
191 return
192 case *image.Paletted:
193 if op == Src && mask == nil {
194 if src0, ok := src.(*image.Uniform); ok {
195 colorIndex := uint8(dst0.Palette.Index(src0.C))
196 i0 := dst0.PixOffset(r.Min.X, r.Min.Y)
197 i1 := i0 + r.Dx()
198 for i := i0; i < i1; i++ {
199 dst0.Pix[i] = colorIndex
200 }
201 firstRow := dst0.Pix[i0:i1]
202 for y := r.Min.Y + 1; y < r.Max.Y; y++ {
203 i0 += dst0.Stride
204 i1 += dst0.Stride
205 copy(dst0.Pix[i0:i1], firstRow)
206 }
207 return
208 } else if !processBackward(dst, r, src, sp) {
209 drawPaletted(dst0, r, src, sp, false)
210 return
211 }
212 }
213 }
214
215 x0, x1, dx := r.Min.X, r.Max.X, 1
216 y0, y1, dy := r.Min.Y, r.Max.Y, 1
217 if processBackward(dst, r, src, sp) {
218 x0, x1, dx = x1-1, x0-1, -1
219 y0, y1, dy = y1-1, y0-1, -1
220 }
221
222 var out color.RGBA64
223 sy := sp.Y + y0 - r.Min.Y
224 my := mp.Y + y0 - r.Min.Y
225 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
226 sx := sp.X + x0 - r.Min.X
227 mx := mp.X + x0 - r.Min.X
228 for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
229 ma := uint32(m)
230 if mask != nil {
231 _, _, _, ma = mask.At(mx, my).RGBA()
232 }
233 switch {
234 case ma == 0:
235 if op == Over {
236
237 } else {
238 dst.Set(x, y, color.Transparent)
239 }
240 case ma == m && op == Src:
241 dst.Set(x, y, src.At(sx, sy))
242 default:
243 sr, sg, sb, sa := src.At(sx, sy).RGBA()
244 if op == Over {
245 dr, dg, db, da := dst.At(x, y).RGBA()
246 a := m - (sa * ma / m)
247 out.R = uint16((dr*a + sr*ma) / m)
248 out.G = uint16((dg*a + sg*ma) / m)
249 out.B = uint16((db*a + sb*ma) / m)
250 out.A = uint16((da*a + sa*ma) / m)
251 } else {
252 out.R = uint16(sr * ma / m)
253 out.G = uint16(sg * ma / m)
254 out.B = uint16(sb * ma / m)
255 out.A = uint16(sa * ma / m)
256 }
257
258
259
260
261 dst.Set(x, y, &out)
262 }
263 }
264 }
265 }
266
267 func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
268
269 a := (m - sa) * 0x101
270 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
271 i1 := i0 + r.Dx()*4
272 for y := r.Min.Y; y != r.Max.Y; y++ {
273 for i := i0; i < i1; i += 4 {
274 dr := &dst.Pix[i+0]
275 dg := &dst.Pix[i+1]
276 db := &dst.Pix[i+2]
277 da := &dst.Pix[i+3]
278
279 *dr = uint8((uint32(*dr)*a/m + sr) >> 8)
280 *dg = uint8((uint32(*dg)*a/m + sg) >> 8)
281 *db = uint8((uint32(*db)*a/m + sb) >> 8)
282 *da = uint8((uint32(*da)*a/m + sa) >> 8)
283 }
284 i0 += dst.Stride
285 i1 += dst.Stride
286 }
287 }
288
289 func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
290 sr8 := uint8(sr >> 8)
291 sg8 := uint8(sg >> 8)
292 sb8 := uint8(sb >> 8)
293 sa8 := uint8(sa >> 8)
294
295
296
297 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
298 i1 := i0 + r.Dx()*4
299 for i := i0; i < i1; i += 4 {
300 dst.Pix[i+0] = sr8
301 dst.Pix[i+1] = sg8
302 dst.Pix[i+2] = sb8
303 dst.Pix[i+3] = sa8
304 }
305 firstRow := dst.Pix[i0:i1]
306 for y := r.Min.Y + 1; y < r.Max.Y; y++ {
307 i0 += dst.Stride
308 i1 += dst.Stride
309 copy(dst.Pix[i0:i1], firstRow)
310 }
311 }
312
313 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
314 dx, dy := r.Dx(), r.Dy()
315 d0 := dst.PixOffset(r.Min.X, r.Min.Y)
316 s0 := src.PixOffset(sp.X, sp.Y)
317 var (
318 ddelta, sdelta int
319 i0, i1, idelta int
320 )
321 if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
322 ddelta = dst.Stride
323 sdelta = src.Stride
324 i0, i1, idelta = 0, dx*4, +4
325 } else {
326
327
328 d0 += (dy - 1) * dst.Stride
329 s0 += (dy - 1) * src.Stride
330 ddelta = -dst.Stride
331 sdelta = -src.Stride
332 i0, i1, idelta = (dx-1)*4, -4, -4
333 }
334 for ; dy > 0; dy-- {
335 dpix := dst.Pix[d0:]
336 spix := src.Pix[s0:]
337 for i := i0; i != i1; i += idelta {
338 s := spix[i : i+4 : i+4]
339 sr := uint32(s[0]) * 0x101
340 sg := uint32(s[1]) * 0x101
341 sb := uint32(s[2]) * 0x101
342 sa := uint32(s[3]) * 0x101
343
344
345 a := (m - sa) * 0x101
346
347 d := dpix[i : i+4 : i+4]
348 d[0] = uint8((uint32(d[0])*a/m + sr) >> 8)
349 d[1] = uint8((uint32(d[1])*a/m + sg) >> 8)
350 d[2] = uint8((uint32(d[2])*a/m + sb) >> 8)
351 d[3] = uint8((uint32(d[3])*a/m + sa) >> 8)
352 }
353 d0 += ddelta
354 s0 += sdelta
355 }
356 }
357
358 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
359 n, dy := 4*r.Dx(), r.Dy()
360 d0 := dst.PixOffset(r.Min.X, r.Min.Y)
361 s0 := src.PixOffset(sp.X, sp.Y)
362 var ddelta, sdelta int
363 if r.Min.Y <= sp.Y {
364 ddelta = dst.Stride
365 sdelta = src.Stride
366 } else {
367
368
369
370
371
372 d0 += (dy - 1) * dst.Stride
373 s0 += (dy - 1) * src.Stride
374 ddelta = -dst.Stride
375 sdelta = -src.Stride
376 }
377 for ; dy > 0; dy-- {
378 copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
379 d0 += ddelta
380 s0 += sdelta
381 }
382 }
383
384 func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
385 i0 := (r.Min.X - dst.Rect.Min.X) * 4
386 i1 := (r.Max.X - dst.Rect.Min.X) * 4
387 si0 := (sp.X - src.Rect.Min.X) * 4
388 yMax := r.Max.Y - dst.Rect.Min.Y
389
390 y := r.Min.Y - dst.Rect.Min.Y
391 sy := sp.Y - src.Rect.Min.Y
392 for ; y != yMax; y, sy = y+1, sy+1 {
393 dpix := dst.Pix[y*dst.Stride:]
394 spix := src.Pix[sy*src.Stride:]
395
396 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
397
398 s := spix[si : si+4 : si+4]
399 sa := uint32(s[3]) * 0x101
400 sr := uint32(s[0]) * sa / 0xff
401 sg := uint32(s[1]) * sa / 0xff
402 sb := uint32(s[2]) * sa / 0xff
403
404 d := dpix[i : i+4 : i+4]
405 dr := uint32(d[0])
406 dg := uint32(d[1])
407 db := uint32(d[2])
408 da := uint32(d[3])
409
410
411 a := (m - sa) * 0x101
412
413 d[0] = uint8((dr*a/m + sr) >> 8)
414 d[1] = uint8((dg*a/m + sg) >> 8)
415 d[2] = uint8((db*a/m + sb) >> 8)
416 d[3] = uint8((da*a/m + sa) >> 8)
417 }
418 }
419 }
420
421 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
422 i0 := (r.Min.X - dst.Rect.Min.X) * 4
423 i1 := (r.Max.X - dst.Rect.Min.X) * 4
424 si0 := (sp.X - src.Rect.Min.X) * 4
425 yMax := r.Max.Y - dst.Rect.Min.Y
426
427 y := r.Min.Y - dst.Rect.Min.Y
428 sy := sp.Y - src.Rect.Min.Y
429 for ; y != yMax; y, sy = y+1, sy+1 {
430 dpix := dst.Pix[y*dst.Stride:]
431 spix := src.Pix[sy*src.Stride:]
432
433 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
434
435 s := spix[si : si+4 : si+4]
436 sa := uint32(s[3]) * 0x101
437 sr := uint32(s[0]) * sa / 0xff
438 sg := uint32(s[1]) * sa / 0xff
439 sb := uint32(s[2]) * sa / 0xff
440
441 d := dpix[i : i+4 : i+4]
442 d[0] = uint8(sr >> 8)
443 d[1] = uint8(sg >> 8)
444 d[2] = uint8(sb >> 8)
445 d[3] = uint8(sa >> 8)
446 }
447 }
448 }
449
450 func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
451 i0 := (r.Min.X - dst.Rect.Min.X) * 4
452 i1 := (r.Max.X - dst.Rect.Min.X) * 4
453 si0 := (sp.X - src.Rect.Min.X) * 1
454 yMax := r.Max.Y - dst.Rect.Min.Y
455
456 y := r.Min.Y - dst.Rect.Min.Y
457 sy := sp.Y - src.Rect.Min.Y
458 for ; y != yMax; y, sy = y+1, sy+1 {
459 dpix := dst.Pix[y*dst.Stride:]
460 spix := src.Pix[sy*src.Stride:]
461
462 for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
463 p := spix[si]
464 d := dpix[i : i+4 : i+4]
465 d[0] = p
466 d[1] = p
467 d[2] = p
468 d[3] = 255
469 }
470 }
471 }
472
473 func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
474 i0 := (r.Min.X - dst.Rect.Min.X) * 4
475 i1 := (r.Max.X - dst.Rect.Min.X) * 4
476 si0 := (sp.X - src.Rect.Min.X) * 4
477 yMax := r.Max.Y - dst.Rect.Min.Y
478
479 y := r.Min.Y - dst.Rect.Min.Y
480 sy := sp.Y - src.Rect.Min.Y
481 for ; y != yMax; y, sy = y+1, sy+1 {
482 dpix := dst.Pix[y*dst.Stride:]
483 spix := src.Pix[sy*src.Stride:]
484
485 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
486 s := spix[si : si+4 : si+4]
487 d := dpix[i : i+4 : i+4]
488 d[0], d[1], d[2] = color.CMYKToRGB(s[0], s[1], s[2], s[3])
489 d[3] = 255
490 }
491 }
492 }
493
494 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
495 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
496 i1 := i0 + r.Dx()*4
497 mi0 := mask.PixOffset(mp.X, mp.Y)
498 sr, sg, sb, sa := src.RGBA()
499 for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
500 for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
501 ma := uint32(mask.Pix[mi])
502 if ma == 0 {
503 continue
504 }
505 ma |= ma << 8
506
507
508 a := (m - (sa * ma / m)) * 0x101
509
510 d := dst.Pix[i : i+4 : i+4]
511 d[0] = uint8((uint32(d[0])*a + sr*ma) / m >> 8)
512 d[1] = uint8((uint32(d[1])*a + sg*ma) / m >> 8)
513 d[2] = uint8((uint32(d[2])*a + sb*ma) / m >> 8)
514 d[3] = uint8((uint32(d[3])*a + sa*ma) / m >> 8)
515 }
516 i0 += dst.Stride
517 i1 += dst.Stride
518 mi0 += mask.Stride
519 }
520 }
521
522 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
523 x0, x1, dx := r.Min.X, r.Max.X, 1
524 y0, y1, dy := r.Min.Y, r.Max.Y, 1
525 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
526 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
527 x0, x1, dx = x1-1, x0-1, -1
528 y0, y1, dy = y1-1, y0-1, -1
529 }
530 }
531
532 sy := sp.Y + y0 - r.Min.Y
533 my := mp.Y + y0 - r.Min.Y
534 sx0 := sp.X + x0 - r.Min.X
535 mx0 := mp.X + x0 - r.Min.X
536 sx1 := sx0 + (x1 - x0)
537 i0 := dst.PixOffset(x0, y0)
538 di := dx * 4
539 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
540 for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
541 ma := uint32(m)
542 if mask != nil {
543 _, _, _, ma = mask.At(mx, my).RGBA()
544 }
545 sr, sg, sb, sa := src.At(sx, sy).RGBA()
546 d := dst.Pix[i : i+4 : i+4]
547 if op == Over {
548 dr := uint32(d[0])
549 dg := uint32(d[1])
550 db := uint32(d[2])
551 da := uint32(d[3])
552
553
554
555
556
557
558
559 a := (m - (sa * ma / m)) * 0x101
560
561 d[0] = uint8((dr*a + sr*ma) / m >> 8)
562 d[1] = uint8((dg*a + sg*ma) / m >> 8)
563 d[2] = uint8((db*a + sb*ma) / m >> 8)
564 d[3] = uint8((da*a + sa*ma) / m >> 8)
565
566 } else {
567 d[0] = uint8(sr * ma / m >> 8)
568 d[1] = uint8(sg * ma / m >> 8)
569 d[2] = uint8(sb * ma / m >> 8)
570 d[3] = uint8(sa * ma / m >> 8)
571 }
572 }
573 i0 += dy * dst.Stride
574 }
575 }
576
577
578 func clamp(i int32) int32 {
579 if i < 0 {
580 return 0
581 }
582 if i > 0xffff {
583 return 0xffff
584 }
585 return i
586 }
587
588
589
590
591
592 func sqDiff(x, y int32) uint32 {
593
594
595
596 d := uint32(x - y)
597 return (d * d) >> 2
598 }
599
600 func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
601
602
603
604
605
606
607
608
609 palette, pix, stride := [][4]int32(nil), []byte(nil), 0
610 if p, ok := dst.(*image.Paletted); ok {
611 palette = make([][4]int32, len(p.Palette))
612 for i, col := range p.Palette {
613 r, g, b, a := col.RGBA()
614 palette[i][0] = int32(r)
615 palette[i][1] = int32(g)
616 palette[i][2] = int32(b)
617 palette[i][3] = int32(a)
618 }
619 pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
620 }
621
622
623
624
625 var quantErrorCurr, quantErrorNext [][4]int32
626 if floydSteinberg {
627 quantErrorCurr = make([][4]int32, r.Dx()+2)
628 quantErrorNext = make([][4]int32, r.Dx()+2)
629 }
630 pxRGBA := func(x, y int) (r, g, b, a uint32) { return src.At(x, y).RGBA() }
631
632
633
634 switch src0 := src.(type) {
635 case *image.RGBA:
636 pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.RGBAAt(x, y).RGBA() }
637 case *image.NRGBA:
638 pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.NRGBAAt(x, y).RGBA() }
639 case *image.YCbCr:
640 pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.YCbCrAt(x, y).RGBA() }
641 }
642
643
644 out := color.RGBA64{A: 0xffff}
645 for y := 0; y != r.Dy(); y++ {
646 for x := 0; x != r.Dx(); x++ {
647
648
649 sr, sg, sb, sa := pxRGBA(sp.X+x, sp.Y+y)
650 er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
651 if floydSteinberg {
652 er = clamp(er + quantErrorCurr[x+1][0]/16)
653 eg = clamp(eg + quantErrorCurr[x+1][1]/16)
654 eb = clamp(eb + quantErrorCurr[x+1][2]/16)
655 ea = clamp(ea + quantErrorCurr[x+1][3]/16)
656 }
657
658 if palette != nil {
659
660
661
662 bestIndex, bestSum := 0, uint32(1<<32-1)
663 for index, p := range palette {
664 sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
665 if sum < bestSum {
666 bestIndex, bestSum = index, sum
667 if sum == 0 {
668 break
669 }
670 }
671 }
672 pix[y*stride+x] = byte(bestIndex)
673
674 if !floydSteinberg {
675 continue
676 }
677 er -= palette[bestIndex][0]
678 eg -= palette[bestIndex][1]
679 eb -= palette[bestIndex][2]
680 ea -= palette[bestIndex][3]
681
682 } else {
683 out.R = uint16(er)
684 out.G = uint16(eg)
685 out.B = uint16(eb)
686 out.A = uint16(ea)
687
688
689
690
691 dst.Set(r.Min.X+x, r.Min.Y+y, &out)
692
693 if !floydSteinberg {
694 continue
695 }
696 sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
697 er -= int32(sr)
698 eg -= int32(sg)
699 eb -= int32(sb)
700 ea -= int32(sa)
701 }
702
703
704 quantErrorNext[x+0][0] += er * 3
705 quantErrorNext[x+0][1] += eg * 3
706 quantErrorNext[x+0][2] += eb * 3
707 quantErrorNext[x+0][3] += ea * 3
708 quantErrorNext[x+1][0] += er * 5
709 quantErrorNext[x+1][1] += eg * 5
710 quantErrorNext[x+1][2] += eb * 5
711 quantErrorNext[x+1][3] += ea * 5
712 quantErrorNext[x+2][0] += er * 1
713 quantErrorNext[x+2][1] += eg * 1
714 quantErrorNext[x+2][2] += eb * 1
715 quantErrorNext[x+2][3] += ea * 1
716 quantErrorCurr[x+2][0] += er * 7
717 quantErrorCurr[x+2][1] += eg * 7
718 quantErrorCurr[x+2][2] += eb * 7
719 quantErrorCurr[x+2][3] += ea * 7
720 }
721
722
723 if floydSteinberg {
724 quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
725 for i := range quantErrorNext {
726 quantErrorNext[i] = [4]int32{}
727 }
728 }
729 }
730 }
731
View as plain text