mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 18:30:26 -06:00
FEATURE: introduce lossy color optimization on resized pngs
This feature ensures optimized images run via pngquant, this results extreme amounts of savings for resized images. Effectively the only impact is that the color palette on small resized images is reduced to 256. To ensure safety we only apply this optimisation to images smaller than 500k. This commit also makes a bunch of image specs less fragile.
This commit is contained in:
parent
2914431729
commit
766e67ce57
@ -318,9 +318,13 @@ class OptimizedImage < ActiveRecord::Base
|
|||||||
convert_with(instructions, to, opts)
|
convert_with(instructions, to, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
MAX_PNGQUANT_SIZE = 500_000
|
||||||
|
|
||||||
def self.convert_with(instructions, to, opts = {})
|
def self.convert_with(instructions, to, opts = {})
|
||||||
Discourse::Utils.execute_command(*instructions)
|
Discourse::Utils.execute_command(*instructions)
|
||||||
FileHelper.optimize_image!(to)
|
|
||||||
|
allow_pngquant = to.downcase.ends_with?(".png") && File.size(to) < MAX_PNGQUANT_SIZE
|
||||||
|
FileHelper.optimize_image!(to, allow_pngquant: allow_pngquant)
|
||||||
true
|
true
|
||||||
rescue => e
|
rescue => e
|
||||||
if opts[:raise_on_error]
|
if opts[:raise_on_error]
|
||||||
|
@ -82,7 +82,12 @@ class FileHelper
|
|||||||
tmp
|
tmp
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.optimize_image!(filename)
|
def self.optimize_image!(filename, allow_pngquant: false)
|
||||||
|
pngquant_options = false
|
||||||
|
if allow_pngquant
|
||||||
|
pngquant_options = { allow_lossy: true }
|
||||||
|
end
|
||||||
|
|
||||||
ImageOptim.new(
|
ImageOptim.new(
|
||||||
# GLOBAL
|
# GLOBAL
|
||||||
timeout: 15,
|
timeout: 15,
|
||||||
@ -92,7 +97,7 @@ class FileHelper
|
|||||||
advpng: false,
|
advpng: false,
|
||||||
pngcrush: false,
|
pngcrush: false,
|
||||||
pngout: false,
|
pngout: false,
|
||||||
pngquant: false,
|
pngquant: pngquant_options,
|
||||||
# JPG
|
# JPG
|
||||||
jpegoptim: { strip: SiteSetting.strip_image_metadata ? "all" : "none" },
|
jpegoptim: { strip: SiteSetting.strip_image_metadata ? "all" : "none" },
|
||||||
jpegtran: false,
|
jpegtran: false,
|
||||||
|
BIN
spec/fixtures/images/pngquant.png
vendored
Normal file
BIN
spec/fixtures/images/pngquant.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
@ -98,6 +98,27 @@ RSpec.describe UploadCreator do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'pngquant' do
|
||||||
|
let(:filename) { "pngquant.png" }
|
||||||
|
let(:file) { file_from_fixtures(filename) }
|
||||||
|
|
||||||
|
it 'should apply pngquant to optimized images' do
|
||||||
|
upload = UploadCreator.new(file, filename,
|
||||||
|
pasted: true,
|
||||||
|
force_optimize: true
|
||||||
|
).create_for(user.id)
|
||||||
|
|
||||||
|
# no optimisation possible without losing details
|
||||||
|
expect(upload.filesize).to eq(9558)
|
||||||
|
|
||||||
|
thumbnail_size = upload.get_optimized_image(upload.width, upload.height, {}).filesize
|
||||||
|
|
||||||
|
# pngquant will lose some colors causing some extra size reduction
|
||||||
|
expect(thumbnail_size).to be < 7500
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
describe 'converting to jpeg' do
|
describe 'converting to jpeg' do
|
||||||
let(:filename) { "should_be_jpeg.png" }
|
let(:filename) { "should_be_jpeg.png" }
|
||||||
let(:file) { file_from_fixtures(filename) }
|
let(:file) { file_from_fixtures(filename) }
|
||||||
|
@ -6,7 +6,7 @@ describe OptimizedImage do
|
|||||||
|
|
||||||
unless ENV["TRAVIS"]
|
unless ENV["TRAVIS"]
|
||||||
describe '.crop' do
|
describe '.crop' do
|
||||||
it 'should work correctly (requires correct version of image optim)' do
|
it 'should produce cropped images' do
|
||||||
tmp_path = "/tmp/cropped.png"
|
tmp_path = "/tmp/cropped.png"
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -17,12 +17,15 @@ describe OptimizedImage do
|
|||||||
5
|
5
|
||||||
)
|
)
|
||||||
|
|
||||||
fixture_path = "#{Rails.root}/spec/fixtures/images/cropped.png"
|
# we don't want to deal with something new here every time image magick
|
||||||
fixture_hex = Digest::MD5.hexdigest(File.read(fixture_path))
|
# is upgraded or pngquant is upgraded, lets just test the basics ...
|
||||||
|
# cropped image should be less than 120 bytes
|
||||||
|
|
||||||
cropped_hex = Digest::MD5.hexdigest(File.read(tmp_path))
|
cropped_size = File.size(tmp_path)
|
||||||
|
|
||||||
|
expect(cropped_size).to be < 120
|
||||||
|
expect(cropped_size).to be > 50
|
||||||
|
|
||||||
expect(cropped_hex).to eq(fixture_hex)
|
|
||||||
ensure
|
ensure
|
||||||
File.delete(tmp_path) if File.exists?(tmp_path)
|
File.delete(tmp_path) if File.exists?(tmp_path)
|
||||||
end
|
end
|
||||||
@ -128,7 +131,7 @@ describe OptimizedImage do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe '.downsize' do
|
describe '.downsize' do
|
||||||
it 'should work correctly (requires correct version of image optim)' do
|
it 'should downsize logo' do
|
||||||
tmp_path = "/tmp/downsized.png"
|
tmp_path = "/tmp/downsized.png"
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -138,12 +141,10 @@ describe OptimizedImage do
|
|||||||
"100x100\>"
|
"100x100\>"
|
||||||
)
|
)
|
||||||
|
|
||||||
fixture_path = "#{Rails.root}/spec/fixtures/images/downsized.png"
|
info = FastImage.new(tmp_path)
|
||||||
fixture_hex = Digest::MD5.hexdigest(File.read(fixture_path))
|
expect(info.size).to eq([100, 27])
|
||||||
|
expect(File.size(tmp_path)).to be < 2300
|
||||||
|
|
||||||
downsized_hex = Digest::MD5.hexdigest(File.read(tmp_path))
|
|
||||||
|
|
||||||
expect(downsized_hex).to eq(fixture_hex)
|
|
||||||
ensure
|
ensure
|
||||||
File.delete(tmp_path) if File.exists?(tmp_path)
|
File.delete(tmp_path) if File.exists?(tmp_path)
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user