image/internal/imageutil: inline the color.YCbCrToRGB calls.

The image/draw benchmark:
benchmark          old ns/op     new ns/op     delta
BenchmarkYCbCr     1198605       978647        -18.35%

Change-Id: Iacfc21e6f641ecb05adc00b3aec0048f1f43d265
Reviewed-on: https://go-review.googlesource.com/7952
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
index 59125da..cde05ad 100644
--- a/src/image/internal/imageutil/gen.go
+++ b/src/image/internal/imageutil/gen.go
@@ -47,7 +47,6 @@
 
 import (
 	"image"
-	"image/color"
 )
 
 // DrawYCbCr draws the YCbCr source image on the RGBA destination image with
@@ -94,10 +93,33 @@
 			dpix := dst.Pix[y*dst.Stride:]
 			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
 			%s
-				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
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
 				dpix[x+3] = 255
 			}
 		}
diff --git a/src/image/internal/imageutil/impl.go b/src/image/internal/imageutil/impl.go
index 5a156e4..d4bd325 100644
--- a/src/image/internal/imageutil/impl.go
+++ b/src/image/internal/imageutil/impl.go
@@ -4,7 +4,6 @@
 
 import (
 	"image"
-	"image/color"
 )
 
 // DrawYCbCr draws the YCbCr source image on the RGBA destination image with
@@ -44,10 +43,32 @@
 			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
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
 				dpix[x+3] = 255
 			}
 		}
@@ -61,10 +82,32 @@
 			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
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
 				dpix[x+3] = 255
 			}
 		}
@@ -78,10 +121,32 @@
 			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
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
 				dpix[x+3] = 255
 			}
 		}
@@ -94,10 +159,32 @@
 			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
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
 				dpix[x+3] = 255
 			}
 		}