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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 66797c484af9e7c031cc342f26b4665b7f76313f
|
4
|
+
data.tar.gz: fc97bea1182999376c00f08fdfb087995dcd84cd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1188b7281b891486501c101d71843a7d89ac1be0e006413cdf98459693fd2a3735ac388b8d529e6459d43d298a906d18ea27c6844a8a68df27a181b0f0c17ee
|
7
|
+
data.tar.gz: 83e1fa789edf1182ccb60976889a510148c8889f51aed4561b953a7b340e583c2af67d249e10e4649a0cf822f56f3136aabae4010b0e8d2aa8e9e412b741e468
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 enta0701
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# Ires
|
2
|
+
`Ires` is image resizer gem.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
|
6
|
+
```erb
|
7
|
+
<!-- Usually -->
|
8
|
+
<%= ires_tag( path: "image_01.jpg", width: 90, height: 120 ) %>
|
9
|
+
|
10
|
+
<!-- Using image_tag options -->
|
11
|
+
<%= ires_tag( path: "http://example.com/image_02.jpg", width: 200, height: 200, mode: "crop", alt: "example image" ) %>
|
12
|
+
```
|
13
|
+
|
14
|
+
### Select mode
|
15
|
+
|
16
|
+
| info | mode |
|
17
|
+
|:---------------------------|:--------------------:|
|
18
|
+
| Resize | resize (default) |
|
19
|
+
| Cropping | crop |
|
20
|
+
| Rsize after Cropping | rsize_to_crop |
|
21
|
+
|
22
|
+
### Saved directory
|
23
|
+
|
24
|
+
```
|
25
|
+
.
|
26
|
+
└── public
|
27
|
+
└── ires
|
28
|
+
├── crop
|
29
|
+
│ └── 300x220
|
30
|
+
│ └── image_300x220.jpg
|
31
|
+
├── original
|
32
|
+
│ └── original
|
33
|
+
│ └── image.jpg
|
34
|
+
├── resize
|
35
|
+
│ ├── 200x150
|
36
|
+
│ │ └── image_200x150.jpg
|
37
|
+
│ ├── 300x220
|
38
|
+
│ │ └── image_300x220.jpg
|
39
|
+
│ ├── 300x400
|
40
|
+
│ │ └── image_300x400.jpg
|
41
|
+
│ ├── 400x300
|
42
|
+
│ │ └── image_400x300.jpg
|
43
|
+
│ └── 90x120
|
44
|
+
│ └── image_90x120.jpg
|
45
|
+
└── resize_to_crop
|
46
|
+
└── 300x220
|
47
|
+
└── image_300x220.jpg
|
48
|
+
```
|
49
|
+
|
50
|
+
`original` directory where downloaded images are saved.
|
51
|
+
|
52
|
+
## Installation
|
53
|
+
Add this line to your application's Gemfile:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
gem 'ires'
|
57
|
+
```
|
58
|
+
|
59
|
+
And then execute:
|
60
|
+
```bash
|
61
|
+
$ bundle
|
62
|
+
```
|
63
|
+
|
64
|
+
Or install it yourself as:
|
65
|
+
```bash
|
66
|
+
$ gem install ires
|
67
|
+
```
|
68
|
+
|
69
|
+
## Caution
|
70
|
+
|
71
|
+
- It works only with `linux` and `darwin` now.
|
72
|
+
- Can build only linux(.so)in this docker.
|
73
|
+
|
74
|
+
|
75
|
+
## Development
|
76
|
+
|
77
|
+
環境はDockerで準備しています
|
78
|
+
|
79
|
+
```shell
|
80
|
+
$ docker build -t ires:v1 .
|
81
|
+
|
82
|
+
# コンテナに入る
|
83
|
+
$ docker run -it -v $(pwd):/go/src/github.com/endotakuya/ires -p 3000:3000 ires:v1 /bin/bash
|
84
|
+
```
|
85
|
+
|
86
|
+
## Gemテスト
|
87
|
+
|
88
|
+
以下、コンテナ内の作業になります
|
89
|
+
|
90
|
+
### 1. Go(shared objectの作成)
|
91
|
+
|
92
|
+
パッケージ管理は[dep](https://github.com/golang/dep)を使っています
|
93
|
+
|
94
|
+
```shell
|
95
|
+
# パッケージの依存関係を解決
|
96
|
+
$ dep ensure
|
97
|
+
|
98
|
+
# shared object として出力する
|
99
|
+
$ CGO_ENABLED=1 GOOS=linux go build -v -buildmode=c-shared -o shared/linux/ires.so ext/main.go
|
100
|
+
```
|
101
|
+
※ 現状のDockerでは、linux環境のみbuildができます
|
102
|
+
※ 他の環境でbuildしたい場合はGCCを追加するか、ホスト側でGoを導入してbuildしてください🙇
|
103
|
+
|
104
|
+
### 2. Railsアプリの起動
|
105
|
+
|
106
|
+
```shell
|
107
|
+
$ test/dummy/bin/rails s -b 0.0.0.0
|
108
|
+
```
|
109
|
+
|
110
|
+
## License
|
111
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Ires'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
Dir.glob('lib/tasks/*.rake').each {|r| import r}
|
18
|
+
require 'bundler/gem_tasks'
|
19
|
+
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
|
23
|
+
Rake::TestTask.new(:test) do |t|
|
24
|
+
t.libs << 'test'
|
25
|
+
t.pattern = 'test/**/*_test.rb'
|
26
|
+
t.verbose = false
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
task default: :test
|
data/ext/Gopkg.lock
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
2
|
+
|
3
|
+
|
4
|
+
[[projects]]
|
5
|
+
branch = "master"
|
6
|
+
name = "github.com/nfnt/resize"
|
7
|
+
packages = ["."]
|
8
|
+
revision = "891127d8d1b52734debe1b3c3d7e747502b6c366"
|
9
|
+
|
10
|
+
[[projects]]
|
11
|
+
name = "github.com/oliamb/cutter"
|
12
|
+
packages = ["."]
|
13
|
+
revision = "5cd9c24de6524b7251ac6b8600b0ba8f43a85963"
|
14
|
+
version = "v0.2.0"
|
15
|
+
|
16
|
+
[solve-meta]
|
17
|
+
analyzer-name = "dep"
|
18
|
+
analyzer-version = 1
|
19
|
+
inputs-digest = "555c9d2045607d7c797b9ed9663b0c2916aa91b14b6001e4119e9be49a742484"
|
20
|
+
solver-name = "gps-cdcl"
|
21
|
+
solver-version = 1
|
data/ext/Gopkg.toml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
# Gopkg.toml example
|
3
|
+
#
|
4
|
+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
5
|
+
# for detailed Gopkg.toml documentation.
|
6
|
+
#
|
7
|
+
# required = ["github.com/user/thing/cmd/thing"]
|
8
|
+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
9
|
+
#
|
10
|
+
# [[constraint]]
|
11
|
+
# name = "github.com/user/project"
|
12
|
+
# version = "1.0.0"
|
13
|
+
#
|
14
|
+
# [[constraint]]
|
15
|
+
# name = "github.com/user/project2"
|
16
|
+
# branch = "dev"
|
17
|
+
# source = "github.com/myfork/project2"
|
18
|
+
#
|
19
|
+
# [[override]]
|
20
|
+
# name = "github.com/x/y"
|
21
|
+
# version = "2.4.0"
|
22
|
+
|
23
|
+
|
24
|
+
[[constraint]]
|
25
|
+
branch = "master"
|
26
|
+
name = "github.com/nfnt/resize"
|
27
|
+
|
28
|
+
[[constraint]]
|
29
|
+
name = "github.com/oliamb/cutter"
|
30
|
+
version = "0.2.0"
|
data/ext/main.go
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"C"
|
5
|
+
"strings"
|
6
|
+
|
7
|
+
"github.com/nfnt/resize"
|
8
|
+
"github.com/oliamb/cutter"
|
9
|
+
"github.com/endotakuya/ires/ext/util/uri"
|
10
|
+
"github.com/endotakuya/ires/ext/operate"
|
11
|
+
)
|
12
|
+
|
13
|
+
const (
|
14
|
+
IMAGE_MODE_RESIZE int = iota
|
15
|
+
IMAGE_MODE_CROP
|
16
|
+
IMAGE_MODE_RESIZE_TO_CROP
|
17
|
+
)
|
18
|
+
|
19
|
+
func init() {}
|
20
|
+
func main() {}
|
21
|
+
|
22
|
+
//export resizeImage
|
23
|
+
func resizeImage(Uri *C.char, width, height int, Dir *C.char) *C.char {
|
24
|
+
dir := C.GoString(Dir)
|
25
|
+
uri := C.GoString(Uri)
|
26
|
+
|
27
|
+
size := []int{width, height}
|
28
|
+
path := util.NewImagePath(uri, dir, IMAGE_MODE_RESIZE, size...)
|
29
|
+
|
30
|
+
// When the image exists, return the image path
|
31
|
+
if !util.IsEmptyImage(path) {
|
32
|
+
return C.CString(strings.Replace(path, dir, "", -1))
|
33
|
+
}
|
34
|
+
|
35
|
+
inputImg, _ := operate.InputImage(uri, dir)
|
36
|
+
outputImg := resize.Resize(uint(width), uint(height), inputImg, resize.Lanczos3)
|
37
|
+
|
38
|
+
_, filePath := operate.CreateImage(outputImg, path)
|
39
|
+
|
40
|
+
fileName := strings.Replace(filePath, dir, "", -1)
|
41
|
+
return C.CString(fileName)
|
42
|
+
}
|
43
|
+
|
44
|
+
//export cropImage
|
45
|
+
func cropImage(Uri *C.char, width, height int, Dir *C.char) *C.char {
|
46
|
+
dir := C.GoString(Dir)
|
47
|
+
uri := C.GoString(Uri)
|
48
|
+
|
49
|
+
size := []int{width, height}
|
50
|
+
path := util.NewImagePath(uri, dir, IMAGE_MODE_CROP, size...)
|
51
|
+
|
52
|
+
// When the image exists, return the image path
|
53
|
+
if !util.IsEmptyImage(path) {
|
54
|
+
return C.CString(strings.Replace(path, dir, "", -1))
|
55
|
+
}
|
56
|
+
|
57
|
+
inputImg, _ := operate.InputImage(uri, dir)
|
58
|
+
outputImg, _ := cutter.Crop(inputImg, cutter.Config{
|
59
|
+
Width: width,
|
60
|
+
Height: height,
|
61
|
+
Mode: cutter.Centered,
|
62
|
+
Options: cutter.Copy,
|
63
|
+
})
|
64
|
+
|
65
|
+
_, filePath := operate.CreateImage(outputImg, path)
|
66
|
+
|
67
|
+
fileName := strings.Replace(filePath, dir, "", -1)
|
68
|
+
return C.CString(fileName)
|
69
|
+
}
|
70
|
+
|
71
|
+
//export resizeToCropImage
|
72
|
+
func resizeToCropImage(Uri *C.char, width, height int, Dir *C.char) *C.char {
|
73
|
+
dir := C.GoString(Dir)
|
74
|
+
uri := C.GoString(Uri)
|
75
|
+
|
76
|
+
size := []int{width, height}
|
77
|
+
path := util.NewImagePath(uri, dir, IMAGE_MODE_RESIZE_TO_CROP, size...)
|
78
|
+
|
79
|
+
// When the image exists, return the image path
|
80
|
+
if !util.IsEmptyImage(path) {
|
81
|
+
return C.CString(strings.Replace(path, dir, "", -1))
|
82
|
+
}
|
83
|
+
|
84
|
+
inputImg, imgPath := operate.InputImage(uri, dir)
|
85
|
+
outputImg := operate.ResizeToCrop(imgPath, size, inputImg)
|
86
|
+
_, filePath := operate.CreateImage(outputImg, path)
|
87
|
+
|
88
|
+
fileName := strings.Replace(filePath, dir, "", -1)
|
89
|
+
return C.CString(fileName)
|
90
|
+
}
|
@@ -0,0 +1,139 @@
|
|
1
|
+
package operate
|
2
|
+
|
3
|
+
import (
|
4
|
+
"image"
|
5
|
+
"image/jpeg"
|
6
|
+
"net/http"
|
7
|
+
"os"
|
8
|
+
|
9
|
+
"github.com/endotakuya/ires/ext/util/uri"
|
10
|
+
"github.com/nfnt/resize"
|
11
|
+
"github.com/oliamb/cutter"
|
12
|
+
)
|
13
|
+
|
14
|
+
// 入力画像
|
15
|
+
func InputImage(uri, dir string) (image.Image, string) {
|
16
|
+
if util.IsLocalFile(uri) {
|
17
|
+
return LocalImage(uri), uri
|
18
|
+
} else {
|
19
|
+
img, path := DownloadImage(uri, util.NewImagePath(uri, dir, 3))
|
20
|
+
return img, path
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
// http経由での画像を保存
|
25
|
+
func DownloadImage(uri, path string) (image.Image, string) {
|
26
|
+
res, err := http.Get(uri)
|
27
|
+
if err != nil {
|
28
|
+
panic(err)
|
29
|
+
}
|
30
|
+
defer res.Body.Close()
|
31
|
+
|
32
|
+
img, _, err := image.Decode(res.Body)
|
33
|
+
if err != nil {
|
34
|
+
panic(err)
|
35
|
+
}
|
36
|
+
return CreateImage(img, path)
|
37
|
+
}
|
38
|
+
|
39
|
+
// 画像を作成
|
40
|
+
func CreateImage(img image.Image, path string) (image.Image, string) {
|
41
|
+
file, err := os.Create(path)
|
42
|
+
if err != nil {
|
43
|
+
panic(err)
|
44
|
+
}
|
45
|
+
defer file.Close()
|
46
|
+
|
47
|
+
jpeg.Encode(file, img, nil)
|
48
|
+
|
49
|
+
return LocalImage(path), path
|
50
|
+
}
|
51
|
+
|
52
|
+
// ローカルの画像を取得
|
53
|
+
func LocalImage(uri string) image.Image {
|
54
|
+
file, err := os.Open(uri)
|
55
|
+
if err != nil{
|
56
|
+
panic(err)
|
57
|
+
}
|
58
|
+
defer file.Close()
|
59
|
+
|
60
|
+
// Decode jpeg into image.Image
|
61
|
+
img, err := jpeg.Decode(file)
|
62
|
+
if err != nil {
|
63
|
+
panic(err)
|
64
|
+
}
|
65
|
+
return img
|
66
|
+
}
|
67
|
+
|
68
|
+
// リサイズ + 切り取り
|
69
|
+
func ResizeToCrop(path string, size []int, inputImg image.Image) image.Image {
|
70
|
+
var outputImg image.Image
|
71
|
+
isAsp, conf := isValidAspectRatio(path, size)
|
72
|
+
|
73
|
+
if isAsp {
|
74
|
+
outputImg = resize.Resize(uint(size[0]), uint(size[1]), inputImg, resize.Lanczos3)
|
75
|
+
} else {
|
76
|
+
var resizeImg image.Image
|
77
|
+
|
78
|
+
// Resize
|
79
|
+
mode := resizeMode(conf, size)
|
80
|
+
switch mode {
|
81
|
+
case 1, 3:
|
82
|
+
resizeImg = resize.Resize(uint(size[0]), 0, inputImg, resize.Lanczos3)
|
83
|
+
case 2, 4:
|
84
|
+
resizeImg = resize.Resize(0, uint(size[1]), inputImg, resize.Lanczos3)
|
85
|
+
default:
|
86
|
+
resizeImg = inputImg
|
87
|
+
}
|
88
|
+
|
89
|
+
// Cropping
|
90
|
+
outputImg, _ = cutter.Crop(resizeImg, cutter.Config{
|
91
|
+
Width: size[0],
|
92
|
+
Height: size[1],
|
93
|
+
Mode: cutter.Centered,
|
94
|
+
Options: cutter.Copy,
|
95
|
+
})
|
96
|
+
|
97
|
+
}
|
98
|
+
return outputImg
|
99
|
+
}
|
100
|
+
|
101
|
+
// 変更するサイズと画像のアスペクト比が一致するかどうか
|
102
|
+
func isValidAspectRatio(path string, size []int) (bool, image.Config) {
|
103
|
+
conf := imageConfig(path)
|
104
|
+
aspH := (conf.Height * size[0]) / conf.Width
|
105
|
+
if aspH == size[1] {
|
106
|
+
return true, conf
|
107
|
+
} else {
|
108
|
+
return false, conf
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
// 入力画像の情報を取得
|
113
|
+
func imageConfig(path string) image.Config {
|
114
|
+
file, err := os.Open(path)
|
115
|
+
if err != nil {
|
116
|
+
panic(err)
|
117
|
+
}
|
118
|
+
defer file.Close()
|
119
|
+
|
120
|
+
conf, _, err := image.DecodeConfig(file)
|
121
|
+
if err != nil {
|
122
|
+
panic(err)
|
123
|
+
}
|
124
|
+
return conf
|
125
|
+
}
|
126
|
+
|
127
|
+
// アスペクト比の異なる画像に対するモード設定
|
128
|
+
func resizeMode(conf image.Config, size []int) int {
|
129
|
+
if conf.Width >= conf.Height && size[0] >= size[1] {
|
130
|
+
return 1
|
131
|
+
} else if conf.Width >= conf.Height && size[0] < size[1] {
|
132
|
+
return 2
|
133
|
+
} else if conf.Width < conf.Height && size[0] >= size[1] {
|
134
|
+
return 3
|
135
|
+
} else if conf.Width < conf.Height && size[0] < size[1] {
|
136
|
+
return 4
|
137
|
+
}
|
138
|
+
return 0
|
139
|
+
}
|