mirror of
https://github.com/golang/go
synced 2024-11-22 05:34:39 -07:00
image: add PixOffset methods; use them in image/draw and image/tiff.
image/draw benchmarks show <1% change for the fast paths. The slow paths got worse by 1-4%, but they're the slow paths. I don't care so much about them, and presumably compiler improvements could claw it back. IIUC 6g's inlining is enabled by default now. benchmark old ns/op new ns/op delta draw.BenchmarkFillOver 2988384 2999624 +0.38% draw.BenchmarkFillSrc 153141 153262 +0.08% draw.BenchmarkCopyOver 2155756 2170831 +0.70% draw.BenchmarkCopySrc 72591 72646 +0.08% draw.BenchmarkNRGBAOver 2487372 2491576 +0.17% draw.BenchmarkNRGBASrc 1361306 1409180 +3.52% draw.BenchmarkYCbCr 2540712 2562359 +0.85% draw.BenchmarkGlyphOver 1004879 1023308 +1.83% draw.BenchmarkRGBA 8746670 8844455 +1.12% draw.BenchmarkGenericOver 31860960 32512960 +2.05% draw.BenchmarkGenericMaskOver 16369060 16435720 +0.41% draw.BenchmarkGenericSrc 13128540 13127810 -0.01% draw.BenchmarkGenericMaskSrc 30059300 28883210 -3.91% R=r, gri CC=golang-dev, rsc https://golang.org/cl/5536059
This commit is contained in:
parent
98af38807e
commit
af08cfa494
@ -171,7 +171,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
|
|||||||
sr, sg, sb, sa := src.RGBA()
|
sr, sg, sb, sa := src.RGBA()
|
||||||
// The 0x101 is here for the same reason as in drawRGBA.
|
// The 0x101 is here for the same reason as in drawRGBA.
|
||||||
a := (m - sa) * 0x101
|
a := (m - sa) * 0x101
|
||||||
i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
|
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
|
||||||
i1 := i0 + r.Dx()*4
|
i1 := i0 + r.Dx()*4
|
||||||
for y := r.Min.Y; y != r.Max.Y; y++ {
|
for y := r.Min.Y; y != r.Max.Y; y++ {
|
||||||
for i := i0; i < i1; i += 4 {
|
for i := i0; i < i1; i += 4 {
|
||||||
@ -195,7 +195,7 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
|
|||||||
// The built-in copy function is faster than a straightforward for loop to fill the destination with
|
// 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
|
// 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.
|
// 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)*4
|
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
|
||||||
i1 := i0 + r.Dx()*4
|
i1 := i0 + r.Dx()*4
|
||||||
for i := i0; i < i1; i += 4 {
|
for i := i0; i < i1; i += 4 {
|
||||||
dst.Pix[i+0] = uint8(sr >> 8)
|
dst.Pix[i+0] = uint8(sr >> 8)
|
||||||
@ -213,8 +213,8 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
|
|||||||
|
|
||||||
func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
|
func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
|
||||||
dx, dy := r.Dx(), r.Dy()
|
dx, dy := r.Dx(), r.Dy()
|
||||||
d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
|
d0 := dst.PixOffset(r.Min.X, r.Min.Y)
|
||||||
s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
|
s0 := src.PixOffset(sp.X, sp.Y)
|
||||||
var (
|
var (
|
||||||
ddelta, sdelta int
|
ddelta, sdelta int
|
||||||
i0, i1, idelta int
|
i0, i1, idelta int
|
||||||
@ -261,8 +261,8 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
|
|||||||
|
|
||||||
func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
|
func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
|
||||||
n, dy := 4*r.Dx(), r.Dy()
|
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
|
d0 := dst.PixOffset(r.Min.X, r.Min.Y)
|
||||||
s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
|
s0 := src.PixOffset(sp.X, sp.Y)
|
||||||
var ddelta, sdelta int
|
var ddelta, sdelta int
|
||||||
if r.Min.Y <= sp.Y {
|
if r.Min.Y <= sp.Y {
|
||||||
ddelta = dst.Stride
|
ddelta = dst.Stride
|
||||||
@ -348,9 +348,7 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
|
|||||||
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
|
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
|
||||||
// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
|
// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
|
||||||
// (i.e. fully opaque) then the op is effectively always Src.
|
// (i.e. fully opaque) then the op is effectively always Src.
|
||||||
var (
|
var yy, cb, cr uint8
|
||||||
yy, cb, cr uint8
|
|
||||||
)
|
|
||||||
x0 := (r.Min.X - dst.Rect.Min.X) * 4
|
x0 := (r.Min.X - dst.Rect.Min.X) * 4
|
||||||
x1 := (r.Max.X - dst.Rect.Min.X) * 4
|
x1 := (r.Max.X - dst.Rect.Min.X) * 4
|
||||||
y0 := r.Min.Y - dst.Rect.Min.Y
|
y0 := r.Min.Y - dst.Rect.Min.Y
|
||||||
@ -405,9 +403,9 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
|
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
|
||||||
i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
|
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
|
||||||
i1 := i0 + r.Dx()*4
|
i1 := i0 + r.Dx()*4
|
||||||
mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
|
mi0 := mask.PixOffset(mp.X, mp.Y)
|
||||||
sr, sg, sb, sa := src.RGBA()
|
sr, sg, sb, sa := src.RGBA()
|
||||||
for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
|
for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
|
||||||
for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
|
for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
|
||||||
@ -451,7 +449,7 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
|
|||||||
sx0 := sp.X + x0 - r.Min.X
|
sx0 := sp.X + x0 - r.Min.X
|
||||||
mx0 := mp.X + x0 - r.Min.X
|
mx0 := mp.X + x0 - r.Min.X
|
||||||
sx1 := sx0 + (x1 - x0)
|
sx1 := sx0 + (x1 - x0)
|
||||||
i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
|
i0 := dst.PixOffset(x0, y0)
|
||||||
di := dx * 4
|
di := dx * 4
|
||||||
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
|
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
|
||||||
for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
|
for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
|
||||||
|
@ -61,15 +61,21 @@ func (p *RGBA) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.RGBA{}
|
return color.RGBA{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
|
return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *RGBA) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
||||||
|
}
|
||||||
|
|
||||||
func (p *RGBA) Set(x, y int, c color.Color) {
|
func (p *RGBA) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.RGBAModel.Convert(c).(color.RGBA)
|
c1 := color.RGBAModel.Convert(c).(color.RGBA)
|
||||||
p.Pix[i+0] = c1.R
|
p.Pix[i+0] = c1.R
|
||||||
p.Pix[i+1] = c1.G
|
p.Pix[i+1] = c1.G
|
||||||
@ -81,7 +87,7 @@ func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = c.R
|
p.Pix[i+0] = c.R
|
||||||
p.Pix[i+1] = c.G
|
p.Pix[i+1] = c.G
|
||||||
p.Pix[i+2] = c.B
|
p.Pix[i+2] = c.B
|
||||||
@ -98,7 +104,7 @@ func (p *RGBA) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &RGBA{}
|
return &RGBA{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &RGBA{
|
return &RGBA{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -150,7 +156,7 @@ func (p *RGBA64) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.RGBA64{}
|
return color.RGBA64{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
return color.RGBA64{
|
return color.RGBA64{
|
||||||
uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
|
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+2])<<8 | uint16(p.Pix[i+3]),
|
||||||
@ -159,11 +165,17 @@ func (p *RGBA64) At(x, y int) color.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *RGBA64) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
||||||
|
}
|
||||||
|
|
||||||
func (p *RGBA64) Set(x, y int, c color.Color) {
|
func (p *RGBA64) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
|
c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
|
||||||
p.Pix[i+0] = uint8(c1.R >> 8)
|
p.Pix[i+0] = uint8(c1.R >> 8)
|
||||||
p.Pix[i+1] = uint8(c1.R)
|
p.Pix[i+1] = uint8(c1.R)
|
||||||
@ -179,7 +191,7 @@ func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = uint8(c.R >> 8)
|
p.Pix[i+0] = uint8(c.R >> 8)
|
||||||
p.Pix[i+1] = uint8(c.R)
|
p.Pix[i+1] = uint8(c.R)
|
||||||
p.Pix[i+2] = uint8(c.G >> 8)
|
p.Pix[i+2] = uint8(c.G >> 8)
|
||||||
@ -200,7 +212,7 @@ func (p *RGBA64) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &RGBA64{}
|
return &RGBA64{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &RGBA64{
|
return &RGBA64{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -252,15 +264,21 @@ func (p *NRGBA) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.NRGBA{}
|
return color.NRGBA{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
|
return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *NRGBA) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
||||||
|
}
|
||||||
|
|
||||||
func (p *NRGBA) Set(x, y int, c color.Color) {
|
func (p *NRGBA) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
|
c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
|
||||||
p.Pix[i+0] = c1.R
|
p.Pix[i+0] = c1.R
|
||||||
p.Pix[i+1] = c1.G
|
p.Pix[i+1] = c1.G
|
||||||
@ -272,7 +290,7 @@ func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = c.R
|
p.Pix[i+0] = c.R
|
||||||
p.Pix[i+1] = c.G
|
p.Pix[i+1] = c.G
|
||||||
p.Pix[i+2] = c.B
|
p.Pix[i+2] = c.B
|
||||||
@ -289,7 +307,7 @@ func (p *NRGBA) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &NRGBA{}
|
return &NRGBA{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &NRGBA{
|
return &NRGBA{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -341,7 +359,7 @@ func (p *NRGBA64) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.NRGBA64{}
|
return color.NRGBA64{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
return color.NRGBA64{
|
return color.NRGBA64{
|
||||||
uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
|
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+2])<<8 | uint16(p.Pix[i+3]),
|
||||||
@ -350,11 +368,17 @@ func (p *NRGBA64) At(x, y int) color.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *NRGBA64) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
||||||
|
}
|
||||||
|
|
||||||
func (p *NRGBA64) Set(x, y int, c color.Color) {
|
func (p *NRGBA64) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
|
c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
|
||||||
p.Pix[i+0] = uint8(c1.R >> 8)
|
p.Pix[i+0] = uint8(c1.R >> 8)
|
||||||
p.Pix[i+1] = uint8(c1.R)
|
p.Pix[i+1] = uint8(c1.R)
|
||||||
@ -370,7 +394,7 @@ func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = uint8(c.R >> 8)
|
p.Pix[i+0] = uint8(c.R >> 8)
|
||||||
p.Pix[i+1] = uint8(c.R)
|
p.Pix[i+1] = uint8(c.R)
|
||||||
p.Pix[i+2] = uint8(c.G >> 8)
|
p.Pix[i+2] = uint8(c.G >> 8)
|
||||||
@ -391,7 +415,7 @@ func (p *NRGBA64) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &NRGBA64{}
|
return &NRGBA64{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &NRGBA64{
|
return &NRGBA64{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -443,15 +467,21 @@ func (p *Alpha) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.Alpha{}
|
return color.Alpha{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
return color.Alpha{p.Pix[i]}
|
return color.Alpha{p.Pix[i]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *Alpha) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Alpha) Set(x, y int, c color.Color) {
|
func (p *Alpha) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
|
p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,7 +489,7 @@ func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = c.A
|
p.Pix[i] = c.A
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +503,7 @@ func (p *Alpha) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &Alpha{}
|
return &Alpha{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &Alpha{
|
return &Alpha{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -525,15 +555,21 @@ func (p *Alpha16) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.Alpha16{}
|
return color.Alpha16{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
|
return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *Alpha16) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Alpha16) Set(x, y int, c color.Color) {
|
func (p *Alpha16) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
|
c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
|
||||||
p.Pix[i+0] = uint8(c1.A >> 8)
|
p.Pix[i+0] = uint8(c1.A >> 8)
|
||||||
p.Pix[i+1] = uint8(c1.A)
|
p.Pix[i+1] = uint8(c1.A)
|
||||||
@ -543,7 +579,7 @@ func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = uint8(c.A >> 8)
|
p.Pix[i+0] = uint8(c.A >> 8)
|
||||||
p.Pix[i+1] = uint8(c.A)
|
p.Pix[i+1] = uint8(c.A)
|
||||||
}
|
}
|
||||||
@ -558,7 +594,7 @@ func (p *Alpha16) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &Alpha16{}
|
return &Alpha16{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &Alpha16{
|
return &Alpha16{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -610,15 +646,21 @@ func (p *Gray) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.Gray{}
|
return color.Gray{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
return color.Gray{p.Pix[i]}
|
return color.Gray{p.Pix[i]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *Gray) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Gray) Set(x, y int, c color.Color) {
|
func (p *Gray) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
|
p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +668,7 @@ func (p *Gray) SetGray(x, y int, c color.Gray) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = c.Y
|
p.Pix[i] = c.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,7 +682,7 @@ func (p *Gray) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &Gray{}
|
return &Gray{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &Gray{
|
return &Gray{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -679,15 +721,21 @@ func (p *Gray16) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.Gray16{}
|
return color.Gray16{}
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
|
return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *Gray16) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Gray16) Set(x, y int, c color.Color) {
|
func (p *Gray16) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
c1 := color.Gray16Model.Convert(c).(color.Gray16)
|
c1 := color.Gray16Model.Convert(c).(color.Gray16)
|
||||||
p.Pix[i+0] = uint8(c1.Y >> 8)
|
p.Pix[i+0] = uint8(c1.Y >> 8)
|
||||||
p.Pix[i+1] = uint8(c1.Y)
|
p.Pix[i+1] = uint8(c1.Y)
|
||||||
@ -697,7 +745,7 @@ func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i+0] = uint8(c.Y >> 8)
|
p.Pix[i+0] = uint8(c.Y >> 8)
|
||||||
p.Pix[i+1] = uint8(c.Y)
|
p.Pix[i+1] = uint8(c.Y)
|
||||||
}
|
}
|
||||||
@ -712,7 +760,7 @@ func (p *Gray16) SubImage(r Rectangle) Image {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &Gray16{}
|
return &Gray16{}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &Gray16{
|
return &Gray16{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
@ -756,15 +804,21 @@ func (p *Paletted) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return p.Palette[0]
|
return p.Palette[0]
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
return p.Palette[p.Pix[i]]
|
return p.Palette[p.Pix[i]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *Paletted) PixOffset(x, y int) int {
|
||||||
|
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Paletted) Set(x, y int, c color.Color) {
|
func (p *Paletted) Set(x, y int, c color.Color) {
|
||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = uint8(p.Palette.Index(c))
|
p.Pix[i] = uint8(p.Palette.Index(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,7 +826,7 @@ func (p *Paletted) ColorIndexAt(x, y int) uint8 {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
return p.Pix[i]
|
return p.Pix[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,7 +834,7 @@ func (p *Paletted) SetColorIndex(x, y int, index uint8) {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
|
i := p.PixOffset(x, y)
|
||||||
p.Pix[i] = index
|
p.Pix[i] = index
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,7 +850,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
|
|||||||
Palette: p.Palette,
|
Palette: p.Palette,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
|
i := p.PixOffset(r.Min.X, r.Min.Y)
|
||||||
return &Paletted{
|
return &Paletted{
|
||||||
Pix: p.Pix[i:],
|
Pix: p.Pix[i:],
|
||||||
Stride: p.Stride,
|
Stride: p.Stride,
|
||||||
|
@ -223,8 +223,8 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
|
|||||||
}
|
}
|
||||||
case mRGB:
|
case mRGB:
|
||||||
img := dst.(*image.RGBA)
|
img := dst.(*image.RGBA)
|
||||||
min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
min := img.PixOffset(0, ymin)
|
||||||
max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
max := img.PixOffset(0, ymax)
|
||||||
var off int
|
var off int
|
||||||
for i := min; i < max; i += 4 {
|
for i := min; i < max; i += 4 {
|
||||||
img.Pix[i+0] = d.buf[off+0]
|
img.Pix[i+0] = d.buf[off+0]
|
||||||
@ -235,16 +235,16 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
|
|||||||
}
|
}
|
||||||
case mNRGBA:
|
case mNRGBA:
|
||||||
img := dst.(*image.NRGBA)
|
img := dst.(*image.NRGBA)
|
||||||
min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
min := img.PixOffset(0, ymin)
|
||||||
max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
max := img.PixOffset(0, ymax)
|
||||||
if len(d.buf) != max-min {
|
if len(d.buf) != max-min {
|
||||||
return FormatError("short data strip")
|
return FormatError("short data strip")
|
||||||
}
|
}
|
||||||
copy(img.Pix[min:max], d.buf)
|
copy(img.Pix[min:max], d.buf)
|
||||||
case mRGBA:
|
case mRGBA:
|
||||||
img := dst.(*image.RGBA)
|
img := dst.(*image.RGBA)
|
||||||
min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
min := img.PixOffset(0, ymin)
|
||||||
max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
|
max := img.PixOffset(0, ymax)
|
||||||
if len(d.buf) != max-min {
|
if len(d.buf) != max-min {
|
||||||
return FormatError("short data strip")
|
return FormatError("short data strip")
|
||||||
}
|
}
|
||||||
|
@ -49,28 +49,32 @@ func (p *YCbCr) At(x, y int) color.Color {
|
|||||||
if !(Point{x, y}.In(p.Rect)) {
|
if !(Point{x, y}.In(p.Rect)) {
|
||||||
return color.YCbCr{}
|
return color.YCbCr{}
|
||||||
}
|
}
|
||||||
|
yi := p.YOffset(x, y)
|
||||||
|
ci := p.COffset(x, y)
|
||||||
|
return color.YCbCr{
|
||||||
|
p.Y[yi],
|
||||||
|
p.Cb[ci],
|
||||||
|
p.Cr[ci],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// YOffset returns the index of the first element of Y that corresponds to
|
||||||
|
// the pixel at (x, y).
|
||||||
|
func (p *YCbCr) YOffset(x, y int) int {
|
||||||
|
return y*p.YStride + x
|
||||||
|
}
|
||||||
|
|
||||||
|
// COffset returns the index of the first element of Cb or Cr that corresponds
|
||||||
|
// to the pixel at (x, y).
|
||||||
|
func (p *YCbCr) COffset(x, y int) int {
|
||||||
switch p.SubsampleRatio {
|
switch p.SubsampleRatio {
|
||||||
case YCbCrSubsampleRatio422:
|
case YCbCrSubsampleRatio422:
|
||||||
i := x / 2
|
return y*p.CStride + (x / 2)
|
||||||
return color.YCbCr{
|
|
||||||
p.Y[y*p.YStride+x],
|
|
||||||
p.Cb[y*p.CStride+i],
|
|
||||||
p.Cr[y*p.CStride+i],
|
|
||||||
}
|
|
||||||
case YCbCrSubsampleRatio420:
|
case YCbCrSubsampleRatio420:
|
||||||
i, j := x/2, y/2
|
return (y/2)*p.CStride + (x / 2)
|
||||||
return color.YCbCr{
|
|
||||||
p.Y[y*p.YStride+x],
|
|
||||||
p.Cb[j*p.CStride+i],
|
|
||||||
p.Cr[j*p.CStride+i],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Default to 4:4:4 subsampling.
|
// Default to 4:4:4 subsampling.
|
||||||
return color.YCbCr{
|
return y*p.CStride + x
|
||||||
p.Y[y*p.YStride+x],
|
|
||||||
p.Cb[y*p.CStride+x],
|
|
||||||
p.Cr[y*p.CStride+x],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubImage returns an image representing the portion of the image p visible
|
// SubImage returns an image representing the portion of the image p visible
|
||||||
|
Loading…
Reference in New Issue
Block a user