Source file src/image/internal/imageutil/gen.go

     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 := new(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 = []string{
   147  	"444",
   148  	"422",
   149  	"420",
   150  	"440",
   151  }
   152  
   153  var sratioLines = map[string]string{
   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  

View as plain text