Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow quality setting for webp images #2674

Merged
merged 2 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions app/models/alchemy/picture_variant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class PictureVariant

ANIMATED_IMAGE_FORMATS = %w[gif webp]
TRANSPARENT_IMAGE_FORMATS = %w[gif webp png]
ENCODABLE_IMAGE_FORMATS = %w[jpg jpeg webp]

attr_reader :picture, :render_format

Expand Down Expand Up @@ -95,8 +96,8 @@ def encoded_image(image, options = {})

convert_format = render_format.sub("jpeg", "jpg") != picture.image_file_format.sub("jpeg", "jpg")

if render_format =~ /jpe?g/ && (convert_format || options[:quality])
quality = options[:quality] || Config.get(:output_image_jpg_quality)
if encodable_image? && (convert_format || options[:quality])
quality = options[:quality] || Config.get(:output_image_quality)
encoding_options << "-quality #{quality}"
end

Expand All @@ -115,5 +116,9 @@ def encoded_image(image, options = {})

image
end

def encodable_image?
render_format.in?(ENCODABLE_IMAGE_FORMATS)
end
end
end
21 changes: 11 additions & 10 deletions config/alchemy/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ items_per_page: 15
#
# ==== Global Options:
#
# output_image_jpg_quality [Integer] # If image gets rendered as JPG this is the quality setting for it. (Default 85)
# output_image_quality [Integer] # If image gets rendered as JPG or WebP this is the quality setting for it. (Default 85)
# preprocess_image_resize [String] # Use this option to resize images to the given size when they are uploaded to the image library. Downsizing example: '1000x1000>' (Default nil)
# image_output_format [String] # The global image output format setting. (Default +original+)
#
# NOTE: You can always override the output format in the settings of your ingredients in elements.yml, I.E. {format: 'gif'}
#
output_image_jpg_quality: 85
output_image_quality: 85
preprocess_image_resize:
image_output_format: original

Expand Down Expand Up @@ -133,7 +133,8 @@ mailer:
mail_from: [email protected]
mail_to: [email protected]
subject: A new contact form message
fields: [salutation, firstname, lastname, address, zip, city, phone, email, message]
fields:
[salutation, firstname, lastname, address, zip, city, phone, email, message]
validate_fields: [lastname, email]

# === User roles
Expand Down Expand Up @@ -166,14 +167,14 @@ uploader:
file_size_limit: 100
allowed_filetypes:
alchemy/attachments:
- '*'
- "*"
alchemy/pictures:
- jpg
- jpeg
- gif
- png
- svg
- webp
- jpg
- jpeg
- gif
- png
- svg
- webp

# === Link Target Options
#
Expand Down
26 changes: 24 additions & 2 deletions lib/alchemy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class << self
#
def get(name)
check_deprecation(name)
show[name.to_s]
key = check_replacement(name)
show[key.to_s]
end

alias_method :parameter, :get
Expand All @@ -27,13 +28,20 @@ def show
@config ||= merge_configs!(alchemy_config, main_app_config, env_specific_config)
end

# A list of deprecated configurations
# A list of deprecated configuration values
# a value of nil means there is no new default
# any not nil value is the new default
def deprecated_configs
{}
end

# A list of replaced configuration keys
def replaced_config_keys
{
output_image_quality: :output_image_jpg_quality
}
end

private

# Alchemy default configuration
Expand Down Expand Up @@ -87,6 +95,20 @@ def check_deprecation(name)
end
end
end

def check_replacement(name)
if replaced_config_keys.key?(name.to_sym)
old_key = replaced_config_keys[name.to_sym]
if show[old_key.to_s]
Alchemy::Deprecation.warn("Using #{old_key} configuration is deprecated and will be removed in Alchemy #{Alchemy::Deprecation.deprecation_horizon}. Please use #{name} instead.")
old_key
else
name
end
else
name
end
end
end
end
end
37 changes: 37 additions & 0 deletions spec/libraries/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,43 @@ module Alchemy
end
end
end

context "if config has been replaced" do
context "with a new default" do
before do
expect(described_class).to receive(:replaced_config_keys).at_least(:once) do
{foo: :bar}
end
end

context "and config uses old key" do
before do
expect(described_class).to receive(:show).at_least(:once) do
{"bar" => :baz}
end
end

it "warns about new key and returns old value" do
expect(Alchemy::Deprecation).to \
receive(:warn).with("Using bar configuration is deprecated and will be removed in Alchemy #{Alchemy::Deprecation.deprecation_horizon}. Please use foo instead.")
expect(Config.get(:foo)).to eq(:baz)
end
end

context "and config uses new key" do
before do
expect(described_class).to receive(:show).at_least(:once) do
{"foo" => :bar}
end
end

it "warns about new key and returns old value" do
expect(Alchemy::Deprecation).to_not receive(:warn)
expect(Config.get(:foo)).to eq(:bar)
end
end
end
end
end

describe ".main_app_config" do
Expand Down
86 changes: 85 additions & 1 deletion spec/models/alchemy/picture_variant_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
it "does not flatten the image." do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq(["webp", ""])
expect(step.arguments).to eq(["webp", "-quality 85"])
end
end
end
Expand Down Expand Up @@ -317,6 +317,90 @@
end
end
end

context "and image has webp format" do
let(:image_file) do
File.new(File.expand_path("../../fixtures/image5.webp", __dir__))
end

let(:alchemy_picture) do
build_stubbed(:alchemy_picture, image_file: image_file, image_file_format: "webp")
end

let(:options) do
{format: format}
end

it "converts the picture into #{format}" do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq([format, "-quality 85"])
end

context "and quality is passed in options" do
let(:options) do
{format: format, quality: "30"}
end

it "sets the quality as well" do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq([format, "-quality 30"])
end
end
end
end
end

context "when webp format is requested" do
let(:options) do
{format: "webp"}
end

context "and the image file format is not WebP" do
it "converts image into webp and sets the default quality" do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq(["webp", "-quality 85"])
end

context "but quality is passed" do
let(:options) do
{format: "webp", quality: "30"}
end

it "converts with given quality" do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq(["webp", "-quality 30"])
end
end
end

context "and image already has webp format" do
let(:image_file) do
File.new(File.expand_path("../../fixtures/image5.webp", __dir__))
end

let(:alchemy_picture) do
build_stubbed(:alchemy_picture, image_file: image_file, image_file_format: "webp")
end

it "does not convert the picture format" do
expect(subject).to_not respond_to(:steps)
end

context "and quality is passed in options" do
let(:options) do
{format: "webp", quality: "30"}
end

it "converts to given quality" do
step = subject.steps[0]
expect(step.name).to eq(:encode)
expect(step.arguments).to eq(["webp", "-quality 30"])
end
end
end
end
end
Loading