From: Nigel Tao Date: Mon, 16 Feb 2015 04:10:50 +0000 (+1100) Subject: image/jpeg: remove the (temporary) dependency on image/draw. X-Git-Tag: go1.5beta1~1980 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=10a4696fb8d080b334a31f0cf43a7ffe3c588ad7;p=gostls13.git image/jpeg: remove the (temporary) dependency on image/draw. Change-Id: Idd66f9c3c9eaa4ff1f950fb90e4800dc625dec08 Reviewed-on: https://go-review.googlesource.com/4916 Reviewed-by: Alex Brainman --- diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go index cffdcbc0d7..b1fc979a7d 100644 --- a/src/image/draw/draw.go +++ b/src/image/draw/draw.go @@ -392,6 +392,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image } } +// TODO(nigeltao): this function is copy/pasted to image/jpeg/reader.go. We +// should un-copy/paste it. func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil // (i.e. fully opaque) then the op is effectively always Src. diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index 72c3f064c0..863f55bf25 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -10,7 +10,6 @@ package jpeg import ( "image" "image/color" - "image/draw" "io" ) @@ -587,10 +586,7 @@ func (d *decoder) applyBlack() (image.Image, error) { // above, so in practice, only the fourth channel (black) is inverted. bounds := d.img3.Bounds() img := image.NewRGBA(bounds) - // TODO(nigeltao): do the draw.Draw YCbCr -> RGB conversion directly, - // instead of having the image/jpeg package depend on the image/draw - // package. - draw.Draw(img, bounds, d.img3, bounds.Min, draw.Src) + drawYCbCr(img, bounds, d.img3, bounds.Min) for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)] @@ -639,6 +635,82 @@ func (d *decoder) applyBlack() (image.Image, error) { return img, nil } +// drawYCbCr is the non-exported drawYCbCr function copy/pasted from the +// image/draw package. It is copy/pasted because it doesn't seem right for the +// image/jpeg package to depend on image/draw. +// +// TODO(nigeltao): remove the copy/paste, possibly by moving this to be an +// exported method on *image.YCbCr. We'd need to make sure we're totally happy +// with the API (for the rest of Go 1 compatibility) though, and if we want to +// have a more general purpose DrawToRGBA method for other image types. +func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { + // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil + // (i.e. fully opaque) then the op is effectively always Src. + 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 image.YCbCrSubsampleRatio444: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio422: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio420: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio440: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + default: + return false + } + return true +} + // Decode reads a JPEG image from r and returns it as an image.Image. func Decode(r io.Reader) (image.Image, error) { var d decoder