Skip to content

Commit 23bd7ba

Browse files
feat!: add automated cleanup of srgb-converted file to avoid accumulating garbage
- Vips processor required moving the srgb conversion to a different location, because it only reads source file lazily, on attempt to write. - jpgicc leaves empty file on failure (and it happens to fail on grayscale, thus the shared examples are in two places)
1 parent e527ae0 commit 23bd7ba

File tree

8 files changed

+28
-8
lines changed

8 files changed

+28
-8
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,3 @@ sample/
2323
Makefile
2424
*.rdb
2525
tags
26-
*.icc.jpg

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

77
## [0.101.0] 14.01.2026
8+
### Added
9+
- [BREAKING] introduced automated cleanup of srgb files after processing
10+
811
### Removed
912
- [BREAKING] support for custom srgb file path
1013

lib/morandi.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ def process(source, options, target_path, local_options = {})
5757
cache_max = 0
5858
concurrency = 2 # Hardcoding to 2 for now to maintain some balance between resource usage and performance
5959
VipsImageProcessor.with_global_options(cache_max: cache_max, concurrency: concurrency) do
60-
VipsImageProcessor.new(source, options).write_to_jpeg(target_path)
60+
srgb_converted_file_path = Morandi::SrgbConversion.perform(source)
61+
VipsImageProcessor.new(srgb_converted_file_path || source, options).write_to_jpeg(target_path)
62+
ensure
63+
FileUtils.rm_f(srgb_converted_file_path) if srgb_converted_file_path
6164
end
6265
else
6366
ImageProcessor.new(source, options, local_options).tap(&:result).write_to_jpeg(target_path)

lib/morandi/profiled_pixbuf.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ module Morandi
99
# NOTE: pixbuf supports colour profiles, but it requires an explicit icc-profile option to embed it when saving file
1010
class ProfiledPixbuf < GdkPixbuf::Pixbuf
1111
def initialize(path, _local_options, max_size_px = nil)
12-
path = srgb_path(path) || path
12+
srgb_converted_file_path = srgb_path(path)
13+
path = srgb_converted_file_path || path
1314

1415
if max_size_px
1516
super(file: path, width: max_size_px, height: max_size_px)
1617
else
1718
super(file: path)
1819
end
20+
ensure
21+
FileUtils.rm_f(srgb_converted_file_path) if srgb_converted_file_path
1922
end
2023

2124
private

lib/morandi/srgb_conversion.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ def self.perform(path)
1313
icc_file_path = default_icc_path(path)
1414
system('jpgicc', '-q97', path, icc_file_path, out: '/dev/null', err: '/dev/null')
1515

16-
return unless valid_jpeg?(icc_file_path)
16+
unless valid_jpeg?(icc_file_path)
17+
FileUtils.rm_f(icc_file_path) # jpgicc likes to leave an empty file after failing
18+
return
19+
end
1720

1821
icc_file_path
1922
end

lib/morandi/vips_image_processor.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ def initialize(path, user_options)
5555
end
5656

5757
def process!
58-
srgb_converted_file_path = Morandi::SrgbConversion.perform(@path)
59-
source_file_path = srgb_converted_file_path || @path
58+
source_file_path = @path
6059
begin
6160
@img = Vips::Image.new_from_file(source_file_path)
6261
rescue Vips::Error => e

spec/morandi_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,20 @@
4545
FileUtils.remove_dir('sample/')
4646
end
4747

48+
shared_examples 'tidy processor' do
49+
it 'only leaves unchanged input, and a new output file with no other leftovers' do
50+
expect { process_image }.to change { Dir['sample/*'].count }.by(1)
51+
52+
expect(File.exist?(file_in)).to eq true
53+
end
54+
end
55+
4856
shared_examples 'an image processor' do |processor_name|
4957
let(:reference_image_prefix) { processor_name == 'pixbuf' ? '' : processor_name }
5058
subject(:process_image) { Morandi.process(file_arg, options, file_out, { 'processor' => processor_name }) }
5159

60+
it_behaves_like 'tidy processor'
61+
5262
context 'when given an input without any options' do
5363
it 'creates output' do
5464
process_image
@@ -470,6 +480,8 @@
470480
generate_test_image_greyscale(file_in, width: original_image_width, height: original_image_height)
471481
end
472482

483+
it_behaves_like 'tidy processor'
484+
473485
it 'changes greyscale image to srgb' do
474486
expect(file_in).to match_colourspace('gray') # Testing a setup to protect from a hidden regression
475487
process_image

spec/visual_report_helper.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ def add_to_visual_report(example, files)
6868
fp.puts %(<pre>#{CGI.escapeHTML(JSON.pretty_generate(example.example_group_instance.options))}</pre>)
6969
fp.puts %(</td><td>)
7070
files.each.with_index do |filename, index|
71-
next if File.basename(filename) == 'sample.jpg.icc.jpg'
72-
7371
base = name_for(filename, example, index)
7472
FileUtils.cp(filename, "spec/reports/#{base}")
7573
fp << %(<div class="img-block"><img src="#{base}" style="max-width: 300px; height: auto;"><br>)

0 commit comments

Comments
 (0)