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,43 @@
1
+ package resize
2
+
3
+ import (
4
+ "testing"
5
+ )
6
+
7
+ func Test_ClampUint8(t *testing.T) {
8
+ var testData = []struct {
9
+ in int32
10
+ expected uint8
11
+ }{
12
+ {0, 0},
13
+ {255, 255},
14
+ {128, 128},
15
+ {-2, 0},
16
+ {256, 255},
17
+ }
18
+ for _, test := range testData {
19
+ actual := clampUint8(test.in)
20
+ if actual != test.expected {
21
+ t.Fail()
22
+ }
23
+ }
24
+ }
25
+
26
+ func Test_ClampUint16(t *testing.T) {
27
+ var testData = []struct {
28
+ in int64
29
+ expected uint16
30
+ }{
31
+ {0, 0},
32
+ {65535, 65535},
33
+ {128, 128},
34
+ {-2, 0},
35
+ {65536, 65535},
36
+ }
37
+ for _, test := range testData {
38
+ actual := clampUint16(test.in)
39
+ if actual != test.expected {
40
+ t.Fail()
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,143 @@
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
+ "math"
21
+ )
22
+
23
+ func nearest(in float64) float64 {
24
+ if in >= -0.5 && in < 0.5 {
25
+ return 1
26
+ }
27
+ return 0
28
+ }
29
+
30
+ func linear(in float64) float64 {
31
+ in = math.Abs(in)
32
+ if in <= 1 {
33
+ return 1 - in
34
+ }
35
+ return 0
36
+ }
37
+
38
+ func cubic(in float64) float64 {
39
+ in = math.Abs(in)
40
+ if in <= 1 {
41
+ return in*in*(1.5*in-2.5) + 1.0
42
+ }
43
+ if in <= 2 {
44
+ return in*(in*(2.5-0.5*in)-4.0) + 2.0
45
+ }
46
+ return 0
47
+ }
48
+
49
+ func mitchellnetravali(in float64) float64 {
50
+ in = math.Abs(in)
51
+ if in <= 1 {
52
+ return (7.0*in*in*in - 12.0*in*in + 5.33333333333) * 0.16666666666
53
+ }
54
+ if in <= 2 {
55
+ return (-2.33333333333*in*in*in + 12.0*in*in - 20.0*in + 10.6666666667) * 0.16666666666
56
+ }
57
+ return 0
58
+ }
59
+
60
+ func sinc(x float64) float64 {
61
+ x = math.Abs(x) * math.Pi
62
+ if x >= 1.220703e-4 {
63
+ return math.Sin(x) / x
64
+ }
65
+ return 1
66
+ }
67
+
68
+ func lanczos2(in float64) float64 {
69
+ if in > -2 && in < 2 {
70
+ return sinc(in) * sinc(in*0.5)
71
+ }
72
+ return 0
73
+ }
74
+
75
+ func lanczos3(in float64) float64 {
76
+ if in > -3 && in < 3 {
77
+ return sinc(in) * sinc(in*0.3333333333333333)
78
+ }
79
+ return 0
80
+ }
81
+
82
+ // range [-256,256]
83
+ func createWeights8(dy, filterLength int, blur, scale float64, kernel func(float64) float64) ([]int16, []int, int) {
84
+ filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
85
+ filterFactor := math.Min(1./(blur*scale), 1)
86
+
87
+ coeffs := make([]int16, dy*filterLength)
88
+ start := make([]int, dy)
89
+ for y := 0; y < dy; y++ {
90
+ interpX := scale*(float64(y)+0.5) - 0.5
91
+ start[y] = int(interpX) - filterLength/2 + 1
92
+ interpX -= float64(start[y])
93
+ for i := 0; i < filterLength; i++ {
94
+ in := (interpX - float64(i)) * filterFactor
95
+ coeffs[y*filterLength+i] = int16(kernel(in) * 256)
96
+ }
97
+ }
98
+
99
+ return coeffs, start, filterLength
100
+ }
101
+
102
+ // range [-65536,65536]
103
+ func createWeights16(dy, filterLength int, blur, scale float64, kernel func(float64) float64) ([]int32, []int, int) {
104
+ filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
105
+ filterFactor := math.Min(1./(blur*scale), 1)
106
+
107
+ coeffs := make([]int32, dy*filterLength)
108
+ start := make([]int, dy)
109
+ for y := 0; y < dy; y++ {
110
+ interpX := scale*(float64(y)+0.5) - 0.5
111
+ start[y] = int(interpX) - filterLength/2 + 1
112
+ interpX -= float64(start[y])
113
+ for i := 0; i < filterLength; i++ {
114
+ in := (interpX - float64(i)) * filterFactor
115
+ coeffs[y*filterLength+i] = int32(kernel(in) * 65536)
116
+ }
117
+ }
118
+
119
+ return coeffs, start, filterLength
120
+ }
121
+
122
+ func createWeightsNearest(dy, filterLength int, blur, scale float64) ([]bool, []int, int) {
123
+ filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
124
+ filterFactor := math.Min(1./(blur*scale), 1)
125
+
126
+ coeffs := make([]bool, dy*filterLength)
127
+ start := make([]int, dy)
128
+ for y := 0; y < dy; y++ {
129
+ interpX := scale*(float64(y)+0.5) - 0.5
130
+ start[y] = int(interpX) - filterLength/2 + 1
131
+ interpX -= float64(start[y])
132
+ for i := 0; i < filterLength; i++ {
133
+ in := (interpX - float64(i)) * filterFactor
134
+ if in >= -0.5 && in < 0.5 {
135
+ coeffs[y*filterLength+i] = true
136
+ } else {
137
+ coeffs[y*filterLength+i] = false
138
+ }
139
+ }
140
+ }
141
+
142
+ return coeffs, start, filterLength
143
+ }
@@ -0,0 +1,318 @@
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 "image"
20
+
21
+ func floatToUint8(x float32) uint8 {
22
+ // Nearest-neighbor values are always
23
+ // positive no need to check lower-bound.
24
+ if x > 0xfe {
25
+ return 0xff
26
+ }
27
+ return uint8(x)
28
+ }
29
+
30
+ func floatToUint16(x float32) uint16 {
31
+ if x > 0xfffe {
32
+ return 0xffff
33
+ }
34
+ return uint16(x)
35
+ }
36
+
37
+ func nearestGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
38
+ newBounds := out.Bounds()
39
+ maxX := in.Bounds().Dx() - 1
40
+
41
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
42
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
43
+ var rgba [4]float32
44
+ var sum float32
45
+ start := offset[y]
46
+ ci := y * filterLength
47
+ for i := 0; i < filterLength; i++ {
48
+ if coeffs[ci+i] {
49
+ xi := start + i
50
+ switch {
51
+ case xi < 0:
52
+ xi = 0
53
+ case xi >= maxX:
54
+ xi = maxX
55
+ }
56
+ r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
57
+ rgba[0] += float32(r)
58
+ rgba[1] += float32(g)
59
+ rgba[2] += float32(b)
60
+ rgba[3] += float32(a)
61
+ sum++
62
+ }
63
+ }
64
+
65
+ offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
66
+ value := floatToUint16(rgba[0] / sum)
67
+ out.Pix[offset+0] = uint8(value >> 8)
68
+ out.Pix[offset+1] = uint8(value)
69
+ value = floatToUint16(rgba[1] / sum)
70
+ out.Pix[offset+2] = uint8(value >> 8)
71
+ out.Pix[offset+3] = uint8(value)
72
+ value = floatToUint16(rgba[2] / sum)
73
+ out.Pix[offset+4] = uint8(value >> 8)
74
+ out.Pix[offset+5] = uint8(value)
75
+ value = floatToUint16(rgba[3] / sum)
76
+ out.Pix[offset+6] = uint8(value >> 8)
77
+ out.Pix[offset+7] = uint8(value)
78
+ }
79
+ }
80
+ }
81
+
82
+ func nearestRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []bool, offset []int, filterLength int) {
83
+ newBounds := out.Bounds()
84
+ maxX := in.Bounds().Dx() - 1
85
+
86
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
87
+ row := in.Pix[x*in.Stride:]
88
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
89
+ var rgba [4]float32
90
+ var sum float32
91
+ start := offset[y]
92
+ ci := y * filterLength
93
+ for i := 0; i < filterLength; i++ {
94
+ if coeffs[ci+i] {
95
+ xi := start + i
96
+ switch {
97
+ case uint(xi) < uint(maxX):
98
+ xi *= 4
99
+ case xi >= maxX:
100
+ xi = 4 * maxX
101
+ default:
102
+ xi = 0
103
+ }
104
+ rgba[0] += float32(row[xi+0])
105
+ rgba[1] += float32(row[xi+1])
106
+ rgba[2] += float32(row[xi+2])
107
+ rgba[3] += float32(row[xi+3])
108
+ sum++
109
+ }
110
+ }
111
+
112
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
113
+ out.Pix[xo+0] = floatToUint8(rgba[0] / sum)
114
+ out.Pix[xo+1] = floatToUint8(rgba[1] / sum)
115
+ out.Pix[xo+2] = floatToUint8(rgba[2] / sum)
116
+ out.Pix[xo+3] = floatToUint8(rgba[3] / sum)
117
+ }
118
+ }
119
+ }
120
+
121
+ func nearestNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []bool, offset []int, filterLength int) {
122
+ newBounds := out.Bounds()
123
+ maxX := in.Bounds().Dx() - 1
124
+
125
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
126
+ row := in.Pix[x*in.Stride:]
127
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
128
+ var rgba [4]float32
129
+ var sum float32
130
+ start := offset[y]
131
+ ci := y * filterLength
132
+ for i := 0; i < filterLength; i++ {
133
+ if coeffs[ci+i] {
134
+ xi := start + i
135
+ switch {
136
+ case uint(xi) < uint(maxX):
137
+ xi *= 4
138
+ case xi >= maxX:
139
+ xi = 4 * maxX
140
+ default:
141
+ xi = 0
142
+ }
143
+ rgba[0] += float32(row[xi+0])
144
+ rgba[1] += float32(row[xi+1])
145
+ rgba[2] += float32(row[xi+2])
146
+ rgba[3] += float32(row[xi+3])
147
+ sum++
148
+ }
149
+ }
150
+
151
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
152
+ out.Pix[xo+0] = floatToUint8(rgba[0] / sum)
153
+ out.Pix[xo+1] = floatToUint8(rgba[1] / sum)
154
+ out.Pix[xo+2] = floatToUint8(rgba[2] / sum)
155
+ out.Pix[xo+3] = floatToUint8(rgba[3] / sum)
156
+ }
157
+ }
158
+ }
159
+
160
+ func nearestRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
161
+ newBounds := out.Bounds()
162
+ maxX := in.Bounds().Dx() - 1
163
+
164
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
165
+ row := in.Pix[x*in.Stride:]
166
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
167
+ var rgba [4]float32
168
+ var sum float32
169
+ start := offset[y]
170
+ ci := y * filterLength
171
+ for i := 0; i < filterLength; i++ {
172
+ if coeffs[ci+i] {
173
+ xi := start + i
174
+ switch {
175
+ case uint(xi) < uint(maxX):
176
+ xi *= 8
177
+ case xi >= maxX:
178
+ xi = 8 * maxX
179
+ default:
180
+ xi = 0
181
+ }
182
+ rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
183
+ rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
184
+ rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
185
+ rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
186
+ sum++
187
+ }
188
+ }
189
+
190
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
191
+ value := floatToUint16(rgba[0] / sum)
192
+ out.Pix[xo+0] = uint8(value >> 8)
193
+ out.Pix[xo+1] = uint8(value)
194
+ value = floatToUint16(rgba[1] / sum)
195
+ out.Pix[xo+2] = uint8(value >> 8)
196
+ out.Pix[xo+3] = uint8(value)
197
+ value = floatToUint16(rgba[2] / sum)
198
+ out.Pix[xo+4] = uint8(value >> 8)
199
+ out.Pix[xo+5] = uint8(value)
200
+ value = floatToUint16(rgba[3] / sum)
201
+ out.Pix[xo+6] = uint8(value >> 8)
202
+ out.Pix[xo+7] = uint8(value)
203
+ }
204
+ }
205
+ }
206
+
207
+ func nearestNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
208
+ newBounds := out.Bounds()
209
+ maxX := in.Bounds().Dx() - 1
210
+
211
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
212
+ row := in.Pix[x*in.Stride:]
213
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
214
+ var rgba [4]float32
215
+ var sum float32
216
+ start := offset[y]
217
+ ci := y * filterLength
218
+ for i := 0; i < filterLength; i++ {
219
+ if coeffs[ci+i] {
220
+ xi := start + i
221
+ switch {
222
+ case uint(xi) < uint(maxX):
223
+ xi *= 8
224
+ case xi >= maxX:
225
+ xi = 8 * maxX
226
+ default:
227
+ xi = 0
228
+ }
229
+ rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
230
+ rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
231
+ rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
232
+ rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
233
+ sum++
234
+ }
235
+ }
236
+
237
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
238
+ value := floatToUint16(rgba[0] / sum)
239
+ out.Pix[xo+0] = uint8(value >> 8)
240
+ out.Pix[xo+1] = uint8(value)
241
+ value = floatToUint16(rgba[1] / sum)
242
+ out.Pix[xo+2] = uint8(value >> 8)
243
+ out.Pix[xo+3] = uint8(value)
244
+ value = floatToUint16(rgba[2] / sum)
245
+ out.Pix[xo+4] = uint8(value >> 8)
246
+ out.Pix[xo+5] = uint8(value)
247
+ value = floatToUint16(rgba[3] / sum)
248
+ out.Pix[xo+6] = uint8(value >> 8)
249
+ out.Pix[xo+7] = uint8(value)
250
+ }
251
+ }
252
+ }
253
+
254
+ func nearestGray(in *image.Gray, out *image.Gray, scale float64, coeffs []bool, offset []int, filterLength int) {
255
+ newBounds := out.Bounds()
256
+ maxX := in.Bounds().Dx() - 1
257
+
258
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
259
+ row := in.Pix[x*in.Stride:]
260
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
261
+ var gray float32
262
+ var sum float32
263
+ start := offset[y]
264
+ ci := y * filterLength
265
+ for i := 0; i < filterLength; i++ {
266
+ if coeffs[ci+i] {
267
+ xi := start + i
268
+ switch {
269
+ case xi < 0:
270
+ xi = 0
271
+ case xi >= maxX:
272
+ xi = maxX
273
+ }
274
+ gray += float32(row[xi])
275
+ sum++
276
+ }
277
+ }
278
+
279
+ offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
280
+ out.Pix[offset] = floatToUint8(gray / sum)
281
+ }
282
+ }
283
+ }
284
+
285
+ func nearestGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []bool, offset []int, filterLength int) {
286
+ newBounds := out.Bounds()
287
+ maxX := in.Bounds().Dx() - 1
288
+
289
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
290
+ row := in.Pix[x*in.Stride:]
291
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
292
+ var gray float32
293
+ var sum float32
294
+ start := offset[y]
295
+ ci := y * filterLength
296
+ for i := 0; i < filterLength; i++ {
297
+ if coeffs[ci+i] {
298
+ xi := start + i
299
+ switch {
300
+ case uint(xi) < uint(maxX):
301
+ xi *= 2
302
+ case xi >= maxX:
303
+ xi = 2 * maxX
304
+ default:
305
+ xi = 0
306
+ }
307
+ gray += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
308
+ sum++
309
+ }
310
+ }
311
+
312
+ offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
313
+ value := floatToUint16(gray / sum)
314
+ out.Pix[offset+0] = uint8(value >> 8)
315
+ out.Pix[offset+1] = uint8(value)
316
+ }
317
+ }
318
+ }