diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index c910947b..595673cb 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -2,6 +2,8 @@ ## unreleased +* Added `svgo-allow-lossy` and `svgo-precision` options to use svgo in lossy mode. This sets svgo `precision`, which can result in substantially smaller svgs. Lower values are more lossy. 3 is the default, but many SVGs will work well even with 0 or 1. [#210] [@gurgeous](https://github.com/gurgeous) + ## v0.31.3 (2023-02-17) * Support Psych4/Ruby 3.1 changes to use safe_yaml methods by default [#203](https://github.com/toy/image_optim/issues/203) [#204](https://github.com/toy/image_optim/pull/204) [@oscillot](https://github.com/oscillot) [@toy](https://github.com/toy) diff --git a/lib/image_optim/worker/svgo.rb b/lib/image_optim/worker/svgo.rb index 67f732bd..0ab91b2a 100644 --- a/lib/image_optim/worker/svgo.rb +++ b/lib/image_optim/worker/svgo.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'image_optim/option_helpers' require 'image_optim/worker' class ImageOptim @@ -16,6 +17,24 @@ class Svgo < Worker Array(v).map(&:to_s) end + ALLOW_LOSSY_OPTION = + option(:allow_lossy, false, 'Allow precision option'){ |v| !!v } + + PRECISION_OPTION = + option(:precision, 3, 'number of digits in the fractional part ' \ + '`0`..`10`, ignored in default/lossless mode') \ + do |v, opt_def| + if allow_lossy + OptionHelpers.limit_with_range(v.to_i, 0..10) + else + if v != opt_def.default + warn "#{self.class.bin_sym} #{opt_def.name} #{v} ignored " \ + 'in default/lossless mode' + end + opt_def.default + end + end + def optimize(src, dst, options = {}) args = %W[ --input #{src} @@ -27,6 +46,7 @@ def optimize(src, dst, options = {}) enable_plugins.each do |plugin_name| args.unshift "--enable=#{plugin_name}" end + args.unshift "--precision=#{precision}" if allow_lossy execute(:svgo, args, options) && optimized?(src, dst) end end diff --git a/spec/image_optim/worker/svgo_spec.rb b/spec/image_optim/worker/svgo_spec.rb new file mode 100644 index 00000000..6e37be13 --- /dev/null +++ b/spec/image_optim/worker/svgo_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'image_optim/worker/svgo' + +describe ImageOptim::Worker::Svgo do + describe 'precision option' do + describe 'default' do + subject{ described_class::PRECISION_OPTION.default } + + it{ is_expected.to eq(3) } + end + + describe 'value' do + let(:subject){ described_class.new(ImageOptim.new, options).precision } + + context 'when lossy not allowed' do + context 'by default' do + let(:options){ {} } + + it{ is_expected.to eq(3) } + end + + context 'when value is passed through options' do + let(:options){ {precision: 5} } + + it 'warns and keeps default' do + expect_any_instance_of(described_class). + to receive(:warn).with(%r{ignored in default/lossless mode}) + is_expected.to eq(3) + end + end + end + + context 'when lossy allowed' do + context 'by default' do + let(:options){ {allow_lossy: true} } + + it{ is_expected.to eq(3) } + end + + context 'when value is passed through options' do + let(:options){ {allow_lossy: true, precision: 5} } + + it 'sets the value without warning' do + expect_any_instance_of(described_class).not_to receive(:warn) + is_expected.to eq(5) + end + end + end + end + end +end