// NewDrawableSize returns a new draw.Image with the same type as p and the given bounds. // If p is not a draw.Image, another type is used. func NewDrawableSize(p image.Image, r image.Rectangle) draw.Image { switch p := p.(type) { case *image.RGBA: return image.NewRGBA(r) case *image.RGBA64: return image.NewRGBA64(r) case *image.NRGBA: return image.NewNRGBA(r) case *image.NRGBA64: return image.NewNRGBA64(r) case *image.Alpha: return image.NewAlpha(r) case *image.Alpha16: return image.NewAlpha16(r) case *image.Gray: return image.NewGray(r) case *image.Gray16: return image.NewGray16(r) case *image.Paletted: pl := make(color.Palette, len(p.Palette)) copy(pl, p.Palette) return image.NewPaletted(r, pl) case *image.CMYK: return image.NewCMYK(r) default: return image.NewRGBA(r) } }
func createRandomImage(maxPaletteSize int) image.Image { r := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{gen.Rand(32) + 1, gen.Rand(32) + 1}} var img Image switch gen.Rand(10) { case 0: img = image.NewAlpha(r) case 1: img = image.NewAlpha16(r) case 2: img = image.NewCMYK(r) case 3: img = image.NewGray(r) case 4: img = image.NewGray16(r) case 5: img = image.NewNRGBA(r) case 6: img = image.NewNRGBA64(r) case 7: img = image.NewPaletted(r, randPalette(maxPaletteSize)) case 8: img = image.NewRGBA(r) case 9: img = image.NewRGBA64(r) default: panic("bad") } fill := gen.Rand(19) var palette []color.Color if fill == 17 { palette = randPalette(maxPaletteSize) } for y := 0; y < r.Max.Y; y++ { for x := 0; x < r.Max.X; x++ { switch { case fill <= 15: img.Set(x, y, color.RGBA64{ ^uint16(0) * uint16((fill>>0)&1), ^uint16(0) * uint16((fill>>1)&1), ^uint16(0) * uint16((fill>>2)&1), ^uint16(0) * uint16((fill>>3)&1), }) case fill == 16: img.Set(x, y, randColor()) case fill == 17: img.Set(x, y, palette[gen.Rand(len(palette))]) case fill == 18: if gen.Rand(3) != 0 { img.Set(x, y, color.RGBA64{}) } else { img.Set(x, y, randColor()) } default: panic("bad") } } } return img.(image.Image) }
func vgradMagenta() image.Image { m := image.NewCMYK(image.Rect(0, 0, 16, 16)) for y := 0; y < 16; y++ { for x := 0; x < 16; x++ { m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f}) } } return m }
// NewDrawableSize returns a new draw.Image with the same type as p and the given bounds. // If p is not a draw.Image, another type is used. func NewDrawableSize(p image.Image, r image.Rectangle) draw.Image { switch p.(type) { case *image.RGBA: return image.NewRGBA(r) case *image.RGBA64: return image.NewRGBA64(r) case *image.NRGBA: return image.NewNRGBA(r) case *image.NRGBA64: return image.NewNRGBA64(r) case *image.Alpha: return image.NewAlpha(r) case *image.Alpha16: return image.NewAlpha16(r) case *image.Gray: return image.NewGray(r) case *image.Gray16: return image.NewGray16(r) case *image.CMYK: return image.NewCMYK(r) default: return image.NewRGBA(r) } }
// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula // used depends on whether the JPEG image is stored as CMYK or YCbCrK, // indicated by the APP14 (Adobe) metadata. // // Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full // ink, so we apply "v = 255 - v" at various points. Note that a double // inversion is a no-op, so inversions might be implicit in the code below. func (d *decoder) applyBlack() (image.Image, error) { if !d.adobeTransformValid { return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata") } // If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB // or CMYK)" as per // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe // we assume that it is YCbCrK. This matches libjpeg's jdapimin.c. if d.adobeTransform != adobeTransformUnknown { // Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get // CMY, and patch in the original K. The RGB to CMY inversion cancels // out the 'Adobe inversion' described in the applyBlack doc comment // above, so in practice, only the fourth channel (black) is inverted. bounds := d.img3.Bounds() img := image.NewRGBA(bounds) drawYCbCr(img, bounds, d.img3, bounds.Min) for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)] } } return &image.CMYK{ Pix: img.Pix, Stride: img.Stride, Rect: img.Rect, }, nil } // The first three channels (cyan, magenta, yellow) of the CMYK // were decoded into d.img3, but each channel was decoded into a separate // []byte slice, and some channels may be subsampled. We interleave the // separate channels into an image.CMYK's single []byte slice containing 4 // contiguous bytes per pixel. bounds := d.img3.Bounds() img := image.NewCMYK(bounds) translations := [4]struct { src []byte stride int }{ {d.img3.Y, d.img3.YStride}, {d.img3.Cb, d.img3.CStride}, {d.img3.Cr, d.img3.CStride}, {d.blackPix, d.blackStride}, } for t, translation := range translations { subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { sy := y - bounds.Min.Y if subsample { sy /= 2 } for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { sx := x - bounds.Min.X if subsample { sx /= 2 } img.Pix[i] = 255 - translation.src[sy*translation.stride+sx] } } } return img, nil }
func BenchmarkNewSetFuncCMYK(b *testing.B) { benchmarkNewSetFunc(b, image.NewCMYK(image.Rect(0, 0, 1, 1))) }
func TestNewDrawable(t *testing.T) { r := image.Rect(0, 0, 1, 1) for _, newImage := range []func(image.Rectangle) image.Image{ func(r image.Rectangle) image.Image { return image.NewRGBA(r) }, func(r image.Rectangle) image.Image { return image.NewRGBA64(r) }, func(r image.Rectangle) image.Image { return image.NewNRGBA(r) }, func(r image.Rectangle) image.Image { return image.NewNRGBA64(r) }, func(r image.Rectangle) image.Image { return image.NewAlpha(r) }, func(r image.Rectangle) image.Image { return image.NewAlpha16(r) }, func(r image.Rectangle) image.Image { return image.NewGray(r) }, func(r image.Rectangle) image.Image { return image.NewGray16(r) }, func(r image.Rectangle) image.Image { return image.NewCMYK(r) }, func(r image.Rectangle) image.Image { return image.NewPaletted(r, color.Palette{ color.RGBA{0, 0, 0, 255}, color.RGBA{255, 0, 0, 255}, color.RGBA{0, 255, 0, 255}, color.RGBA{0, 0, 255, 255}, color.RGBA{255, 255, 255, 255}, }) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio444) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio422) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio420) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio440) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio411) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio410) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio444) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio422) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio420) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio440) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio411) }, func(r image.Rectangle) image.Image { return image.NewNYCbCrA(r, image.YCbCrSubsampleRatio410) }, func(r image.Rectangle) image.Image { return image.NewUniform(color.RGBA{}) }, func(r image.Rectangle) image.Image { return &testImageDefault{image.NewRGBA(r)} }, } { p := newImage(r) t.Run(fmt.Sprintf("%T", p), func(t *testing.T) { NewDrawable(p) }) } }
// bench benchmarks drawing src and mask images onto a dst image with the // given op and the color models to create those images from. // The created images' pixels are initialized to non-zero values. func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { b.StopTimer() var dst Image switch dcm { case color.RGBAModel: dst1 := image.NewRGBA(image.Rect(0, 0, dstw, dsth)) for y := 0; y < dsth; y++ { for x := 0; x < dstw; x++ { dst1.SetRGBA(x, y, color.RGBA{ uint8(5 * x % 0x100), uint8(7 * y % 0x100), uint8((7*x + 5*y) % 0x100), 0xff, }) } } dst = dst1 case color.RGBA64Model: dst1 := image.NewRGBA64(image.Rect(0, 0, dstw, dsth)) for y := 0; y < dsth; y++ { for x := 0; x < dstw; x++ { dst1.SetRGBA64(x, y, color.RGBA64{ uint16(53 * x % 0x10000), uint16(59 * y % 0x10000), uint16((59*x + 53*y) % 0x10000), 0xffff, }) } } dst = dst1 default: // The == operator isn't defined on a color.Palette (a slice), so we // use reflection. if reflect.DeepEqual(dcm, palette) { dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette) for y := 0; y < dsth; y++ { for x := 0; x < dstw; x++ { dst1.SetColorIndex(x, y, uint8(x^y)&1) } } dst = dst1 } else { b.Fatal("unknown destination color model", dcm) } } var src image.Image switch scm { case nil: src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0x44}} case color.CMYKModel: src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { src1.SetCMYK(x, y, color.CMYK{ uint8(13 * x % 0x100), uint8(11 * y % 0x100), uint8((11*x + 13*y) % 0x100), uint8((31*x + 37*y) % 0x100), }) } } src = src1 case color.GrayModel: src1 := image.NewGray(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { src1.SetGray(x, y, color.Gray{ uint8((11*x + 13*y) % 0x100), }) } } src = src1 case color.RGBAModel: src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { src1.SetRGBA(x, y, color.RGBA{ uint8(13 * x % 0x80), uint8(11 * y % 0x80), uint8((11*x + 13*y) % 0x80), 0x7f, }) } } src = src1 case color.RGBA64Model: src1 := image.NewRGBA64(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { src1.SetRGBA64(x, y, color.RGBA64{ uint16(103 * x % 0x8000), uint16(101 * y % 0x8000), uint16((101*x + 103*y) % 0x8000), 0x7fff, }) } } src = src1 case color.NRGBAModel: src1 := image.NewNRGBA(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { src1.SetNRGBA(x, y, color.NRGBA{ uint8(13 * x % 0x100), uint8(11 * y % 0x100), uint8((11*x + 13*y) % 0x100), 0x7f, }) } } src = src1 case color.YCbCrModel: yy := make([]uint8, srcw*srch) cb := make([]uint8, srcw*srch) cr := make([]uint8, srcw*srch) for i := range yy { yy[i] = uint8(3 * i % 0x100) cb[i] = uint8(5 * i % 0x100) cr[i] = uint8(7 * i % 0x100) } src = &image.YCbCr{ Y: yy, Cb: cb, Cr: cr, YStride: srcw, CStride: srcw, SubsampleRatio: image.YCbCrSubsampleRatio444, Rect: image.Rect(0, 0, srcw, srch), } default: b.Fatal("unknown source color model", scm) } var mask image.Image switch mcm { case nil: // No-op. case color.AlphaModel: mask1 := image.NewAlpha(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { for x := 0; x < srcw; x++ { a := uint8((23*x + 29*y) % 0x100) // Glyph masks are typically mostly zero, // so we only set a quarter of mask1's pixels. if a >= 0xc0 { mask1.SetAlpha(x, y, color.Alpha{a}) } } } mask = mask1 default: b.Fatal("unknown mask color model", mcm) } b.StartTimer() for i := 0; i < b.N; i++ { // Scatter the destination rectangle to draw into. x := 3 * i % (dstw - srcw) y := 7 * i % (dsth - srch) DrawMask(dst, dst.Bounds().Add(image.Pt(x, y)), src, image.ZP, mask, image.ZP, op) } }
return image.NewNRGBA64(r) }, func(r image.Rectangle) image.Image { return image.NewAlpha(r) }, func(r image.Rectangle) image.Image { return image.NewAlpha16(r) }, func(r image.Rectangle) image.Image { return image.NewGray(r) }, func(r image.Rectangle) image.Image { return image.NewGray16(r) }, func(r image.Rectangle) image.Image { return image.NewCMYK(r) }, func(r image.Rectangle) image.Image { return image.NewPaletted(r, testPalette) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio444) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio422) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio420) }, func(r image.Rectangle) image.Image { return image.NewYCbCr(r, image.YCbCrSubsampleRatio440)