mirror of
https://github.com/golang/go
synced 2024-11-19 11:04:47 -07:00
image: change Pix from []FooColor to []uint8.
Some benchmark numbers below. The image/draw fast-paths show dramatic improvement, the generic slow-paths show a smaller slow-down. BEFORE png.BenchmarkEncodePaletted 200 8203800 ns/op 37.45 MB/s png.BenchmarkEncodeRGBOpaque 100 26940440 ns/op 45.61 MB/s png.BenchmarkEncodeRGBA 20 73821000 ns/op 16.65 MB/s jpeg.BenchmarkEncodeRGBOpaque 50 35598640 ns/op 34.52 MB/s draw.BenchmarkFillOver 500 4024226 ns/op draw.BenchmarkFillSrc 10000 152736 ns/op draw.BenchmarkCopyOver 500 3452824 ns/op draw.BenchmarkCopySrc 50000 73218 ns/op draw.BenchmarkNRGBAOver 500 3941234 ns/op draw.BenchmarkNRGBASrc 1000 2484400 ns/op draw.BenchmarkYCbCr 1000 2609005 ns/op draw.BenchmarkGlyphOver 2000 1169575 ns/op draw.BenchmarkRGBA 200 9031390 ns/op draw.BenchmarkGenericOver 50 34636620 ns/op draw.BenchmarkGenericMaskOver 100 16561150 ns/op draw.BenchmarkGenericSrc 100 13873760 ns/op draw.BenchmarkGenericMaskSrc 100 25198860 ns/op AFTER png.BenchmarkEncodePaletted 200 8206600 ns/op 37.43 MB/s png.BenchmarkEncodeRGBOpaque 100 26129530 ns/op 47.03 MB/s png.BenchmarkEncodeRGBA 20 75776750 ns/op 16.22 MB/s jpeg.BenchmarkEncodeRGBOpaque 50 37192940 ns/op 33.04 MB/s draw.BenchmarkFillOver 500 3008134 ns/op draw.BenchmarkFillSrc 10000 154214 ns/op draw.BenchmarkCopyOver 1000 2169988 ns/op draw.BenchmarkCopySrc 50000 73095 ns/op draw.BenchmarkNRGBAOver 1000 2491079 ns/op draw.BenchmarkNRGBASrc 2000 1361244 ns/op draw.BenchmarkYCbCr 1000 2554269 ns/op draw.BenchmarkGlyphOver 2000 1042225 ns/op draw.BenchmarkRGBA 100 10233340 ns/op draw.BenchmarkGenericOver 50 38421560 ns/op draw.BenchmarkGenericMaskOver 100 17521190 ns/op draw.BenchmarkGenericSrc 100 16351200 ns/op draw.BenchmarkGenericMaskSrc 100 26538190 ns/op R=r CC=golang-dev https://golang.org/cl/4675076
This commit is contained in:
parent
6ec6f1ef62
commit
8bd5089513
@ -92,18 +92,19 @@ func (c *conn) writeSocket() {
|
||||
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())
|
||||
}
|
||||
|
@ -58,10 +58,13 @@ func decodeRGBA(r io.Reader, c image.Config) (image.Image, os.Error) {
|
||||
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
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
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
|
||||
@ -29,7 +29,7 @@ func (c RGBAColor) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
@ -39,7 +39,7 @@ func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
}
|
||||
@ -62,7 +62,7 @@ func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
@ -82,7 +82,7 @@ func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
|
||||
return
|
||||
}
|
||||
|
||||
// An AlphaColor represents an 8-bit alpha.
|
||||
// AlphaColor represents an 8-bit alpha.
|
||||
type AlphaColor struct {
|
||||
A uint8
|
||||
}
|
||||
@ -93,7 +93,7 @@ func (c AlphaColor) RGBA() (r, g, b, a uint32) {
|
||||
return a, a, a, a
|
||||
}
|
||||
|
||||
// An Alpha16Color represents a 16-bit alpha.
|
||||
// Alpha16Color represents a 16-bit alpha.
|
||||
type Alpha16Color struct {
|
||||
A uint16
|
||||
}
|
||||
@ -103,7 +103,7 @@ func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
}
|
||||
@ -114,7 +114,7 @@ func (c GrayColor) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
}
|
||||
@ -124,7 +124,7 @@ func (c Gray16Color) RGBA() (r, g, b, a uint32) {
|
||||
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
|
||||
|
@ -170,19 +170,22 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
||||
}
|
||||
|
||||
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
|
||||
@ -191,8 +194,8 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
|
||||
|
||||
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
|
||||
@ -200,7 +203,7 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
|
||||
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.
|
||||
@ -208,28 +211,29 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
|
||||
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
|
||||
@ -237,7 +241,9 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
|
||||
}
|
||||
|
||||
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
|
||||
@ -246,63 +252,58 @@ func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp imag
|
||||
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
|
||||
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
|
||||
|
||||
rgba := dpix[x]
|
||||
dr := uint32(rgba.R)
|
||||
dg := uint32(rgba.G)
|
||||
db := uint32(rgba.B)
|
||||
da := uint32(rgba.A)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,17 +311,19 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
|
||||
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
|
||||
@ -329,9 +332,9 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
|
||||
}
|
||||
|
||||
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
|
||||
@ -346,14 +349,16 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
|
||||
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
|
||||
@ -362,20 +367,17 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
|
||||
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
|
||||
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[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)}
|
||||
dpix[i+0] = uint8(sr >> 8)
|
||||
dpix[i+1] = uint8(sg >> 8)
|
||||
dpix[i+2] = uint8(sb >> 8)
|
||||
dpix[i+3] = uint8(sa >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -385,47 +387,55 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
|
||||
// (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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,22 +455,22 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
|
||||
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
|
||||
@ -468,17 +478,18 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
|
||||
// (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
|
||||
}
|
||||
|
@ -5,13 +5,13 @@
|
||||
// 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
|
||||
@ -24,11 +24,12 @@ type Image interface {
|
||||
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
|
||||
@ -42,24 +43,31 @@ func (p *RGBA) At(x, y int) Color {
|
||||
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
|
||||
@ -72,7 +80,7 @@ func (p *RGBA) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -85,10 +93,10 @@ func (p *RGBA) Opaque() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -100,15 +108,16 @@ func (p *RGBA) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -122,24 +131,44 @@ func (p *RGBA64) At(x, y int) Color {
|
||||
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
|
||||
@ -152,7 +181,7 @@ func (p *RGBA64) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -165,10 +194,10 @@ func (p *RGBA64) Opaque() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -180,15 +209,16 @@ func (p *RGBA64) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -202,24 +232,31 @@ func (p *NRGBA) At(x, y int) Color {
|
||||
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
|
||||
@ -232,7 +269,7 @@ func (p *NRGBA) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -245,10 +282,10 @@ func (p *NRGBA) Opaque() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -260,15 +297,16 @@ func (p *NRGBA) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -282,24 +320,44 @@ func (p *NRGBA64) At(x, y int) Color {
|
||||
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
|
||||
@ -312,7 +370,7 @@ func (p *NRGBA64) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -325,10 +383,10 @@ func (p *NRGBA64) Opaque() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -340,15 +398,16 @@ func (p *NRGBA64) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -363,7 +422,7 @@ func (p *Alpha) At(x, y int) Color {
|
||||
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) {
|
||||
@ -371,7 +430,7 @@ 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) {
|
||||
@ -379,7 +438,7 @@ 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
|
||||
@ -392,7 +451,7 @@ func (p *Alpha) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -407,8 +466,8 @@ func (p *Alpha) Opaque() bool {
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -420,15 +479,16 @@ func (p *Alpha) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -442,24 +502,27 @@ func (p *Alpha16) At(x, y int) Color {
|
||||
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
|
||||
@ -472,7 +535,7 @@ func (p *Alpha16) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -485,10 +548,10 @@ func (p *Alpha16) Opaque() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -500,15 +563,16 @@ func (p *Alpha16) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -523,7 +587,7 @@ func (p *Gray) At(x, y int) Color {
|
||||
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) {
|
||||
@ -531,7 +595,7 @@ 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) {
|
||||
@ -539,7 +603,7 @@ 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
|
||||
@ -552,7 +616,7 @@ func (p *Gray) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -567,15 +631,16 @@ func (p *Gray) Opaque() bool {
|
||||
|
||||
// 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
|
||||
@ -589,24 +654,27 @@ func (p *Gray16) At(x, y int) Color {
|
||||
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
|
||||
@ -619,7 +687,7 @@ func (p *Gray16) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -634,8 +702,8 @@ func (p *Gray16) Opaque() bool {
|
||||
|
||||
// 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.
|
||||
@ -679,11 +747,12 @@ func (p PalettedColorModel) Index(c Color) int {
|
||||
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
|
||||
@ -742,7 +811,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
|
||||
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,
|
||||
@ -776,6 +845,6 @@ func (p *Paletted) Opaque() bool {
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
@ -319,16 +319,7 @@ func (d *decoder) processSOS(n int) os.Error {
|
||||
|
||||
// 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:
|
||||
|
@ -397,14 +397,14 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
|
||||
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)
|
||||
|
@ -275,11 +275,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
||||
|
||||
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
|
||||
@ -287,7 +282,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
||||
bpp = 3
|
||||
case cbP8:
|
||||
bpp = 1
|
||||
paletted = m.(*image.Paletted)
|
||||
case cbTCA8:
|
||||
bpp = 4
|
||||
case cbTC16:
|
||||
@ -323,12 +317,13 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
||||
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 {
|
||||
@ -341,6 +336,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
||||
}
|
||||
}
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user