mirror of
https://github.com/golang/go
synced 2024-11-26 05:17:58 -07:00
image: add RGBA64Image interface
The new RGBA64At method is equivalent to the existing At method (and the new SetRGBA64 method is equivalent to the existing Set method in the image/draw package), but they can avoid allocations from converting concrete color types to the color.Color interface type. Also update api/go1.17.txt and doc/go1.17.html Fixes #44808 Change-Id: I8671f3144512b1200fa373840ed6729a5d61bc35 Reviewed-on: https://go-review.googlesource.com/c/go/+/311129 Trust: Nigel Tao <nigeltao@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
9401172166
commit
86743e7d86
@ -28,6 +28,38 @@ pkg encoding/csv, method (*Reader) FieldPos(int) (int, int)
|
||||
pkg go/build, type Context struct, ToolTags []string
|
||||
pkg go/parser, const SkipObjectResolution = 64
|
||||
pkg go/parser, const SkipObjectResolution Mode
|
||||
pkg image, method (*Alpha) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Alpha) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Alpha16) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Alpha16) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*CMYK) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*CMYK) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Gray) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Gray) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Gray16) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Gray16) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NRGBA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*NRGBA) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NRGBA64) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*NRGBA64) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NYCbCrA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Paletted) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Paletted) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*RGBA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*RGBA) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At }
|
||||
pkg image, type RGBA64Image interface, At(int, int) color.Color
|
||||
pkg image, type RGBA64Image interface, Bounds() Rectangle
|
||||
pkg image, type RGBA64Image interface, ColorModel() color.Model
|
||||
pkg image, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
|
||||
pkg image/draw, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At, Set, SetRGBA64 }
|
||||
pkg image/draw, type RGBA64Image interface, At(int, int) color.Color
|
||||
pkg image/draw, type RGBA64Image interface, Bounds() image.Rectangle
|
||||
pkg image/draw, type RGBA64Image interface, ColorModel() color.Model
|
||||
pkg image/draw, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
|
||||
pkg image/draw, type RGBA64Image interface, Set(int, int, color.Color)
|
||||
pkg image/draw, type RGBA64Image interface, SetRGBA64(int, int, color.RGBA64)
|
||||
pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry
|
||||
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
|
||||
pkg math, const MaxInt = 9223372036854775807
|
||||
@ -153,7 +185,7 @@ pkg time, const Layout = "01/02 03:04:05PM '06 -0700"
|
||||
pkg time, const Layout ideal-string
|
||||
pkg time, func UnixMicro(int64) Time
|
||||
pkg time, func UnixMilli(int64) Time
|
||||
pkg time, method (Time) IsDST() bool
|
||||
pkg time, method (Time) GoString() string
|
||||
pkg time, method (Time) IsDST() bool
|
||||
pkg time, method (Time) UnixMicro() int64
|
||||
pkg time, method (Time) UnixMilli() int64
|
||||
|
@ -693,6 +693,19 @@ func Foo() bool {
|
||||
</dd>
|
||||
</dl><!-- go/format -->
|
||||
|
||||
<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 311129 -->
|
||||
The concrete image types (<code>RGBA</code>, <code>Gray16</code> and so on)
|
||||
now implement a new <a href="/pkg/image/#RGBA64Image"><code>RGBA64Image</code></a>
|
||||
interface. Those concrete types, other than the chroma-subsampling
|
||||
related <code>YCbCr</code> and <code>NYCbCrA</code>, also now implement
|
||||
<a href="/pkg/image/draw/#RGBA64Image"><code>draw.RGBA64Image</code></a>, a
|
||||
new interface in the <code>image/draw</code> package.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- image -->
|
||||
|
||||
<dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 293649 -->
|
||||
|
@ -23,6 +23,16 @@ type Image interface {
|
||||
Set(x, y int, c color.Color)
|
||||
}
|
||||
|
||||
// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a
|
||||
// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to
|
||||
// calling Set, but it can avoid allocations from converting concrete color
|
||||
// types to the color.Color interface type.
|
||||
type RGBA64Image interface {
|
||||
image.RGBA64Image
|
||||
Set(x, y int, c color.Color)
|
||||
SetRGBA64(x, y int, c color.RGBA64)
|
||||
}
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer interface {
|
||||
// Quantize appends up to cap(p) - len(p) colors to p and returns the
|
||||
|
@ -45,6 +45,17 @@ type Image interface {
|
||||
At(x, y int) color.Color
|
||||
}
|
||||
|
||||
// RGBA64Image is an Image whose pixels can be converted directly to a
|
||||
// color.RGBA64.
|
||||
type RGBA64Image interface {
|
||||
// RGBA64At returns the RGBA64 color of the pixel at (x, y). It is
|
||||
// equivalent to calling At(x, y).RGBA() and converting the resulting
|
||||
// 32-bit return values to a color.RGBA64, but it can avoid allocations
|
||||
// from converting concrete color types to the color.Color interface type.
|
||||
RGBA64At(x, y int) color.RGBA64
|
||||
Image
|
||||
}
|
||||
|
||||
// PalettedImage is an image whose colors may come from a limited palette.
|
||||
// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
|
||||
// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
|
||||
@ -90,6 +101,24 @@ func (p *RGBA) At(x, y int) color.Color {
|
||||
return p.RGBAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *RGBA) RGBA64At(x, y int) color.RGBA64 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.RGBA64{}
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
r := uint16(s[0])
|
||||
g := uint16(s[1])
|
||||
b := uint16(s[2])
|
||||
a := uint16(s[3])
|
||||
return color.RGBA64{
|
||||
(r << 8) | r,
|
||||
(g << 8) | g,
|
||||
(b << 8) | b,
|
||||
(a << 8) | a,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *RGBA) RGBAAt(x, y int) color.RGBA {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.RGBA{}
|
||||
@ -118,6 +147,18 @@ func (p *RGBA) Set(x, y int, c color.Color) {
|
||||
s[3] = c1.A
|
||||
}
|
||||
|
||||
func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(c.R >> 8)
|
||||
s[1] = uint8(c.G >> 8)
|
||||
s[2] = uint8(c.B >> 8)
|
||||
s[3] = uint8(c.A >> 8)
|
||||
}
|
||||
|
||||
func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -311,6 +352,11 @@ func (p *NRGBA) At(x, y int) color.Color {
|
||||
return p.NRGBAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NRGBAAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.NRGBA{}
|
||||
@ -339,6 +385,24 @@ func (p *NRGBA) Set(x, y int, c color.Color) {
|
||||
s[3] = c1.A
|
||||
}
|
||||
|
||||
func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
|
||||
if (a != 0) && (a != 0xffff) {
|
||||
r = (r * 0xffff) / a
|
||||
g = (g * 0xffff) / a
|
||||
b = (b * 0xffff) / a
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(r >> 8)
|
||||
s[1] = uint8(g >> 8)
|
||||
s[2] = uint8(b >> 8)
|
||||
s[3] = uint8(a >> 8)
|
||||
}
|
||||
|
||||
func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -415,6 +479,11 @@ func (p *NRGBA64) At(x, y int) color.Color {
|
||||
return p.NRGBA64At(x, y)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NRGBA64At(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.NRGBA64{}
|
||||
@ -452,6 +521,28 @@ func (p *NRGBA64) Set(x, y int, c color.Color) {
|
||||
s[7] = uint8(c1.A)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
|
||||
if (a != 0) && (a != 0xffff) {
|
||||
r = (r * 0xffff) / a
|
||||
g = (g * 0xffff) / a
|
||||
b = (b * 0xffff) / a
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(r >> 8)
|
||||
s[1] = uint8(r)
|
||||
s[2] = uint8(g >> 8)
|
||||
s[3] = uint8(g)
|
||||
s[4] = uint8(b >> 8)
|
||||
s[5] = uint8(b)
|
||||
s[6] = uint8(a >> 8)
|
||||
s[7] = uint8(a)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -532,6 +623,12 @@ func (p *Alpha) At(x, y int) color.Color {
|
||||
return p.AlphaAt(x, y)
|
||||
}
|
||||
|
||||
func (p *Alpha) RGBA64At(x, y int) color.RGBA64 {
|
||||
a := uint16(p.AlphaAt(x, y).A)
|
||||
a |= a << 8
|
||||
return color.RGBA64{a, a, a, a}
|
||||
}
|
||||
|
||||
func (p *Alpha) AlphaAt(x, y int) color.Alpha {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Alpha{}
|
||||
@ -554,6 +651,14 @@ func (p *Alpha) Set(x, y int, c color.Color) {
|
||||
p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
|
||||
}
|
||||
|
||||
func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(c.A >> 8)
|
||||
}
|
||||
|
||||
func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -626,6 +731,11 @@ func (p *Alpha16) At(x, y int) color.Color {
|
||||
return p.Alpha16At(x, y)
|
||||
}
|
||||
|
||||
func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 {
|
||||
a := p.Alpha16At(x, y).A
|
||||
return color.RGBA64{a, a, a, a}
|
||||
}
|
||||
|
||||
func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Alpha16{}
|
||||
@ -650,6 +760,15 @@ func (p *Alpha16) Set(x, y int, c color.Color) {
|
||||
p.Pix[i+1] = uint8(c1.A)
|
||||
}
|
||||
|
||||
func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i+0] = uint8(c.A >> 8)
|
||||
p.Pix[i+1] = uint8(c.A)
|
||||
}
|
||||
|
||||
func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -723,6 +842,12 @@ func (p *Gray) At(x, y int) color.Color {
|
||||
return p.GrayAt(x, y)
|
||||
}
|
||||
|
||||
func (p *Gray) RGBA64At(x, y int) color.RGBA64 {
|
||||
gray := uint16(p.GrayAt(x, y).Y)
|
||||
gray |= gray << 8
|
||||
return color.RGBA64{gray, gray, gray, 0xffff}
|
||||
}
|
||||
|
||||
func (p *Gray) GrayAt(x, y int) color.Gray {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Gray{}
|
||||
@ -745,6 +870,16 @@ func (p *Gray) Set(x, y int, c color.Color) {
|
||||
p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
|
||||
}
|
||||
|
||||
func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
// This formula is the same as in color.grayModel.
|
||||
gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(gray)
|
||||
}
|
||||
|
||||
func (p *Gray) SetGray(x, y int, c color.Gray) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -804,6 +939,11 @@ func (p *Gray16) At(x, y int) color.Color {
|
||||
return p.Gray16At(x, y)
|
||||
}
|
||||
|
||||
func (p *Gray16) RGBA64At(x, y int) color.RGBA64 {
|
||||
gray := p.Gray16At(x, y).Y
|
||||
return color.RGBA64{gray, gray, gray, 0xffff}
|
||||
}
|
||||
|
||||
func (p *Gray16) Gray16At(x, y int) color.Gray16 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Gray16{}
|
||||
@ -828,6 +968,17 @@ func (p *Gray16) Set(x, y int, c color.Color) {
|
||||
p.Pix[i+1] = uint8(c1.Y)
|
||||
}
|
||||
|
||||
func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
// This formula is the same as in color.gray16Model.
|
||||
gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i+0] = uint8(gray >> 8)
|
||||
p.Pix[i+1] = uint8(gray)
|
||||
}
|
||||
|
||||
func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -888,6 +1039,11 @@ func (p *CMYK) At(x, y int) color.Color {
|
||||
return p.CMYKAt(x, y)
|
||||
}
|
||||
|
||||
func (p *CMYK) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.CMYKAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *CMYK) CMYKAt(x, y int) color.CMYK {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.CMYK{}
|
||||
@ -916,6 +1072,19 @@ func (p *CMYK) Set(x, y int, c color.Color) {
|
||||
s[3] = c1.K
|
||||
}
|
||||
|
||||
func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8))
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = cc
|
||||
s[1] = mm
|
||||
s[2] = yy
|
||||
s[3] = kk
|
||||
}
|
||||
|
||||
func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
@ -988,6 +1157,26 @@ func (p *Paletted) At(x, y int) color.Color {
|
||||
return p.Palette[p.Pix[i]]
|
||||
}
|
||||
|
||||
func (p *Paletted) RGBA64At(x, y int) color.RGBA64 {
|
||||
if len(p.Palette) == 0 {
|
||||
return color.RGBA64{}
|
||||
}
|
||||
c := color.Color(nil)
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
c = p.Palette[0]
|
||||
} else {
|
||||
i := p.PixOffset(x, y)
|
||||
c = p.Palette[p.Pix[i]]
|
||||
}
|
||||
r, g, b, a := c.RGBA()
|
||||
return color.RGBA64{
|
||||
uint16(r),
|
||||
uint16(g),
|
||||
uint16(b),
|
||||
uint16(a),
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@ -1002,6 +1191,14 @@ func (p *Paletted) Set(x, y int, c color.Color) {
|
||||
p.Pix[i] = uint8(p.Palette.Index(c))
|
||||
}
|
||||
|
||||
func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(p.Palette.Index(c))
|
||||
}
|
||||
|
||||
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return 0
|
||||
|
@ -6,6 +6,7 @@ package image
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"image/color/palette"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -191,6 +192,80 @@ func Test16BitsPerColorChannel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRGBA64Image(t *testing.T) {
|
||||
// memset sets every element of s to v.
|
||||
memset := func(s []byte, v byte) {
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
r := Rect(0, 0, 3, 2)
|
||||
testCases := []Image{
|
||||
NewAlpha(r),
|
||||
NewAlpha16(r),
|
||||
NewCMYK(r),
|
||||
NewGray(r),
|
||||
NewGray16(r),
|
||||
NewNRGBA(r),
|
||||
NewNRGBA64(r),
|
||||
NewNYCbCrA(r, YCbCrSubsampleRatio444),
|
||||
NewPaletted(r, palette.Plan9),
|
||||
NewRGBA(r),
|
||||
NewRGBA64(r),
|
||||
NewYCbCr(r, YCbCrSubsampleRatio444),
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
switch tc := tc.(type) {
|
||||
// Most of the concrete image types in the testCases implement the
|
||||
// draw.RGBA64Image interface: they have a SetRGBA64 method. We use an
|
||||
// interface literal here, instead of importing "image/draw", to avoid
|
||||
// an import cycle.
|
||||
//
|
||||
// The YCbCr and NYCbCrA types are special-cased. Chroma subsampling
|
||||
// means that setting one pixel can modify neighboring pixels. They
|
||||
// don't have Set or SetRGBA64 methods because that side effect could
|
||||
// be surprising. Here, we just memset the channel buffers instead.
|
||||
case interface {
|
||||
SetRGBA64(x, y int, c color.RGBA64)
|
||||
}:
|
||||
tc.SetRGBA64(1, 1, color.RGBA64{0x7FFF, 0x3FFF, 0x0000, 0x7FFF})
|
||||
|
||||
case *NYCbCrA:
|
||||
memset(tc.YCbCr.Y, 0x77)
|
||||
memset(tc.YCbCr.Cb, 0x88)
|
||||
memset(tc.YCbCr.Cr, 0x99)
|
||||
memset(tc.A, 0xAA)
|
||||
|
||||
case *YCbCr:
|
||||
memset(tc.Y, 0x77)
|
||||
memset(tc.Cb, 0x88)
|
||||
memset(tc.Cr, 0x99)
|
||||
|
||||
default:
|
||||
t.Errorf("could not initialize pixels for %T", tc)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check that RGBA64At(x, y) is equivalent to At(x, y).RGBA().
|
||||
rgba64Image, ok := tc.(RGBA64Image)
|
||||
if !ok {
|
||||
t.Errorf("%T is not an RGBA64Image", tc)
|
||||
continue
|
||||
}
|
||||
got := rgba64Image.RGBA64At(1, 1)
|
||||
wantR, wantG, wantB, wantA := tc.At(1, 1).RGBA()
|
||||
if (uint32(got.R) != wantR) || (uint32(got.G) != wantG) ||
|
||||
(uint32(got.B) != wantB) || (uint32(got.A) != wantA) {
|
||||
t.Errorf("%T:\ngot (0x%04X, 0x%04X, 0x%04X, 0x%04X)\n"+
|
||||
"want (0x%04X, 0x%04X, 0x%04X, 0x%04X)", tc,
|
||||
got.R, got.G, got.B, got.A,
|
||||
wantR, wantG, wantB, wantA)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAt(b *testing.B) {
|
||||
for _, tc := range testImages {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
|
@ -71,6 +71,11 @@ func (p *YCbCr) At(x, y int) color.Color {
|
||||
return p.YCbCrAt(x, y)
|
||||
}
|
||||
|
||||
func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.YCbCrAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.YCbCr{}
|
||||
@ -210,6 +215,11 @@ func (p *NYCbCrA) At(x, y int) color.Color {
|
||||
return p.NYCbCrAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
|
||||
if !(Point{X: x, Y: y}.In(p.Rect)) {
|
||||
return color.NYCbCrA{}
|
||||
|
Loading…
Reference in New Issue
Block a user