Skip to content
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
1 change: 1 addition & 0 deletions lib/dynamic_image/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class InvalidSignature < DynamicImage::Errors::Error; end
# the size works out to less than a pixel, as <tt>"0x0"</tt> does, or <tt>"1x1"</tt> against a very wide image.
#
# @see DynamicImage::ImageSizing#fit
# @see DynamicImage::Model::Transformations#resize
class InvalidSizeOptions < DynamicImage::Errors::Error; end

# Raised when a transformation can't be applied, either because a rotation isn't a multiple of 90 degrees or
Expand Down
17 changes: 16 additions & 1 deletion lib/dynamic_image/model/transformations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ module Transformations
# @param max_size [Vector2d, String] the size to fit within, either a vector or a <tt>"{width}x{height}"</tt>
# string. Either dimension may be omitted to scale by the other alone.
# @return [self]
# @raise [DynamicImage::Errors::InvalidSizeOptions] if the result is less than a pixel in either dimension
# @raise [DynamicImage::Errors::InvalidImage] if the stored data can't be processed
def resize(max_size)
transform_image do |image|
resized = image.resize(real_size.fit(max_size))
resized = image.resize(fit_size(max_size))
scale_crop(resized.size)
resized
end
Expand All @@ -30,6 +32,7 @@ def resize(max_size)
# @param degrees [Integer] the angle, which must be a multiple of 90. Rotating by 0 is a no-op.
# @return [self]
# @raise [DynamicImage::Errors::InvalidTransformation] if the angle isn't a multiple of 90
# @raise [DynamicImage::Errors::InvalidImage] if the stored data can't be processed
#
# @example
# image.rotate(90)
Expand All @@ -52,6 +55,16 @@ def rotate(degrees = 90)

private

# Scales +max_size+ against the image, rejecting a result smaller than a pixel in either dimension, as
# {DynamicImage::ImageSizing#fit} does for the sizes rendered on request.
def fit_size(max_size)
new_size = real_size.fit(max_size)
return new_size if new_size.x >= 1 && new_size.y >= 1

raise DynamicImage::Errors::InvalidSizeOptions,
"#{new_size} has a dimension smaller than one pixel"
end

def scale_crop(new_size)
scale = new_size.to_f_vector / real_size

Expand Down Expand Up @@ -121,6 +134,8 @@ def transform_image(&block)
end
read_image_metadata
self
rescue Vips::Error => e
raise DynamicImage::Errors::InvalidImage, e.message
end
end
end
Expand Down
32 changes: 32 additions & 0 deletions spec/dynamic_image/model/transformations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,27 @@
expect(resized.crop_gravity).to eq(Vector2d(1, 1))
end
end

context "when the size is smaller than a pixel" do
subject(:resized) { image.resize("0x0") }

it "raises an error" do
expect { resized }.to(
raise_error(DynamicImage::Errors::InvalidSizeOptions)
)
end
end

context "when vips fails to process the data" do
before do
allow(DynamicImage::ImageProcessor)
.to receive(:new).and_raise(Vips::Error, "unable to read")
end

it "raises an error" do
expect { resized }.to raise_error(DynamicImage::Errors::InvalidImage)
end
end
end

describe "#rotate" do
Expand All @@ -96,6 +117,17 @@
end
end

context "when vips fails to process the data" do
before do
allow(DynamicImage::ImageProcessor)
.to receive(:new).and_raise(Vips::Error, "unable to read")
end

it "raises an error" do
expect { rotated }.to raise_error(DynamicImage::Errors::InvalidImage)
end
end

context "with a 90 degree rotation" do
it "rotates the image" do
expect(rotated.real_size).to eq(Vector2d.new(200, 320))
Expand Down
Loading