func benchSpeed(b *testing.B, bt BenchType, asm bool) { raw := readImage(b, "testdata/lenna.jpg") src := image.NewYCbCr(image.Rect(0, 0, bt.win, bt.hin), image.YCbCrSubsampleRatio420) convert(b, src, raw, asm, bt.interlaced, bt.filter) dst := image.NewYCbCr(image.Rect(0, 0, bt.wout, bt.hout), image.YCbCrSubsampleRatio420) converter := prepare(b, dst, src, asm, bt.interlaced, bt.filter, 0) b.SetBytes(int64(bt.wout*bt.hout*3) >> 1) b.ResetTimer() for i := 0; i < b.N; i++ { converter.Convert(dst, src) } }
func makeImages(r image.Rectangle) []image.Image { return []image.Image{ image.NewGray(r), image.NewGray16(r), image.NewNRGBA(r), image.NewNRGBA64(r), image.NewPaletted(r, somePalette), image.NewRGBA(r), image.NewRGBA64(r), image.NewYCbCr(r, image.YCbCrSubsampleRatio444), image.NewYCbCr(r, image.YCbCrSubsampleRatio422), image.NewYCbCr(r, image.YCbCrSubsampleRatio420), image.NewYCbCr(r, image.YCbCrSubsampleRatio440), } }
func NewImageOfTypeRect(src image.Image, bounds image.Rectangle) image.Image { switch i := src.(type) { case *image.Alpha: return image.NewAlpha(bounds) case *image.Alpha16: return image.NewAlpha16(bounds) case *image.Gray: return image.NewGray(bounds) case *image.Gray16: return image.NewGray16(bounds) case *image.NRGBA: return image.NewNRGBA(bounds) case *image.NRGBA64: return image.NewNRGBA64(bounds) case *image.Paletted: return image.NewPaletted(bounds, i.Palette) case *image.RGBA: return image.NewRGBA(bounds) case *image.RGBA64: return image.NewRGBA64(bounds) case *image.YCbCr: return image.NewYCbCr(bounds, i.SubsampleRatio) } panic("Unknown image type") }
// makeImg allocates and initializes the destination image. func (d *decoder) makeImg(h0, v0, mxx, myy int) { if d.jpegColorSpace == Grayscale { m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy)) d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray) return } else if d.jpegColorSpace == YCbCr { var subsampleRatio image.YCbCrSubsampleRatio switch { case h0 == 1 && v0 == 1: subsampleRatio = image.YCbCrSubsampleRatio444 case h0 == 1 && v0 == 2: subsampleRatio = image.YCbCrSubsampleRatio440 case h0 == 2 && v0 == 1: subsampleRatio = image.YCbCrSubsampleRatio422 case h0 == 2 && v0 == 2: subsampleRatio = image.YCbCrSubsampleRatio420 default: panic("unreachable") } m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) } else if d.jpegColorSpace == RGBA { m := image.NewRGBA(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy)) d.img4 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.RGBA) } else { } }
func BenchmarkHalveYCrCb(b *testing.B) { m := image.NewYCbCr(orig, image.YCbCrSubsampleRatio422) b.ResetTimer() for i := 0; i < b.N; i++ { halve(m) } }
func runTestCaseWith(t *testing.T, tc *TestCase, asm bool, cycles int) image.Image { srcRaw := readImage(t, "testdata/"+tc.file).(*image.YCbCr) dstRaw := image.NewYCbCr(image.Rect(0, 0, tc.dst.Max.X*2, tc.dst.Max.Y*2), srcRaw.SubsampleRatio) var src, dst, ref image.Image if tc.src.Empty() { tc.src = srcRaw.Bounds() } suffix := "yuv" if tc.rgb { suffix = "rgb" src = toRgb(srcRaw).SubImage(tc.src) ref = toRgb(srcRaw).SubImage(tc.src) dst = toRgb(dstRaw).SubImage(tc.dst) } else { src = srcRaw.SubImage(tc.src) refRaw := image.NewYCbCr(src.Bounds(), srcRaw.SubsampleRatio) err := Convert(refRaw, src, nil) expect(t, err, nil) ref = refRaw.SubImage(tc.src) dst = dstRaw.SubImage(tc.dst) } fwd := prepare(t, dst, src, asm, tc.interlaced, tc.filter, tc.threads) bwd := prepare(t, src, dst, asm, tc.interlaced, tc.filter, tc.threads) for i := 0; i < cycles; i++ { err := fwd.Convert(dst, src) expect(t, err, nil) err = bwd.Convert(src, dst) expect(t, err, nil) } if len(tc.psnrs) > 0 { checkPsnrs(t, ref, src, tc.psnrRect, tc.psnrs) } if len(tc.dump) > 0 { sb := src.Bounds() db := dst.Bounds() asmSuffix := "go" if asm { asmSuffix = "asm" } name := fmt.Sprintf("testdata/%v-%vx%v-%vx%v-%v-%v-%v-%v.png", tc.dump, sb.Dx(), sb.Dy(), db.Dx(), db.Dy(), suffix, toInterlacedString(tc.interlaced), asmSuffix, tc.filter.Name()) writeImage(t, name, src) } return src }
func benchRescale(b *testing.B, w, h, thumbW, thumbH int) { // Most JPEGs are YCbCr, so bench with that. im := image.NewYCbCr(image.Rect(0, 0, w, h), image.YCbCrSubsampleRatio422) o := &DecodeOpts{MaxWidth: thumbW, MaxHeight: thumbH} b.ResetTimer() for i := 0; i < b.N; i++ { _ = rescale(im, o, false) } }
func testInterlacedFailWith(t *testing.T, rgb bool) { src := readImage(t, "testdata/lenna.jpg") dst := image.Image(image.NewYCbCr(image.Rect(0, 0, 640, 480), image.YCbCrSubsampleRatio420)) if rgb { src = toRgb(src) dst = toRgb(dst) } convert(t, dst, src, false, true, NewBicubicFilter()) convert(t, dst, src, true, true, NewBicubicFilter()) }
// Benchmark resize of 16 MPix jpeg image to 800px width. func jpegThumb(b *testing.B, interp InterpolationFunction) { input := image.NewYCbCr(image.Rect(0, 0, 4896, 3264), image.YCbCrSubsampleRatio422) var output image.Image for i := 0; i < b.N; i++ { output = Resize(800, 0, input, interp) } output.At(0, 0) }
// ensureImg ensures that d.img is large enough to hold the decoded frame. func (d *Decoder) ensureImg() { if d.img != nil { p0, p1 := d.img.Rect.Min, d.img.Rect.Max if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh { return } } m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420) d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr) d.upMB = make([]mb, d.mbw) }
func ImageTransformByProfile(src_image image.Image, src_prof, dst_prof *Profile) (image.Image, error) { var dst_image image.Image rect := src_image.Bounds() width := rect.Dx() height := rect.Dy() colorModel := src_image.ColorModel() // 今のところ RGBA, YCbCr のみ対応 if (colorModel != color.YCbCrModel) && (colorModel != color.RGBAModel) { return nil, fmt.Errorf("ImageTransformByProfile: Unsupported ColorModel(%d)", colorModel) } var src_rgba *image.RGBA var src_ycbcr *image.YCbCr if colorModel == color.YCbCrModel { // YCbCr の場合は RGB に変換する src_ycbcr = src_image.(*image.YCbCr) src_rgba = image.NewRGBA(rect) DrawYCbCr(src_rgba, rect, src_ycbcr, image.Pt(0, 0)) } else { src_rgba = src_image.(*image.RGBA) // type assertions } transform := CreateTransform(src_prof, DATA_RGBA_8, dst_prof, DATA_RGBA_8) defer transform.DeleteTransform() if transform == nil { return nil, fmt.Errorf("ImageTransformByProfile: CreateTransform Failedl(%d)", colorModel) } dst_rgba := image.NewRGBA(rect) src_pix := src_rgba.Pix dst_pix := dst_rgba.Pix len_pix := len(src_pix) transform.DoTransform(src_pix, dst_pix, len_pix) // YCbCr の場合は RGB から戻す if colorModel == color.YCbCrModel { dst_ycbcr := image.NewYCbCr(rect, src_ycbcr.SubsampleRatio) var x int var y int for y = 0; y < height; y++ { for x = 0; x < width; x++ { r, g, b, _ := dst_rgba.At(x, y).RGBA() yy, cb, cr := color.RGBToYCbCr(uint8(r), uint8(g), uint8(b)) yi := dst_ycbcr.YOffset(x, y) ci := dst_ycbcr.COffset(x, y) dst_ycbcr.Y[yi] = yy dst_ycbcr.Cb[ci] = cb dst_ycbcr.Cr[ci] = cr } } dst_image = image.Image(dst_ycbcr) } else { dst_image = image.Image(dst_rgba) } return dst_image, nil }
func convertFiles(t Tester, w, h int, input string, filter Filter, rgb bool) (image.Image, image.Image) { src := readImage(t, input) raw := image.NewYCbCr(image.Rect(0, 0, w*2, h*2), image.YCbCrSubsampleRatio420) dst := raw.SubImage(image.Rect(7, 7, 7+w, 7+h)) if rgb { src = toRgb(src) dst = toRgb(dst) } err := Convert(dst, src, filter) expect(t, err, nil) return src, dst }
func benchRescale(b *testing.B, w, h, thumbW, thumbH int) { // Most JPEGs are YCbCr, so bench with that. im := image.NewYCbCr(image.Rect(0, 0, w, h), image.YCbCrSubsampleRatio422) o := &DecodeOpts{MaxWidth: thumbW, MaxHeight: thumbH} sw, sh, needRescale := o.rescaleDimensions(im.Bounds(), false) if !needRescale { b.Fatal("opts.rescaleDimensions failed to indicate image needs rescale") } b.ResetTimer() for i := 0; i < b.N; i++ { _ = rescale(im, sw, sh) } }
func TestNewPixelGetter(t *testing.T) { var img image.Image var pg *pixelGetter img = image.NewNRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA || pg.imgNRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA") } img = image.NewNRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA64 || pg.imgNRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA64") } img = image.NewRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA || pg.imgRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA") } img = image.NewRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA64 || pg.imgRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA64") } img = image.NewGray(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray || pg.imgGray == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray") } img = image.NewGray16(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray16 || pg.imgGray16 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray16") } img = image.NewYCbCr(image.Rect(0, 0, 1, 1), image.YCbCrSubsampleRatio422) pg = newPixelGetter(img) if pg.imgType != itYCbCr || pg.imgYCbCr == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter YCbCr") } img = image.NewUniform(color.NRGBA64{0, 0, 0, 0}) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Uniform)") } img = image.NewAlpha(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Alpha)") } }
func TestEncodeYCbCrStreamGeneric(t *testing.T) { r := image.Rect(0, 0, 16, 16) img := image.NewYCbCr(r, image.YCbCrSubsampleRatio444) c := color.YCbCr{Y: 70, Cb: 146, Cr: 164} for i := range img.Y { img.Y[i] = c.Y } for i := range img.Cb { img.Cb[i] = c.Cb } for i := range img.Cr { img.Cr[i] = c.Cr } var buf bytes.Buffer encodeImageStream(&buf, img) expectImageBuffer(buf.Bytes(), r, c, t) }
func FromImage(src image.Image) *image.YCbCr { r := src.Bounds() dst := image.NewYCbCr(src.Bounds(), image.YCbCrSubsampleRatio444) for x := r.Min.X; x < r.Max.X; x++ { for y := r.Min.Y; y < r.Max.Y; y++ { c := src.At(x, y) r, g, b, _ := c.RGBA() yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) i := dst.YOffset(x, y) dst.Y[i] = yy dst.Cb[i] = cb dst.Cr[i] = cr } } return dst }
func NewEncoder(codec uint32, in image.Image, out io.Writer) (*Encoder, error) { _codec := C.avcodec_find_encoder(codec) if _codec == nil { return nil, fmt.Errorf("could not find codec") } c := C.avcodec_alloc_context3(_codec) f := C.avcodec_alloc_frame() c.bit_rate = 400000 // resolution must be a multiple of two w, h := C.int(in.Bounds().Dx()), C.int(in.Bounds().Dy()) if w%2 == 1 || h%2 == 1 { return nil, fmt.Errorf("Bad image dimensions (%d, %d), must be even", w, h) } log.Printf("Encoder dimensions: %d, %d", w, h) c.width = w c.height = h c.time_base = C.AVRational{1, 25} // FPS c.gop_size = 10 // emit one intra frame every ten frames c.max_b_frames = 1 underlying_im := image.NewYCbCr(in.Bounds(), image.YCbCrSubsampleRatio420) c.pix_fmt = C.PIX_FMT_YUV420P f.data[0] = ptr(underlying_im.Y) f.data[1] = ptr(underlying_im.Cb) f.data[2] = ptr(underlying_im.Cr) f.linesize[0] = w f.linesize[1] = w / 2 f.linesize[2] = w / 2 if C.avcodec_open2(c, _codec, nil) < 0 { return nil, fmt.Errorf("could not open codec") } _swscontext := C.sws_getContext(w, h, C.PIX_FMT_RGB0, w, h, C.PIX_FMT_YUV420P, C.SWS_BICUBIC, nil, nil, nil) e := &Encoder{codec, in, underlying_im, out, _codec, c, _swscontext, f, make([]byte, 16*1024)} return e, nil }
// ResizeImage resizes the given image IF it is larger than maxWidth or maxHeight func ResizeImage(src image.Image, maxWidth int64, maxHeight int64, square bool) (image.Image, error) { var dst image.Image // Check the original dimensions first, and bail out if this image is not larger than max dimensions srcSize := src.Bounds().Size() if int64(srcSize.X) < maxWidth && int64(srcSize.Y) < maxHeight { return src, nil } // Use the original image dimensions to keep it in pro // Distorting images is a sin of which we are never guilty ratio := float64(maxWidth) / float64(srcSize.X) yRatio := float64(maxHeight) / float64(srcSize.Y) if yRatio < ratio { ratio = yRatio } // Now adjust desired width and height according to ratio width := float64(srcSize.X) * ratio height := float64(srcSize.Y) * ratio // Create a new resized image with the desired dimensions and fill it with resized image data // We switch on input image type - is YCbCrSubsampleRatio444 correct? switch src.(type) { case *image.YCbCr: dst = image.NewYCbCr(image.Rect(0, 0, int(width), int(height)), image.YCbCrSubsampleRatio444) case *image.RGBA: dst = image.NewRGBA(image.Rect(0, 0, int(width), int(height))) default: dst = nil } err := rez.Convert(dst, src, rez.NewBicubicFilter()) // IF we want thumbnails to be square/cropped we could do this // for now we don't need this. We may not even want it for camping? // err := imaging.Thumbnail(srcImage, 100, 100, imaging.Lanczos) if err != nil { return nil, err } return dst, nil }
func testYCbCr(t *testing.T, r image.Rectangle, subsampleRatio image.YCbCrSubsampleRatio, delta image.Point) { // Create a YCbCr image m, whose bounds are r translated by (delta.X, delta.Y). r1 := r.Add(delta) img := image.NewYCbCr(r1, subsampleRatio) // Initialize img's pixels. For 422 and 420 subsampling, some of the Cb and Cr elements // will be set multiple times. That's OK. We just want to avoid a uniform image. for y := r1.Min.Y; y < r1.Max.Y; y++ { for x := r1.Min.X; x < r1.Max.X; x++ { yi := img.YOffset(x, y) ci := img.COffset(x, y) img.Y[yi] = uint8(16*y + x) img.Cb[ci] = uint8(y + 16*x) img.Cr[ci] = uint8(y + 16*x) } } m := imageYCbCrToYCC(img) // Make various sub-images of m. for y0 := delta.Y + 3; y0 < delta.Y+7; y0++ { for y1 := delta.Y + 8; y1 < delta.Y+13; y1++ { for x0 := delta.X + 3; x0 < delta.X+7; x0++ { for x1 := delta.X + 8; x1 < delta.X+13; x1++ { subRect := image.Rect(x0, y0, x1, y1) sub := m.SubImage(subRect).(*ycc) // For each point in the sub-image's bounds, check that m.At(x, y) equals sub.At(x, y). for y := sub.Rect.Min.Y; y < sub.Rect.Max.Y; y++ { for x := sub.Rect.Min.X; x < sub.Rect.Max.X; x++ { color0 := m.At(x, y).(color.YCbCr) color1 := sub.At(x, y).(color.YCbCr) if color0 != color1 { t.Errorf("r=%v, subsampleRatio=%v, delta=%v, x=%d, y=%d, color0=%v, color1=%v", r, subsampleRatio, delta, x, y, color0, color1) return } } } } } } } }
func benchYCbCr(b *testing.B, interp InterpolationFunction) { m := image.NewYCbCr(image.Rect(0, 0, benchMaxX, benchMaxY), image.YCbCrSubsampleRatio422) // Initialize m's pixels to create a non-uniform image. for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ { for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ { yi := m.YOffset(x, y) ci := m.COffset(x, y) m.Y[yi] = uint8(16*y + x) m.Cb[ci] = uint8(y + 16*x) m.Cr[ci] = uint8(y + 16*x) } } var out image.Image b.ResetTimer() for i := 0; i < b.N; i++ { out = Resize(benchWidth, benchHeight, m, interp) } out.At(0, 0) }
func TestIsOpaque(t *testing.T) { type opqt struct { img image.Image opaque bool } var testData []opqt testData = append(testData, opqt{image.NewNRGBA(image.Rect(0, 0, 1, 1)), false}) testData = append(testData, opqt{image.NewNRGBA64(image.Rect(0, 0, 1, 1)), false}) testData = append(testData, opqt{image.NewRGBA(image.Rect(0, 0, 1, 1)), false}) testData = append(testData, opqt{image.NewRGBA64(image.Rect(0, 0, 1, 1)), false}) testData = append(testData, opqt{image.NewGray(image.Rect(0, 0, 1, 1)), true}) testData = append(testData, opqt{image.NewGray16(image.Rect(0, 0, 1, 1)), true}) testData = append(testData, opqt{image.NewYCbCr(image.Rect(0, 0, 1, 1), image.YCbCrSubsampleRatio444), true}) testData = append(testData, opqt{image.NewAlpha(image.Rect(0, 0, 1, 1)), false}) img1 := image.NewNRGBA(image.Rect(0, 0, 1, 1)) img1.Set(0, 0, color.NRGBA{0x00, 0x00, 0x00, 0xff}) testData = append(testData, opqt{img1, true}) img2 := image.NewNRGBA64(image.Rect(0, 0, 1, 1)) img2.Set(0, 0, color.NRGBA{0x00, 0x00, 0x00, 0xff}) testData = append(testData, opqt{img2, true}) img3 := image.NewRGBA(image.Rect(0, 0, 1, 1)) img3.Set(0, 0, color.NRGBA{0x00, 0x00, 0x00, 0xff}) testData = append(testData, opqt{img3, true}) img4 := image.NewRGBA64(image.Rect(0, 0, 1, 1)) img4.Set(0, 0, color.NRGBA{0x00, 0x00, 0x00, 0xff}) testData = append(testData, opqt{img4, true}) imgp1 := image.NewPaletted(image.Rect(0, 0, 1, 1), []color.Color{color.NRGBA{0x00, 0x00, 0x00, 0xff}}) imgp1.SetColorIndex(0, 0, 0) testData = append(testData, opqt{imgp1, true}) imgp2 := image.NewPaletted(image.Rect(0, 0, 1, 1), []color.Color{color.NRGBA{0x00, 0x00, 0x00, 0xfe}}) imgp2.SetColorIndex(0, 0, 0) testData = append(testData, opqt{imgp2, false}) for _, d := range testData { isop := isOpaque(d.img) if isop != d.opaque { t.Errorf("isOpaque failed %#v, %v", d.img, isop) } } }
// makeImg allocates and initializes the destination image. func (d *decoder) makeImg(h0, v0, mxx, myy int) { if d.nComp == nGrayComponent { m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy)) d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray) return } var subsampleRatio image.YCbCrSubsampleRatio switch h0 * v0 { case 1: subsampleRatio = image.YCbCrSubsampleRatio444 case 2: subsampleRatio = image.YCbCrSubsampleRatio422 case 4: subsampleRatio = image.YCbCrSubsampleRatio420 default: panic("unreachable") } m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) }
// makeImg allocates and initializes the destination image. func (d *decoder) makeImg(mxx, myy int) { if d.nComp == 1 { m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy)) d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray) return } h0 := d.comp[0].h v0 := d.comp[0].v hRatio := h0 / d.comp[1].h vRatio := v0 / d.comp[1].v var subsampleRatio image.YCbCrSubsampleRatio switch hRatio<<4 | vRatio { case 0x11: subsampleRatio = image.YCbCrSubsampleRatio444 case 0x12: subsampleRatio = image.YCbCrSubsampleRatio440 case 0x21: subsampleRatio = image.YCbCrSubsampleRatio422 case 0x22: subsampleRatio = image.YCbCrSubsampleRatio420 case 0x41: subsampleRatio = image.YCbCrSubsampleRatio411 case 0x42: subsampleRatio = image.YCbCrSubsampleRatio410 default: panic("unreachable") } m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) if d.nComp == 4 { h3, v3 := d.comp[3].h, d.comp[3].v d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy) d.blackStride = 8 * h3 * mxx } }
func BenchmarkNewAtFuncYCbCR(b *testing.B) { benchmarkNewAtFunc(b, image.NewYCbCr(image.Rect(0, 0, 1, 1), image.YCbCrSubsampleRatio444)) }
func srcYCbCr(boundsHint image.Rectangle) (image.Image, error) { m := image.NewYCbCr(boundsHint, image.YCbCrSubsampleRatio420) fillPix(rand.New(rand.NewSource(3)), m.Y, m.Cb, m.Cr) return m, nil }
func TestGetPixel(t *testing.T) { var pg *pixelGetter // RGBA, NRGBA, RGBA64, NRGBA64 palette := []color.Color{ color.NRGBA{0, 0, 0, 0}, color.NRGBA{255, 255, 255, 255}, color.NRGBA{50, 100, 150, 255}, color.NRGBA{150, 100, 50, 200}, } images1 := []draw.Image{ image.NewRGBA(image.Rect(-1, -2, 3, 4)), image.NewRGBA64(image.Rect(-1, -2, 3, 4)), image.NewNRGBA(image.Rect(-1, -2, 3, 4)), image.NewNRGBA64(image.Rect(-1, -2, 3, 4)), image.NewPaletted(image.Rect(-1, -2, 3, 4), palette), } colors1 := []struct { c color.NRGBA px pixel }{ {color.NRGBA{0, 0, 0, 0}, pixel{0, 0, 0, 0}}, {color.NRGBA{255, 255, 255, 255}, pixel{1, 1, 1, 1}}, {color.NRGBA{50, 100, 150, 255}, pixel{0.196, 0.392, 0.588, 1}}, {color.NRGBA{150, 100, 50, 200}, pixel{0.588, 0.392, 0.196, 0.784}}, } for _, img := range images1 { pg = newPixelGetter(img) for _, k := range colors1 { for _, x := range []int{-1, 0, 2} { for _, y := range []int{-2, 0, 3} { img.Set(x, y, k.c) px := pg.getPixel(x, y) if !comparePixels(k.px, px, 0.005) { t.Errorf("getPixel %T %v %dx%d %v %v", img, k.c, x, y, k.px, px) } } } } } // Uniform (Generic) for _, k := range colors1 { img := image.NewUniform(k.c) pg = newPixelGetter(img) for _, x := range []int{-1, 0, 2} { for _, y := range []int{-2, 0, 3} { px := pg.getPixel(x, y) if !comparePixels(k.px, px, 0.005) { t.Errorf("getPixel %T %v %dx%d %v %v", img, k.c, x, y, k.px, px) } } } } // YCbCr colors2 := []struct { c color.NRGBA px pixel }{ {color.NRGBA{0, 0, 0, 255}, pixel{0, 0, 0, 1}}, {color.NRGBA{255, 255, 255, 255}, pixel{1, 1, 1, 1}}, {color.NRGBA{50, 100, 150, 255}, pixel{0.196, 0.392, 0.588, 1}}, } for _, k := range colors2 { img := image.NewYCbCr(image.Rect(-1, -2, 3, 4), image.YCbCrSubsampleRatio444) pg = newPixelGetter(img) for _, x := range []int{-1, 0, 2} { for _, y := range []int{-2, 0, 3} { iy := img.YOffset(x, y) ic := img.COffset(x, y) img.Y[iy], img.Cb[ic], img.Cr[ic] = color.RGBToYCbCr(k.c.R, k.c.G, k.c.B) px := pg.getPixel(x, y) if !comparePixels(k.px, px, 0.005) { t.Errorf("getPixel %T %v %dx%d %v %v", img, k.c, x, y, k.px, px) } } } } // Gray, Gray16 images2 := []draw.Image{ image.NewGray(image.Rect(-1, -2, 3, 4)), image.NewGray16(image.Rect(-1, -2, 3, 4)), } colors3 := []struct { c color.NRGBA px pixel }{ {color.NRGBA{0, 0, 0, 0}, pixel{0, 0, 0, 1}}, {color.NRGBA{255, 255, 255, 255}, pixel{1, 1, 1, 1}}, {color.NRGBA{50, 100, 150, 255}, pixel{0.356, 0.356, 0.356, 1}}, {color.NRGBA{150, 100, 50, 200}, pixel{0.337, 0.337, 0.337, 1}}, } for _, img := range images2 { pg = newPixelGetter(img) for _, k := range colors3 { for _, x := range []int{-1, 0, 2} { for _, y := range []int{-2, 0, 3} { img.Set(x, y, k.c) px := pg.getPixel(x, y) if !comparePixels(k.px, px, 0.005) { t.Errorf("getPixel %T %v %dx%d %v %v", img, k.c, x, y, k.px, px) } } } } } }
func TestConvertYCbCr(t *testing.T) { testImage := []Image{ image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio420), image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio422), image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio440), image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio444), } for _, img := range testImage { m := img.(*image.YCbCr) for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ { for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ { yi := m.YOffset(x, y) ci := m.COffset(x, y) m.Y[yi] = uint8(16*y + x) m.Cb[ci] = uint8(y + 16*x) m.Cr[ci] = uint8(y + 16*x) } } // test conversion from YCbCr to ycc yc := imageYCbCrToYCC(m) for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ { for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ { ystride := 3 * (m.Rect.Max.X - m.Rect.Min.X) xstride := 3 yi := m.YOffset(x, y) ci := m.COffset(x, y) si := (y * ystride) + (x * xstride) if m.Y[yi] != yc.Pix[si] { t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d si: %d", m.Y[yi], yc.Pix[si], x, y, yi, si) } if m.Cb[ci] != yc.Pix[si+1] { t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d si: %d", m.Cb[ci], yc.Pix[si+1], x, y, ci, si+1) } if m.Cr[ci] != yc.Pix[si+2] { t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d si: %d", m.Cr[ci], yc.Pix[si+2], x, y, ci, si+2) } } } // test conversion from ycc back to YCbCr ym := yc.YCbCr() for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ { for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ { yi := m.YOffset(x, y) ci := m.COffset(x, y) if m.Y[yi] != ym.Y[yi] { t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d", m.Y[yi], ym.Y[yi], x, y, yi) } if m.Cb[ci] != ym.Cb[ci] { t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d", m.Cb[ci], ym.Cb[ci], x, y, ci) } if m.Cr[ci] != ym.Cr[ci] { t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d", m.Cr[ci], ym.Cr[ci], x, y, ci) } } } } }
// Copies an image to a new image of the same kind: func CloneKind(src image.Image) image.Image { srcBounds := src.Bounds().Canon() zeroedBounds := srcBounds.Sub(srcBounds.Min) switch si := src.(type) { case *image.RGBA: out := image.NewRGBA(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetRGBA(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.RGBA)) } } return out case *image.YCbCr: out := image.NewYCbCr(zeroedBounds, si.SubsampleRatio) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { ycbcr := si.At(x, y).(color.YCbCr) yoffs := out.YOffset(x-srcBounds.Min.X, y-srcBounds.Min.Y) coffs := out.COffset(x-srcBounds.Min.X, y-srcBounds.Min.Y) out.Y[yoffs] = ycbcr.Y out.Cb[coffs] = ycbcr.Cb out.Cr[coffs] = ycbcr.Cr } } return out case *image.Paletted: out := image.NewPaletted(zeroedBounds, si.Palette) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetColorIndex(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.ColorIndexAt(x, y)) } } return out case *image.RGBA64: out := image.NewRGBA64(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetRGBA64(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.RGBA64)) } } return out case *image.NRGBA: out := image.NewNRGBA(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetNRGBA(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.NRGBA)) } } return out case *image.NRGBA64: out := image.NewNRGBA64(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetNRGBA64(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.NRGBA64)) } } return out case *image.Alpha: out := image.NewAlpha(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetAlpha(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.Alpha)) } } return out case *image.Alpha16: out := image.NewAlpha16(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetAlpha16(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.Alpha16)) } } return out case *image.Gray: out := image.NewGray(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetGray(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.Gray)) } } return out case *image.Gray16: out := image.NewGray16(zeroedBounds) for y := srcBounds.Min.Y; y < srcBounds.Max.Y; y++ { for x := srcBounds.Min.X; x < srcBounds.Max.X; x++ { out.SetGray16(x-srcBounds.Min.X, y-srcBounds.Min.Y, si.At(x, y).(color.Gray16)) } } return out default: panic(fmt.Errorf("Unhandled image format type: %s", reflect.TypeOf(src).Name())) } }
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) }) } }
// YCbCr converts ycc to a YCbCr image with the same subsample ratio // as the YCbCr image that ycc was generated from. func (p *ycc) YCbCr() *image.YCbCr { ycbcr := image.NewYCbCr(p.Rect, p.SubsampleRatio) var off int switch ycbcr.SubsampleRatio { case image.YCbCrSubsampleRatio422: for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ { yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ { xx := (x - ycbcr.Rect.Min.X) yi := yy + xx ci := cy + xx/2 ycbcr.Y[yi] = p.Pix[off+0] ycbcr.Cb[ci] = p.Pix[off+1] ycbcr.Cr[ci] = p.Pix[off+2] off += 3 } } case image.YCbCrSubsampleRatio420: for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ { yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ { xx := (x - ycbcr.Rect.Min.X) yi := yy + xx ci := cy + xx/2 ycbcr.Y[yi] = p.Pix[off+0] ycbcr.Cb[ci] = p.Pix[off+1] ycbcr.Cr[ci] = p.Pix[off+2] off += 3 } } case image.YCbCrSubsampleRatio440: for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ { yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ { xx := (x - ycbcr.Rect.Min.X) yi := yy + xx ci := cy + xx ycbcr.Y[yi] = p.Pix[off+0] ycbcr.Cb[ci] = p.Pix[off+1] ycbcr.Cr[ci] = p.Pix[off+2] off += 3 } } default: // Default to 4:4:4 subsampling. for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ { yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ { xx := (x - ycbcr.Rect.Min.X) yi := yy + xx ci := cy + xx ycbcr.Y[yi] = p.Pix[off+0] ycbcr.Cb[ci] = p.Pix[off+1] ycbcr.Cr[ci] = p.Pix[off+2] off += 3 } } } return ycbcr }