ires 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }