Prechádzať zdrojové kódy

move Clone to separate file

Grigory Dryapak 8 rokov pred
rodič
commit
0198c96e30
4 zmenil súbory, kde vykonal 519 pridanie a 506 odobranie
  1. 272 0
      clone.go
  2. 247 0
      clone_test.go
  3. 0 266
      helpers.go
  4. 0 240
      helpers_test.go

+ 272 - 0
clone.go

@@ -0,0 +1,272 @@
+package imaging
+
+import (
+	"image"
+	"image/color"
+)
+
+// Clone returns a copy of the given image.
+func Clone(img image.Image) *image.NRGBA {
+	dstBounds := img.Bounds().Sub(img.Bounds().Min)
+	dst := image.NewNRGBA(dstBounds)
+
+	switch src := img.(type) {
+	case *image.NRGBA:
+		copyNRGBA(dst, src)
+	case *image.NRGBA64:
+		copyNRGBA64(dst, src)
+	case *image.RGBA:
+		copyRGBA(dst, src)
+	case *image.RGBA64:
+		copyRGBA64(dst, src)
+	case *image.Gray:
+		copyGray(dst, src)
+	case *image.Gray16:
+		copyGray16(dst, src)
+	case *image.YCbCr:
+		copyYCbCr(dst, src)
+	case *image.Paletted:
+		copyPaletted(dst, src)
+	default:
+		copyImage(dst, src)
+	}
+
+	return dst
+}
+
+func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	rowSize := dstW * 4
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
+		}
+	})
+}
+
+func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				dst.Pix[di+0] = src.Pix[si+0]
+				dst.Pix[di+1] = src.Pix[si+2]
+				dst.Pix[di+2] = src.Pix[si+4]
+				dst.Pix[di+3] = src.Pix[si+6]
+				di += 4
+				si += 8
+			}
+		}
+	})
+}
+
+func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				a := src.Pix[si+3]
+				dst.Pix[di+3] = a
+
+				switch a {
+				case 0:
+					dst.Pix[di+0] = 0
+					dst.Pix[di+1] = 0
+					dst.Pix[di+2] = 0
+				case 0xff:
+					dst.Pix[di+0] = src.Pix[si+0]
+					dst.Pix[di+1] = src.Pix[si+1]
+					dst.Pix[di+2] = src.Pix[si+2]
+				default:
+					var tmp uint16
+					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+					dst.Pix[di+0] = uint8(tmp)
+					tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
+					dst.Pix[di+1] = uint8(tmp)
+					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+					dst.Pix[di+2] = uint8(tmp)
+				}
+
+				di += 4
+				si += 4
+			}
+		}
+	})
+}
+
+func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				a := src.Pix[si+6]
+				dst.Pix[di+3] = a
+
+				switch a {
+				case 0:
+					dst.Pix[di+0] = 0
+					dst.Pix[di+1] = 0
+					dst.Pix[di+2] = 0
+				case 0xff:
+					dst.Pix[di+0] = src.Pix[si+0]
+					dst.Pix[di+1] = src.Pix[si+2]
+					dst.Pix[di+2] = src.Pix[si+4]
+				default:
+					var tmp uint16
+					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+					dst.Pix[di+0] = uint8(tmp)
+					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+					dst.Pix[di+1] = uint8(tmp)
+					tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
+					dst.Pix[di+2] = uint8(tmp)
+				}
+
+				di += 4
+				si += 8
+			}
+		}
+	})
+}
+
+func copyGray(dst *image.NRGBA, src *image.Gray) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := src.Pix[si]
+				dst.Pix[di+0] = c
+				dst.Pix[di+1] = c
+				dst.Pix[di+2] = c
+				dst.Pix[di+3] = 0xff
+				di += 4
+				si++
+			}
+		}
+	})
+}
+
+func copyGray16(dst *image.NRGBA, src *image.Gray16) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := src.Pix[si]
+				dst.Pix[di+0] = c
+				dst.Pix[di+1] = c
+				dst.Pix[di+2] = c
+				dst.Pix[di+3] = 0xff
+				di += 4
+				si += 2
+			}
+		}
+	})
+}
+
+func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				srcX := srcMinX + dstX
+				srcY := srcMinY + dstY
+				siy := src.YOffset(srcX, srcY)
+				sic := src.COffset(srcX, srcY)
+				r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
+				dst.Pix[di+0] = r
+				dst.Pix[di+1] = g
+				dst.Pix[di+2] = b
+				dst.Pix[di+3] = 0xff
+				di += 4
+			}
+		}
+	})
+}
+
+func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	plen := len(src.Palette)
+	pnew := make([]color.NRGBA, plen)
+	for i := 0; i < plen; i++ {
+		pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
+	}
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := pnew[src.Pix[si]]
+				dst.Pix[di+0] = c.R
+				dst.Pix[di+1] = c.G
+				dst.Pix[di+2] = c.B
+				dst.Pix[di+3] = c.A
+				di += 4
+				si++
+			}
+		}
+	})
+}
+
+func copyImage(dst *image.NRGBA, src image.Image) {
+	srcMinX := src.Bounds().Min.X
+	srcMinY := src.Bounds().Min.Y
+	dstW := dst.Bounds().Dx()
+	dstH := dst.Bounds().Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
+				dst.Pix[di+0] = c.R
+				dst.Pix[di+1] = c.G
+				dst.Pix[di+2] = c.B
+				dst.Pix[di+3] = c.A
+				di += 4
+			}
+		}
+	})
+}
+
+// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
+func toNRGBA(img image.Image) *image.NRGBA {
+	if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
+		return img
+	}
+	return Clone(img)
+}

+ 247 - 0
clone_test.go

@@ -0,0 +1,247 @@
+package imaging
+
+import (
+	"image"
+	"image/color"
+	"testing"
+)
+
+func TestClone(t *testing.T) {
+	td := []struct {
+		desc string
+		src  image.Image
+		want *image.NRGBA
+	}{
+		{
+			"Clone NRGBA",
+			&image.NRGBA{
+				Rect:   image.Rect(-1, -1, 0, 1),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone NRGBA64",
+			&image.NRGBA64{
+				Rect:   image.Rect(-1, -1, 0, 1),
+				Stride: 1 * 8,
+				Pix: []uint8{
+					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+				},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone RGBA",
+			&image.RGBA{
+				Rect:   image.Rect(-1, -1, 0, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 3),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone RGBA64",
+			&image.RGBA64{
+				Rect:   image.Rect(-1, -1, 0, 2),
+				Stride: 1 * 8,
+				Pix: []uint8{
+					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+				},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 3),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone Gray",
+			&image.Gray{
+				Rect:   image.Rect(-1, -1, 0, 1),
+				Stride: 1 * 1,
+				Pix:    []uint8{0x11, 0xee},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone Gray16",
+			&image.Gray16{
+				Rect:   image.Rect(-1, -1, 0, 1),
+				Stride: 1 * 2,
+				Pix:    []uint8{0x11, 0x11, 0xee, 0xee},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+			},
+		},
+		{
+			"Clone Alpha",
+			&image.Alpha{
+				Rect:   image.Rect(-1, -1, 0, 1),
+				Stride: 1 * 1,
+				Pix:    []uint8{0x11, 0xee},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 1, 2),
+				Stride: 1 * 4,
+				Pix:    []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
+			},
+		},
+		{
+			"Clone YCbCr",
+			&image.YCbCr{
+				Rect:           image.Rect(-1, -1, 5, 0),
+				SubsampleRatio: image.YCbCrSubsampleRatio444,
+				YStride:        6,
+				CStride:        6,
+				Y:              []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
+				Cb:             []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
+				Cr:             []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 6, 1),
+				Stride: 6 * 4,
+				Pix: []uint8{
+					0x00, 0x00, 0x00, 0xff,
+					0xff, 0xff, 0xff, 0xff,
+					0x7f, 0x7f, 0x7f, 0xff,
+					0x7f, 0x00, 0x00, 0xff,
+					0x00, 0x7f, 0x00, 0xff,
+					0x00, 0x00, 0x7f, 0xff,
+				},
+			},
+		},
+		{
+			"Clone YCbCr 444",
+			&image.YCbCr{
+				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+				Cb:             []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
+				Cr:             []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
+				YStride:        4,
+				CStride:        4,
+				SubsampleRatio: image.YCbCrSubsampleRatio444,
+				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+			&image.NRGBA{
+				Pix:    []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+				Stride: 16,
+				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+		},
+		{
+			"Clone YCbCr 440",
+			&image.YCbCr{
+				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+				Cb:             []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
+				Cr:             []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
+				YStride:        4,
+				CStride:        4,
+				SubsampleRatio: image.YCbCrSubsampleRatio440,
+				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+			&image.NRGBA{
+				Pix:    []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+				Stride: 16,
+				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+		},
+		{
+			"Clone YCbCr 422",
+			&image.YCbCr{
+				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+				Cb:             []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
+				Cr:             []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
+				YStride:        4,
+				CStride:        2,
+				SubsampleRatio: image.YCbCrSubsampleRatio422,
+				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+			&image.NRGBA{
+				Pix:    []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+				Stride: 16,
+				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+		},
+		{
+			"Clone YCbCr 420",
+			&image.YCbCr{
+				Y:       []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+				Cb:      []uint8{0x01, 0xaa, 0x80, 0x80},
+				Cr:      []uint8{0x95, 0xb5, 0x80, 0x80},
+				YStride: 4, CStride: 2,
+				SubsampleRatio: image.YCbCrSubsampleRatio420,
+				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+			&image.NRGBA{
+				Pix:    []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+				Stride: 16,
+				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+			},
+		},
+		{
+			"Clone Paletted",
+			&image.Paletted{
+				Rect:   image.Rect(-1, -1, 5, 0),
+				Stride: 6 * 1,
+				Palette: color.Palette{
+					color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
+					color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
+					color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
+					color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
+					color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
+					color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
+				},
+				Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
+			},
+			&image.NRGBA{
+				Rect:   image.Rect(0, 0, 6, 1),
+				Stride: 6 * 4,
+				Pix: []uint8{
+					0x00, 0x00, 0x00, 0xff,
+					0xff, 0xff, 0xff, 0xff,
+					0x7f, 0x7f, 0x7f, 0xff,
+					0x7f, 0x00, 0x00, 0xff,
+					0x00, 0x7f, 0x00, 0xff,
+					0x00, 0x00, 0x7f, 0xff,
+				},
+			},
+		},
+	}
+
+	for _, d := range td {
+		got := Clone(d.src)
+		want := d.want
+
+		delta := 0
+		if _, ok := d.src.(*image.YCbCr); ok {
+			delta = 1
+		}
+
+		if !compareNRGBA(got, want, delta) {
+			t.Errorf("test [%s] failed: %#v", d.desc, got)
+		}
+	}
+}

+ 0 - 266
helpers.go

@@ -165,269 +165,3 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
 
 	return dst
 }
-
-// Clone returns a copy of the given image.
-func Clone(img image.Image) *image.NRGBA {
-	dstBounds := img.Bounds().Sub(img.Bounds().Min)
-	dst := image.NewNRGBA(dstBounds)
-
-	switch src := img.(type) {
-	case *image.NRGBA:
-		copyNRGBA(dst, src)
-	case *image.NRGBA64:
-		copyNRGBA64(dst, src)
-	case *image.RGBA:
-		copyRGBA(dst, src)
-	case *image.RGBA64:
-		copyRGBA64(dst, src)
-	case *image.Gray:
-		copyGray(dst, src)
-	case *image.Gray16:
-		copyGray16(dst, src)
-	case *image.YCbCr:
-		copyYCbCr(dst, src)
-	case *image.Paletted:
-		copyPaletted(dst, src)
-	default:
-		copyImage(dst, src)
-	}
-
-	return dst
-}
-
-func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	rowSize := dstW * 4
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
-		}
-	})
-}
-
-func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				dst.Pix[di+0] = src.Pix[si+0]
-				dst.Pix[di+1] = src.Pix[si+2]
-				dst.Pix[di+2] = src.Pix[si+4]
-				dst.Pix[di+3] = src.Pix[si+6]
-				di += 4
-				si += 8
-			}
-		}
-	})
-}
-
-func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				a := src.Pix[si+3]
-				dst.Pix[di+3] = a
-
-				switch a {
-				case 0:
-					dst.Pix[di+0] = 0
-					dst.Pix[di+1] = 0
-					dst.Pix[di+2] = 0
-				case 0xff:
-					dst.Pix[di+0] = src.Pix[si+0]
-					dst.Pix[di+1] = src.Pix[si+1]
-					dst.Pix[di+2] = src.Pix[si+2]
-				default:
-					var tmp uint16
-					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
-					dst.Pix[di+0] = uint8(tmp)
-					tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
-					dst.Pix[di+1] = uint8(tmp)
-					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
-					dst.Pix[di+2] = uint8(tmp)
-				}
-
-				di += 4
-				si += 4
-			}
-		}
-	})
-}
-
-func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				a := src.Pix[si+6]
-				dst.Pix[di+3] = a
-
-				switch a {
-				case 0:
-					dst.Pix[di+0] = 0
-					dst.Pix[di+1] = 0
-					dst.Pix[di+2] = 0
-				case 0xff:
-					dst.Pix[di+0] = src.Pix[si+0]
-					dst.Pix[di+1] = src.Pix[si+2]
-					dst.Pix[di+2] = src.Pix[si+4]
-				default:
-					var tmp uint16
-					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
-					dst.Pix[di+0] = uint8(tmp)
-					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
-					dst.Pix[di+1] = uint8(tmp)
-					tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
-					dst.Pix[di+2] = uint8(tmp)
-				}
-
-				di += 4
-				si += 8
-			}
-		}
-	})
-}
-
-func copyGray(dst *image.NRGBA, src *image.Gray) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				c := src.Pix[si]
-				dst.Pix[di+0] = c
-				dst.Pix[di+1] = c
-				dst.Pix[di+2] = c
-				dst.Pix[di+3] = 0xff
-				di += 4
-				si++
-			}
-		}
-	})
-}
-
-func copyGray16(dst *image.NRGBA, src *image.Gray16) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				c := src.Pix[si]
-				dst.Pix[di+0] = c
-				dst.Pix[di+1] = c
-				dst.Pix[di+2] = c
-				dst.Pix[di+3] = 0xff
-				di += 4
-				si += 2
-			}
-		}
-	})
-}
-
-func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				srcX := srcMinX + dstX
-				srcY := srcMinY + dstY
-				siy := src.YOffset(srcX, srcY)
-				sic := src.COffset(srcX, srcY)
-				r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
-				dst.Pix[di+0] = r
-				dst.Pix[di+1] = g
-				dst.Pix[di+2] = b
-				dst.Pix[di+3] = 0xff
-				di += 4
-			}
-		}
-	})
-}
-
-func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
-	srcMinX := src.Rect.Min.X
-	srcMinY := src.Rect.Min.Y
-	dstW := dst.Rect.Dx()
-	dstH := dst.Rect.Dy()
-	plen := len(src.Palette)
-	pnew := make([]color.NRGBA, plen)
-	for i := 0; i < plen; i++ {
-		pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
-	}
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			si := src.PixOffset(srcMinX, srcMinY+dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				c := pnew[src.Pix[si]]
-				dst.Pix[di+0] = c.R
-				dst.Pix[di+1] = c.G
-				dst.Pix[di+2] = c.B
-				dst.Pix[di+3] = c.A
-				di += 4
-				si++
-			}
-		}
-	})
-}
-
-func copyImage(dst *image.NRGBA, src image.Image) {
-	srcMinX := src.Bounds().Min.X
-	srcMinY := src.Bounds().Min.Y
-	dstW := dst.Bounds().Dx()
-	dstH := dst.Bounds().Dy()
-	parallel(dstH, func(partStart, partEnd int) {
-		for dstY := partStart; dstY < partEnd; dstY++ {
-			di := dst.PixOffset(0, dstY)
-			for dstX := 0; dstX < dstW; dstX++ {
-				c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
-				dst.Pix[di+0] = c.R
-				dst.Pix[di+1] = c.G
-				dst.Pix[di+2] = c.B
-				dst.Pix[di+3] = c.A
-				di += 4
-			}
-		}
-	})
-}
-
-// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
-func toNRGBA(img image.Image) *image.NRGBA {
-	if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
-		return img
-	}
-	return Clone(img)
-}

+ 0 - 240
helpers_test.go

@@ -140,246 +140,6 @@ func TestNew(t *testing.T) {
 	}
 }
 
-func TestClone(t *testing.T) {
-	td := []struct {
-		desc string
-		src  image.Image
-		want *image.NRGBA
-	}{
-		{
-			"Clone NRGBA",
-			&image.NRGBA{
-				Rect:   image.Rect(-1, -1, 0, 1),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone NRGBA64",
-			&image.NRGBA64{
-				Rect:   image.Rect(-1, -1, 0, 1),
-				Stride: 1 * 8,
-				Pix: []uint8{
-					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
-					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
-				},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone RGBA",
-			&image.RGBA{
-				Rect:   image.Rect(-1, -1, 0, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 3),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone RGBA64",
-			&image.RGBA64{
-				Rect:   image.Rect(-1, -1, 0, 2),
-				Stride: 1 * 8,
-				Pix: []uint8{
-					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
-					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
-				},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 3),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone Gray",
-			&image.Gray{
-				Rect:   image.Rect(-1, -1, 0, 1),
-				Stride: 1 * 1,
-				Pix:    []uint8{0x11, 0xee},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone Gray16",
-			&image.Gray16{
-				Rect:   image.Rect(-1, -1, 0, 1),
-				Stride: 1 * 2,
-				Pix:    []uint8{0x11, 0x11, 0xee, 0xee},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
-			},
-		},
-		{
-			"Clone Alpha",
-			&image.Alpha{
-				Rect:   image.Rect(-1, -1, 0, 1),
-				Stride: 1 * 1,
-				Pix:    []uint8{0x11, 0xee},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 1, 2),
-				Stride: 1 * 4,
-				Pix:    []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
-			},
-		},
-		{
-			"Clone YCbCr",
-			&image.YCbCr{
-				Rect:           image.Rect(-1, -1, 5, 0),
-				SubsampleRatio: image.YCbCrSubsampleRatio444,
-				YStride:        6,
-				CStride:        6,
-				Y:              []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
-				Cb:             []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
-				Cr:             []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 6, 1),
-				Stride: 6 * 4,
-				Pix: []uint8{
-					0x00, 0x00, 0x00, 0xff,
-					0xff, 0xff, 0xff, 0xff,
-					0x7f, 0x7f, 0x7f, 0xff,
-					0x7f, 0x00, 0x00, 0xff,
-					0x00, 0x7f, 0x00, 0xff,
-					0x00, 0x00, 0x7f, 0xff,
-				},
-			},
-		},
-		{
-			"Clone YCbCr 444",
-			&image.YCbCr{
-				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
-				Cb:             []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
-				Cr:             []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
-				YStride:        4,
-				CStride:        4,
-				SubsampleRatio: image.YCbCrSubsampleRatio444,
-				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-			&image.NRGBA{
-				Pix:    []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
-				Stride: 16,
-				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-		},
-		{
-			"Clone YCbCr 440",
-			&image.YCbCr{
-				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
-				Cb:             []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
-				Cr:             []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
-				YStride:        4,
-				CStride:        4,
-				SubsampleRatio: image.YCbCrSubsampleRatio440,
-				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-			&image.NRGBA{
-				Pix:    []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
-				Stride: 16,
-				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-		},
-		{
-			"Clone YCbCr 422",
-			&image.YCbCr{
-				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
-				Cb:             []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
-				Cr:             []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
-				YStride:        4,
-				CStride:        2,
-				SubsampleRatio: image.YCbCrSubsampleRatio422,
-				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-			&image.NRGBA{
-				Pix:    []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
-				Stride: 16,
-				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-		},
-		{
-			"Clone YCbCr 420",
-			&image.YCbCr{
-				Y:       []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
-				Cb:      []uint8{0x01, 0xaa, 0x80, 0x80},
-				Cr:      []uint8{0x95, 0xb5, 0x80, 0x80},
-				YStride: 4, CStride: 2,
-				SubsampleRatio: image.YCbCrSubsampleRatio420,
-				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-			&image.NRGBA{
-				Pix:    []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
-				Stride: 16,
-				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
-			},
-		},
-		{
-			"Clone Paletted",
-			&image.Paletted{
-				Rect:   image.Rect(-1, -1, 5, 0),
-				Stride: 6 * 1,
-				Palette: color.Palette{
-					color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
-					color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
-					color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
-					color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
-					color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
-					color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
-				},
-				Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
-			},
-			&image.NRGBA{
-				Rect:   image.Rect(0, 0, 6, 1),
-				Stride: 6 * 4,
-				Pix: []uint8{
-					0x00, 0x00, 0x00, 0xff,
-					0xff, 0xff, 0xff, 0xff,
-					0x7f, 0x7f, 0x7f, 0xff,
-					0x7f, 0x00, 0x00, 0xff,
-					0x00, 0x7f, 0x00, 0xff,
-					0x00, 0x00, 0x7f, 0xff,
-				},
-			},
-		},
-	}
-
-	for _, d := range td {
-		got := Clone(d.src)
-		want := d.want
-
-		delta := 0
-		if _, ok := d.src.(*image.YCbCr); ok {
-			delta = 1
-		}
-
-		if !compareNRGBA(got, want, delta) {
-			t.Errorf("test [%s] failed: %#v", d.desc, got)
-		}
-	}
-}
-
 func TestFormats(t *testing.T) {
 	formatNames := map[Format]string{
 		JPEG:       "JPEG",