imagetools 1.4.0 → 1.5.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 +4 -4
- data/Gemfile.lock +1 -1
- data/exe/imageblog +5 -0
- data/lib/imagetools/imageblog.rb +148 -0
- data/lib/imagetools/imageconcat.rb +9 -3
- data/lib/imagetools/imagefilter.rb +40 -25
- data/lib/imagetools/version.rb +1 -1
- data/sample/hugo_dst/1200x400.png +0 -0
- data/sample/hugo_dst/1200x800.png +0 -0
- data/sample/hugo_dst/600x200.png +0 -0
- data/sample/hugo_src/0000.png +0 -0
- data/sample/hugo_src/0001.png +0 -0
- data/sample/hugo_src/0002.png +0 -0
- data/test_imageblog.sh +2 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7303f9715297bac5f4feca1db6973cf36c4ebdc9b501f8282341db2d0c5c5641
|
4
|
+
data.tar.gz: de5711c1b8c876f1dd115e074cf1c0aa23a9ce5a72d93a7ae3e4e0c127c0d0b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb8a0db8ffeb034dfa894dec821b610dd784db057b87173b55711aaf9c78660a4502dd95d3f22ac42bcb549f2aabb41a61566cf21d4b5f4698eabf6abe026623
|
7
|
+
data.tar.gz: 7b5ba2a33f6df6e74764357eee21598c93ccd6364c5bba9a26b162055f8da63516cab8ead119696160ad803cee8c8e851da0d8f52b3ba090a60293cea6f3aba2
|
data/Gemfile.lock
CHANGED
data/exe/imageblog
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# imagehugo: hugo用の画像処理。リネームとサムネイル&アイキャッチ画像の生成。
|
3
|
+
|
4
|
+
require 'imagetools/version'
|
5
|
+
require 'imagetools/imagefilter'
|
6
|
+
require 'rmagick'
|
7
|
+
require 'optparse'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
module Imagetools
|
11
|
+
class ImageItem
|
12
|
+
attr_accessor :srcfile, :dstfile, :outfile
|
13
|
+
def to_s
|
14
|
+
"#{srcfile}=>#{dstfile}=>#{outfile}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Imageblog
|
19
|
+
def self.run(argv)
|
20
|
+
STDOUT.sync = true
|
21
|
+
opts = {}
|
22
|
+
opt = OptionParser.new(argv)
|
23
|
+
opt.version = VERSION
|
24
|
+
opt.banner = "Usage: #{opt.program_name} [-h|--help] <dir> or <image1 image2 image3 ...>"
|
25
|
+
opt.separator('')
|
26
|
+
opt.separator("Examples:")
|
27
|
+
opt.separator(" #{opt.program_name} ~/tmp # concat two recent IMG_*jpg images.")
|
28
|
+
opt.separator(" #{opt.program_name} image1.jpg image2.jpg image3.jpg # concat specified images.")
|
29
|
+
opt.separator('')
|
30
|
+
opt.separator("Options:")
|
31
|
+
opt.on_head('-h', '--help', 'Show this message') do |v|
|
32
|
+
puts opt.help
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
opt.on('-v', '--verbose', 'Verbose message') {|v| opts[:v] = v}
|
36
|
+
opt.on('--dry-run', 'Message only') {|v| opts[:dry_run] = v}
|
37
|
+
opt.on('-o OUTDIR', '--output=OUTDIR', 'Output dir') {|v| opts[:o] = v}
|
38
|
+
opt.on('-n NUM', '--number=NUM', 'Process image number') {|v| opts[:n] = v.to_i}
|
39
|
+
opt.on('-b BASENAME', '--base=BASENAME', 'Output file basename') {|v| opts[:b] = v}
|
40
|
+
opt.parse!(argv)
|
41
|
+
opts[:b] ||= Time.now.strftime("%Y%m%d")
|
42
|
+
dir, image_files = get_image_files(opts, argv)
|
43
|
+
if image_files.size == 0
|
44
|
+
puts opt.help
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
command = Imageblog.new(opts)
|
48
|
+
command.run(dir, image_files)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.get_image_files(opts, argv)
|
52
|
+
image_files = []
|
53
|
+
# ディレクトリが処理対象かどうかを決める
|
54
|
+
dir = nil
|
55
|
+
if argv.size == 1
|
56
|
+
# 引き数が1個の場合は最初の引き数
|
57
|
+
path = File.expand_path(argv[0])
|
58
|
+
if FileTest.directory?(path)
|
59
|
+
dir = path
|
60
|
+
end
|
61
|
+
elsif argv.size == 0
|
62
|
+
# 引き数がない場合カレントディレクトリ
|
63
|
+
dir = File.expand_path('.')
|
64
|
+
end
|
65
|
+
if dir
|
66
|
+
concat_number = opts[:n] || 2
|
67
|
+
# ディレクトリが指定されていた場合、指定ディレクトリ内のIMG_ファイルの最新n個を対象とする
|
68
|
+
# 最新の基準は(ファイル名基準)
|
69
|
+
match_files = Dir.glob("#{dir}/*.{jpg,jpeg,png}", File::FNM_CASEFOLD).sort
|
70
|
+
# match_files.sort {|a, b|
|
71
|
+
# File.mtime(a) <=> File.mtime(b)
|
72
|
+
# }
|
73
|
+
# 後ろからn個を取得(小さい方の数とする)
|
74
|
+
count = [match_files.size, concat_number].min
|
75
|
+
image_files = match_files[-count..-1]
|
76
|
+
else
|
77
|
+
# それ以外は指定された引き数を全て対象とする
|
78
|
+
argv.each do |arg|
|
79
|
+
arg = File.expand_path(arg)
|
80
|
+
dir = File.dirname(arg)
|
81
|
+
if FileTest.file?(arg) && (arg =~ /\.jpe?g$/i || arg =~ /\.png/i)
|
82
|
+
image_files << arg
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return dir, image_files
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize(opts)
|
90
|
+
@opts = opts
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def run(dir, image_files)
|
95
|
+
outdir = dir
|
96
|
+
if @opts[:o]
|
97
|
+
outdir = @opts[:o]
|
98
|
+
end
|
99
|
+
rename_images(image_files, outdir)
|
100
|
+
# concat_images(image_files, output_path)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def rename_images(image_files, outdir)
|
105
|
+
# サムネイルはhoge_0.jpg
|
106
|
+
# アイキャッチはhoge_1.jpg hoge_2.jpg以降が通常の画像
|
107
|
+
items = []
|
108
|
+
thumbnal_item = nil # hoge_0.jpgとする
|
109
|
+
image_files.each_with_index do |image_file, index|
|
110
|
+
item = ImageItem.new
|
111
|
+
item.srcfile = image_file
|
112
|
+
|
113
|
+
src_basename = File.basename(image_file)
|
114
|
+
extname = File.extname(src_basename)
|
115
|
+
dst_basename = @opts[:b]
|
116
|
+
|
117
|
+
item.dstfile = File.join(outdir, "#{dst_basename}_#{index + 1}#{extname}")
|
118
|
+
if index == 0
|
119
|
+
thumbnal_item = ImageItem.new
|
120
|
+
thumbnal_item.srcfile = image_file
|
121
|
+
thumbnal_item.dstfile = File.join(outdir, "#{dst_basename}_0#{extname}")
|
122
|
+
end
|
123
|
+
items << item
|
124
|
+
end
|
125
|
+
items.each do |item|
|
126
|
+
FileUtils.cp(item.srcfile, item.dstfile)
|
127
|
+
end
|
128
|
+
FileUtils.cp(thumbnal_item.srcfile, thumbnal_item.dstfile)
|
129
|
+
|
130
|
+
#フィルタ実行
|
131
|
+
config = Config.new
|
132
|
+
config.init_default
|
133
|
+
opts = {}
|
134
|
+
filter = Imagefilter.new(opts, config)
|
135
|
+
items.each do |item|
|
136
|
+
item.outfile = filter.run(item.dstfile)
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# サムネイル
|
141
|
+
config.resize_width = 400
|
142
|
+
filter = Imagefilter.new(opts, config)
|
143
|
+
thumbnal_item.outfile = filter.run(thumbnal_item.dstfile)
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
@@ -26,7 +26,7 @@ module Imagetools
|
|
26
26
|
opt.on('-v', '--verbose', 'Verbose message') {|v| opts[:v] = v}
|
27
27
|
opt.on('--dry-run', 'Message only') {|v| opts[:dry_run] = v}
|
28
28
|
opt.on('-o OUTNAME', '--output=OUTNAME', 'Output file') {|v| opts[:o] = v}
|
29
|
-
opt.on('-n NUM', '--number=NUM', '
|
29
|
+
opt.on('-n NUM', '--number=NUM', 'Concat image number') {|v| opts[:n] = v.to_i}
|
30
30
|
opt.parse!(argv)
|
31
31
|
image_files = get_image_files(opts, argv)
|
32
32
|
if image_files.size < 2
|
@@ -89,14 +89,20 @@ module Imagetools
|
|
89
89
|
def concat_images(image_files, output_file)
|
90
90
|
puts image_files.join("+") + "=#{output_file}"
|
91
91
|
|
92
|
+
# 結果の画像リスト
|
92
93
|
result_image_list = Magick::ImageList.new
|
94
|
+
|
93
95
|
image_files.each do |image_file|
|
94
|
-
#
|
96
|
+
# 個別画像の背景色を白に変換
|
97
|
+
# 一気に行く方法がないので、ImageListを作成しbackground_colorとflatten_imagesを組み合わる。
|
95
98
|
image_list = Magick::ImageList.new(image_file) {self.background_color = 'white'}
|
96
99
|
image = image_list.flatten_images
|
100
|
+
|
101
|
+
# 結果の画像リストに追加
|
97
102
|
result_image_list << image
|
98
103
|
end
|
99
|
-
|
104
|
+
|
105
|
+
#append(false)で横方向に結合
|
100
106
|
result = result_image_list.append(false)
|
101
107
|
|
102
108
|
width = result.columns
|
@@ -9,20 +9,45 @@ module Imagetools
|
|
9
9
|
class Config
|
10
10
|
FILENAME_SEARCH = 's (\d+)-(\d+)-(\d+) (\d+)\.(\d+)\.(\d+)'
|
11
11
|
FILENAME_REPLACE = 's_\1\2\3_\4\5\6'
|
12
|
+
RESIZE_WIDTH = 1280
|
13
|
+
|
14
|
+
def self.create_from_yaml(yaml)
|
15
|
+
config = Config.new
|
16
|
+
config.filename_search1 = config_value(yaml, "filename", "search1", false)
|
17
|
+
config.filename_replace1 = config_value(yaml, "filename", "replace1", false)
|
18
|
+
config.filename_search2 = config_value(yaml, "filename", "search2", false)
|
19
|
+
config.filename_replace2 = config_value(yaml, "filename", "replace2", false)
|
20
|
+
config.filename_search3 = config_value(yaml, "filename", "search3", false)
|
21
|
+
config.filename_replace3 = config_value(yaml, "filename", "replace3", false)
|
22
|
+
config.resize_width = config_value(yaml, "resize", "width", false)
|
23
|
+
config.init_default
|
24
|
+
config
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def self.config_value(yaml, section, key, require)
|
29
|
+
return nil unless yaml
|
30
|
+
return nil unless yaml[section]
|
31
|
+
value = yaml[section][key]
|
32
|
+
if require && (value.nil? || value.empty?)
|
33
|
+
raise RuntimeError, "#{section}:#{key}: is empty"
|
34
|
+
end
|
35
|
+
value
|
36
|
+
end
|
12
37
|
|
13
|
-
def initialize
|
14
|
-
@yaml = yaml
|
15
|
-
@filename_search1 = config_value("filename", "search1", false) || FILENAME_SEARCH
|
16
|
-
@filename_replace1 = config_value("filename", "replace1", false) || FILENAME_REPLACE
|
17
|
-
@filename_search2 = config_value("filename", "search2", false)
|
18
|
-
@filename_replace2 = config_value("filename", "replace2", false)
|
19
|
-
@filename_search3 = config_value("filename", "search3", false)
|
20
|
-
@filename_replace3 = config_value("filename", "replace3", false)
|
38
|
+
def initialize
|
21
39
|
end
|
22
40
|
|
23
|
-
|
24
|
-
|
25
|
-
|
41
|
+
def init_default
|
42
|
+
@filename_search1 ||= FILENAME_SEARCH
|
43
|
+
@filename_replace1 ||= FILENAME_REPLACE
|
44
|
+
@resize_width ||= RESIZE_WIDTH
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_accessor :filename_search1, :filename_replace1,
|
48
|
+
:filename_search2, :filename_replace2,
|
49
|
+
:filename_search3, :filename_replace3
|
50
|
+
attr_accessor :resize_width
|
26
51
|
|
27
52
|
def filename_patterns
|
28
53
|
[
|
@@ -31,16 +56,6 @@ module Imagetools
|
|
31
56
|
[@filename_search3, @filename_replace3],
|
32
57
|
]
|
33
58
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
def config_value(section, key, require)
|
37
|
-
return nil unless @yaml
|
38
|
-
value = @yaml[section][key]
|
39
|
-
if require && (value.nil? || value.empty?)
|
40
|
-
raise RuntimeError, "#{section}:#{key}: is empty"
|
41
|
-
end
|
42
|
-
value
|
43
|
-
end
|
44
59
|
end
|
45
60
|
|
46
61
|
class Imagefilter
|
@@ -49,8 +64,7 @@ module Imagetools
|
|
49
64
|
|
50
65
|
CONVERT_CMD = "convert"
|
51
66
|
DWEBP_CMD = "dwebp"
|
52
|
-
|
53
|
-
RESIZE_CMD = "mogrify -background white -resize 1280x\\> "
|
67
|
+
RESIZE_CMD = "mogrify -background white -resize %dx\\> "
|
54
68
|
ROTATE_CMD = "exiftran -ai "
|
55
69
|
COMPRESS_CMD = "jpegoptim --strip-all --max=90 "
|
56
70
|
EXTERNAL_CMDS = [RESIZE_CMD, ROTATE_CMD, COMPRESS_CMD]
|
@@ -99,7 +113,7 @@ EOM
|
|
99
113
|
if FileTest.file?(config_file)
|
100
114
|
yaml = YAML.load_file(config_file)
|
101
115
|
end
|
102
|
-
config = Config.
|
116
|
+
config = Config.create_from_yaml(yaml)
|
103
117
|
if opts[:t]
|
104
118
|
ret = selftest
|
105
119
|
exit(ret)
|
@@ -269,7 +283,8 @@ EOM
|
|
269
283
|
return filepath
|
270
284
|
end
|
271
285
|
puts "resize: #{filepath}"
|
272
|
-
|
286
|
+
resize_cmd = sprintf(RESIZE_CMD, @config.resize_width)
|
287
|
+
cmd = "#{resize_cmd} \"#{filepath}\""
|
273
288
|
system(cmd)
|
274
289
|
return filepath
|
275
290
|
end
|
data/lib/imagetools/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test_imageblog.sh
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imagetools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- src
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rmagick
|
@@ -72,6 +72,7 @@ email:
|
|
72
72
|
executables:
|
73
73
|
- iconcreator
|
74
74
|
- iconextractor
|
75
|
+
- imageblog
|
75
76
|
- imageburst
|
76
77
|
- imageconcat
|
77
78
|
- imagefilter
|
@@ -102,6 +103,7 @@ files:
|
|
102
103
|
- build.sh
|
103
104
|
- exe/iconcreator
|
104
105
|
- exe/iconextractor
|
106
|
+
- exe/imageblog
|
105
107
|
- exe/imageburst
|
106
108
|
- exe/imageconcat
|
107
109
|
- exe/imagefilter
|
@@ -113,6 +115,7 @@ files:
|
|
113
115
|
- lib/imagetools.rb
|
114
116
|
- lib/imagetools/iconcreator.rb
|
115
117
|
- lib/imagetools/iconextractor.rb
|
118
|
+
- lib/imagetools/imageblog.rb
|
116
119
|
- lib/imagetools/imageburst.rb
|
117
120
|
- lib/imagetools/imageconcat.rb
|
118
121
|
- lib/imagetools/imagefilter.rb
|
@@ -142,12 +145,19 @@ files:
|
|
142
145
|
- sample/demo/demo/Base.lproj/Main.storyboard
|
143
146
|
- sample/demo/demo/Info.plist
|
144
147
|
- sample/demo/demo/ViewController.swift
|
148
|
+
- sample/hugo_dst/1200x400.png
|
149
|
+
- sample/hugo_dst/1200x800.png
|
150
|
+
- sample/hugo_dst/600x200.png
|
151
|
+
- sample/hugo_src/0000.png
|
152
|
+
- sample/hugo_src/0001.png
|
153
|
+
- sample/hugo_src/0002.png
|
145
154
|
- sample/icon.png
|
146
155
|
- sample/icon.sketch
|
147
156
|
- sample_iconcreator.sh
|
148
157
|
- test.sh
|
149
158
|
- test_iconcreator.sh
|
150
159
|
- test_iconextractor.sh
|
160
|
+
- test_imageblog.sh
|
151
161
|
- test_imageburst.sh
|
152
162
|
- test_imageconcat.sh
|
153
163
|
- test_imagefilter.sh
|