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,96 @@
1
+ package util
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strconv"
7
+ "strings"
8
+ "io/ioutil"
9
+ )
10
+
11
+ // ローカルの画像かどうか
12
+ func IsLocalFile(path string) bool {
13
+ if strings.Index(path, "http") == -1 {
14
+ return true
15
+ } else {
16
+ return false
17
+ }
18
+ }
19
+
20
+ // 画像名を取得
21
+ func getImageName(uri string) (string, string) {
22
+ splitPath := strings.Split(uri, "/")
23
+ fileName := splitPath[len(splitPath)-1] // ex. sample.jpg
24
+ ext := filepath.Ext(fileName) // ex. .jpg
25
+ return strings.Replace(fileName, ext, "", 1), ext
26
+ }
27
+
28
+ // 画像のフルパスを生成
29
+ func NewImagePath(uri, dir string, mode int, size ...int) string {
30
+ name := NewImageName(uri, size...)
31
+ return FilePath(name, dir, mode, size...)
32
+ }
33
+
34
+ // ファイル名を生成
35
+ func NewImageName(uri string, size ...int) string {
36
+ imageName, ext := getImageName(uri)
37
+ if len(size) == 2 {
38
+ imageName += "_" + PrefixSize(size...)
39
+ }
40
+ imageName += ext
41
+ return imageName
42
+ }
43
+
44
+ // 画像を保存するパスの設定
45
+ func FilePath(name string, d string, mode int, size ...int) string {
46
+ paths := []rune(d)
47
+ pathsLastIndex := len(paths) - 1
48
+ lastChar := string(paths[pathsLastIndex])
49
+ if lastChar == "/" {
50
+ d = string(paths[:pathsLastIndex])
51
+ }
52
+
53
+ // 画像格納先
54
+ var oDir string
55
+ switch mode {
56
+ case 0: oDir = "ires/resize"
57
+ case 1: oDir = "ires/crop"
58
+ case 2: oDir = "ires/resize_to_crop"
59
+ default: oDir = "ires/original"
60
+ }
61
+
62
+ var prefix string
63
+ if len(size) == 2 {
64
+ prefix = PrefixSize(size...)
65
+ } else {
66
+ prefix = "original"
67
+ }
68
+ oDir += "/" + prefix
69
+
70
+ // Create directory
71
+ oPath := filepath.Join(d, oDir)
72
+ if _, err := os.Stat(oPath); err != nil {
73
+ if err := os.MkdirAll(oPath, 0777); err != nil {
74
+ panic(err)
75
+ }
76
+ }
77
+
78
+ pullPath := filepath.Join(oPath, name)
79
+ return pullPath
80
+ }
81
+
82
+ // サイズからプレフィックスを作成 ex. 640x480
83
+ func PrefixSize(size ...int) string {
84
+ prefix := strconv.Itoa(size[0]) + "x" + strconv.Itoa(size[1])
85
+ return prefix
86
+ }
87
+
88
+ // リサイズ済みのファイルがあれば、処理せず返す
89
+ func IsEmptyImage(path string) bool {
90
+ _, err := ioutil.ReadFile(path)
91
+ if err != nil {
92
+ return true
93
+ } else {
94
+ return false
95
+ }
96
+ }
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any purpose
4
+ with or without fee is hereby granted, provided that the above copyright notice
5
+ and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
11
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
12
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
13
+ THIS SOFTWARE.
@@ -0,0 +1,149 @@
1
+ Resize
2
+ ======
3
+
4
+ Image resizing for the [Go programming language](http://golang.org) with common interpolation methods.
5
+
6
+ [![Build Status](https://travis-ci.org/nfnt/resize.svg)](https://travis-ci.org/nfnt/resize)
7
+
8
+ Installation
9
+ ------------
10
+
11
+ ```bash
12
+ $ go get github.com/nfnt/resize
13
+ ```
14
+
15
+ It's that easy!
16
+
17
+ Usage
18
+ -----
19
+
20
+ This package needs at least Go 1.1. Import package with
21
+
22
+ ```go
23
+ import "github.com/nfnt/resize"
24
+ ```
25
+
26
+ The resize package provides 2 functions:
27
+
28
+ * `resize.Resize` creates a scaled image with new dimensions (`width`, `height`) using the interpolation function `interp`.
29
+ If either `width` or `height` is set to 0, it will be set to an aspect ratio preserving value.
30
+ * `resize.Thumbnail` downscales an image preserving its aspect ratio to the maximum dimensions (`maxWidth`, `maxHeight`).
31
+ It will return the original image if original sizes are smaller than the provided dimensions.
32
+
33
+ ```go
34
+ resize.Resize(width, height uint, img image.Image, interp resize.InterpolationFunction) image.Image
35
+ resize.Thumbnail(maxWidth, maxHeight uint, img image.Image, interp resize.InterpolationFunction) image.Image
36
+ ```
37
+
38
+ The provided interpolation functions are (from fast to slow execution time)
39
+
40
+ - `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation)
41
+ - `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation)
42
+ - `Bicubic`: [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation)
43
+ - `MitchellNetravali`: [Mitchell-Netravali interpolation](http://dl.acm.org/citation.cfm?id=378514)
44
+ - `Lanczos2`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=2
45
+ - `Lanczos3`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=3
46
+
47
+ Which of these methods gives the best results depends on your use case.
48
+
49
+ Sample usage:
50
+
51
+ ```go
52
+ package main
53
+
54
+ import (
55
+ "github.com/nfnt/resize"
56
+ "image/jpeg"
57
+ "log"
58
+ "os"
59
+ )
60
+
61
+ func main() {
62
+ // open "test.jpg"
63
+ file, err := os.Open("test.jpg")
64
+ if err != nil {
65
+ log.Fatal(err)
66
+ }
67
+
68
+ // decode jpeg into image.Image
69
+ img, err := jpeg.Decode(file)
70
+ if err != nil {
71
+ log.Fatal(err)
72
+ }
73
+ file.Close()
74
+
75
+ // resize to width 1000 using Lanczos resampling
76
+ // and preserve aspect ratio
77
+ m := resize.Resize(1000, 0, img, resize.Lanczos3)
78
+
79
+ out, err := os.Create("test_resized.jpg")
80
+ if err != nil {
81
+ log.Fatal(err)
82
+ }
83
+ defer out.Close()
84
+
85
+ // write new image to file
86
+ jpeg.Encode(out, m, nil)
87
+ }
88
+ ```
89
+
90
+ Caveats
91
+ -------
92
+
93
+ * Optimized access routines are used for `image.RGBA`, `image.NRGBA`, `image.RGBA64`, `image.NRGBA64`, `image.YCbCr`, `image.Gray`, and `image.Gray16` types. All other image types are accessed in a generic way that will result in slow processing speed.
94
+ * JPEG images are stored in `image.YCbCr`. This image format stores data in a way that will decrease processing speed. A resize may be up to 2 times slower than with `image.RGBA`.
95
+
96
+
97
+ Downsizing Samples
98
+ -------
99
+
100
+ Downsizing is not as simple as it might look like. Images have to be filtered before they are scaled down, otherwise aliasing might occur.
101
+ Filtering is highly subjective: Applying too much will blur the whole image, too little will make aliasing become apparent.
102
+ Resize tries to provide sane defaults that should suffice in most cases.
103
+
104
+ ### Artificial sample
105
+
106
+ Original image
107
+ ![Rings](http://nfnt.github.com/img/rings_lg_orig.png)
108
+
109
+ <table>
110
+ <tr>
111
+ <th><img src="http://nfnt.github.com/img/rings_300_NearestNeighbor.png" /><br>Nearest-Neighbor</th>
112
+ <th><img src="http://nfnt.github.com/img/rings_300_Bilinear.png" /><br>Bilinear</th>
113
+ </tr>
114
+ <tr>
115
+ <th><img src="http://nfnt.github.com/img/rings_300_Bicubic.png" /><br>Bicubic</th>
116
+ <th><img src="http://nfnt.github.com/img/rings_300_MitchellNetravali.png" /><br>Mitchell-Netravali</th>
117
+ </tr>
118
+ <tr>
119
+ <th><img src="http://nfnt.github.com/img/rings_300_Lanczos2.png" /><br>Lanczos2</th>
120
+ <th><img src="http://nfnt.github.com/img/rings_300_Lanczos3.png" /><br>Lanczos3</th>
121
+ </tr>
122
+ </table>
123
+
124
+ ### Real-Life sample
125
+
126
+ Original image
127
+ ![Original](http://nfnt.github.com/img/IMG_3694_720.jpg)
128
+
129
+ <table>
130
+ <tr>
131
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_NearestNeighbor.png" /><br>Nearest-Neighbor</th>
132
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_Bilinear.png" /><br>Bilinear</th>
133
+ </tr>
134
+ <tr>
135
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_Bicubic.png" /><br>Bicubic</th>
136
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_MitchellNetravali.png" /><br>Mitchell-Netravali</th>
137
+ </tr>
138
+ <tr>
139
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_Lanczos2.png" /><br>Lanczos2</th>
140
+ <th><img src="http://nfnt.github.com/img/IMG_3694_300_Lanczos3.png" /><br>Lanczos3</th>
141
+ </tr>
142
+ </table>
143
+
144
+
145
+ License
146
+ -------
147
+
148
+ Copyright (c) 2012 Jan Schlicht <janschlicht@gmail.com>
149
+ Resize is released under a MIT style license.
@@ -0,0 +1,438 @@
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 "image"
20
+
21
+ // Keep value in [0,255] range.
22
+ func clampUint8(in int32) uint8 {
23
+ // casting a negative int to an uint will result in an overflown
24
+ // large uint. this behavior will be exploited here and in other functions
25
+ // to achieve a higher performance.
26
+ if uint32(in) < 256 {
27
+ return uint8(in)
28
+ }
29
+ if in > 255 {
30
+ return 255
31
+ }
32
+ return 0
33
+ }
34
+
35
+ // Keep value in [0,65535] range.
36
+ func clampUint16(in int64) uint16 {
37
+ if uint64(in) < 65536 {
38
+ return uint16(in)
39
+ }
40
+ if in > 65535 {
41
+ return 65535
42
+ }
43
+ return 0
44
+ }
45
+
46
+ func resizeGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
47
+ newBounds := out.Bounds()
48
+ maxX := in.Bounds().Dx() - 1
49
+
50
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
51
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
52
+ var rgba [4]int64
53
+ var sum int64
54
+ start := offset[y]
55
+ ci := y * filterLength
56
+ for i := 0; i < filterLength; i++ {
57
+ coeff := coeffs[ci+i]
58
+ if coeff != 0 {
59
+ xi := start + i
60
+ switch {
61
+ case xi < 0:
62
+ xi = 0
63
+ case xi >= maxX:
64
+ xi = maxX
65
+ }
66
+
67
+ r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
68
+
69
+ rgba[0] += int64(coeff) * int64(r)
70
+ rgba[1] += int64(coeff) * int64(g)
71
+ rgba[2] += int64(coeff) * int64(b)
72
+ rgba[3] += int64(coeff) * int64(a)
73
+ sum += int64(coeff)
74
+ }
75
+ }
76
+
77
+ offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
78
+
79
+ value := clampUint16(rgba[0] / sum)
80
+ out.Pix[offset+0] = uint8(value >> 8)
81
+ out.Pix[offset+1] = uint8(value)
82
+ value = clampUint16(rgba[1] / sum)
83
+ out.Pix[offset+2] = uint8(value >> 8)
84
+ out.Pix[offset+3] = uint8(value)
85
+ value = clampUint16(rgba[2] / sum)
86
+ out.Pix[offset+4] = uint8(value >> 8)
87
+ out.Pix[offset+5] = uint8(value)
88
+ value = clampUint16(rgba[3] / sum)
89
+ out.Pix[offset+6] = uint8(value >> 8)
90
+ out.Pix[offset+7] = uint8(value)
91
+ }
92
+ }
93
+ }
94
+
95
+ func resizeRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
96
+ newBounds := out.Bounds()
97
+ maxX := in.Bounds().Dx() - 1
98
+
99
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
100
+ row := in.Pix[x*in.Stride:]
101
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
102
+ var rgba [4]int32
103
+ var sum int32
104
+ start := offset[y]
105
+ ci := y * filterLength
106
+ for i := 0; i < filterLength; i++ {
107
+ coeff := coeffs[ci+i]
108
+ if coeff != 0 {
109
+ xi := start + i
110
+ switch {
111
+ case uint(xi) < uint(maxX):
112
+ xi *= 4
113
+ case xi >= maxX:
114
+ xi = 4 * maxX
115
+ default:
116
+ xi = 0
117
+ }
118
+
119
+ rgba[0] += int32(coeff) * int32(row[xi+0])
120
+ rgba[1] += int32(coeff) * int32(row[xi+1])
121
+ rgba[2] += int32(coeff) * int32(row[xi+2])
122
+ rgba[3] += int32(coeff) * int32(row[xi+3])
123
+ sum += int32(coeff)
124
+ }
125
+ }
126
+
127
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
128
+
129
+ out.Pix[xo+0] = clampUint8(rgba[0] / sum)
130
+ out.Pix[xo+1] = clampUint8(rgba[1] / sum)
131
+ out.Pix[xo+2] = clampUint8(rgba[2] / sum)
132
+ out.Pix[xo+3] = clampUint8(rgba[3] / sum)
133
+ }
134
+ }
135
+ }
136
+
137
+ func resizeNRGBA(in *image.NRGBA, out *image.RGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
138
+ newBounds := out.Bounds()
139
+ maxX := in.Bounds().Dx() - 1
140
+
141
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
142
+ row := in.Pix[x*in.Stride:]
143
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
144
+ var rgba [4]int32
145
+ var sum int32
146
+ start := offset[y]
147
+ ci := y * filterLength
148
+ for i := 0; i < filterLength; i++ {
149
+ coeff := coeffs[ci+i]
150
+ if coeff != 0 {
151
+ xi := start + i
152
+ switch {
153
+ case uint(xi) < uint(maxX):
154
+ xi *= 4
155
+ case xi >= maxX:
156
+ xi = 4 * maxX
157
+ default:
158
+ xi = 0
159
+ }
160
+
161
+ // Forward alpha-premultiplication
162
+ a := int32(row[xi+3])
163
+ r := int32(row[xi+0]) * a
164
+ r /= 0xff
165
+ g := int32(row[xi+1]) * a
166
+ g /= 0xff
167
+ b := int32(row[xi+2]) * a
168
+ b /= 0xff
169
+
170
+ rgba[0] += int32(coeff) * r
171
+ rgba[1] += int32(coeff) * g
172
+ rgba[2] += int32(coeff) * b
173
+ rgba[3] += int32(coeff) * a
174
+ sum += int32(coeff)
175
+ }
176
+ }
177
+
178
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
179
+
180
+ out.Pix[xo+0] = clampUint8(rgba[0] / sum)
181
+ out.Pix[xo+1] = clampUint8(rgba[1] / sum)
182
+ out.Pix[xo+2] = clampUint8(rgba[2] / sum)
183
+ out.Pix[xo+3] = clampUint8(rgba[3] / sum)
184
+ }
185
+ }
186
+ }
187
+
188
+ func resizeRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
189
+ newBounds := out.Bounds()
190
+ maxX := in.Bounds().Dx() - 1
191
+
192
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
193
+ row := in.Pix[x*in.Stride:]
194
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
195
+ var rgba [4]int64
196
+ var sum int64
197
+ start := offset[y]
198
+ ci := y * filterLength
199
+ for i := 0; i < filterLength; i++ {
200
+ coeff := coeffs[ci+i]
201
+ if coeff != 0 {
202
+ xi := start + i
203
+ switch {
204
+ case uint(xi) < uint(maxX):
205
+ xi *= 8
206
+ case xi >= maxX:
207
+ xi = 8 * maxX
208
+ default:
209
+ xi = 0
210
+ }
211
+
212
+ rgba[0] += int64(coeff) * (int64(row[xi+0])<<8 | int64(row[xi+1]))
213
+ rgba[1] += int64(coeff) * (int64(row[xi+2])<<8 | int64(row[xi+3]))
214
+ rgba[2] += int64(coeff) * (int64(row[xi+4])<<8 | int64(row[xi+5]))
215
+ rgba[3] += int64(coeff) * (int64(row[xi+6])<<8 | int64(row[xi+7]))
216
+ sum += int64(coeff)
217
+ }
218
+ }
219
+
220
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
221
+
222
+ value := clampUint16(rgba[0] / sum)
223
+ out.Pix[xo+0] = uint8(value >> 8)
224
+ out.Pix[xo+1] = uint8(value)
225
+ value = clampUint16(rgba[1] / sum)
226
+ out.Pix[xo+2] = uint8(value >> 8)
227
+ out.Pix[xo+3] = uint8(value)
228
+ value = clampUint16(rgba[2] / sum)
229
+ out.Pix[xo+4] = uint8(value >> 8)
230
+ out.Pix[xo+5] = uint8(value)
231
+ value = clampUint16(rgba[3] / sum)
232
+ out.Pix[xo+6] = uint8(value >> 8)
233
+ out.Pix[xo+7] = uint8(value)
234
+ }
235
+ }
236
+ }
237
+
238
+ func resizeNRGBA64(in *image.NRGBA64, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
239
+ newBounds := out.Bounds()
240
+ maxX := in.Bounds().Dx() - 1
241
+
242
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
243
+ row := in.Pix[x*in.Stride:]
244
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
245
+ var rgba [4]int64
246
+ var sum int64
247
+ start := offset[y]
248
+ ci := y * filterLength
249
+ for i := 0; i < filterLength; i++ {
250
+ coeff := coeffs[ci+i]
251
+ if coeff != 0 {
252
+ xi := start + i
253
+ switch {
254
+ case uint(xi) < uint(maxX):
255
+ xi *= 8
256
+ case xi >= maxX:
257
+ xi = 8 * maxX
258
+ default:
259
+ xi = 0
260
+ }
261
+
262
+ // Forward alpha-premultiplication
263
+ a := int64(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
264
+ r := int64(uint16(row[xi+0])<<8|uint16(row[xi+1])) * a
265
+ r /= 0xffff
266
+ g := int64(uint16(row[xi+2])<<8|uint16(row[xi+3])) * a
267
+ g /= 0xffff
268
+ b := int64(uint16(row[xi+4])<<8|uint16(row[xi+5])) * a
269
+ b /= 0xffff
270
+
271
+ rgba[0] += int64(coeff) * r
272
+ rgba[1] += int64(coeff) * g
273
+ rgba[2] += int64(coeff) * b
274
+ rgba[3] += int64(coeff) * a
275
+ sum += int64(coeff)
276
+ }
277
+ }
278
+
279
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
280
+
281
+ value := clampUint16(rgba[0] / sum)
282
+ out.Pix[xo+0] = uint8(value >> 8)
283
+ out.Pix[xo+1] = uint8(value)
284
+ value = clampUint16(rgba[1] / sum)
285
+ out.Pix[xo+2] = uint8(value >> 8)
286
+ out.Pix[xo+3] = uint8(value)
287
+ value = clampUint16(rgba[2] / sum)
288
+ out.Pix[xo+4] = uint8(value >> 8)
289
+ out.Pix[xo+5] = uint8(value)
290
+ value = clampUint16(rgba[3] / sum)
291
+ out.Pix[xo+6] = uint8(value >> 8)
292
+ out.Pix[xo+7] = uint8(value)
293
+ }
294
+ }
295
+ }
296
+
297
+ func resizeGray(in *image.Gray, out *image.Gray, scale float64, coeffs []int16, offset []int, filterLength int) {
298
+ newBounds := out.Bounds()
299
+ maxX := in.Bounds().Dx() - 1
300
+
301
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
302
+ row := in.Pix[(x-newBounds.Min.X)*in.Stride:]
303
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
304
+ var gray int32
305
+ var sum int32
306
+ start := offset[y]
307
+ ci := y * filterLength
308
+ for i := 0; i < filterLength; i++ {
309
+ coeff := coeffs[ci+i]
310
+ if coeff != 0 {
311
+ xi := start + i
312
+ switch {
313
+ case xi < 0:
314
+ xi = 0
315
+ case xi >= maxX:
316
+ xi = maxX
317
+ }
318
+ gray += int32(coeff) * int32(row[xi])
319
+ sum += int32(coeff)
320
+ }
321
+ }
322
+
323
+ offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
324
+ out.Pix[offset] = clampUint8(gray / sum)
325
+ }
326
+ }
327
+ }
328
+
329
+ func resizeGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []int32, offset []int, filterLength int) {
330
+ newBounds := out.Bounds()
331
+ maxX := in.Bounds().Dx() - 1
332
+
333
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
334
+ row := in.Pix[x*in.Stride:]
335
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
336
+ var gray int64
337
+ var sum int64
338
+ start := offset[y]
339
+ ci := y * filterLength
340
+ for i := 0; i < filterLength; i++ {
341
+ coeff := coeffs[ci+i]
342
+ if coeff != 0 {
343
+ xi := start + i
344
+ switch {
345
+ case uint(xi) < uint(maxX):
346
+ xi *= 2
347
+ case xi >= maxX:
348
+ xi = 2 * maxX
349
+ default:
350
+ xi = 0
351
+ }
352
+ gray += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
353
+ sum += int64(coeff)
354
+ }
355
+ }
356
+
357
+ offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
358
+ value := clampUint16(gray / sum)
359
+ out.Pix[offset+0] = uint8(value >> 8)
360
+ out.Pix[offset+1] = uint8(value)
361
+ }
362
+ }
363
+ }
364
+
365
+ func resizeYCbCr(in *ycc, out *ycc, scale float64, coeffs []int16, offset []int, filterLength int) {
366
+ newBounds := out.Bounds()
367
+ maxX := in.Bounds().Dx() - 1
368
+
369
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
370
+ row := in.Pix[x*in.Stride:]
371
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
372
+ var p [3]int32
373
+ var sum int32
374
+ start := offset[y]
375
+ ci := y * filterLength
376
+ for i := 0; i < filterLength; i++ {
377
+ coeff := coeffs[ci+i]
378
+ if coeff != 0 {
379
+ xi := start + i
380
+ switch {
381
+ case uint(xi) < uint(maxX):
382
+ xi *= 3
383
+ case xi >= maxX:
384
+ xi = 3 * maxX
385
+ default:
386
+ xi = 0
387
+ }
388
+ p[0] += int32(coeff) * int32(row[xi+0])
389
+ p[1] += int32(coeff) * int32(row[xi+1])
390
+ p[2] += int32(coeff) * int32(row[xi+2])
391
+ sum += int32(coeff)
392
+ }
393
+ }
394
+
395
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
396
+ out.Pix[xo+0] = clampUint8(p[0] / sum)
397
+ out.Pix[xo+1] = clampUint8(p[1] / sum)
398
+ out.Pix[xo+2] = clampUint8(p[2] / sum)
399
+ }
400
+ }
401
+ }
402
+
403
+ func nearestYCbCr(in *ycc, out *ycc, scale float64, coeffs []bool, offset []int, filterLength int) {
404
+ newBounds := out.Bounds()
405
+ maxX := in.Bounds().Dx() - 1
406
+
407
+ for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
408
+ row := in.Pix[x*in.Stride:]
409
+ for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
410
+ var p [3]float32
411
+ var sum float32
412
+ start := offset[y]
413
+ ci := y * filterLength
414
+ for i := 0; i < filterLength; i++ {
415
+ if coeffs[ci+i] {
416
+ xi := start + i
417
+ switch {
418
+ case uint(xi) < uint(maxX):
419
+ xi *= 3
420
+ case xi >= maxX:
421
+ xi = 3 * maxX
422
+ default:
423
+ xi = 0
424
+ }
425
+ p[0] += float32(row[xi+0])
426
+ p[1] += float32(row[xi+1])
427
+ p[2] += float32(row[xi+2])
428
+ sum++
429
+ }
430
+ }
431
+
432
+ xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
433
+ out.Pix[xo+0] = floatToUint8(p[0] / sum)
434
+ out.Pix[xo+1] = floatToUint8(p[1] / sum)
435
+ out.Pix[xo+2] = floatToUint8(p[2] / sum)
436
+ }
437
+ }
438
+ }