9fans.net/go@v0.0.5/draw/draw.go (about) 1 package draw // import "9fans.net/go/draw" 2 3 // An Op represents a Porter-Duff compositing operator. 4 // 5 // See T. Porter, T. Duff. “Compositing Digital Images”, 6 // Computer Graphics (Proc. SIGGRAPH), 18:3, pp. 253-259, 1984. 7 type Op int 8 9 const ( 10 Clear Op = 0 11 12 SinD Op = 8 13 DinS Op = 4 14 SoutD Op = 2 15 DoutS Op = 1 16 17 S = SinD | SoutD 18 SoverD = SinD | SoutD | DoutS 19 SatopD = SinD | DoutS 20 SxorD = SoutD | DoutS 21 22 D = DinS | DoutS 23 DoverS = DinS | DoutS | SoutD 24 DatopS = DinS | SoutD 25 DxorS = DoutS | SoutD // == SxorD 26 27 Ncomp = 12 28 ) 29 30 func setdrawop(d *Display, op Op) { 31 if op != SoverD { 32 a := d.bufimage(2) 33 a[0] = 'O' 34 a[1] = byte(op) 35 } 36 } 37 38 func draw(dst *Image, r Rectangle, src *Image, p0 Point, mask *Image, p1 Point, op Op) { 39 setdrawop(dst.Display, op) 40 41 a := dst.Display.bufimage(1 + 4 + 4 + 4 + 4*4 + 2*4 + 2*4) 42 if src == nil { 43 src = dst.Display.Black 44 } 45 if mask == nil { 46 mask = dst.Display.Opaque 47 } 48 a[0] = 'd' 49 bplong(a[1:], dst.id) 50 bplong(a[5:], src.id) 51 bplong(a[9:], mask.id) 52 bplong(a[13:], uint32(r.Min.X)) 53 bplong(a[17:], uint32(r.Min.Y)) 54 bplong(a[21:], uint32(r.Max.X)) 55 bplong(a[25:], uint32(r.Max.Y)) 56 bplong(a[29:], uint32(p0.X)) 57 bplong(a[33:], uint32(p0.Y)) 58 bplong(a[37:], uint32(p1.X)) 59 bplong(a[41:], uint32(p1.Y)) 60 } 61 62 func (dst *Image) draw(r Rectangle, src, mask *Image, p1 Point) { 63 draw(dst, r, src, p1, mask, p1, SoverD) 64 } 65 66 // Draw is the standard drawing function. Only those pixels within the 67 // intersection of dst.R and dst.Clipr will be affected; draw ignores 68 // dst.Repl. The operation proceeds as follows (this is a description of 69 // the behavior, not the implementation): 70 // 71 // 1. If Repl is set in src or mask, replicate their contents to fill 72 // their clip rectangles. 73 // 74 // 2. Translate src and mask so p is aligned with r.Min. 75 // 76 // 3. Set r to the intersection of r and dst.R. 77 // 78 // 4. Intersect r with src.Clipr. If src.Repl is false, also intersect r 79 // with src.R. 80 // 81 // 5. Intersect r with mask.Clipr. If mask.Repl is false, also intersect 82 // r with mask.R 83 // 84 // 6. For each location in r, combine the dst pixel with the src pixel 85 // using the alpha value corresponding to the mask pixel. If the mask has 86 // an explicit alpha channel, the alpha value corresponding to the mask 87 // pixel is simply that pixel's alpha chan- nel. Otherwise, the alpha 88 // value is the NTSC greyscale equivalent of the color value, with white 89 // meaning opaque and black transparent. In terms of the Porter-Duff 90 // compositing algebra, draw replaces the dst pixels with (src in mask) 91 // over dst. (In the extended form provided by DrawOp, “over” is replaced 92 // by op). 93 // 94 // The various pixel channel formats involved need not be identical. 95 // If the channels involved are smaller than 8-bits, they will be 96 // promoted before the calculation by replicating the extant bits; after 97 // the calculation, they will be truncated to their proper sizes. 98 // 99 // Mask may be nil, in which case a fully opaque mask is assumed. 100 func (dst *Image) Draw(r Rectangle, src, mask *Image, p Point) { 101 dst.Display.mu.Lock() 102 defer dst.Display.mu.Unlock() 103 draw(dst, r, src, p, mask, p, SoverD) 104 } 105 106 // DrawOp is like Draw but specifies a Porter-Duff operator op to use in place of “S over D”. 107 // That is, dst.Draw(r, src, mask, p) is the same as dst.DrawOp(r, src, mask, p, SoverD). 108 func (dst *Image) DrawOp(r Rectangle, src, mask *Image, p Point, op Op) { 109 dst.Display.mu.Lock() 110 defer dst.Display.mu.Unlock() 111 draw(dst, r, src, p, mask, p, op) 112 } 113 114 // GenDraw is like Draw except that it aligns the source and mask differently: 115 // src is aligned so p0 corresponds to r.Min, while mask is aligned so p1 corresponds to r.Min. 116 // GenDraw differs from Draw only when both of src or mask are non-trivial. 117 // For most purposes, Draw is sufficient. 118 func (dst *Image) GenDraw(r Rectangle, src *Image, p0 Point, mask *Image, p1 Point) { 119 dst.Display.mu.Lock() 120 defer dst.Display.mu.Unlock() 121 draw(dst, r, src, p0, mask, p1, SoverD) 122 } 123 124 // GenDrawOp is like GenDraw but specifies a Porter-Duff operator op to use in place of “S over D”. 125 func GenDrawOp(dst *Image, r Rectangle, src *Image, p0 Point, mask *Image, p1 Point, op Op) { 126 dst.Display.mu.Lock() 127 defer dst.Display.mu.Unlock() 128 draw(dst, r, src, p0, mask, p1, op) 129 }