ires 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +111 -0
  4. data/Rakefile +30 -0
  5. data/ext/Gopkg.lock +21 -0
  6. data/ext/Gopkg.toml +30 -0
  7. data/ext/main.go +90 -0
  8. data/ext/operate/image.go +139 -0
  9. data/ext/util/uri/uri.go +96 -0
  10. data/ext/vendor/github.com/nfnt/resize/LICENSE +13 -0
  11. data/ext/vendor/github.com/nfnt/resize/README.md +149 -0
  12. data/ext/vendor/github.com/nfnt/resize/converter.go +438 -0
  13. data/ext/vendor/github.com/nfnt/resize/converter_test.go +43 -0
  14. data/ext/vendor/github.com/nfnt/resize/filters.go +143 -0
  15. data/ext/vendor/github.com/nfnt/resize/nearest.go +318 -0
  16. data/ext/vendor/github.com/nfnt/resize/nearest_test.go +57 -0
  17. data/ext/vendor/github.com/nfnt/resize/resize.go +614 -0
  18. data/ext/vendor/github.com/nfnt/resize/resize_test.go +330 -0
  19. data/ext/vendor/github.com/nfnt/resize/thumbnail.go +55 -0
  20. data/ext/vendor/github.com/nfnt/resize/thumbnail_test.go +47 -0
  21. data/ext/vendor/github.com/nfnt/resize/ycc.go +227 -0
  22. data/ext/vendor/github.com/nfnt/resize/ycc_test.go +214 -0
  23. data/ext/vendor/github.com/oliamb/cutter/LICENSE +20 -0
  24. data/ext/vendor/github.com/oliamb/cutter/README.md +88 -0
  25. data/ext/vendor/github.com/oliamb/cutter/benchmark_test.go +54 -0
  26. data/ext/vendor/github.com/oliamb/cutter/cutter.go +183 -0
  27. data/ext/vendor/github.com/oliamb/cutter/cutter/main.go +68 -0
  28. data/ext/vendor/github.com/oliamb/cutter/cutter_test.go +267 -0
  29. data/ext/vendor/github.com/oliamb/cutter/example_test.go +35 -0
  30. data/ext/vendor/github.com/oliamb/cutter/fixtures/gopher.jpg +0 -0
  31. data/lib/ires.rb +4 -0
  32. data/lib/ires/engine.rb +7 -0
  33. data/lib/ires/service.rb +19 -0
  34. data/lib/ires/util.rb +39 -0
  35. data/lib/ires/version.rb +3 -0
  36. data/lib/ires/view_helper.rb +42 -0
  37. data/lib/tasks/ires.rake +11 -0
  38. data/shared/darwin/ires.h +64 -0
  39. data/shared/darwin/ires.so +0 -0
  40. data/shared/linux/ires.h +64 -0
  41. data/shared/linux/ires.so +0 -0
  42. metadata +154 -0
