Skip to content

Commit d49df1c

Browse files
committed
Add analyze methods for getting metadata
Besides processing images it would be nice to analyze images as well to get metadata like: width, height and rotation. This is currently based on the ActiveStorage::Analyzer::ImageAnalyzer.
1 parent 709bcf7 commit d49df1c

File tree

6 files changed

+92
-0
lines changed

6 files changed

+92
-0
lines changed

lib/image_processing.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "image_processing/chainable"
22
require "image_processing/builder"
33
require "image_processing/pipeline"
4+
require "image_processing/analyzer"
45
require "image_processing/processor"
56
require "image_processing/version"
67

lib/image_processing/analyzer.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module ImageProcessing
2+
# Abstract class inherited by individual analyzers.
3+
class Analyzer
4+
def initialize(image)
5+
@image = image
6+
end
7+
8+
def analyze
9+
{ width: @image.width, height: @image.height, rotated: rotated? }
10+
end
11+
end
12+
end

lib/image_processing/mini_magick.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ def self.valid_image?(file)
1616
false
1717
end
1818

19+
def self.analyze(file)
20+
if valid_image?(file)
21+
image = ::MiniMagick::Image.new(file.path)
22+
Analyzer.new(image).analyze
23+
else
24+
{}
25+
end
26+
end
27+
28+
class Analyzer < ImageProcessing::Analyzer
29+
ROTATIONS = %w[ RightTop LeftBottom TopRight BottomLeft ]
30+
31+
private
32+
33+
def rotated?
34+
ROTATIONS.include?(@image["%[orientation]"])
35+
rescue ::MiniMagick::Error
36+
false
37+
end
38+
end
39+
1940
class Processor < ImageProcessing::Processor
2041
accumulator :magick, ::MiniMagick::Tool
2142

lib/image_processing/vips.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
module ImageProcessing
77
module Vips
88
extend Chainable
9+
ROTATIONS = /Right-top|Left-bottom|Top-right|Bottom-left/
910

1011
# Returns whether the given image file is processable.
1112
def self.valid_image?(file)
@@ -15,6 +16,27 @@ def self.valid_image?(file)
1516
false
1617
end
1718

19+
def self.analyze(file)
20+
if valid_image?(file)
21+
image = ::Vips::Image.new_from_file(file.path, access: :sequential)
22+
Analyzer.new(image).analyze
23+
else
24+
{}
25+
end
26+
end
27+
28+
class Analyzer < ImageProcessing::Analyzer
29+
ROTATIONS = /Right-top|Left-bottom|Top-right|Bottom-left/
30+
31+
private
32+
33+
def rotated?
34+
ROTATIONS === @image.get("exif-ifd0-Orientation")
35+
rescue ::Vips::Error
36+
false
37+
end
38+
end
39+
1840
class Processor < ImageProcessing::Processor
1941
accumulator :image, ::Vips::Image
2042

test/mini_magick_test.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,24 @@
106106
assert_dimensions [300, 400], pipeline.loader(geometry: "400x400").call
107107
end unless ENV["GM"]
108108

109+
it "analyzes the image" do
110+
result = ImageProcessing::MiniMagick.analyze(@portrait)
111+
expected = { width: 600, height: 800, rotated: false }
112+
assert_equal expected, result
113+
end
114+
115+
it "analyzes the rotated image" do
116+
result = ImageProcessing::MiniMagick.analyze(fixture_image("rotated.jpg"))
117+
expected = { width: 800, height: 600, rotated: true }
118+
assert_equal expected, result
119+
end
120+
121+
it "does not analyze an invalid image" do
122+
result = ImageProcessing::MiniMagick.analyze(fixture_image("invalid.jpg"))
123+
expected = {}
124+
assert_equal expected, result
125+
end
126+
109127
it "auto orients by default" do
110128
result = ImageProcessing::MiniMagick.call(fixture_image("rotated.jpg"))
111129
assert_dimensions [600, 800], result

test/vips_test.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@
7676
assert_dimensions [600, 800], result
7777
end
7878

79+
it "analyzes a image" do
80+
result = ImageProcessing::Vips.analyze(@portrait)
81+
expected = { width: 600, height: 800, rotated: false }
82+
assert_equal expected, result
83+
end
84+
85+
it "analyzes a rotated image" do
86+
result = ImageProcessing::Vips.analyze(fixture_image("rotated.jpg"))
87+
expected = { width: 800, height: 600, rotated: true }
88+
assert_equal expected, result
89+
end
90+
91+
it "does not analyze an invalid image" do
92+
result = ImageProcessing::Vips.analyze(fixture_image("invalid.jpg"))
93+
expected = {}
94+
assert_equal expected, result
95+
end
96+
7997
it "applies loader options" do
8098
result = ImageProcessing::Vips.loader(shrink: 2).call(@portrait)
8199
assert_dimensions [300, 400], result

0 commit comments

Comments
 (0)