tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/image/internal/imageutil/gen.go (about) 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 }