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,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
+ }
@@ -0,0 +1,4 @@
1
+ require 'ires/engine'
2
+ require 'ires/service'
3
+ require 'ires/view_helper'
4
+ require 'ires/util'
@@ -0,0 +1,7 @@
1
+ module Ires
2
+ class Engine < ::Rails::Engine
3
+ ActiveSupport.on_load :action_view do
4
+ ActionView::Base.send(:include, Ires::ViewHelper)
5
+ end
6
+ end
7
+ end
@@ -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
@@ -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