return
}
p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
- for x, dx := 0, b.Dx(); x < dx; {
+ for x, dx := 0, 4*b.Dx(); x < dx; {
nx := dx - x
- if nx > len(c.flushBuf1)/4 {
- nx = len(c.flushBuf1) / 4
+ if nx > len(c.flushBuf1) {
+ nx = len(c.flushBuf1) &^ 3
}
- for i, rgba := range p[x : x+nx] {
- c.flushBuf1[4*i+0] = rgba.B
- c.flushBuf1[4*i+1] = rgba.G
- c.flushBuf1[4*i+2] = rgba.R
+ for i := 0; i < nx; i += 4 {
+ // X11's order is BGRX, not RGBA.
+ c.flushBuf1[i+0] = p[x+i+2]
+ c.flushBuf1[i+1] = p[x+i+1]
+ c.flushBuf1[i+2] = p[x+i+0]
}
x += nx
- if _, err := c.w.Write(c.flushBuf1[:4*nx]); err != nil {
+ if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
if err != os.EOF {
log.Println("x11:", err.String())
}
if err != nil {
return nil, err
}
- p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width]
- for x := range p {
+ p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
+ for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
// BMP images are stored in BGR order rather than RGB order.
- p[x] = image.RGBAColor{b[3*x+2], b[3*x+1], b[3*x+0], 0xFF}
+ p[i+0] = b[j+2]
+ p[i+1] = b[j+1]
+ p[i+2] = b[j+0]
+ p[i+3] = 0xFF
}
}
return rgba, nil
package image
-// All Colors can convert themselves, with a possible loss of precision,
-// to 64-bit alpha-premultiplied RGBA. Each channel value ranges within
-// [0, 0xFFFF].
+// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
+// of precision. Each value ranges within [0, 0xFFFF], but is represented by a
+// uint32 so that multiplying by a blend factor up to 0xFFFF will not overflow.
type Color interface {
RGBA() (r, g, b, a uint32)
}
-// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
// having 8 bits for each of red, green, blue and alpha.
type RGBAColor struct {
R, G, B, A uint8
return
}
-// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// RGBA64Color represents a 64-bit alpha-premultiplied color,
// having 16 bits for each of red, green, blue and alpha.
type RGBA64Color struct {
R, G, B, A uint16
return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
}
-// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
type NRGBAColor struct {
R, G, B, A uint8
}
return
}
-// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
// having 16 bits for each of red, green, blue and alpha.
type NRGBA64Color struct {
R, G, B, A uint16
return
}
-// An AlphaColor represents an 8-bit alpha.
+// AlphaColor represents an 8-bit alpha.
type AlphaColor struct {
A uint8
}
return a, a, a, a
}
-// An Alpha16Color represents a 16-bit alpha.
+// Alpha16Color represents a 16-bit alpha.
type Alpha16Color struct {
A uint16
}
return a, a, a, a
}
-// A GrayColor represents an 8-bit grayscale color.
+// GrayColor represents an 8-bit grayscale color.
type GrayColor struct {
Y uint8
}
return y, y, y, 0xffff
}
-// A Gray16Color represents a 16-bit grayscale color.
+// Gray16Color represents a 16-bit grayscale color.
type Gray16Color struct {
Y uint16
}
return y, y, y, 0xffff
}
-// A ColorModel can convert foreign Colors, with a possible loss of precision,
+// ColorModel can convert foreign Colors, with a possible loss of precision,
// to a Color from its own color model.
type ColorModel interface {
Convert(c Color) Color
}
func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
- cr, cg, cb, ca := src.RGBA()
+ sr, sg, sb, sa := src.RGBA()
// The 0x101 is here for the same reason as in drawRGBA.
- a := (m - ca) * 0x101
- i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
- i1 := i0 + r.Dx()
+ a := (m - sa) * 0x101
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
for y := r.Min.Y; y != r.Max.Y; y++ {
- dpix := dst.Pix[i0:i1]
- for i, rgba := range dpix {
- dr := (uint32(rgba.R)*a)/m + cr
- dg := (uint32(rgba.G)*a)/m + cg
- db := (uint32(rgba.B)*a)/m + cb
- da := (uint32(rgba.A)*a)/m + ca
- dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ for i := i0; i < i1; i += 4 {
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
+ dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
}
i0 += dst.Stride
i1 += dst.Stride
func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
dx, dy := r.Dx(), r.Dy()
- d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
- s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + sp.X - src.Rect.Min.X
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
var (
ddelta, sdelta int
i0, i1, idelta int
if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
ddelta = dst.Stride
sdelta = src.Stride
- i0, i1, idelta = 0, dx, +1
+ i0, i1, idelta = 0, dx*4, +4
} else {
// If the source start point is higher than the destination start point, or equal height but to the left,
// then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
s0 += (dy - 1) * src.Stride
ddelta = -dst.Stride
sdelta = -src.Stride
- i0, i1, idelta = dx-1, -1, -1
+ i0, i1, idelta = (dx-1)*4, -4, -4
}
for ; dy > 0; dy-- {
dpix := dst.Pix[d0:]
spix := src.Pix[s0:]
for i := i0; i != i1; i += idelta {
- // For unknown reasons, even though both dpix[i] and spix[i] are
- // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
- // for the source but to do it manually for the destination.
- sr, sg, sb, sa := spix[i].RGBA()
- rgba := dpix[i]
- dr := uint32(rgba.R)
- dg := uint32(rgba.G)
- db := uint32(rgba.B)
- da := uint32(rgba.A)
+ sr := uint32(spix[i+0]) * 0x101
+ sg := uint32(spix[i+1]) * 0x101
+ sb := uint32(spix[i+2]) * 0x101
+ sa := uint32(spix[i+3]) * 0x101
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
- dr = (dr*a)/m + sr
- dg = (dg*a)/m + sg
- db = (db*a)/m + sb
- da = (da*a)/m + sa
- dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
}
d0 += ddelta
s0 += sdelta
}
func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
- xMax := r.Max.X - dst.Rect.Min.X
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
yMax := r.Max.Y - dst.Rect.Min.Y
y := r.Min.Y - dst.Rect.Min.Y
dpix := dst.Pix[y*dst.Stride:]
spix := src.Pix[sy*src.Stride:]
- x := r.Min.X - dst.Rect.Min.X
- sx := sp.X - src.Rect.Min.X
- for ; x != xMax; x, sx = x+1, sx+1 {
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
// Convert from non-premultiplied color to pre-multiplied color.
- // The order of operations here is to match the NRGBAColor.RGBA
- // method in image/color.go.
- snrgba := spix[sx]
- sa := uint32(snrgba.A)
- sr := uint32(snrgba.R) * 0x101 * sa / 0xff
- sg := uint32(snrgba.G) * 0x101 * sa / 0xff
- sb := uint32(snrgba.B) * 0x101 * sa / 0xff
- sa *= 0x101
-
- rgba := dpix[x]
- dr := uint32(rgba.R)
- dg := uint32(rgba.G)
- db := uint32(rgba.B)
- da := uint32(rgba.A)
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
- dr = (dr*a + sr*m) / m
- dg = (dg*a + sg*m) / m
- db = (db*a + sb*m) / m
- da = (da*a + sa*m) / m
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
}
}
}
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
- i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
- i1 := i0 + r.Dx()
- j0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
- cr, cg, cb, ca := src.RGBA()
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+ sr, sg, sb, sa := src.RGBA()
for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
- dpix := dst.Pix[i0:i1]
- mpix := mask.Pix[j0:]
- for i, rgba := range dpix {
- ma := uint32(mpix[i].A)
+ for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
+ ma := uint32(mask.Pix[mi])
if ma == 0 {
continue
}
ma |= ma << 8
- dr := uint32(rgba.R)
- dg := uint32(rgba.G)
- db := uint32(rgba.B)
- da := uint32(rgba.A)
+
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
// The 0x101 is here for the same reason as in drawRGBA.
- a := (m - (ca * ma / m)) * 0x101
- dr = (dr*a + cr*ma) / m
- dg = (dg*a + cg*ma) / m
- db = (db*a + cb*ma) / m
- da = (da*a + ca*ma) / m
- dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ a := (m - (sa * ma / m)) * 0x101
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
}
i0 += dst.Stride
i1 += dst.Stride
- j0 += mask.Stride
+ mi0 += mask.Stride
}
}
if r.Dy() < 1 {
return
}
- cr, cg, cb, ca := src.RGBA()
- color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
+ sr, sg, sb, sa := src.RGBA()
// The built-in copy function is faster than a straightforward for loop to fill the destination with
// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
// then use the first row as the slice source for the remaining rows.
- i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
- i1 := i0 + r.Dx()
- firstRow := dst.Pix[i0:i1]
- for i := range firstRow {
- firstRow[i] = color
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ for i := i0; i < i1; i += 4 {
+ dst.Pix[i+0] = uint8(sr >> 8)
+ dst.Pix[i+1] = uint8(sg >> 8)
+ dst.Pix[i+2] = uint8(sb >> 8)
+ dst.Pix[i+3] = uint8(sa >> 8)
}
+ firstRow := dst.Pix[i0:i1]
for y := r.Min.Y + 1; y < r.Max.Y; y++ {
i0 += dst.Stride
i1 += dst.Stride
}
func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
- dx, dy := r.Dx(), r.Dy()
- d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
- s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + sp.X - src.Rect.Min.X
+ n, dy := 4*r.Dx(), r.Dy()
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
var ddelta, sdelta int
if r.Min.Y <= sp.Y {
ddelta = dst.Stride
sdelta = -src.Stride
}
for ; dy > 0; dy-- {
- copy(dst.Pix[d0:d0+dx], src.Pix[s0:s0+dx])
+ copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
d0 += ddelta
s0 += sdelta
}
}
func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
- xMax := r.Max.X - dst.Rect.Min.X
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
yMax := r.Max.Y - dst.Rect.Min.Y
y := r.Min.Y - dst.Rect.Min.Y
dpix := dst.Pix[y*dst.Stride:]
spix := src.Pix[sy*src.Stride:]
- x := r.Min.X - dst.Rect.Min.X
- sx := sp.X - src.Rect.Min.X
- for ; x != xMax; x, sx = x+1, sx+1 {
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
// Convert from non-premultiplied color to pre-multiplied color.
- // The order of operations here is to match the NRGBAColor.RGBA
- // method in image/color.go.
- snrgba := spix[sx]
- sa := uint32(snrgba.A)
- sr := uint32(snrgba.R) * 0x101 * sa / 0xff
- sg := uint32(snrgba.G) * 0x101 * sa / 0xff
- sb := uint32(snrgba.B) * 0x101 * sa / 0xff
- sa *= 0x101
-
- dpix[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)}
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dpix[i+0] = uint8(sr >> 8)
+ dpix[i+1] = uint8(sg >> 8)
+ dpix[i+2] = uint8(sb >> 8)
+ dpix[i+3] = uint8(sa >> 8)
}
}
}
// (i.e. fully opaque) then the op is effectively always Src.
var (
yy, cb, cr uint8
- rr, gg, bb uint8
)
- x0 := r.Min.X - dst.Rect.Min.X
- x1 := r.Max.X - dst.Rect.Min.X
+ x0 := (r.Min.X - dst.Rect.Min.X) * 4
+ x1 := (r.Max.X - dst.Rect.Min.X) * 4
y0 := r.Min.Y - dst.Rect.Min.Y
y1 := r.Max.Y - dst.Rect.Min.Y
switch src.SubsampleRatio {
case ycbcr.SubsampleRatio422:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
- for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
i := sx / 2
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+i]
cr = src.Cr[sy*src.CStride+i]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
}
}
case ycbcr.SubsampleRatio420:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
- for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
i, j := sx/2, sy/2
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[j*src.CStride+i]
cr = src.Cr[j*src.CStride+i]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
}
}
default:
// Default to 4:4:4 subsampling.
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
- for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+sx]
cr = src.Cr[sy*src.CStride+sx]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
}
}
}
my := mp.Y + y0 - r.Min.Y
sx0 := sp.X + x0 - r.Min.X
mx0 := mp.X + x0 - r.Min.X
- i0 := (y0 - dst.Rect.Min.Y) * dst.Stride
+ sx1 := sx0 + (x1 - x0)
+ i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+ di := dx * 4
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
- dpix := dst.Pix[i0:]
- for x, sx, mx := x0, sx0, mx0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+ for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
ma := uint32(m)
if mask != nil {
_, _, _, ma = mask.At(mx, my).RGBA()
}
sr, sg, sb, sa := src.At(sx, sy).RGBA()
- var dr, dg, db, da uint32
if op == Over {
- rgba := dpix[x-dst.Rect.Min.X]
- dr = uint32(rgba.R)
- dg = uint32(rgba.G)
- db = uint32(rgba.B)
- da = uint32(rgba.A)
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
// We work in 16-bit color, and so would normally do:
// dr |= dr << 8
// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
// This yields the same result, but is fewer arithmetic operations.
a := (m - (sa * ma / m)) * 0x101
- dr = (dr*a + sr*ma) / m
- dg = (dg*a + sg*ma) / m
- db = (db*a + sb*ma) / m
- da = (da*a + sa*ma) / m
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+
} else {
- dr = sr * ma / m
- dg = sg * ma / m
- db = sb * ma / m
- da = sa * ma / m
+ dst.Pix[i+0] = uint8(sr * ma / m >> 8)
+ dst.Pix[i+1] = uint8(sg * ma / m >> 8)
+ dst.Pix[i+2] = uint8(sb * ma / m >> 8)
+ dst.Pix[i+3] = uint8(sa * ma / m >> 8)
}
- dpix[x-dst.Rect.Min.X] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
}
i0 += dy * dst.Stride
}
// Package image implements a basic 2-D image library.
package image
-// A Config consists of an image's color model and dimensions.
+// Config holds an image's color model and dimensions.
type Config struct {
ColorModel ColorModel
Width, Height int
}
-// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
+// Image is a finite rectangular grid of Colors drawn from a ColorModel.
type Image interface {
// ColorModel returns the Image's ColorModel.
ColorModel() ColorModel
At(x, y int) Color
}
-// An RGBA is an in-memory image of RGBAColor values.
+// RGBA is an in-memory image of RGBAColor values.
type RGBA struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []RGBAColor
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return RGBAColor{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}
func (p *RGBA) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toRGBAColor(c).(RGBAColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toRGBAColor(c).(RGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
}
func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &RGBA{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
return &RGBA{
Pix: p.Pix[i:],
Stride: p.Stride,
if p.Rect.Empty() {
return true
}
- i0, i1 := 0, p.Rect.Dx()
+ i0, i1 := 3, p.Rect.Dx()*4
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
return false
}
}
// NewRGBA returns a new RGBA with the given width and height.
func NewRGBA(w, h int) *RGBA {
- buf := make([]RGBAColor, w*h)
- return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
+ buf := make([]uint8, 4*w*h)
+ return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
}
-// An RGBA64 is an in-memory image of RGBA64Color values.
+// RGBA64 is an in-memory image of RGBA64Color values.
type RGBA64 struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []RGBA64Color
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return RGBA64Color{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return RGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
}
func (p *RGBA64) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toRGBA64Color(c).(RGBA64Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toRGBA64Color(c).(RGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
}
func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &RGBA64{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
return &RGBA64{
Pix: p.Pix[i:],
Stride: p.Stride,
if p.Rect.Empty() {
return true
}
- i0, i1 := 0, p.Rect.Dx()
+ i0, i1 := 6, p.Rect.Dx()*8
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
// NewRGBA64 returns a new RGBA64 with the given width and height.
func NewRGBA64(w, h int) *RGBA64 {
- pix := make([]RGBA64Color, w*h)
- return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 8*w*h)
+ return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
}
-// An NRGBA is an in-memory image of NRGBAColor values.
+// NRGBA is an in-memory image of NRGBAColor values.
type NRGBA struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []NRGBAColor
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return NRGBAColor{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}
func (p *NRGBA) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toNRGBAColor(c).(NRGBAColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toNRGBAColor(c).(NRGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
}
func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &NRGBA{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
return &NRGBA{
Pix: p.Pix[i:],
Stride: p.Stride,
if p.Rect.Empty() {
return true
}
- i0, i1 := 0, p.Rect.Dx()
+ i0, i1 := 3, p.Rect.Dx()*4
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
return false
}
}
// NewNRGBA returns a new NRGBA with the given width and height.
func NewNRGBA(w, h int) *NRGBA {
- pix := make([]NRGBAColor, w*h)
- return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 4*w*h)
+ return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
}
-// An NRGBA64 is an in-memory image of NRGBA64Color values.
+// NRGBA64 is an in-memory image of NRGBA64Color values.
type NRGBA64 struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []NRGBA64Color
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return NRGBA64Color{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return NRGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
}
func (p *NRGBA64) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toNRGBA64Color(c).(NRGBA64Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toNRGBA64Color(c).(NRGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
}
func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &NRGBA64{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
return &NRGBA64{
Pix: p.Pix[i:],
Stride: p.Stride,
if p.Rect.Empty() {
return true
}
- i0, i1 := 0, p.Rect.Dx()
+ i0, i1 := 6, p.Rect.Dx()*8
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
// NewNRGBA64 returns a new NRGBA64 with the given width and height.
func NewNRGBA64(w, h int) *NRGBA64 {
- pix := make([]NRGBA64Color, w*h)
- return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 8*w*h)
+ return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha is an in-memory image of AlphaColor values.
+// Alpha is an in-memory image of AlphaColor values.
type Alpha struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []AlphaColor
+ // Pix holds the image's pixels, as alpha values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
return AlphaColor{}
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ return AlphaColor{p.Pix[i]}
}
func (p *Alpha) Set(x, y int, c Color) {
return
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toAlphaColor(c).(AlphaColor)
+ p.Pix[i] = toAlphaColor(c).(AlphaColor).A
}
func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
return
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ p.Pix[i] = c.A
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &Alpha{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
return &Alpha{
Pix: p.Pix[i:],
Stride: p.Stride,
}
i0, i1 := 0, p.Rect.Dx()
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i++ {
+ if p.Pix[i] != 0xff {
return false
}
}
// NewAlpha returns a new Alpha with the given width and height.
func NewAlpha(w, h int) *Alpha {
- pix := make([]AlphaColor, w*h)
- return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 1*w*h)
+ return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha16 is an in-memory image of Alpha16Color values.
+// Alpha16 is an in-memory image of Alpha16Color values.
type Alpha16 struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []Alpha16Color
+ // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return Alpha16Color{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
}
func (p *Alpha16) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toAlpha16Color(c).(Alpha16Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toAlpha16Color(c).(Alpha16Color)
+ p.Pix[i+0] = uint8(c1.A >> 8)
+ p.Pix[i+1] = uint8(c1.A)
}
func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.A >> 8)
+ p.Pix[i+1] = uint8(c.A)
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &Alpha16{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
return &Alpha16{
Pix: p.Pix[i:],
Stride: p.Stride,
if p.Rect.Empty() {
return true
}
- i0, i1 := 0, p.Rect.Dx()
+ i0, i1 := 0, p.Rect.Dx()*2
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 2 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
// NewAlpha16 returns a new Alpha16 with the given width and height.
func NewAlpha16(w, h int) *Alpha16 {
- pix := make([]Alpha16Color, w*h)
- return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 2*w*h)
+ return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
}
-// A Gray is an in-memory image of GrayColor values.
+// Gray is an in-memory image of GrayColor values.
type Gray struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []GrayColor
+ // Pix holds the image's pixels, as gray values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
return GrayColor{}
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ return GrayColor{p.Pix[i]}
}
func (p *Gray) Set(x, y int, c Color) {
return
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toGrayColor(c).(GrayColor)
+ p.Pix[i] = toGrayColor(c).(GrayColor).Y
}
func (p *Gray) SetGray(x, y int, c GrayColor) {
return
}
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ p.Pix[i] = c.Y
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &Gray{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
return &Gray{
Pix: p.Pix[i:],
Stride: p.Stride,
// NewGray returns a new Gray with the given width and height.
func NewGray(w, h int) *Gray {
- pix := make([]GrayColor, w*h)
- return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 1*w*h)
+ return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
}
-// A Gray16 is an in-memory image of Gray16Color values.
+// Gray16 is an in-memory image of Gray16Color values.
type Gray16 struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []Gray16Color
+ // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
if !(Point{x, y}.In(p.Rect)) {
return Gray16Color{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return p.Pix[i]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
}
func (p *Gray16) Set(x, y int, c Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = toGray16Color(c).(Gray16Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toGray16Color(c).(Gray16Color)
+ p.Pix[i+0] = uint8(c1.Y >> 8)
+ p.Pix[i+1] = uint8(c1.Y)
}
func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- p.Pix[i] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.Y >> 8)
+ p.Pix[i+1] = uint8(c.Y)
}
// SubImage returns an image representing the portion of the image p visible
if r.Empty() {
return &Gray16{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
return &Gray16{
Pix: p.Pix[i:],
Stride: p.Stride,
// NewGray16 returns a new Gray16 with the given width and height.
func NewGray16(w, h int) *Gray16 {
- pix := make([]Gray16Color, w*h)
- return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
+ pix := make([]uint8, 2*w*h)
+ return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
}
// A PalettedColorModel represents a fixed palette of at most 256 colors.
return ret
}
-// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+// Paletted is an in-memory image of uint8 indices into a given palette.
type Paletted struct {
- // Pix holds the image's pixels. The pixel at (x, y) is
- // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
- Pix []uint8
+ // Pix holds the image's pixels, as palette indices. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
Palette: p.Palette,
}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
return &Paletted{
Pix: p.Pix[i:],
Stride: p.Stride,
// NewPaletted returns a new Paletted with the given width, height and palette.
func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
- pix := make([]uint8, w*h)
- return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
+ pix := make([]uint8, 1*w*h)
+ return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
}
// Perform the inverse DCT and store the MCU component to the image.
if d.nComp == nGrayComponent {
- idct(d.tmp[:64], 8, &b)
- // Convert from []uint8 to []image.GrayColor.
- p := d.img1.Pix[8*(my*d.img1.Stride+mx):]
- for y := 0; y < 8; y++ {
- dst := p[y*d.img1.Stride:]
- src := d.tmp[8*y:]
- for x := 0; x < 8; x++ {
- dst[x] = image.GrayColor{src[x]}
- }
- }
+ idct(d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride, &b)
} else {
switch i {
case 0:
if sj > ymax {
sj = ymax
}
- offset := (sj-b.Min.Y)*m.Stride - b.Min.X
+ offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
for i := 0; i < 8; i++ {
sx := p.X + i
if sx > xmax {
sx = xmax
}
- col := &m.Pix[offset+sx]
- yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+ pix := m.Pix[offset+sx*4:]
+ yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
yBlock[8*j+i] = int(yy)
cbBlock[8*j+i] = int(cb)
crBlock[8*j+i] = int(cr)
bpp := 0 // Bytes per pixel.
- // Used by fast paths for common image types
- var paletted *image.Paletted
- var rgba *image.RGBA
- rgba, _ = m.(*image.RGBA)
-
switch cb {
case cbG8:
bpp = 1
bpp = 3
case cbP8:
bpp = 1
- paletted = m.(*image.Paletted)
case cbTCA8:
bpp = 4
case cbTC16:
case cbTC8:
// We have previously verified that the alpha value is fully opaque.
cr0 := cr[0]
- if rgba != nil {
- offset := (y - b.Min.Y) * rgba.Stride
- for _, color := range rgba.Pix[offset : offset+b.Dx()] {
- cr0[i+0] = color.R
- cr0[i+1] = color.G
- cr0[i+2] = color.B
+ if rgba, _ := m.(*image.RGBA); rgba != nil {
+ j0 := (y - b.Min.Y) * rgba.Stride
+ j1 := j0 + b.Dx()*4
+ for j := j0; j < j1; j += 4 {
+ cr0[i+0] = rgba.Pix[j+0]
+ cr0[i+1] = rgba.Pix[j+1]
+ cr0[i+2] = rgba.Pix[j+2]
i += 3
}
} else {
}
}
case cbP8:
+ paletted := m.(*image.Paletted)
offset := (y - b.Min.Y) * paletted.Stride
copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
case cbTCA8: