func newAtFuncYCbCr(p *image.YCbCr) AtFunc { return func(x, y int) (r, g, b, a uint32) { yi := p.YOffset(x, y) ci := p.COffset(x, y) y1 := int32(p.Y[yi]) * 0x10100 cb1 := int32(p.Cb[ci]) - 128 cr1 := int32(p.Cr[ci]) - 128 r1 := (y1 + 91881*cr1) >> 8 g1 := (y1 - 22554*cb1 - 46802*cr1) >> 8 b1 := (y1 + 116130*cb1) >> 8 if r1 < 0 { r1 = 0 } else if r1 > 0xffff { r1 = 0xffff } if g1 < 0 { g1 = 0 } else if g1 > 0xffff { g1 = 0xffff } if b1 < 0 { b1 = 0 } else if b1 > 0xffff { b1 = 0xffff } return uint32(r1), uint32(g1), uint32(b1), 0xffff } }
// encodePGM encodes gotImage in the PGM format in the IMC4 layout. func encodePGM(gotImage image.Image) ([]byte, error) { var ( m *image.YCbCr ma *nycbcra.Image ) switch g := gotImage.(type) { case *image.YCbCr: m = g case *nycbcra.Image: m = &g.YCbCr ma = g default: return nil, fmt.Errorf("lossy image did not decode to an *image.YCbCr") } if m.SubsampleRatio != image.YCbCrSubsampleRatio420 { return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YCbCr") } b := m.Bounds() w, h := b.Dx(), b.Dy() w2, h2 := (w+1)/2, (h+1)/2 outW, outH := 2*w2, h+h2 if ma != nil { outH += h } buf := new(bytes.Buffer) fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH) for y := b.Min.Y; y < b.Max.Y; y++ { o := m.YOffset(b.Min.X, y) buf.Write(m.Y[o : o+w]) if w&1 != 0 { buf.WriteByte(0x00) } } for y := b.Min.Y; y < b.Max.Y; y += 2 { o := m.COffset(b.Min.X, y) buf.Write(m.Cb[o : o+w2]) buf.Write(m.Cr[o : o+w2]) } if ma != nil { for y := b.Min.Y; y < b.Max.Y; y++ { o := ma.AOffset(b.Min.X, y) buf.Write(ma.A[o : o+w]) if w&1 != 0 { buf.WriteByte(0x00) } } } return buf.Bytes(), nil }
func convertYCbCr(dest *Image, src *image.YCbCr) { var r, g, b uint8 var x, y, i, yi, ci int for x = dest.Rect.Min.X; x < dest.Rect.Max.X; x++ { for y = dest.Rect.Min.Y; y < dest.Rect.Max.Y; y++ { yi, ci = src.YOffset(x, y), src.COffset(x, y) r, g, b = color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) i = dest.PixOffset(x, y) dest.Pix[i+0] = b dest.Pix[i+1] = g dest.Pix[i+2] = r dest.Pix[i+3] = 0xff } } }