Source file src/image/internal/imageutil/gen.go
1
2
3
4
5
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 = `// Code 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]) * 0x10101
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
View as plain text