ires 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +111 -0
- data/Rakefile +30 -0
- data/ext/Gopkg.lock +21 -0
- data/ext/Gopkg.toml +30 -0
- data/ext/main.go +90 -0
- data/ext/operate/image.go +139 -0
- data/ext/util/uri/uri.go +96 -0
- data/ext/vendor/github.com/nfnt/resize/LICENSE +13 -0
- data/ext/vendor/github.com/nfnt/resize/README.md +149 -0
- data/ext/vendor/github.com/nfnt/resize/converter.go +438 -0
- data/ext/vendor/github.com/nfnt/resize/converter_test.go +43 -0
- data/ext/vendor/github.com/nfnt/resize/filters.go +143 -0
- data/ext/vendor/github.com/nfnt/resize/nearest.go +318 -0
- data/ext/vendor/github.com/nfnt/resize/nearest_test.go +57 -0
- data/ext/vendor/github.com/nfnt/resize/resize.go +614 -0
- data/ext/vendor/github.com/nfnt/resize/resize_test.go +330 -0
- data/ext/vendor/github.com/nfnt/resize/thumbnail.go +55 -0
- data/ext/vendor/github.com/nfnt/resize/thumbnail_test.go +47 -0
- data/ext/vendor/github.com/nfnt/resize/ycc.go +227 -0
- data/ext/vendor/github.com/nfnt/resize/ycc_test.go +214 -0
- data/ext/vendor/github.com/oliamb/cutter/LICENSE +20 -0
- data/ext/vendor/github.com/oliamb/cutter/README.md +88 -0
- data/ext/vendor/github.com/oliamb/cutter/benchmark_test.go +54 -0
- data/ext/vendor/github.com/oliamb/cutter/cutter.go +183 -0
- data/ext/vendor/github.com/oliamb/cutter/cutter/main.go +68 -0
- data/ext/vendor/github.com/oliamb/cutter/cutter_test.go +267 -0
- data/ext/vendor/github.com/oliamb/cutter/example_test.go +35 -0
- data/ext/vendor/github.com/oliamb/cutter/fixtures/gopher.jpg +0 -0
- data/lib/ires.rb +4 -0
- data/lib/ires/engine.rb +7 -0
- data/lib/ires/service.rb +19 -0
- data/lib/ires/util.rb +39 -0
- data/lib/ires/version.rb +3 -0
- data/lib/ires/view_helper.rb +42 -0
- data/lib/tasks/ires.rake +11 -0
- data/shared/darwin/ires.h +64 -0
- data/shared/darwin/ires.so +0 -0
- data/shared/linux/ires.h +64 -0
- data/shared/linux/ires.so +0 -0
- 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
|
+
}
|