Home | History | Annotate | Download | only in imageutil
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // +build ignore
      6 
      7 package main
      8 
      9 import (
     10 	"bytes"
     11 	"flag"
     12 	"fmt"
     13 	"go/format"
     14 	"io/ioutil"
     15 	"log"
     16 	"os"
     17 )
     18 
     19 var debug = flag.Bool("debug", false, "")
     20 
     21 func main() {
     22 	flag.Parse()
     23 
     24 	w := new(bytes.Buffer)
     25 	w.WriteString(pre)
     26 	for _, sratio := range subsampleRatios {
     27 		fmt.Fprintf(w, sratioCase, sratio, sratioLines[sratio])
     28 	}
     29 	w.WriteString(post)
     30 
     31 	if *debug {
     32 		os.Stdout.Write(w.Bytes())
     33 		return
     34 	}
     35 	out, err := format.Source(w.Bytes())
     36 	if err != nil {
     37 		log.Fatal(err)
     38 	}
     39 	if err := ioutil.WriteFile("impl.go", out, 0660); err != nil {
     40 		log.Fatal(err)
     41 	}
     42 }
     43 
     44 const pre = `// generated by "go run gen.go". DO NOT EDIT.
     45 
     46 package imageutil
     47 
     48 import (
     49 	"image"
     50 )
     51 
     52 // DrawYCbCr draws the YCbCr source image on the RGBA destination image with
     53 // r.Min in dst aligned with sp in src. It reports whether the draw was
     54 // successful. If it returns false, no dst pixels were changed.
     55 //
     56 // This function assumes that r is entirely within dst's bounds and the
     57 // translation of r from dst coordinate space to src coordinate space is
     58 // entirely within src's bounds.
     59 func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
     60 	// This function exists in the image/internal/imageutil package because it
     61 	// is needed by both the image/draw and image/jpeg packages, but it doesn't
     62 	// seem right for one of those two to depend on the other.
     63 	//
     64 	// Another option is to have this code be exported in the image package,
     65 	// but we'd need to make sure we're totally happy with the API (for the
     66 	// rest of Go 1 compatibility), and decide if we want to have a more
     67 	// general purpose DrawToRGBA method for other image types. One possibility
     68 	// is:
     69 	//
     70 	// func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle)
     71 	//
     72 	// in the spirit of the built-in copy function for 1-dimensional slices,
     73 	// that also allowed a CopyFromRGBA method if needed.
     74 
     75 	x0 := (r.Min.X - dst.Rect.Min.X) * 4
     76 	x1 := (r.Max.X - dst.Rect.Min.X) * 4
     77 	y0 := r.Min.Y - dst.Rect.Min.Y
     78 	y1 := r.Max.Y - dst.Rect.Min.Y
     79 	switch src.SubsampleRatio {
     80 `
     81 
     82 const post = `
     83 	default:
     84 		return false
     85 	}
     86 	return true
     87 }
     88 `
     89 
     90 const sratioCase = `
     91 	case image.YCbCrSubsampleRatio%s:
     92 		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
     93 			dpix := dst.Pix[y*dst.Stride:]
     94 			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
     95 			%s
     96 
     97 				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
     98 				yy1 := int32(src.Y[yi]) * 0x010100 // Convert 0x12 to 0x121200.
     99 				cb1 := int32(src.Cb[ci]) - 128
    100 				cr1 := int32(src.Cr[ci]) - 128
    101 
    102 				// The bit twiddling below is equivalent to
    103 				//
    104 				// r := (yy1 + 91881*cr1) >> 16
    105 				// if r < 0 {
    106 				//     r = 0
    107 				// } else if r > 0xff {
    108 				//     r = ^int32(0)
    109 				// }
    110 				//
    111 				// but uses fewer branches and is faster.
    112 				// Note that the uint8 type conversion in the return
    113 				// statement will convert ^int32(0) to 0xff.
    114 				// The code below to compute g and b uses a similar pattern.
    115 				r := yy1 + 91881*cr1
    116 				if uint32(r)&0xff000000 == 0 {
    117 					r >>= 16
    118 				} else {
    119 					r = ^(r >> 31)
    120 				}
    121 
    122 				g := yy1 - 22554*cb1 - 46802*cr1
    123 				if uint32(g)&0xff000000 == 0 {
    124 					g >>= 16
    125 				} else {
    126 					g = ^(g >> 31)
    127 				}
    128 
    129 				b := yy1 + 116130*cb1
    130 				if uint32(b)&0xff000000 == 0 {
    131 					b >>= 16
    132 				} else {
    133 					b = ^(b >> 31)
    134 				}
    135 
    136 
    137 				// use a temp slice to hint to the compiler that a single bounds check suffices
    138 				rgba := dpix[x : x+4 : len(dpix)]
    139 				rgba[0] = uint8(r)
    140 				rgba[1] = uint8(g)
    141 				rgba[2] = uint8(b)
    142 				rgba[3] = 255
    143 			}
    144 		}
    145 `
    146 
    147 var subsampleRatios = []string{
    148 	"444",
    149 	"422",
    150 	"420",
    151 	"440",
    152 }
    153 
    154 var sratioLines = map[string]string{
    155 	"444": `
    156 		ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
    157 		for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
    158 	`,
    159 	"422": `
    160 		ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
    161 		for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
    162 			ci := ciBase + sx/2
    163 	`,
    164 	"420": `
    165 		ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
    166 		for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
    167 			ci := ciBase + sx/2
    168 	`,
    169 	"440": `
    170 		ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
    171 		for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
    172 	`,
    173 }
    174