images-convert 0.4.1
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/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +25 -0
- data/.github/workflows/ci.yml +79 -0
- data/.github/workflows/release.yml +122 -0
- data/.gitignore +14 -0
- data/CHANGELOG.md +146 -0
- data/Gemfile +9 -0
- data/LICENSE +41 -0
- data/README.md +378 -0
- data/RELEASE_NOTES_v0.2.12.md +66 -0
- data/RELEASE_NOTES_v0.2.3.md +19 -0
- data/RELEASE_NOTES_v0.3.0.md +66 -0
- data/RELEASE_NOTES_v0.4.0.md +14 -0
- data/RELEASE_NOTES_v0.4.1.md +13 -0
- data/Rakefile +13 -0
- data/bin/images-convert +8 -0
- data/bin/imgconv +8 -0
- data/images-convert.gemspec +39 -0
- data/lib/images_convert/cleanup.rb +31 -0
- data/lib/images_convert/configuration.rb +303 -0
- data/lib/images_convert/mini_magick_stub.rb +121 -0
- data/lib/images_convert/version.rb +5 -0
- data/lib/images_convert/waifu2x_test_stub.rb +93 -0
- data/lib/images_convert.rb +1557 -0
- data/lib/rubygems_plugin.rb +34 -0
- data/lib/waifu2x/downloader.rb +89 -0
- data/lib/waifu2x/pdf_builder.rb +105 -0
- data/lib/waifu2x/processor.rb +301 -0
- data/lib/waifu2x/setup.rb +127 -0
- data/lib/waifu2x/version.rb +5 -0
- data/lib/waifu2x.rb +221 -0
- data/test/images/autumn.jpg +0 -0
- data/test/images/spring.jpg +0 -0
- data/test/images/summer.jpg +0 -0
- data/test/images/winter.jpg +0 -0
- data/test/support/waifu2x_test_stub.rb +91 -0
- data/test/test_config.rb +143 -0
- data/test/test_fixtures.rb +144 -0
- data/test/test_formats.rb +213 -0
- data/test/test_help.rb +33 -0
- data/test/test_helper.rb +17 -0
- data/test/test_helper_mini_magick_stub.rb +4 -0
- data/test/test_selection.rb +142 -0
- data/test/test_version.rb +16 -0
- data/test/test_waifu2x.rb +81 -0
- metadata +179 -0
data/lib/waifu2x.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fileutils'
|
5
|
+
require_relative 'waifu2x/version'
|
6
|
+
require_relative 'waifu2x/processor'
|
7
|
+
require_relative 'waifu2x/pdf_builder'
|
8
|
+
require_relative 'waifu2x/setup'
|
9
|
+
require_relative 'images_convert/waifu2x_test_stub'
|
10
|
+
|
11
|
+
module Waifu2x
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
def self.process(input_dir, output_pdf, **options)
|
15
|
+
temp_dir = Dir.mktmpdir('waifu2x-pdf')
|
16
|
+
|
17
|
+
begin
|
18
|
+
output_mode = (options[:output_mode] || 'pdf').to_s
|
19
|
+
output_images_root = options[:output_dir]
|
20
|
+
pdf_override = options[:output_pdf]
|
21
|
+
|
22
|
+
recursive = options.key?(:recursive) ? options[:recursive] : false
|
23
|
+
pattern = recursive ? File.join(input_dir, '**', '*.{jpg,jpeg,png,gif,webp}') : File.join(input_dir, '*.{jpg,jpeg,png,gif,webp}')
|
24
|
+
input_images = Dir.glob(pattern)
|
25
|
+
if input_images.empty?
|
26
|
+
raise "入力ディレクトリに対象画像が見つかりませんでした: #{input_dir} (対応拡張子: jpg, jpeg, png, gif, webp)"
|
27
|
+
end
|
28
|
+
|
29
|
+
resolved = Setup.resolve_paths(
|
30
|
+
waifu2x_bin: options[:waifu2x_bin],
|
31
|
+
models_path: options[:models_path],
|
32
|
+
auto_download: options[:auto_download],
|
33
|
+
download_url: options[:download_url],
|
34
|
+
model: options[:model]
|
35
|
+
)
|
36
|
+
|
37
|
+
total_images_sec = 0.0
|
38
|
+
total_pdf_sec = 0.0
|
39
|
+
|
40
|
+
if recursive && output_pdf.nil?
|
41
|
+
dirs = input_images.map { |p| File.dirname(p) }.uniq.sort
|
42
|
+
dirs.each do |dir|
|
43
|
+
if output_mode == 'images' || output_mode == 'both'
|
44
|
+
out_dir = if output_images_root
|
45
|
+
File.join(output_images_root, File.basename(dir))
|
46
|
+
else
|
47
|
+
File.join(File.dirname(dir), "#{File.basename(dir)} 高解像度")
|
48
|
+
end
|
49
|
+
FileUtils.mkdir_p(out_dir)
|
50
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
51
|
+
Processor.process_images(
|
52
|
+
dir,
|
53
|
+
out_dir,
|
54
|
+
scale: options[:scale] || 2,
|
55
|
+
noise: options[:noise] || 1,
|
56
|
+
model: options[:model] || 'anime_style_art_rgb',
|
57
|
+
processor: options[:processor] || :waifu2x_ncnn_vulkan,
|
58
|
+
waifu2x_bin: resolved[:bin],
|
59
|
+
models_path: resolved[:models],
|
60
|
+
recursive: false,
|
61
|
+
auto_scale_a4: options[:auto_scale_a4],
|
62
|
+
pdf_density: options[:pdf_density],
|
63
|
+
verbose: options[:verbose],
|
64
|
+
image_format: options[:image_format],
|
65
|
+
on_error: options[:on_error]
|
66
|
+
)
|
67
|
+
images_sec = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
|
68
|
+
total_images_sec += images_sec
|
69
|
+
puts format('%s done in %.2fs: %s', 'Images'.ljust(6), images_sec, out_dir)
|
70
|
+
end
|
71
|
+
|
72
|
+
if %w[images both].include?(output_mode) && (options[:image_format].to_s.downcase == 'webp')
|
73
|
+
Dir.glob(File.join(out_dir, '*.png')).each do |png|
|
74
|
+
begin
|
75
|
+
File.delete(png)
|
76
|
+
rescue StandardError
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if output_mode == 'pdf' || output_mode == 'both'
|
82
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
83
|
+
page_images = nil
|
84
|
+
if output_mode == 'both'
|
85
|
+
if options[:image_format].to_s.downcase == 'webp'
|
86
|
+
page_images = Dir.glob(File.join(out_dir, '*.webp')).sort
|
87
|
+
else
|
88
|
+
exts = %w[png jpg jpeg webp]
|
89
|
+
page_images = exts.flat_map { |e| Dir.glob(File.join(out_dir, "*.#{e}")) }.sort
|
90
|
+
end
|
91
|
+
else
|
92
|
+
Dir.mktmpdir('waifu2x-pdf-dir') do |dir_temp|
|
93
|
+
Processor.process_images(
|
94
|
+
dir,
|
95
|
+
dir_temp,
|
96
|
+
scale: options[:scale] || 2,
|
97
|
+
noise: options[:noise] || 1,
|
98
|
+
model: options[:model] || 'anime_style_art_rgb',
|
99
|
+
processor: options[:processor] || :waifu2x_ncnn_vulkan,
|
100
|
+
waifu2x_bin: resolved[:bin],
|
101
|
+
models_path: resolved[:models],
|
102
|
+
recursive: false,
|
103
|
+
auto_scale_a4: options[:auto_scale_a4],
|
104
|
+
pdf_density: options[:pdf_density],
|
105
|
+
verbose: options[:verbose],
|
106
|
+
image_format: 'png',
|
107
|
+
on_error: options[:on_error]
|
108
|
+
)
|
109
|
+
page_images = Dir.glob(File.join(dir_temp, '*.png')).sort
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
next if page_images.nil? || page_images.empty?
|
114
|
+
|
115
|
+
out_path = pdf_override || output_pdf || File.join(File.dirname(dir), "#{File.basename(dir)}.pdf")
|
116
|
+
PDFBuilder.create_pdf(
|
117
|
+
page_images,
|
118
|
+
out_path,
|
119
|
+
pdf_compression: options[:pdf_compression],
|
120
|
+
pdf_quality: options[:pdf_quality],
|
121
|
+
pdf_density: options[:pdf_density],
|
122
|
+
a4_print: options[:a4_print]
|
123
|
+
)
|
124
|
+
pdf_sec = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
|
125
|
+
total_pdf_sec += pdf_sec
|
126
|
+
puts format('%s done in %.2fs: %s', 'PDF'.ljust(6), pdf_sec, out_path)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
else
|
130
|
+
if output_mode == 'images' || output_mode == 'both'
|
131
|
+
out_dir = output_images_root || File.join(File.dirname(File.expand_path(input_dir)), "#{File.basename(File.expand_path(input_dir))} 高解像度")
|
132
|
+
FileUtils.mkdir_p(out_dir)
|
133
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
134
|
+
Processor.process_images(
|
135
|
+
input_dir,
|
136
|
+
out_dir,
|
137
|
+
scale: options[:scale] || 2,
|
138
|
+
noise: options[:noise] || 1,
|
139
|
+
model: options[:model] || 'anime_style_art_rgb',
|
140
|
+
processor: options[:processor] || :waifu2x_ncnn_vulkan,
|
141
|
+
waifu2x_bin: resolved[:bin],
|
142
|
+
models_path: resolved[:models],
|
143
|
+
recursive: recursive,
|
144
|
+
auto_scale_a4: options[:auto_scale_a4],
|
145
|
+
pdf_density: options[:pdf_density],
|
146
|
+
verbose: options[:verbose],
|
147
|
+
image_format: options[:image_format],
|
148
|
+
on_error: options[:on_error]
|
149
|
+
)
|
150
|
+
images_sec = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
|
151
|
+
total_images_sec += images_sec
|
152
|
+
puts format('%s done in %.2fs: %s', 'Images'.ljust(6), images_sec, out_dir)
|
153
|
+
end
|
154
|
+
|
155
|
+
if %w[images both].include?(output_mode) && (options[:image_format].to_s.downcase == 'webp')
|
156
|
+
Dir.glob(File.join(out_dir, '*.png')).each do |png|
|
157
|
+
begin
|
158
|
+
File.delete(png)
|
159
|
+
rescue StandardError
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
if output_mode == 'pdf' || output_mode == 'both'
|
165
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
166
|
+
if output_mode == 'both'
|
167
|
+
if options[:image_format].to_s.downcase == 'webp'
|
168
|
+
image_paths = Dir.glob(File.join(out_dir, '*.webp')).sort
|
169
|
+
else
|
170
|
+
exts = %w[png jpg jpeg webp]
|
171
|
+
image_paths = exts.flat_map { |e| Dir.glob(File.join(out_dir, "*.#{e}")) }.sort
|
172
|
+
end
|
173
|
+
else
|
174
|
+
Processor.process_images(
|
175
|
+
input_dir,
|
176
|
+
temp_dir,
|
177
|
+
scale: options[:scale] || 2,
|
178
|
+
noise: options[:noise] || 1,
|
179
|
+
model: options[:model] || 'anime_style_art_rgb',
|
180
|
+
processor: options[:processor] || :waifu2x_ncnn_vulkan,
|
181
|
+
waifu2x_bin: resolved[:bin],
|
182
|
+
models_path: resolved[:models],
|
183
|
+
recursive: recursive,
|
184
|
+
auto_scale_a4: options[:auto_scale_a4],
|
185
|
+
pdf_density: options[:pdf_density],
|
186
|
+
verbose: options[:verbose],
|
187
|
+
image_format: 'png',
|
188
|
+
on_error: options[:on_error]
|
189
|
+
)
|
190
|
+
image_paths = Dir.glob(File.join(temp_dir, '*.png')).sort
|
191
|
+
end
|
192
|
+
|
193
|
+
if image_paths.empty?
|
194
|
+
raise '画像処理の結果が得られませんでした(出力画像が0件)。入力画像やwaifu2xの動作をご確認ください。'
|
195
|
+
end
|
196
|
+
pdf_destination = pdf_override || output_pdf || File.join(File.dirname(File.expand_path(input_dir)), "#{File.basename(File.expand_path(input_dir))}.pdf")
|
197
|
+
PDFBuilder.create_pdf(
|
198
|
+
image_paths,
|
199
|
+
pdf_destination,
|
200
|
+
pdf_compression: options[:pdf_compression],
|
201
|
+
pdf_quality: options[:pdf_quality],
|
202
|
+
pdf_density: options[:pdf_density],
|
203
|
+
a4_print: options[:a4_print]
|
204
|
+
)
|
205
|
+
|
206
|
+
if File.exist?(pdf_destination)
|
207
|
+
pdf_sec = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
|
208
|
+
total_pdf_sec += pdf_sec
|
209
|
+
puts format('%s done in %.2fs: %s', 'PDF'.ljust(6), pdf_sec, pdf_destination)
|
210
|
+
else
|
211
|
+
raise "PDFの作成に失敗しました: #{pdf_destination}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
ensure
|
216
|
+
puts format('Total %s time: %.2fs', 'images', total_images_sec) if total_images_sec > 0.0
|
217
|
+
puts format('Total %s time: %.2fs', 'PDF'.ljust(6), total_pdf_sec) if total_pdf_sec > 0.0
|
218
|
+
FileUtils.remove_entry(temp_dir) if Dir.exist?(temp_dir)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module Waifu2x
|
7
|
+
module TestInstrumentation
|
8
|
+
class << self
|
9
|
+
def enabled?
|
10
|
+
path = ENV['IMGCONV_TEST_WAIFU2X_CALL_LOG']
|
11
|
+
path && !path.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def log(payload)
|
15
|
+
path = ENV['IMGCONV_TEST_WAIFU2X_CALL_LOG']
|
16
|
+
return unless path && !path.empty?
|
17
|
+
|
18
|
+
FileUtils.mkdir_p(File.dirname(path))
|
19
|
+
File.open(path, 'a') do |f|
|
20
|
+
f.write(JSON.dump(payload))
|
21
|
+
f.write("\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def fake_paths
|
26
|
+
{
|
27
|
+
bin: File.expand_path('waifu2x-ncnn-vulkan', Dir.tmpdir),
|
28
|
+
models: File.expand_path('waifu2x-models', Dir.tmpdir)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if defined?(Waifu2x::Processor)
|
36
|
+
class << Waifu2x::Processor
|
37
|
+
unless method_defined?(:process_images_without_test_stub)
|
38
|
+
alias_method :process_images_without_test_stub, :process_images
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_images(input_dir, output_dir, **options)
|
42
|
+
if Waifu2x::TestInstrumentation.enabled?
|
43
|
+
FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir)
|
44
|
+
format = options[:image_format].to_s
|
45
|
+
format = 'png' if format.empty?
|
46
|
+
stub_path = File.join(output_dir, "waifu2x_stub_output.#{format}")
|
47
|
+
File.write(stub_path, 'waifu2x-stub')
|
48
|
+
Waifu2x::TestInstrumentation.log({ input_dir: input_dir, output_dir: output_dir, options: options })
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
process_images_without_test_stub(input_dir, output_dir, **options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if defined?(Waifu2x::Setup)
|
58
|
+
class << Waifu2x::Setup
|
59
|
+
unless method_defined?(:resolve_paths_without_test_stub)
|
60
|
+
alias_method :resolve_paths_without_test_stub, :resolve_paths
|
61
|
+
end
|
62
|
+
|
63
|
+
def resolve_paths(**options)
|
64
|
+
if Waifu2x::TestInstrumentation.enabled?
|
65
|
+
fake = Waifu2x::TestInstrumentation.fake_paths
|
66
|
+
return { bin: fake[:bin], models: fake[:models] }
|
67
|
+
end
|
68
|
+
|
69
|
+
resolve_paths_without_test_stub(**options)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if defined?(Waifu2x::PDFBuilder)
|
75
|
+
class << Waifu2x::PDFBuilder
|
76
|
+
unless method_defined?(:create_pdf_without_test_stub)
|
77
|
+
alias_method :create_pdf_without_test_stub, :create_pdf
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_pdf(image_paths, output_path, options = {})
|
81
|
+
if Waifu2x::TestInstrumentation.enabled?
|
82
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
83
|
+
File.write(output_path, "waifu2x-pdf-stub\n")
|
84
|
+
Waifu2x::TestInstrumentation.log({ pdf_output: output_path, images: image_paths, options: options })
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
create_pdf_without_test_stub(image_paths, output_path, options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/test/test_config.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# 概要: config 動作のスモークテスト
|
4
|
+
# 目的:
|
5
|
+
# - 初回実行で ~/.images-convert/config.yml が作成されること
|
6
|
+
# - `config set JPG WebP 1024x` の反映(from/to/resize)
|
7
|
+
# - `config set ... 50%` のような百分率リサイズも受け入れること
|
8
|
+
# - `cleanup` 実行で設定ディレクトリが削除されること
|
9
|
+
|
10
|
+
require_relative './test_helper'
|
11
|
+
require 'open3'
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
class CLIConfigTest < Minitest::Test
|
15
|
+
ROOT = File.expand_path('..', __dir__)
|
16
|
+
BIN = File.join(ROOT, 'bin', 'imgconv')
|
17
|
+
LIB = File.join(ROOT, 'lib')
|
18
|
+
|
19
|
+
def run_cmd_env(env, *args)
|
20
|
+
cmd = ['ruby', '-I', LIB, BIN] + args
|
21
|
+
stdout, stderr, status = Open3.capture3(env, *cmd)
|
22
|
+
[stdout, stderr, status]
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_isolated_home
|
26
|
+
Dir.mktmpdir do |home|
|
27
|
+
env = { 'HOME' => home }
|
28
|
+
yield env
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# 1) config.yml が存在すること(config 実行で作成)
|
33
|
+
def test_config_creates_config_yaml
|
34
|
+
with_isolated_home do |env|
|
35
|
+
stdout, stderr, status = run_cmd_env(env, 'config')
|
36
|
+
assert status.success?, "config failed: #{status.exitstatus}, stderr=\n#{stderr}\nstdout=\n#{stdout}"
|
37
|
+
cfg = File.join(env['HOME'], '.images-convert', 'config.yml')
|
38
|
+
assert File.exist?(cfg), "expected config file to exist: #{cfg}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# 2) set JPG WebP 1024x の反映
|
43
|
+
# 3) 1024x がサイズとして表示されること
|
44
|
+
def test_config_set_jpg_webp_1024x_reflected
|
45
|
+
with_isolated_home do |env|
|
46
|
+
_o1, e1, s1 = run_cmd_env(env, 'config', 'set', 'JPG', 'WebP', '1024x')
|
47
|
+
assert s1.success?, "config set failed: #{e1}"
|
48
|
+
stdout, stderr, status = run_cmd_env(env, 'config')
|
49
|
+
assert status.success?, "config failed: #{status.exitstatus}, stderr=\n#{stderr}"
|
50
|
+
assert_includes stdout, 'デフォルト入力形式: JPG', stdout
|
51
|
+
assert_includes stdout, 'デフォルト出力形式: WebP', stdout
|
52
|
+
assert_includes stdout, 'デフォルトリサイズ: 1024x', stdout
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# 4) 50% の指定も受け入れること
|
57
|
+
def test_config_set_resize_percent_accepted
|
58
|
+
with_isolated_home do |env|
|
59
|
+
_o1, e1, s1 = run_cmd_env(env, 'config', 'set', 'JPG', 'JPG', '50%')
|
60
|
+
assert s1.success?, "config set failed: #{e1}"
|
61
|
+
stdout, stderr, status = run_cmd_env(env, 'config')
|
62
|
+
assert status.success?, "config failed: #{status.exitstatus}, stderr=\n#{stderr}"
|
63
|
+
assert_includes stdout, 'デフォルトリサイズ: 50%', stdout
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_config_set_latest_mode_exif
|
68
|
+
with_isolated_home do |env|
|
69
|
+
stdout, stderr, status = run_cmd_env(env, 'config', 'set-latest-mode', 'exif')
|
70
|
+
assert status.success?, "set-latest-mode failed: #{status.exitstatus}, stderr=\n#{stderr}\nstdout=\n#{stdout}"
|
71
|
+
|
72
|
+
stdout_config, stderr_config, status_config = run_cmd_env(env, 'config')
|
73
|
+
assert status_config.success?, "config failed: #{status_config.exitstatus}, stderr=\n#{stderr_config}"
|
74
|
+
assert_includes stdout_config, '最新判定モード: exif', stdout_config
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_config_set_latest_mode_invalid
|
79
|
+
with_isolated_home do |env|
|
80
|
+
stdout, stderr, status = run_cmd_env(env, 'config', 'set-latest-mode', 'invalid')
|
81
|
+
refute status.success?, 'expected set-latest-mode invalid to fail'
|
82
|
+
combined = stdout + stderr
|
83
|
+
assert_includes combined, 'MODE には mtime または exif', combined
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_config_reset_restores_defaults
|
88
|
+
with_isolated_home do |env|
|
89
|
+
_, _, status = run_cmd_env(env, 'config', 'set', 'JPG', 'WebP', '1024x')
|
90
|
+
assert status.success?, 'config set should succeed before reset'
|
91
|
+
|
92
|
+
stdout_reset, stderr_reset, status_reset = run_cmd_env(env, 'config', 'reset', '--force')
|
93
|
+
assert status_reset.success?, "config reset failed: #{stderr_reset}\nstdout=\n#{stdout_reset}"
|
94
|
+
assert_includes stdout_reset, '設定を既定値にリセットしました。', stdout_reset
|
95
|
+
assert_includes stdout_reset, 'デフォルト出力形式: JPG', stdout_reset
|
96
|
+
assert_includes stdout_reset, 'デフォルトリサイズ: 1920x', stdout_reset
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_config_set_waifu2x_updates_settings
|
101
|
+
with_isolated_home do |env|
|
102
|
+
stdout, stderr, status = run_cmd_env(
|
103
|
+
env,
|
104
|
+
'config',
|
105
|
+
'set-waifu2x',
|
106
|
+
'--scale', '4',
|
107
|
+
'--noise', '3',
|
108
|
+
'--model', 'anime',
|
109
|
+
'--no-auto-scale-a4',
|
110
|
+
'--no-a4-print',
|
111
|
+
'--image_format', 'png',
|
112
|
+
'--on_error', 'skip'
|
113
|
+
)
|
114
|
+
assert status.success?, "set-waifu2x failed: #{status.exitstatus}, stderr=\n#{stderr}\nstdout=\n#{stdout}"
|
115
|
+
|
116
|
+
stdout_config, stderr_config, status_config = run_cmd_env(env, 'config')
|
117
|
+
assert status_config.success?, "config failed: #{status_config.exitstatus}, stderr=\n#{stderr_config}"
|
118
|
+
assert_includes stdout_config, 'waifu2x 既定倍率: 4', stdout_config
|
119
|
+
assert_includes stdout_config, 'waifu2x ノイズ除去: 3', stdout_config
|
120
|
+
assert_includes stdout_config, 'waifu2x モデル: anime', stdout_config
|
121
|
+
assert_includes stdout_config, 'waifu2x A4自動スケール: false', stdout_config
|
122
|
+
assert_includes stdout_config, 'waifu2x A4レイアウトPDF: false', stdout_config
|
123
|
+
assert_includes stdout_config, 'waifu2x 出力フォーマット: png', stdout_config
|
124
|
+
assert_includes stdout_config, 'waifu2x エラー時動作: skip', stdout_config
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# 5) cleanup 時には、config.yml が消されること
|
129
|
+
def test_cleanup_removes_config_dir
|
130
|
+
with_isolated_home do |env|
|
131
|
+
# まず config で作成
|
132
|
+
_o1, e1, s1 = run_cmd_env(env, 'config')
|
133
|
+
assert s1.success?, "config failed: #{e1}"
|
134
|
+
cfg_dir = File.join(env['HOME'], '.images-convert')
|
135
|
+
assert Dir.exist?(cfg_dir), 'config dir expected to exist before cleanup'
|
136
|
+
|
137
|
+
# cleanup 実行
|
138
|
+
stdout, stderr, status = run_cmd_env(env, 'cleanup')
|
139
|
+
assert status.success?, "cleanup failed: #{status.exitstatus}, stderr=\n#{stderr}\nstdout=\n#{stdout}"
|
140
|
+
refute Dir.exist?(cfg_dir), 'config dir should be removed after cleanup'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './test_helper_mini_magick_stub'
|
4
|
+
require 'open3'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
class CLIFixturesTest < Minitest::Test
|
9
|
+
ROOT = File.expand_path('..', __dir__)
|
10
|
+
BIN = File.join(ROOT, 'bin', 'imgconv')
|
11
|
+
LIB = File.join(ROOT, 'lib')
|
12
|
+
FIX = File.join(ROOT, 'test', 'images')
|
13
|
+
|
14
|
+
def run_cmd_env(env, *args)
|
15
|
+
base_env = { 'IMGCONV_TEST_FAKE_MINIMAGICK' => '1' }.merge(env)
|
16
|
+
cmd = ['ruby', '-I', LIB, BIN] + args
|
17
|
+
Open3.capture3(base_env, *cmd)
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_isolated_home
|
21
|
+
Dir.mktmpdir do |home|
|
22
|
+
env = { 'HOME' => home }
|
23
|
+
yield env
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_fixtures(src_dir, names)
|
28
|
+
names.each do |name|
|
29
|
+
FileUtils.cp(File.join(FIX, "#{name}.jpg"), File.join(src_dir, "#{name}.jpg"))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def configure_defaults(env, from: 'JPG', to: 'PNG', resize: '1920x')
|
34
|
+
_o, e1, s1 = run_cmd_env(env, 'config', 'set', from, to, resize)
|
35
|
+
assert s1.success?, "config set #{from} #{to} failed: #{e1}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def configure_directories(env, input:, output:)
|
39
|
+
_o, e, s = run_cmd_env(env, 'config', 'set-dir', input, output)
|
40
|
+
assert s.success?, "config set-dir failed: #{e}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_bulk_convert_jpg_to_png_with_fixtures
|
44
|
+
with_isolated_home do |env|
|
45
|
+
configure_defaults(env)
|
46
|
+
Dir.mktmpdir do |src|
|
47
|
+
Dir.mktmpdir do |dst|
|
48
|
+
copy_fixtures(src, %w[spring summer autumn winter])
|
49
|
+
|
50
|
+
stdout, stderr, status = run_cmd_env(env, 'convert', src, dst, '--from', 'JPG', '--to', 'PNG', '--overwrite')
|
51
|
+
assert status.success?, "bulk convert fixtures failed: #{status.exitstatus}\nstderr=\n#{stderr}\nstdout=\n#{stdout}"
|
52
|
+
|
53
|
+
%w[spring summer autumn winter].each do |name|
|
54
|
+
assert File.exist?(File.join(dst, "#{name}.png")), "expected output #{name}.png to exist"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_latest_two_selection_converts_two_newest_files
|
62
|
+
with_isolated_home do |env|
|
63
|
+
configure_defaults(env)
|
64
|
+
Dir.mktmpdir do |src|
|
65
|
+
Dir.mktmpdir do |dst|
|
66
|
+
copy_fixtures(src, %w[spring summer autumn winter])
|
67
|
+
base_time = Time.now - 3600
|
68
|
+
{
|
69
|
+
'spring' => base_time + 100,
|
70
|
+
'summer' => base_time + 2000,
|
71
|
+
'autumn' => base_time + 300,
|
72
|
+
'winter' => base_time + 4000,
|
73
|
+
}.each do |name, t|
|
74
|
+
File.utime(t, t, File.join(src, "#{name}.jpg"))
|
75
|
+
end
|
76
|
+
|
77
|
+
configure_directories(env, input: src, output: dst)
|
78
|
+
|
79
|
+
stdout, stderr, status = run_cmd_env(env, '--latest', '2')
|
80
|
+
assert status.success?, "--latest 2 failed: #{status.exitstatus}\nstderr=\n#{stderr}\nstdout=\n#{stdout}"
|
81
|
+
|
82
|
+
converted = Dir.glob(File.join(dst, '*.png')).map { |p| File.basename(p, '.png') }
|
83
|
+
assert_equal %w[summer winter].sort, converted.sort, "expected latest two images to be converted"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_bulk_with_suffix_writes_suffixed_files
|
90
|
+
with_isolated_home do |env|
|
91
|
+
configure_defaults(env)
|
92
|
+
Dir.mktmpdir do |src|
|
93
|
+
Dir.mktmpdir do |dst|
|
94
|
+
copy_fixtures(src, %w[spring summer])
|
95
|
+
|
96
|
+
stdout, stderr, status = run_cmd_env(env, 'convert', src, dst, '--suffix', '_web')
|
97
|
+
assert status.success?, "bulk with suffix failed: #{status.exitstatus}\nstderr=\n#{stderr}\nstdout=\n#{stdout}"
|
98
|
+
|
99
|
+
%w[spring summer].each do |name|
|
100
|
+
assert File.exist?(File.join(dst, "#{name}_web.png")), "expected suffixed output for #{name}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_recursive_bulk_keeps_subdirs_and_suffix
|
108
|
+
with_isolated_home do |env|
|
109
|
+
configure_defaults(env)
|
110
|
+
Dir.mktmpdir do |src|
|
111
|
+
Dir.mktmpdir do |dst|
|
112
|
+
FileUtils.cp(File.join(FIX, 'spring.jpg'), File.join(src, 'spring.jpg'))
|
113
|
+
sub = File.join(src, 'seasons')
|
114
|
+
FileUtils.mkdir_p(sub)
|
115
|
+
FileUtils.cp(File.join(FIX, 'summer.jpg'), File.join(sub, 'summer.jpg'))
|
116
|
+
|
117
|
+
stdout, stderr, status = run_cmd_env(env, 'convert', src, dst, '--from', 'JPG', '--to', 'PNG', '--recursive', '--suffix', '_web')
|
118
|
+
assert status.success?, "recursive bulk failed: #{status.exitstatus}\nstderr=\n#{stderr}\nstdout=\n#{stdout}"
|
119
|
+
|
120
|
+
assert File.exist?(File.join(dst, 'spring_web.png')), 'expected root image to be converted with suffix'
|
121
|
+
assert File.exist?(File.join(dst, 'seasons', 'summer_web.png')), 'expected nested image to be converted with suffix'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_single_file_delete_removes_source
|
128
|
+
with_isolated_home do |env|
|
129
|
+
configure_defaults(env)
|
130
|
+
Dir.mktmpdir do |dir|
|
131
|
+
src = File.join(dir, 'src')
|
132
|
+
dst = File.join(dir, 'dst')
|
133
|
+
FileUtils.mkdir_p(src)
|
134
|
+
FileUtils.mkdir_p(dst)
|
135
|
+
FileUtils.cp(File.join(FIX, 'autumn.jpg'), File.join(src, 'autumn.jpg'))
|
136
|
+
|
137
|
+
stdout, stderr, status = run_cmd_env(env, 'convert', 'autumn', '--input_dir', src, '--output_dir', dst, '--delete', '--overwrite')
|
138
|
+
assert status.success?, "single convert with --delete failed: #{status.exitstatus}\nstderr=\n#{stderr}\nstdout=\n#{stdout}"
|
139
|
+
assert File.exist?(File.join(dst, 'autumn.png')), 'expected output file to be created'
|
140
|
+
refute File.exist?(File.join(src, 'autumn.jpg')), 'expected source file to be deleted'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|