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.
- 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
data/ext/util/uri/uri.go
ADDED
@@ -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
|
+
[](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
|
+

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

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