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
@@ -0,0 +1,68 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"errors"
|
5
|
+
"flag"
|
6
|
+
"fmt"
|
7
|
+
"github.com/oliamb/cutter"
|
8
|
+
"image"
|
9
|
+
"image/jpeg"
|
10
|
+
"image/png"
|
11
|
+
"log"
|
12
|
+
"os"
|
13
|
+
"path/filepath"
|
14
|
+
)
|
15
|
+
|
16
|
+
func main() {
|
17
|
+
s := len(os.Args)
|
18
|
+
if s < 4 {
|
19
|
+
usage()
|
20
|
+
return
|
21
|
+
}
|
22
|
+
fmt.Println("Args", os.Args)
|
23
|
+
|
24
|
+
inPath := os.Args[s-2]
|
25
|
+
fi, err := os.Open(inPath)
|
26
|
+
if err != nil {
|
27
|
+
log.Fatal("Cannot open input file '", inPath, "':", err)
|
28
|
+
}
|
29
|
+
|
30
|
+
outPath := os.Args[s-1]
|
31
|
+
fo, err := os.Create(outPath)
|
32
|
+
if err != nil {
|
33
|
+
log.Fatal("Cannot create output file '", outPath, "':", err)
|
34
|
+
}
|
35
|
+
|
36
|
+
img, _, err := image.Decode(fi)
|
37
|
+
if err != nil {
|
38
|
+
log.Fatal("Cannot decode image at '", inPath, "':", err)
|
39
|
+
}
|
40
|
+
|
41
|
+
cImg, err := cutter.Crop(img, cutter.Config{
|
42
|
+
Height: 1000, // height in pixel or Y ratio(see Ratio Option below)
|
43
|
+
Width: 1000, // width in pixel or X ratio
|
44
|
+
Mode: cutter.TopLeft, // Accepted Mode: TopLeft, Centered
|
45
|
+
Anchor: image.Point{100, 100}, // Position of the top left point
|
46
|
+
Options: 0, // Accepted Option: Ratio
|
47
|
+
})
|
48
|
+
if err != nil {
|
49
|
+
log.Fatal("Cannot crop image:", err)
|
50
|
+
}
|
51
|
+
|
52
|
+
switch filepath.Ext(outPath) {
|
53
|
+
case ".png":
|
54
|
+
err = png.Encode(fo, cImg)
|
55
|
+
case ".jpg":
|
56
|
+
err = jpeg.Encode(fo, cImg, &jpeg.Options{})
|
57
|
+
default:
|
58
|
+
err = errors.New("Unsupported format: " + filepath.Ext(outPath))
|
59
|
+
}
|
60
|
+
if err != nil {
|
61
|
+
log.Fatal(err)
|
62
|
+
}
|
63
|
+
fmt.Println("Image saved to", outPath)
|
64
|
+
}
|
65
|
+
|
66
|
+
func usage() {
|
67
|
+
flag.Usage()
|
68
|
+
}
|
@@ -0,0 +1,267 @@
|
|
1
|
+
package cutter
|
2
|
+
|
3
|
+
import (
|
4
|
+
"image"
|
5
|
+
"os"
|
6
|
+
"testing"
|
7
|
+
)
|
8
|
+
|
9
|
+
func TestCrop(t *testing.T) {
|
10
|
+
img := getImage()
|
11
|
+
|
12
|
+
c := Config{
|
13
|
+
Width: 512,
|
14
|
+
Height: 400,
|
15
|
+
}
|
16
|
+
r, err := Crop(img, c)
|
17
|
+
if err != nil {
|
18
|
+
t.Fatal(err)
|
19
|
+
}
|
20
|
+
if r.Bounds().Dx() != 512 {
|
21
|
+
t.Error("Bad width should be 512 but is", r.Bounds().Dx())
|
22
|
+
}
|
23
|
+
if r.Bounds().Dy() != 400 {
|
24
|
+
t.Error("Bad width should be 400 but is", r.Bounds().Dy())
|
25
|
+
}
|
26
|
+
if r.Bounds().Min.X != 0 {
|
27
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
28
|
+
}
|
29
|
+
if r.Bounds().Min.Y != 0 {
|
30
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
func TestCrop_Centered(t *testing.T) {
|
35
|
+
img := getImage()
|
36
|
+
|
37
|
+
c := Config{
|
38
|
+
Width: 512,
|
39
|
+
Height: 400,
|
40
|
+
Mode: Centered,
|
41
|
+
}
|
42
|
+
r, err := Crop(img, c)
|
43
|
+
if err != nil {
|
44
|
+
t.Fatal(err)
|
45
|
+
}
|
46
|
+
if r.Bounds().Dx() != 512 {
|
47
|
+
t.Error("Bad width should be 512 but is", r.Bounds().Dx())
|
48
|
+
}
|
49
|
+
if r.Bounds().Dy() != 400 {
|
50
|
+
t.Error("Bad width should be 512 but is", r.Bounds().Dy())
|
51
|
+
}
|
52
|
+
if r.Bounds().Min.X != 544 {
|
53
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
54
|
+
}
|
55
|
+
if r.Bounds().Min.Y != 518 {
|
56
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
func TestCrop_Centered_Ratio_WithoutAnchorPosition(t *testing.T) {
|
61
|
+
// (0,0)-(64,64) 32 64 (32,32)-(32,32)
|
62
|
+
img := image.NewGray(image.Rect(0, 0, 64, 64))
|
63
|
+
c := Config{
|
64
|
+
Width: 32,
|
65
|
+
Height: 64,
|
66
|
+
Mode: Centered,
|
67
|
+
Options: Ratio,
|
68
|
+
}
|
69
|
+
r, err := Crop(img, c)
|
70
|
+
if err != nil {
|
71
|
+
t.Fatal(err)
|
72
|
+
}
|
73
|
+
if r.Bounds().Dx() != 32 {
|
74
|
+
t.Error("Bad Width", r.Bounds().Dx())
|
75
|
+
}
|
76
|
+
if r.Bounds().Dy() != 64 {
|
77
|
+
t.Error("Bad Height", r.Bounds().Dy())
|
78
|
+
}
|
79
|
+
if r.Bounds().Min.X != 16 {
|
80
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
81
|
+
}
|
82
|
+
if r.Bounds().Min.Y != 0 {
|
83
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
func TestCutter_Crop_TooBigArea(t *testing.T) {
|
88
|
+
img := getImage()
|
89
|
+
|
90
|
+
c := Config{
|
91
|
+
Width: 2000,
|
92
|
+
Height: 2000,
|
93
|
+
Anchor: image.Point{100, 100},
|
94
|
+
}
|
95
|
+
r, err := Crop(img, c)
|
96
|
+
if err != nil {
|
97
|
+
t.Fatal(err)
|
98
|
+
}
|
99
|
+
if r.Bounds().Dx() != 1500 {
|
100
|
+
t.Error("Bad width should be 1500 but is", r.Bounds().Dx())
|
101
|
+
}
|
102
|
+
if r.Bounds().Dy() != 1337 {
|
103
|
+
t.Error("Bad width should be 1337 but is", r.Bounds().Dy())
|
104
|
+
}
|
105
|
+
if r.Bounds().Min.X != 100 {
|
106
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
107
|
+
}
|
108
|
+
if r.Bounds().Min.Y != 100 {
|
109
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
func TestCrop_TooBigAreaFromCenter(t *testing.T) {
|
114
|
+
img := getImage()
|
115
|
+
|
116
|
+
c := Config{
|
117
|
+
Width: 1000,
|
118
|
+
Height: 2000,
|
119
|
+
Anchor: image.Point{1200, 100},
|
120
|
+
Mode: Centered,
|
121
|
+
}
|
122
|
+
r, err := Crop(img, c)
|
123
|
+
if err != nil {
|
124
|
+
t.Fatal(err)
|
125
|
+
}
|
126
|
+
if r.Bounds().Dx() != 900 {
|
127
|
+
t.Error("Bad width should be 900 but is", r.Bounds().Dx())
|
128
|
+
}
|
129
|
+
if r.Bounds().Dy() != 1100 {
|
130
|
+
t.Error("Bad width should be 1100 but is", r.Bounds().Dy(), r.Bounds())
|
131
|
+
}
|
132
|
+
if r.Bounds().Min.X != 700 {
|
133
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
134
|
+
}
|
135
|
+
if r.Bounds().Min.Y != 0 {
|
136
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
func TestCrop_OptionRatio(t *testing.T) {
|
141
|
+
img := getImage()
|
142
|
+
|
143
|
+
c := Config{
|
144
|
+
Width: 4,
|
145
|
+
Height: 3,
|
146
|
+
Anchor: image.Point{},
|
147
|
+
Mode: TopLeft,
|
148
|
+
Options: Ratio,
|
149
|
+
}
|
150
|
+
|
151
|
+
r, err := Crop(img, c)
|
152
|
+
if err != nil {
|
153
|
+
t.Error(err)
|
154
|
+
}
|
155
|
+
if r.Bounds().Min.X != 0 {
|
156
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
157
|
+
}
|
158
|
+
if r.Bounds().Min.Y != 0 {
|
159
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
160
|
+
}
|
161
|
+
if r.Bounds().Dx() != 1600 {
|
162
|
+
t.Error("Bad Width", r.Bounds().Dx())
|
163
|
+
}
|
164
|
+
if r.Bounds().Dy() != 1200 {
|
165
|
+
t.Error("Bad Height", r.Bounds().Dy(), r.Bounds())
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
func TestCutter_Crop_OptionRatio_Inverted(t *testing.T) {
|
170
|
+
img := getImage()
|
171
|
+
|
172
|
+
c := Config{
|
173
|
+
Width: 3,
|
174
|
+
Height: 4,
|
175
|
+
Anchor: image.Point{},
|
176
|
+
Mode: TopLeft,
|
177
|
+
Options: Ratio,
|
178
|
+
}
|
179
|
+
|
180
|
+
r, err := Crop(img, c)
|
181
|
+
if err != nil {
|
182
|
+
t.Error(err)
|
183
|
+
}
|
184
|
+
if r.Bounds().Min.X != 0 {
|
185
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
186
|
+
}
|
187
|
+
if r.Bounds().Min.Y != 0 {
|
188
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
189
|
+
}
|
190
|
+
if r.Bounds().Dy() != 1437 {
|
191
|
+
t.Error("Bad Height", r.Bounds().Dy(), r.Bounds())
|
192
|
+
}
|
193
|
+
if r.Bounds().Dx() != 1077 {
|
194
|
+
t.Error("Bad Width", r.Bounds().Dx())
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
func TestCutter_Crop_OptionRatio_DecentredAnchor_Overflow(t *testing.T) {
|
199
|
+
img := getImage()
|
200
|
+
c := Config{
|
201
|
+
Width: 3,
|
202
|
+
Height: 4,
|
203
|
+
Anchor: image.Point{100, 80},
|
204
|
+
Mode: Centered,
|
205
|
+
Options: Ratio,
|
206
|
+
}
|
207
|
+
|
208
|
+
r, err := Crop(img, c)
|
209
|
+
if err != nil {
|
210
|
+
t.Error(err)
|
211
|
+
}
|
212
|
+
if r.Bounds().Min.X != 40 {
|
213
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
214
|
+
}
|
215
|
+
if r.Bounds().Min.Y != 0 {
|
216
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
217
|
+
}
|
218
|
+
if r.Bounds().Dy() != 160 {
|
219
|
+
t.Error("Bad Height", r.Bounds().Dy(), r.Bounds())
|
220
|
+
}
|
221
|
+
if r.Bounds().Dx() != 120 {
|
222
|
+
t.Error("Bad Width", r.Bounds().Dx())
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
func TestCropForceCopy(t *testing.T) {
|
227
|
+
img := getImage()
|
228
|
+
|
229
|
+
c := Config{
|
230
|
+
Width: 512,
|
231
|
+
Height: 400,
|
232
|
+
Options: Copy,
|
233
|
+
}
|
234
|
+
r, err := Crop(img, c)
|
235
|
+
if err != nil {
|
236
|
+
t.Fatal(err)
|
237
|
+
}
|
238
|
+
if r.Bounds().Dx() != 512 {
|
239
|
+
t.Error("Bad width should be 512 but is", r.Bounds().Dx())
|
240
|
+
}
|
241
|
+
if r.Bounds().Dy() != 400 {
|
242
|
+
t.Error("Bad width should be 400 but is", r.Bounds().Dy())
|
243
|
+
}
|
244
|
+
if r.Bounds().Min.X != 0 {
|
245
|
+
t.Error("Invalid Bounds Min X", r.Bounds().Min.X)
|
246
|
+
}
|
247
|
+
if r.Bounds().Min.Y != 0 {
|
248
|
+
t.Error("Invalid Bounds Min Y", r.Bounds().Min.Y)
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
func getImage() image.Image {
|
253
|
+
return image.NewGray(image.Rect(0, 0, 1600, 1437))
|
254
|
+
}
|
255
|
+
|
256
|
+
func getGopherImage() image.Image {
|
257
|
+
fi, err := os.Open("fixtures/gopher.jpg")
|
258
|
+
if err != nil {
|
259
|
+
panic(err)
|
260
|
+
}
|
261
|
+
defer fi.Close()
|
262
|
+
img, _, err := image.Decode(fi)
|
263
|
+
if err != nil {
|
264
|
+
panic(err)
|
265
|
+
}
|
266
|
+
return img
|
267
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
package cutter
|
2
|
+
|
3
|
+
import (
|
4
|
+
"fmt"
|
5
|
+
"image"
|
6
|
+
_ "image/jpeg"
|
7
|
+
"log"
|
8
|
+
"os"
|
9
|
+
_ "testing"
|
10
|
+
)
|
11
|
+
|
12
|
+
func ExampleCrop() {
|
13
|
+
f, err := os.Open("fixtures/gopher.jpg")
|
14
|
+
if err != nil {
|
15
|
+
log.Fatal("Cannot open file", err)
|
16
|
+
}
|
17
|
+
img, _, err := image.Decode(f)
|
18
|
+
if err != nil {
|
19
|
+
log.Fatal("Cannot decode image:", err)
|
20
|
+
}
|
21
|
+
|
22
|
+
cImg, err := Crop(img, Config{
|
23
|
+
Height: 500, // height in pixel or Y ratio(see Ratio Option below)
|
24
|
+
Width: 500, // width in pixel or X ratio
|
25
|
+
Mode: TopLeft, // Accepted Mode: TopLeft, Centered
|
26
|
+
Anchor: image.Point{10, 10}, // Position of the top left point
|
27
|
+
Options: 0, // Accepted Option: Ratio
|
28
|
+
})
|
29
|
+
|
30
|
+
if err != nil {
|
31
|
+
log.Fatal("Cannot crop image:", err)
|
32
|
+
}
|
33
|
+
fmt.Println("cImg dimension:", cImg.Bounds())
|
34
|
+
// Output: cImg dimension: (10,10)-(510,510)
|
35
|
+
}
|
Binary file
|
data/lib/ires.rb
ADDED
data/lib/ires/engine.rb
ADDED
data/lib/ires/service.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "ffi"
|
2
|
+
require 'ires/util'
|
3
|
+
|
4
|
+
module Ires
|
5
|
+
module Service
|
6
|
+
extend FFI::Library
|
7
|
+
|
8
|
+
os = Ires::Util.current_os
|
9
|
+
return if os.nil?
|
10
|
+
|
11
|
+
# NOTE: ires.so is golang object
|
12
|
+
ffi_lib File.expand_path("../../shared/#{os}/ires.so", File.dirname(__FILE__))
|
13
|
+
|
14
|
+
# resize func
|
15
|
+
attach_function :resizeImage, [:string, :int, :int, :string], :string
|
16
|
+
attach_function :cropImage, [:string, :int, :int, :string], :string
|
17
|
+
attach_function :resizeToCropImage, [:string, :int, :int, :string], :string
|
18
|
+
end
|
19
|
+
end
|
data/lib/ires/util.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module Ires
|
4
|
+
module Util
|
5
|
+
class << self
|
6
|
+
# Reszie image directory
|
7
|
+
# return [none(ffi)]
|
8
|
+
def current_os
|
9
|
+
if ["darwin", "linux"].include?(os)
|
10
|
+
return os
|
11
|
+
else
|
12
|
+
logger.fatal "Ires is not supported by this #{os}"
|
13
|
+
return nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Search OS
|
18
|
+
# return [String]
|
19
|
+
def os
|
20
|
+
@os ||= (
|
21
|
+
host_os = RbConfig::CONFIG['host_os']
|
22
|
+
case host_os
|
23
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
24
|
+
"windows"
|
25
|
+
when /darwin|mac os/
|
26
|
+
"darwin"
|
27
|
+
when /linux/
|
28
|
+
"linux"
|
29
|
+
when /solaris|bsd/
|
30
|
+
"unix"
|
31
|
+
else
|
32
|
+
"unknown"
|
33
|
+
end
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|