Просмотр исходного кода

Support 411 and 410 subsampling rations for go1.5+

Charlie Vieth 10 лет назад
Родитель
Сommit
14554cc7da
2 измененных файлов с 281 добавлено и 116 удалено
  1. 275 115
      ycc.go
  2. 6 1
      ycc_test.go

+ 275 - 115
ycc.go

@@ -88,140 +88,300 @@ func newYCC(r image.Rectangle, s image.YCbCrSubsampleRatio) *ycc {
 	return &ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: s}
 	return &ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: s}
 }
 }
 
 
+// Copy of image.YCbCrSubsampleRatio constants - this allows us to support
+// older versions of Go where these constants are not defined (i.e. Go 1.4)
+const (
+	ycbcrSubsampleRatio444 image.YCbCrSubsampleRatio = iota
+	ycbcrSubsampleRatio422
+	ycbcrSubsampleRatio420
+	ycbcrSubsampleRatio440
+	ycbcrSubsampleRatio411
+	ycbcrSubsampleRatio410
+)
+
 // YCbCr converts ycc to a YCbCr image with the same subsample ratio
 // YCbCr converts ycc to a YCbCr image with the same subsample ratio
 // as the YCbCr image that ycc was generated from.
 // as the YCbCr image that ycc was generated from.
 func (p *ycc) YCbCr() *image.YCbCr {
 func (p *ycc) YCbCr() *image.YCbCr {
 	ycbcr := image.NewYCbCr(p.Rect, p.SubsampleRatio)
 	ycbcr := image.NewYCbCr(p.Rect, p.SubsampleRatio)
+	switch ycbcr.SubsampleRatio {
+	case ycbcrSubsampleRatio422:
+		return p.ycbcr422(ycbcr)
+	case ycbcrSubsampleRatio420:
+		return p.ycbcr420(ycbcr)
+	case ycbcrSubsampleRatio440:
+		return p.ycbcr440(ycbcr)
+	case ycbcrSubsampleRatio444:
+		return p.ycbcr444(ycbcr)
+	case ycbcrSubsampleRatio411:
+		return p.ycbcr411(ycbcr)
+	case ycbcrSubsampleRatio410:
+		return p.ycbcr410(ycbcr)
+	}
+	return ycbcr
+}
+
+// imageYCbCrToYCC converts a YCbCr image to a ycc image for resizing.
+func imageYCbCrToYCC(in *image.YCbCr) *ycc {
+	w, h := in.Rect.Dx(), in.Rect.Dy()
+	p := ycc{
+		Pix:            make([]uint8, 3*w*h),
+		Stride:         3 * w,
+		Rect:           image.Rect(0, 0, w, h),
+		SubsampleRatio: in.SubsampleRatio,
+	}
+	switch in.SubsampleRatio {
+	case ycbcrSubsampleRatio422:
+		return convertToYCC422(in, &p)
+	case ycbcrSubsampleRatio420:
+		return convertToYCC420(in, &p)
+	case ycbcrSubsampleRatio440:
+		return convertToYCC440(in, &p)
+	case ycbcrSubsampleRatio444:
+		return convertToYCC444(in, &p)
+	case ycbcrSubsampleRatio411:
+		return convertToYCC411(in, &p)
+	case ycbcrSubsampleRatio410:
+		return convertToYCC410(in, &p)
+	}
+	return &p
+}
+
+func (p *ycc) ycbcr422(ycbcr *image.YCbCr) *image.YCbCr {
 	var off int
 	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := y * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x/2
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = Pix[off+2]
+			off += 3
+		}
+	}
+	return ycbcr
+}
 
 
-	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
-			}
+func (p *ycc) ycbcr420(ycbcr *image.YCbCr) *image.YCbCr {
+	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := (y / 2) * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x/2
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = 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
-			}
+	}
+	return ycbcr
+}
+
+func (p *ycc) ycbcr440(ycbcr *image.YCbCr) *image.YCbCr {
+	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := (y / 2) * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = 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
-			}
+	}
+	return ycbcr
+}
+
+func (p *ycc) ycbcr444(ycbcr *image.YCbCr) *image.YCbCr {
+	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := y * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = Pix[off+2]
+			off += 3
+		}
+	}
+	return ycbcr
+}
+
+func (p *ycc) ycbcr411(ycbcr *image.YCbCr) *image.YCbCr {
+	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := y * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x/4
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = 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
+}
+
+func (p *ycc) ycbcr410(ycbcr *image.YCbCr) *image.YCbCr {
+	var off int
+	Pix := p.Pix
+	Y := ycbcr.Y
+	Cb := ycbcr.Cb
+	Cr := ycbcr.Cr
+	for y := 0; y < ycbcr.Rect.Max.Y-ycbcr.Rect.Min.Y; y++ {
+		yy := y * ycbcr.YStride
+		cy := (y / 2) * ycbcr.CStride
+		for x := 0; x < ycbcr.Rect.Max.X-ycbcr.Rect.Min.X; x++ {
+			ci := cy + x/4
+			Y[yy+x] = Pix[off+0]
+			Cb[ci] = Pix[off+1]
+			Cr[ci] = Pix[off+2]
+			off += 3
 		}
 		}
 	}
 	}
 	return ycbcr
 	return ycbcr
 }
 }
 
 
