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,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
+ }