@@ -0,0 +1,330 @@
1
+ package resize
2
+
3
+ import (
4
+ "image"
5
+ "image/color"
6
+ "runtime"
7
+ "testing"
8
+ )
9
+
10
+ var img = image.NewGray16(image.Rect(0, 0, 3, 3))
11
+
12
+ func init() {
13
+ runtime.GOMAXPROCS(runtime.NumCPU())
14
+ img.Set(1, 1, color.White)
15
+ }
16
+
17
+ func Test_Param1(t *testing.T) {
18
+ m := Resize(0, 0, img, NearestNeighbor)
19
+ if m.Bounds() != img.Bounds() {
20
+ t.Fail()
21
+ }
22
+ }
23
+
24
+ func Test_Param2(t *testing.T) {
25
+ m := Resize(100, 0, img, NearestNeighbor)
26
+ if m.Bounds() != image.Rect(0, 0, 100, 100) {
27
+ t.Fail()
28
+ }
29
+ }
30
+
31
+ func Test_ZeroImg(t *testing.T) {
32
+ zeroImg := image.NewGray16(image.Rect(0, 0, 0, 0))
33
+
34
+ m := Resize(0, 0, zeroImg, NearestNeighbor)
35
+ if m.Bounds() != zeroImg.Bounds() {
36
+ t.Fail()
37
+ }
38
+ }
39
+
40
+ func Test_CorrectResize(t *testing.T) {
41
+ zeroImg := image.NewGray16(image.Rect(0, 0, 256, 256))
42
+
43
+ m := Resize(60, 0, zeroImg, NearestNeighbor)
44
+ if m.Bounds() != image.Rect(0, 0, 60, 60) {
45
+ t.Fail()
46
+ }
47
+ }
48
+
49
+ func Test_SameColorWithRGBA(t *testing.T) {
50
+ img := image.NewRGBA(image.Rect(0, 0, 20, 20))
51
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
52
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
53
+ img.SetRGBA(x, y, color.RGBA{0x80, 0x80, 0x80, 0xFF})
54
+ }
55
+ }
56
+ out := Resize(10, 10, img, Lanczos3)
57
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
58
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
59
+ color := out.At(x, y).(color.RGBA)
60
+ if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
61
+ t.Errorf("%+v", color)
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ func Test_SameColorWithNRGBA(t *testing.T) {
68
+ img := image.NewNRGBA(image.Rect(0, 0, 20, 20))
69
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
70
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
71
+ img.SetNRGBA(x, y, color.NRGBA{0x80, 0x80, 0x80, 0xFF})
72
+ }
73
+ }
74
+ out := Resize(10, 10, img, Lanczos3)
75
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
76
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
77
+ color := out.At(x, y).(color.RGBA)
78
+ if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
79
+ t.Errorf("%+v", color)
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ func Test_SameColorWithRGBA64(t *testing.T) {
86
+ img := image.NewRGBA64(image.Rect(0, 0, 20, 20))
87
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
88
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
89
+ img.SetRGBA64(x, y, color.RGBA64{0x8000, 0x8000, 0x8000, 0xFFFF})
90
+ }
91
+ }
92
+ out := Resize(10, 10, img, Lanczos3)
93
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
94
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
95
+ color := out.At(x, y).(color.RGBA64)
96
+ if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
97
+ t.Errorf("%+v", color)
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ func Test_SameColorWithNRGBA64(t *testing.T) {
104
+ img := image.NewNRGBA64(image.Rect(0, 0, 20, 20))
105
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
106
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
107
+ img.SetNRGBA64(x, y, color.NRGBA64{0x8000, 0x8000, 0x8000, 0xFFFF})
108
+ }
109
+ }
110
+ out := Resize(10, 10, img, Lanczos3)
111
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
112
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
113
+ color := out.At(x, y).(color.RGBA64)
114
+ if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
115
+ t.Errorf("%+v", color)
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ func Test_SameColorWithGray(t *testing.T) {
122
+ img := image.NewGray(image.Rect(0, 0, 20, 20))
123
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
124
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
125
+ img.SetGray(x, y, color.Gray{0x80})
126
+ }
127
+ }
128
+ out := Resize(10, 10, img, Lanczos3)
129
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
130
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
131
+ color := out.At(x, y).(color.Gray)
132
+ if color.Y != 0x80 {
133
+ t.Errorf("%+v", color)
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ func Test_SameColorWithGray16(t *testing.T) {
140
+ img := image.NewGray16(image.Rect(0, 0, 20, 20))
141
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
142
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
143
+ img.SetGray16(x, y, color.Gray16{0x8000})
144
+ }
145
+ }
146
+ out := Resize(10, 10, img, Lanczos3)
147
+ for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
148
+ for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
149
+ color := out.At(x, y).(color.Gray16)
150
+ if color.Y != 0x8000 {
151
+ t.Errorf("%+v", color)
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ func Test_Bounds(t *testing.T) {
158
+ img := image.NewRGBA(image.Rect(20, 10, 200, 99))
159
+ out := Resize(80, 80, img, Lanczos2)
160
+ out.At(0, 0)
161
+ }
162
+
163
+ func Test_SameSizeReturnsOriginal(t *testing.T) {
164
+ img := image.NewRGBA(image.Rect(0, 0, 10, 10))
165
+ out := Resize(0, 0, img, Lanczos2)
166
+
167
+ if img != out {
168
+ t.Fail()
169
+ }
170
+
171
+ out = Resize(10, 10, img, Lanczos2)
172
+
173
+ if img != out {
174
+ t.Fail()
175
+ }
176
+ }
177
+
178
+ func Test_PixelCoordinates(t *testing.T) {
179
+ checkers := image.NewGray(image.Rect(0, 0, 4, 4))
180
+ checkers.Pix = []uint8{
181
+ 255, 0, 255, 0,
182
+ 0, 255, 0, 255,
183
+ 255, 0, 255, 0,
184
+ 0, 255, 0, 255,
185
+ }
186
+
187
+ resized := Resize(12, 12, checkers, NearestNeighbor).(*image.Gray)
188
+
189
+ if resized.Pix[0] != 255 || resized.Pix[1] != 255 || resized.Pix[2] != 255 {
190
+ t.Fail()
191
+ }
192
+
193
+ if resized.Pix[3] != 0 || resized.Pix[4] != 0 || resized.Pix[5] != 0 {
194
+ t.Fail()
195
+ }
196
+ }
197
+
198
+ func Test_ResizeWithPremultipliedAlpha(t *testing.T) {
199
+ img := image.NewRGBA(image.Rect(0, 0, 1, 4))
200
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
201
+ // 0x80 = 0.5 * 0xFF.
202
+ img.SetRGBA(0, y, color.RGBA{0x80, 0x80, 0x80, 0x80})
203
+ }
204
+
205
+ out := Resize(1, 2, img, MitchellNetravali)
206
+
207
+ outputColor := out.At(0, 0).(color.RGBA)
208
+ if outputColor.R != 0x80 {
209
+ t.Fail()
210
+ }
211
+ }
212
+
213
+ func Test_ResizeWithTranslucentColor(t *testing.T) {
214
+ img := image.NewNRGBA(image.Rect(0, 0, 1, 2))
215
+
216
+ // Set the pixel colors to an "invisible green" and white.
217
+ // After resizing, the green shouldn't be visible.
218
+ img.SetNRGBA(0, 0, color.NRGBA{0x00, 0xFF, 0x00, 0x00})
219
+ img.SetNRGBA(0, 1, color.NRGBA{0x00, 0x00, 0x00, 0xFF})
220
+
221
+ out := Resize(1, 1, img, Bilinear)
222
+
223
+ _, g, _, _ := out.At(0, 0).RGBA()
224
+ if g != 0x00 {
225
+ t.Errorf("%+v", g)
226
+ }
227
+ }
228
+
229
+ const (
230
+ // Use a small image size for benchmarks. We don't want memory performance
231
+ // to affect the benchmark results.
232
+ benchMaxX = 250
233
+ benchMaxY = 250
234
+
235
+ // Resize values near the original size require increase the amount of time
236
+ // resize spends converting the image.
237
+ benchWidth = 200
238
+ benchHeight = 200
239
+ )
240
+
241
+ func benchRGBA(b *testing.B, interp InterpolationFunction) {
242
+ m := image.NewRGBA(image.Rect(0, 0, benchMaxX, benchMaxY))
243
+ // Initialize m's pixels to create a non-uniform image.
244
+ for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
245
+ for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
246
+ i := m.PixOffset(x, y)
247
+ m.Pix[i+0] = uint8(y + 4*x)
248
+ m.Pix[i+1] = uint8(y + 4*x)
249
+ m.Pix[i+2] = uint8(y + 4*x)
250
+ m.Pix[i+3] = uint8(4*y + x)
251
+ }
252
+ }
253
+
254
+ var out image.Image
255
+ b.ResetTimer()
256
+ for i := 0; i < b.N; i++ {
257
+ out = Resize(benchWidth, benchHeight, m, interp)
258
+ }
259
+ out.At(0, 0)
260
+ }
261
+
262
+ // The names of some interpolation functions are truncated so that the columns
263
+ // of 'go test -bench' line up.
264
+ func Benchmark_Nearest_RGBA(b *testing.B) {
265
+ benchRGBA(b, NearestNeighbor)
266
+ }
267
+
268
+ func Benchmark_Bilinear_RGBA(b *testing.B) {
269
+ benchRGBA(b, Bilinear)
270
+ }
271
+
272
+ func Benchmark_Bicubic_RGBA(b *testing.B) {
273
+ benchRGBA(b, Bicubic)
274
+ }
275
+
276
+ func Benchmark_Mitchell_RGBA(b *testing.B) {
277
+ benchRGBA(b, MitchellNetravali)
278
+ }
279
+
280
+ func Benchmark_Lanczos2_RGBA(b *testing.B) {
281
+ benchRGBA(b, Lanczos2)
282
+ }
283
+
284
+ func Benchmark_Lanczos3_RGBA(b *testing.B) {
285
+ benchRGBA(b, Lanczos3)
286
+ }
287
+
288
+ func benchYCbCr(b *testing.B, interp InterpolationFunction) {
289
+ m := image.NewYCbCr(image.Rect(0, 0, benchMaxX, benchMaxY), image.YCbCrSubsampleRatio422)
290
+ // Initialize m's pixels to create a non-uniform image.
291
+ for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
292
+ for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
293
+ yi := m.YOffset(x, y)
294
+ ci := m.COffset(x, y)
295
+ m.Y[yi] = uint8(16*y + x)
296
+ m.Cb[ci] = uint8(y + 16*x)
297
+ m.Cr[ci] = uint8(y + 16*x)
298
+ }
299
+ }
300
+ var out image.Image
301
+ b.ResetTimer()
302
+ for i := 0; i < b.N; i++ {
303
+ out = Resize(benchWidth, benchHeight, m, interp)
304
+ }
305
+ out.At(0, 0)
306
+ }
307
+
308
+ func Benchmark_Nearest_YCC(b *testing.B) {
309
+ benchYCbCr(b, NearestNeighbor)
310
+ }
311
+
312
+ func Benchmark_Bilinear_YCC(b *testing.B) {
313
+ benchYCbCr(b, Bilinear)
314
+ }
315
+
316
+ func Benchmark_Bicubic_YCC(b *testing.B) {
317
+ benchYCbCr(b, Bicubic)
318
+ }
319
+
320
+ func Benchmark_Mitchell_YCC(b *testing.B) {
321
+ benchYCbCr(b, MitchellNetravali)
322
+ }
323
+
324
+ func Benchmark_Lanczos2_YCC(b *testing.B) {
325
+ benchYCbCr(b, Lanczos2)
326
+ }
327
+
328
+ func Benchmark_Lanczos3_YCC(b *testing.B) {
329
+ benchYCbCr(b, Lanczos3)
330
+ }
@@ -0,0 +1,55 @@
1
+ /*
2
+ Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any purpose
5
+ with or without fee is hereby granted, provided that the above copyright notice
6
+ and this permission notice appear in all copies.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
10
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
12
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
13
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
14
+ THIS SOFTWARE.
15
+ */
16
+
17
+ package resize
18
+
19
+ import (
20
+ "image"
21
+ )
22
+
23
+ // Thumbnail will downscale provided image to max width and height preserving
24
+ // original aspect ratio and using the interpolation function interp.
25
+ // It will return original image, without processing it, if original sizes
26
+ // are already smaller than provided constraints.
27
+ func Thumbnail(maxWidth, maxHeight uint, img image.Image, interp InterpolationFunction) image.Image {
28
+ origBounds := img.Bounds()
29
+ origWidth := uint(origBounds.Dx())
30
+ origHeight := uint(origBounds.Dy())
31
+ newWidth, newHeight := origWidth, origHeight
32
+
33
+ // Return original image if it have same or smaller size as constraints
34
+ if maxWidth >= origWidth && maxHeight >= origHeight {
35
+ return img
36
+ }
37
+
38
+ // Preserve aspect ratio
39
+ if origWidth > maxWidth {
40
+ newHeight = uint(origHeight * maxWidth / origWidth)
41
+ if newHeight < 1 {
42
+ newHeight = 1
43
+ }
44
+ newWidth = maxWidth
45
+ }
46
+
47
+ if newHeight > maxHeight {
48
+ newWidth = uint(newWidth * maxHeight / newHeight)
49
+ if newWidth < 1 {
50
+ newWidth = 1
51
+ }
52
+ newHeight = maxHeight
53
+ }
54
+ return Resize(newWidth, newHeight, img, interp)
55
+ }
@@ -0,0 +1,47 @@
1
+ package resize
2
+
3
+ import (
4
+ "image"
5
+ "runtime"
6
+ "testing"
7
+ )
8
+
9
+ func init() {
10
+ runtime.GOMAXPROCS(runtime.NumCPU())
11
+ }
12
+
13
+ var thumbnailTests = []struct {
14
+ origWidth int
15
+ origHeight int
16
+ maxWidth uint
17
+ maxHeight uint
18
+ expectedWidth uint
19
+ expectedHeight uint
20
+ }{
21
+ {5, 5, 10, 10, 5, 5},
22
+ {10, 10, 5, 5, 5, 5},
23
+ {10, 50, 10, 10, 2, 10},
24
+ {50, 10, 10, 10, 10, 2},
25
+ {50, 100, 60, 90, 45, 90},
26
+ {120, 100, 60, 90, 60, 50},
27
+ {200, 250, 200, 150, 120, 150},
28
+ }
29
+
30
+ func TestThumbnail(t *testing.T) {
31
+ for i, tt := range thumbnailTests {
32
+ img := image.NewGray16(image.Rect(0, 0, tt.origWidth, tt.origHeight))
33
+
34
+ outImg := Thumbnail(tt.maxWidth, tt.maxHeight, img, NearestNeighbor)
35
+
36
+ newWidth := uint(outImg.Bounds().Dx())
37
+ newHeight := uint(outImg.Bounds().Dy())
38
+ if newWidth != tt.expectedWidth ||
39
+ newHeight != tt.expectedHeight {
40
+ t.Errorf("%d. Thumbnail(%v, %v, img, NearestNeighbor) => "+
41
+ "width: %v, height: %v, want width: %v, height: %v",
42
+ i, tt.maxWidth, tt.maxHeight,
43
+ newWidth, newHeight, tt.expectedWidth, tt.expectedHeight,
44
+ )
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,227 @@
1
+ /*
2
+ Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any purpose
5
+ with or without fee is hereby granted, provided that the above copyright notice
6
+ and this permission notice appear in all copies.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
10
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
12
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
13
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
14
+ THIS SOFTWARE.
15
+ */
16
+
17
+ package resize
18
+
19
+ import (
20
+ "image"
21
+ "image/color"
22
+ )
23
+
24
+ // ycc is an in memory YCbCr image. The Y, Cb and Cr samples are held in a
25
+ // single slice to increase resizing performance.
26
+ type ycc struct {
27
+ // Pix holds the image's pixels, in Y, Cb, Cr order. The pixel at
28
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*3].
29
+ Pix []uint8
30
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
31
+ Stride int
32
+ // Rect is the image's bounds.
33
+ Rect image.Rectangle
34
+ // SubsampleRatio is the subsample ratio of the original YCbCr image.
35
+ SubsampleRatio image.YCbCrSubsampleRatio
36
+ }
37
+
38
+ // PixOffset returns the index of the first element of Pix that corresponds to
39
+ // the pixel at (x, y).
40
+ func (p *ycc) PixOffset(x, y int) int {
41
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*3
42
+ }
43
+
44
+ func (p *ycc) Bounds() image.Rectangle {
45
+ return p.Rect
46
+ }
47
+
48
+ func (p *ycc) ColorModel() color.Model {
49
+ return color.YCbCrModel
50
+ }
51
+
52
+ func (p *ycc) At(x, y int) color.Color {
53
+ if !(image.Point{x, y}.In(p.Rect)) {
54
+ return color.YCbCr{}
55
+ }
56
+ i := p.PixOffset(x, y)
57
+ return color.YCbCr{
58
+ p.Pix[i+0],
59
+ p.Pix[i+1],
60
+ p.Pix[i+2],
61
+ }
62
+ }
63
+
64
+ func (p *ycc) Opaque() bool {
65
+ return true
66
+ }
67
+
68
+ // SubImage returns an image representing the portion of the image p visible
69
+ // through r. The returned value shares pixels with the original image.
70
+ func (p *ycc) SubImage(r image.Rectangle) image.Image {
71
+ r = r.Intersect(p.Rect)
72
+ if r.Empty() {
73
+ return &ycc{SubsampleRatio: p.SubsampleRatio}
74
+ }
75
+ i := p.PixOffset(r.Min.X, r.Min.Y)
76
+ return &ycc{
77
+ Pix: p.Pix[i:],
78
+ Stride: p.Stride,
79
+ Rect: r,
80
+ SubsampleRatio: p.SubsampleRatio,
81
+ }
82
+ }
83
+
84
+ // newYCC returns a new ycc with the given bounds and subsample ratio.
85
+ func newYCC(r image.Rectangle, s image.YCbCrSubsampleRatio) *ycc {
86
+ w, h := r.Dx(), r.Dy()
87
+ buf := make([]uint8, 3*w*h)
88
+ return &ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: s}
89
+ }
90
+
91
+ // YCbCr converts ycc to a YCbCr image with the same subsample ratio
92
+ // as the YCbCr image that ycc was generated from.
93
+ func (p *ycc) YCbCr() *image.YCbCr {
94
+ ycbcr := image.NewYCbCr(p.Rect, p.SubsampleRatio)
95
+ var off int
96
+
97
+ switch ycbcr.SubsampleRatio {
98
+ case image.YCbCrSubsampleRatio422:
99
+ for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
100
+ yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
101
+ cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride
102
+ for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
103
+ xx := (x - ycbcr.Rect.Min.X)
104
+ yi := yy + xx
105
+ ci := cy + xx/2
106
+ ycbcr.Y[yi] = p.Pix[off+0]
107
+ ycbcr.Cb[ci] = p.Pix[off+1]
108
+ ycbcr.Cr[ci] = p.Pix[off+2]
109
+ off += 3
110
+ }
111
+ }
112
+ case image.YCbCrSubsampleRatio420:
113
+ for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
114
+ yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
115
+ cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride
116
+ for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
117
+ xx := (x - ycbcr.Rect.Min.X)
118
+ yi := yy + xx
119
+ ci := cy + xx/2
120
+ ycbcr.Y[yi] = p.Pix[off+0]
121
+ ycbcr.Cb[ci] = p.Pix[off+1]
122
+ ycbcr.Cr[ci] = p.Pix[off+2]
123
+ off += 3
124
+ }
125
+ }
126
+ case image.YCbCrSubsampleRatio440:
127
+ for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
128
+ yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
129
+ cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride
130
+ for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
131
+ xx := (x - ycbcr.Rect.Min.X)
132
+ yi := yy + xx
133
+ ci := cy + xx
134
+ ycbcr.Y[yi] = p.Pix[off+0]
135
+ ycbcr.Cb[ci] = p.Pix[off+1]
136
+ ycbcr.Cr[ci] = p.Pix[off+2]
137
+ off += 3
138
+ }
139
+ }
140
+ default:
141
+ // Default to 4:4:4 subsampling.
142
+ for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
143
+ yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
144
+ cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride
145
+ for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
146
+ xx := (x - ycbcr.Rect.Min.X)
147
+ yi := yy + xx
148
+ ci := cy + xx
149
+ ycbcr.Y[yi] = p.Pix[off+0]
150
+ ycbcr.Cb[ci] = p.Pix[off+1]
151
+ ycbcr.Cr[ci] = p.Pix[off+2]
152
+ off += 3
153
+ }
154
+ }
155
+ }
156
+ return ycbcr
157
+ }
158
+
159
+ // imageYCbCrToYCC converts a YCbCr image to a ycc image for resizing.
160
+ func imageYCbCrToYCC(in *image.YCbCr) *ycc {
161
+ w, h := in.Rect.Dx(), in.Rect.Dy()
162
+ r := image.Rect(0, 0, w, h)
163
+ buf := make([]uint8, 3*w*h)
164
+ p := ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: in.SubsampleRatio}
165
+ var off int
166
+
167
+ switch in.SubsampleRatio {
168
+ case image.YCbCrSubsampleRatio422:
169
+ for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
170
+ yy := (y - in.Rect.Min.Y) * in.YStride
171
+ cy := (y - in.Rect.Min.Y) * in.CStride
172
+ for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
173
+ xx := (x - in.Rect.Min.X)
174
+ yi := yy + xx
175
+ ci := cy + xx/2
176
+ p.Pix[off+0] = in.Y[yi]
177
+ p.Pix[off+1] = in.Cb[ci]
178
+ p.Pix[off+2] = in.Cr[ci]
179
+ off += 3
180
+ }
181
+ }
182
+ case image.YCbCrSubsampleRatio420:
183
+ for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
184
+ yy := (y - in.Rect.Min.Y) * in.YStride
185
+ cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
186
+ for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
187
+ xx := (x - in.Rect.Min.X)
188
+ yi := yy + xx
189
+ ci := cy + xx/2
190
+ p.Pix[off+0] = in.Y[yi]
191
+ p.Pix[off+1] = in.Cb[ci]
192
+ p.Pix[off+2] = in.Cr[ci]
193
+ off += 3
194
+ }
195
+ }
196
+ case image.YCbCrSubsampleRatio440:
197
+ for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
198
+ yy := (y - in.Rect.Min.Y) * in.YStride
199
+ cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
200
+ for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
201
+ xx := (x - in.Rect.Min.X)
202
+ yi := yy + xx
203
+ ci := cy + xx
204
+ p.Pix[off+0] = in.Y[yi]
205
+ p.Pix[off+1] = in.Cb[ci]
206
+ p.Pix[off+2] = in.Cr[ci]
207
+ off += 3
208
+ }
209
+ }
210
+ default:
211
+ // Default to 4:4:4 subsampling.
212
+ for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
213
+ yy := (y - in.Rect.Min.Y) * in.YStride
214
+ cy := (y - in.Rect.Min.Y) * in.CStride
215
+ for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
216
+ xx := (x - in.Rect.Min.X)
217
+ yi := yy + xx
218
+ ci := cy + xx
219
+ p.Pix[off+0] = in.Y[yi]
220
+ p.Pix[off+1] = in.Cb[ci]
221
+ p.Pix[off+2] = in.Cr[ci]
222
+ off += 3
223
+ }
224
+ }
225
+ }
226
+ return &p
227
+ }