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
10 changes: 10 additions & 0 deletions doc/minimagick.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ It accepts the following special options:
* `:geometry` -- geometry that should be applied when loading
* `:auto_orient` -- whether the image should be automatically oriented after it's loaded (defaults to `true`)
* `:define` -- creates definitions that coders and decoders use for reading and writing image data
* `:inherit_fds` -- IO objects the command inherits, so the source may name one as `/dev/fd/N` and be read without a copy (requires mini_magick 5.4.0, and a system that exposes descriptors as `/dev/fd`)

```rb
ImageProcessing::MiniMagick.loader(loader: "jpg").call(image)
Expand All @@ -376,6 +377,15 @@ ImageProcessing::MiniMagick.loader(auto_orient: false).call(image)

ImageProcessing::MiniMagick.loader(define: { jpeg: { size: "300x300" } }).call(image)
# convert -define jpeg:size=300x300 input.jpg -auto-orient output.jpg

File.open("input.pdf", "rb") do |file|
ImageProcessing::MiniMagick
.source("/dev/fd/#{file.fileno}")
.loader(inherit_fds: [file], page: 0)
.convert("png")
.call
# convert /dev/fd/3[0] -auto-orient output.png
end
```

All other options given will be interpreted as ImageMagick operations to be
Expand Down
23 changes: 18 additions & 5 deletions lib/image_processing/mini_magick.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ module ImageProcessing
module MiniMagick
extend Chainable

def self.convert_shim(&block)
# mini_magick gained `inherit_fds:` on MiniMagick::Shell#execute in 5.4.0.
INHERIT_FDS_MINIMUM_VERSION = Gem::Version.new("5.4.0")

def self.convert_shim(inherit_fds: nil, &block)
if inherit_fds && ::MiniMagick.version < INHERIT_FDS_MINIMUM_VERSION
raise LoadError, "The `inherit_fds` loader option requires mini_magick #{INHERIT_FDS_MINIMUM_VERSION} or newer, but mini_magick #{::MiniMagick.version} is loaded. Please upgrade the gem."
end

options = inherit_fds ? { inherit_fds: inherit_fds } : {}

if ::MiniMagick.respond_to?(:convert)
::MiniMagick.convert(&block)
::MiniMagick.convert(**options, &block)
else
::MiniMagick::Tool::Convert.new(&block)
::MiniMagick::Tool::Convert.new(**options, &block)
end
end

Expand All @@ -37,12 +46,16 @@ class Processor < ImageProcessing::Processor
# Initializes the image on disk into a MiniMagick::Tool object. Accepts
# additional options related to loading the image (e.g. geometry).
# Additionally auto-orients the image to be upright.
def self.load_image(path_or_magick, loader: nil, page: nil, geometry: nil, auto_orient: true, **options)
# `inherit_fds` names IO objects the tool inherits, so the source may be a
# `/dev/fd/N` path. The source stays a path, so `loader`, `page` and
# `geometry` still apply to it, which they would not if the caller passed
# a pre-built MiniMagick::Tool carrying the descriptor.
def self.load_image(path_or_magick, loader: nil, page: nil, geometry: nil, auto_orient: true, inherit_fds: nil, **options)
if path_or_magick.is_a?(::MiniMagick::Tool)
magick = path_or_magick
else
source_path = path_or_magick
magick = ::ImageProcessing::MiniMagick.convert_shim
magick = ::ImageProcessing::MiniMagick.convert_shim(inherit_fds: inherit_fds)

Utils.apply_options(magick, **options)

Expand Down
62 changes: 62 additions & 0 deletions test/mini_magick_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
@square = fixture_image("square.jpg")
end

def with_mini_magick_version(version)
original = MiniMagick.method(:version)
MiniMagick.define_singleton_method(:version) { Gem::Version.new(version) }
yield
ensure
MiniMagick.define_singleton_method(:version, original)
end

it "applies imagemagick operations" do
actual = ImageProcessing::MiniMagick.flip.call(@portrait)
expected = Tempfile.new(["result", ".jpg"], binmode: true).tap do |tempfile|
Expand Down Expand Up @@ -66,6 +74,60 @@
refute_equal 0, processed.size
end

if MiniMagick.version >= ImageProcessing::MiniMagick::INHERIT_FDS_MINIMUM_VERSION
it "reads a source given as a descriptor named in inherit_fds" do
tiff = Tempfile.new(["file", ".tiff"])
ImageProcessing::MiniMagick.convert_shim do |convert|
convert.merge! [@portrait.path, @portrait.path, @portrait.path]
convert << tiff.path
end

File.open(tiff.path, "rb") do |file|
processed = ImageProcessing::MiniMagick
.source("/dev/fd/#{file.fileno}")
.loader(loader: "tiff", page: 0, inherit_fds: [file])
.convert!("jpg")

assert_equal 1, MiniMagick::Image.new(processed.path).pages.size
end
end

it "applies loader, page and geometry to a source named as an inherited descriptor" do
magick = ImageProcessing::MiniMagick
.source("/dev/fd/3")
.loader(inherit_fds: [@portrait], loader: "jpg", page: 0, geometry: "300x300")
.call(save: false)

assert_equal %W[jpg:/dev/fd/3[0][300x300] -auto-orient], magick.args
end
else
it "tells the caller to upgrade when the installed mini_magick predates inherit_fds" do
error = assert_raises(LoadError) do
ImageProcessing::MiniMagick
.source(@portrait)
.loader(inherit_fds: [@portrait])
.convert!("jpg")
end

assert_includes error.message, MiniMagick.version.to_s
assert_includes error.message, "5.4.0"
end
end

it "names both the required and the running mini_magick version when it predates inherit_fds" do
error = assert_raises(LoadError) do
with_mini_magick_version("5.3.3") do
ImageProcessing::MiniMagick
.source(@portrait)
.loader(inherit_fds: [@portrait])
.convert!("jpg")
end
end

assert_includes error.message, "5.3.3"
assert_includes error.message, "5.4.0"
end

it "disallows split layers by default" do
tiff = Tempfile.new(["file", ".tiff"])
ImageProcessing::MiniMagick.convert_shim do |convert|
Expand Down
Loading