func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) { // A YCbCr image is always fully opaque, and so if the mask is implicitly nil // (i.e. fully opaque) then the op is effectively always Src. var ( yy, cb, cr uint8 ) x0 := (r.Min.X - dst.Rect.Min.X) * 4 x1 := (r.Max.X - dst.Rect.Min.X) * 4 y0 := r.Min.Y - dst.Rect.Min.Y y1 := r.Max.Y - dst.Rect.Min.Y switch src.SubsampleRatio { case ycbcr.SubsampleRatio422: for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride:] for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 { i := sx / 2 yy = src.Y[sy*src.YStride+sx] cb = src.Cb[sy*src.CStride+i] cr = src.Cr[sy*src.CStride+i] rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb dpix[x+3] = 255 } } case ycbcr.SubsampleRatio420: for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride:] for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 { i, j := sx/2, sy/2 yy = src.Y[sy*src.YStride+sx] cb = src.Cb[j*src.CStride+i] cr = src.Cr[j*src.CStride+i] rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb dpix[x+3] = 255 } } default: // Default to 4:4:4 subsampling. for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride:] for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 { yy = src.Y[sy*src.YStride+sx] cb = src.Cb[sy*src.CStride+sx] cr = src.Cr[sy*src.CStride+sx] rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb dpix[x+3] = 255 } } } }
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) { // A YCbCr image is always fully opaque, and so if the mask is implicitly nil // (i.e. fully opaque) then the op is effectively always Src. var ( yy, cb, cr uint8 rr, gg, bb uint8 ) switch src.SubsampleRatio { case ycbcr.SubsampleRatio422: for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { i := sx / 2 yy = src.Y[sy*src.YStride+sx] cb = src.Cb[sy*src.CStride+i] cr = src.Cr[sy*src.CStride+i] rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x] = image.RGBAColor{rr, gg, bb, 255} } } case ycbcr.SubsampleRatio420: for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { i, j := sx/2, sy/2 yy = src.Y[sy*src.YStride+sx] cb = src.Cb[j*src.CStride+i] cr = src.Cr[j*src.CStride+i] rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x] = image.RGBAColor{rr, gg, bb, 255} } } default: // Default to 4:4:4 subsampling. for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { yy = src.Y[sy*src.YStride+sx] cb = src.Cb[sy*src.CStride+sx] cr = src.Cr[sy*src.CStride+sx] rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) dpix[x] = image.RGBAColor{rr, gg, bb, 255} } } } }
// resizeYCbCr returns a scaled copy of the YCbCr image slice r of m. // The returned image has width w and height h. func resizeYCbCr(m *ycbcr.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) { var verticalRes int switch m.SubsampleRatio { case ycbcr.SubsampleRatio420: verticalRes = 2 case ycbcr.SubsampleRatio422: verticalRes = 1 default: return nil, false } ww, hh := uint64(w), uint64(h) dx, dy := uint64(r.Dx()), uint64(r.Dy()) // See comment in Resize. n, sum := dx*dy, make([]uint64, 4*w*h) for y := r.Min.Y; y < r.Max.Y; y++ { Y := m.Y[y*m.YStride:] Cb := m.Cb[y/verticalRes*m.CStride:] Cr := m.Cr[y/verticalRes*m.CStride:] for x := r.Min.X; x < r.Max.X; x++ { // Get the source pixel. r8, g8, b8 := ycbcr.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2]) r64 := uint64(r8) g64 := uint64(g8) b64 := uint64(b8) // Spread the source pixel over 1 or more destination rows. py := uint64(y) * hh for remy := hh; remy > 0; { qy := dy - (py % dy) if qy > remy { qy = remy } // Spread the source pixel over 1 or more destination columns. px := uint64(x) * ww index := 4 * ((py/dy)*ww + (px / dx)) for remx := ww; remx > 0; { qx := dx - (px % dx) if qx > remx { qx = remx } qxy := qx * qy sum[index+0] += r64 * qxy sum[index+1] += g64 * qxy sum[index+2] += b64 * qxy sum[index+3] += 0xFFFF * qxy index += 4 px += qx remx -= qx } py += qy remy -= qy } } } return average(sum, w, h, n), true }