-// imageYCbCrToYCC converts a YCbCr image to a ycc image for resizing.
-func imageYCbCrToYCC(in *image.YCbCr) *ycc {
-	w, h := in.Rect.Dx(), in.Rect.Dy()
-	r := image.Rect(0, 0, w, h)
-	buf := make([]uint8, 3*w*h)
-	p := ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: in.SubsampleRatio}
+func convertToYCC422(in *image.YCbCr, p *ycc) *ycc {
 	var off int
 	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := y * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x/2
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
+		}
+	}
+	return p
+}
 
 
-	switch in.SubsampleRatio {
-	case image.YCbCrSubsampleRatio422:
-		for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
-			yy := (y - in.Rect.Min.Y) * in.YStride
-			cy := (y - in.Rect.Min.Y) * in.CStride
-			for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
-				xx := (x - in.Rect.Min.X)
-				yi := yy + xx
-				ci := cy + xx/2
-				p.Pix[off+0] = in.Y[yi]
-				p.Pix[off+1] = in.Cb[ci]
-				p.Pix[off+2] = in.Cr[ci]
-				off += 3
-			}
+func convertToYCC420(in *image.YCbCr, p *ycc) *ycc {
+	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := (y / 2) * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x/2
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
 		}
 		}
-	case image.YCbCrSubsampleRatio420:
-		for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
-			yy := (y - in.Rect.Min.Y) * in.YStride
-			cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
-			for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
-				xx := (x - in.Rect.Min.X)
-				yi := yy + xx
-				ci := cy + xx/2
-				p.Pix[off+0] = in.Y[yi]
-				p.Pix[off+1] = in.Cb[ci]
-				p.Pix[off+2] = in.Cr[ci]
-				off += 3
-			}
+	}
+	return p
+}
+
+func convertToYCC440(in *image.YCbCr, p *ycc) *ycc {
+	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := (y / 2) * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
 		}
 		}
-	case image.YCbCrSubsampleRatio440:
-		for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
-			yy := (y - in.Rect.Min.Y) * in.YStride
-			cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
-			for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
-				xx := (x - in.Rect.Min.X)
-				yi := yy + xx
-				ci := cy + xx
-				p.Pix[off+0] = in.Y[yi]
-				p.Pix[off+1] = in.Cb[ci]
-				p.Pix[off+2] = in.Cr[ci]
-				off += 3
-			}
+	}
+	return p
+}
+
+func convertToYCC444(in *image.YCbCr, p *ycc) *ycc {
+	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := y * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
 		}
 		}
-	default:
-		// Default to 4:4:4 subsampling.
-		for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
-			yy := (y - in.Rect.Min.Y) * in.YStride
-			cy := (y - in.Rect.Min.Y) * in.CStride
-			for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
-				xx := (x - in.Rect.Min.X)
-				yi := yy + xx
-				ci := cy + xx
-				p.Pix[off+0] = in.Y[yi]
-				p.Pix[off+1] = in.Cb[ci]
-				p.Pix[off+2] = in.Cr[ci]
-				off += 3
-			}
+	}
+	return p
+}
+
+func convertToYCC411(in *image.YCbCr, p *ycc) *ycc {
+	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := y * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x/4
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
 		}
 		}
 	}
 	}
-	return &p
+	return p
+}
+
+func convertToYCC410(in *image.YCbCr, p *ycc) *ycc {
+	var off int
+	Pix := p.Pix
+	Y := in.Y
+	Cb := in.Cb
+	Cr := in.Cr
+	for y := 0; y < in.Rect.Max.Y-in.Rect.Min.Y; y++ {
+		yy := y * in.YStride
+		cy := (y / 2) * in.CStride
+		for x := 0; x < in.Rect.Max.X-in.Rect.Min.X; x++ {
+			ci := cy + x/4
+			Pix[off+0] = Y[yy+x]
+			Pix[off+1] = Cb[ci]
+			Pix[off+2] = Cr[ci]
+			off += 3
+		}
+	}
+	return p
 }
 }

+ 6 - 1
ycc_test.go

@@ -1,3 +1,5 @@
+// +build go1.5
+
 /*
 /*
 Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
 Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
 
 
@@ -33,6 +35,8 @@ func TestImage(t *testing.T) {
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio422),
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio422),
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio440),
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio440),
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio444),
 		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio444),
+		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio411),
+		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio410),
 	}
 	}
 	for _, m := range testImage {
 	for _, m := range testImage {
 		if !image.Rect(0, 0, 10, 10).Eq(m.Bounds()) {
 		if !image.Rect(0, 0, 10, 10).Eq(m.Bounds()) {
@@ -60,8 +64,9 @@ func TestConvertYCbCr(t *testing.T) {
 		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio422),
 		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.YCbCrSubsampleRatio440),
 		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio444),
 		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio444),
+		image.NewYCbCr(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio411),
+		image.NewYCbCr(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio410),
 	}
 	}
-
 	for _, img := range testImage {
 	for _, img := range testImage {
 		m := img.(*image.YCbCr)
 		m := img.(*image.YCbCr)
 		for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
 		for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {