gen.mx raw

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