riiif 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ruby.yml +7 -4
- data/Gemfile +2 -5
- data/README.md +10 -0
- data/app/extractors/riiif/image_magick_info_extractor.rb +1 -1
- data/app/extractors/riiif/vips_info_extractor.rb +9 -8
- data/app/services/riiif/imagemagick_command_factory.rb +5 -0
- data/app/transformers/riiif/vips_transformer.rb +1 -0
- data/lib/riiif/engine.rb +3 -0
- data/lib/riiif/version.rb +1 -1
- data/lib/riiif.rb +4 -0
- data/riiif.gemspec +1 -0
- data/spec/extractors/riiif/image_magick_info_extractor_spec.rb +9 -0
- data/spec/extractors/riiif/vips_info_extractor_spec.rb +19 -18
- data/spec/models/riiif/image_spec.rb +15 -2
- data/spec/services/riiif/imagemagick_command_factory_spec.rb +15 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/transformers/riiif/vips_transformer_spec.rb +19 -1
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9993f1679d618e86c346172bc70c57947d1fcf8d06ee7c704981b099270fe605
|
|
4
|
+
data.tar.gz: dab42c9074cf26db432fca000121fcf54772cd03d80d05cbfbdb38ca9b53ae40
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 162484c5fa19da91a13ba5168e0902f7ccaa315026299eca14f7556abee5b2c00d7d1667cd840dff77156089f355230f763460cc9a761071d9eb277c51394a74
|
|
7
|
+
data.tar.gz: 68d5b87acb4e5d19efff588dbdc5a352e839529be45bff33a58443497f0939dc94a30001ff95cb3be37d52c99090b5c3b49f70638902f047e8a78c9960e969ba
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -18,12 +18,15 @@ jobs:
|
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
strategy:
|
|
20
20
|
matrix:
|
|
21
|
-
ruby: ["3.2", "3.3"]
|
|
22
|
-
rails: ["8.
|
|
21
|
+
ruby: ["3.2", "3.3", "3.4"]
|
|
22
|
+
rails: ["8.1.1", "8.0.4", "7.2.3"]
|
|
23
23
|
steps:
|
|
24
24
|
- name: Install ImageMagick
|
|
25
|
-
run:
|
|
26
|
-
|
|
25
|
+
run: |
|
|
26
|
+
sudo rm -f /var/lib/man-db/auto-update
|
|
27
|
+
sudo apt-get update
|
|
28
|
+
sudo apt-get install -y --no-install-recommends imagemagick
|
|
29
|
+
- uses: actions/checkout@v7
|
|
27
30
|
- name: Set up Ruby
|
|
28
31
|
uses: ruby/setup-ruby@v1
|
|
29
32
|
with:
|
data/Gemfile
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
-
gem 'byebug'
|
|
4
3
|
# Specify your gem's dependencies in riiif.gemspec
|
|
5
4
|
gemspec
|
|
6
5
|
|
|
7
6
|
# BEGIN ENGINE_CART BLOCK
|
|
8
|
-
# engine_cart: 2.0
|
|
9
|
-
# engine_cart stanza:
|
|
7
|
+
# engine_cart: 2.6.0
|
|
8
|
+
# engine_cart stanza: 2.5.0
|
|
10
9
|
# the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
|
|
11
10
|
file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', File.dirname(__FILE__)))
|
|
12
11
|
if File.exist?(file)
|
|
@@ -27,7 +26,5 @@ else
|
|
|
27
26
|
gem 'rails', ENV['RAILS_VERSION']
|
|
28
27
|
end
|
|
29
28
|
end
|
|
30
|
-
|
|
31
|
-
gem 'sass-rails', '~> 5.0'
|
|
32
29
|
end
|
|
33
30
|
# END ENGINE_CART BLOCK
|
data/README.md
CHANGED
|
@@ -102,6 +102,16 @@ To use [libvips](https://www.libvips.org/) instead of ImageMagick
|
|
|
102
102
|
Riiif::Engine.config.use_vips = true
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
### EXIF orientation
|
|
106
|
+
|
|
107
|
+
By default, derivatives and `info.json` dimensions use the raw stored pixels and ignore the EXIF Orientation tag. To apply it (as browsers and thumbnailers do):
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
Riiif::Engine.config.autorotate = true
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This works with ImageMagick and libvips. Cached derivatives and `info.json` need to be cleared after changing it.
|
|
114
|
+
|
|
105
115
|
## Usage
|
|
106
116
|
|
|
107
117
|
Add the routes to your application by inserting the following line into `config/routes.rb`
|
|
@@ -6,7 +6,7 @@ module Riiif
|
|
|
6
6
|
|
|
7
7
|
def extract
|
|
8
8
|
height, width, format, channels = Riiif::CommandRunner.execute(
|
|
9
|
-
"#{external_command} -format '%h %w %m %[channels]' '#{@path}[0]'"
|
|
9
|
+
"#{external_command}#{' -auto-orient' if Riiif.autorotate?} -format '%h %w %m %[channels]' '#{@path}[0]'"
|
|
10
10
|
).split(' ')
|
|
11
11
|
|
|
12
12
|
{
|
|
@@ -6,16 +6,17 @@ module Riiif
|
|
|
6
6
|
self.external_command = 'vipsheader'
|
|
7
7
|
|
|
8
8
|
def extract
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
vipsloader = Riiif::CommandRunner.execute(
|
|
10
|
+
"#{external_command} -f vips-loader '#{@path}'"
|
|
11
|
+
).strip
|
|
12
|
+
image = ::Vips::Image.new_from_file(@path.to_s)
|
|
13
|
+
image = image.autorot if Riiif.autorotate?
|
|
13
14
|
|
|
14
15
|
{
|
|
15
|
-
height:
|
|
16
|
-
width:
|
|
17
|
-
format:
|
|
18
|
-
channels:
|
|
16
|
+
height: image.height,
|
|
17
|
+
width: image.width,
|
|
18
|
+
format: vipsloader.match?("pngload") ? "PNG" : "JPEG",
|
|
19
|
+
channels: image.has_alpha? ? "srgba" : "srgb"
|
|
19
20
|
}
|
|
20
21
|
end
|
|
21
22
|
end
|
|
@@ -29,6 +29,7 @@ module Riiif
|
|
|
29
29
|
def command
|
|
30
30
|
[
|
|
31
31
|
external_command,
|
|
32
|
+
auto_orient,
|
|
32
33
|
crop,
|
|
33
34
|
size,
|
|
34
35
|
rotation,
|
|
@@ -79,6 +80,10 @@ module Riiif
|
|
|
79
80
|
end
|
|
80
81
|
end
|
|
81
82
|
|
|
83
|
+
def auto_orient
|
|
84
|
+
' -auto-orient' if Riiif.autorotate?
|
|
85
|
+
end
|
|
86
|
+
|
|
82
87
|
def crop
|
|
83
88
|
directive = Crop.new(transformation.region, info).to_imagemagick
|
|
84
89
|
" -crop #{directive}" if directive
|
|
@@ -15,6 +15,7 @@ module Riiif
|
|
|
15
15
|
def initialize(path, image_info, transformation, compression: 85, subsample: true, strip_metadata: true)
|
|
16
16
|
super(path, image_info, transformation)
|
|
17
17
|
@image = ::Vips::Image.new_from_file(path.to_s)
|
|
18
|
+
@image = @image.autorot if Riiif.autorotate?
|
|
18
19
|
@compression = compression
|
|
19
20
|
@subsample = subsample
|
|
20
21
|
@strip_metadata = strip_metadata
|
data/lib/riiif/engine.rb
CHANGED
|
@@ -15,6 +15,9 @@ module Riiif
|
|
|
15
15
|
# https://www.libvips.org/
|
|
16
16
|
config.use_vips = false
|
|
17
17
|
|
|
18
|
+
# Set to true to apply EXIF orientation to derivatives and reported dimensions
|
|
19
|
+
config.autorotate = false
|
|
20
|
+
|
|
18
21
|
config.before_configuration do
|
|
19
22
|
# see https://github.com/fxn/zeitwerk#for_gem
|
|
20
23
|
# We put a generator into LOCAL APP lib/generators, so tell
|
data/lib/riiif/version.rb
CHANGED
data/lib/riiif.rb
CHANGED
data/riiif.gemspec
CHANGED
|
@@ -3,6 +3,15 @@ RSpec.describe Riiif::ImageMagickInfoExtractor do
|
|
|
3
3
|
expect(described_class.external_command).to eq "identify"
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
+
context 'when autorotate is enabled' do
|
|
7
|
+
before { allow(Riiif).to receive(:autorotate?).and_return(true) }
|
|
8
|
+
|
|
9
|
+
it 'asks identify to auto-orient' do
|
|
10
|
+
expect(Riiif::CommandRunner).to receive(:execute).with(/\Aidentify -auto-orient /).and_return('376 500 JPEG srgb')
|
|
11
|
+
expect(described_class.new('x.jpg').extract).to include(width: 500, height: 376)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
6
15
|
context 'with a jpg' do
|
|
7
16
|
let(:image) { Rails.root.join("spec", "fixtures", "test.jpg") }
|
|
8
17
|
|
|
@@ -6,15 +6,9 @@ RSpec.describe Riiif::VipsInfoExtractor do
|
|
|
6
6
|
allow(Vips::Image).to receive(:new_from_file).and_return(image)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
let(:image) { double(has_alpha?: false) }
|
|
10
|
-
|
|
11
|
-
let(:fake_info)
|
|
12
|
-
"width: 500
|
|
13
|
-
height: 376
|
|
14
|
-
interpretation: srgb
|
|
15
|
-
filename: spec/fixtures/test.tif
|
|
16
|
-
vips-loader: tiffload"
|
|
17
|
-
end
|
|
9
|
+
let(:image) { double(has_alpha?: false, width: 500, height: 376) }
|
|
10
|
+
|
|
11
|
+
let(:fake_info) { "tiffload" }
|
|
18
12
|
|
|
19
13
|
it 'uses vipsheader as its external command' do
|
|
20
14
|
expect(described_class.external_command).to eq "vipsheader"
|
|
@@ -31,16 +25,23 @@ RSpec.describe Riiif::VipsInfoExtractor do
|
|
|
31
25
|
end
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
context '
|
|
35
|
-
let(:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
context 'when autorotate is enabled' do
|
|
29
|
+
let(:oriented) { double(has_alpha?: false, width: 376, height: 500) }
|
|
30
|
+
|
|
31
|
+
before do
|
|
32
|
+
allow(Riiif).to receive(:autorotate?).and_return(true)
|
|
33
|
+
allow(image).to receive(:autorot).and_return(oriented)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'reports the dimensions after orientation is applied' do
|
|
37
|
+
expect(described_class.new("path/to/image.jpg").extract).to include(width: 376, height: 500)
|
|
43
38
|
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'on a file with transparency' do
|
|
42
|
+
let(:image) { double(has_alpha?: true, width: 50, height: 50) }
|
|
43
|
+
|
|
44
|
+
let(:fake_info) { "pngload" }
|
|
44
45
|
|
|
45
46
|
it 'returns the extracted attributes' do
|
|
46
47
|
expect(described_class.new(image).extract).to eq({
|
|
@@ -58,8 +58,21 @@ RSpec.describe Riiif::Image do
|
|
|
58
58
|
|
|
59
59
|
describe 'get info' do
|
|
60
60
|
subject { described_class.new('Cave_26,_Ajanta') }
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
|
|
62
|
+
before do
|
|
63
|
+
stub_request(:get, "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Cave_26,_Ajanta.jpg/600px-Cave_26,_Ajanta.jpg")
|
|
64
|
+
.with(
|
|
65
|
+
headers: {
|
|
66
|
+
'Accept' => '*/*',
|
|
67
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
|
68
|
+
'User-Agent' => 'Ruby'
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
.to_return(status: 200, body: File.binread('spec/fixtures/test.jpg'), headers: {})
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'gets the info' do
|
|
75
|
+
expect(subject.info).to eq Riiif::ImageInformation.new(width: 300, height: 397)
|
|
63
76
|
end
|
|
64
77
|
end
|
|
65
78
|
|
|
@@ -16,6 +16,21 @@ RSpec.describe Riiif::ImagemagickCommandFactory do
|
|
|
16
16
|
format: target)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
context 'with autorotate' do
|
|
20
|
+
subject { described_class.new(tiff, info, transformation).command }
|
|
21
|
+
|
|
22
|
+
let(:source) { 'tif' }
|
|
23
|
+
let(:target) { 'jpg' }
|
|
24
|
+
|
|
25
|
+
it { is_expected.not_to match(/-auto-orient/) }
|
|
26
|
+
|
|
27
|
+
context 'when enabled' do
|
|
28
|
+
before { allow(Riiif).to receive(:autorotate?).and_return(true) }
|
|
29
|
+
|
|
30
|
+
it { is_expected.to match(/convert -auto-orient /) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
19
34
|
context "when the target format is jpeg" do
|
|
20
35
|
subject { described_class.new(tiff, info, transformation).command }
|
|
21
36
|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -49,9 +49,27 @@ RSpec.describe Riiif::VipsTransformer do
|
|
|
49
49
|
let(:path) { Pathname.new("path/to/image.tif") }
|
|
50
50
|
|
|
51
51
|
it 'normalizes pathnames to strings' do
|
|
52
|
-
expect(Vips::Image).to receive(:new_from_file).with("path/to/image.tif")
|
|
52
|
+
expect(Vips::Image).to receive(:new_from_file).with("path/to/image.tif").and_return(image)
|
|
53
53
|
described_class.new(path, image_info, transformation)
|
|
54
54
|
end
|
|
55
|
+
|
|
56
|
+
it 'does not apply EXIF orientation by default' do
|
|
57
|
+
expect(image).not_to receive(:autorot)
|
|
58
|
+
expect(described_class.new(path, image_info, transformation).image).to eq image
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'when autorotate is enabled' do
|
|
62
|
+
let(:oriented) { double('Oriented Vips Image', has_alpha?: false) }
|
|
63
|
+
|
|
64
|
+
before do
|
|
65
|
+
allow(Riiif).to receive(:autorotate?).and_return(true)
|
|
66
|
+
allow(image).to receive(:autorot).and_return(oriented)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'applies the EXIF orientation to the source image' do
|
|
70
|
+
expect(described_class.new(path, image_info, transformation).image).to eq oriented
|
|
71
|
+
end
|
|
72
|
+
end
|
|
55
73
|
end
|
|
56
74
|
|
|
57
75
|
describe '#transform' do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: riiif
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Coyne
|
|
@@ -169,6 +169,20 @@ dependencies:
|
|
|
169
169
|
- - ">="
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
171
|
version: '0'
|
|
172
|
+
- !ruby/object:Gem::Dependency
|
|
173
|
+
name: webmock
|
|
174
|
+
requirement: !ruby/object:Gem::Requirement
|
|
175
|
+
requirements:
|
|
176
|
+
- - ">="
|
|
177
|
+
- !ruby/object:Gem::Version
|
|
178
|
+
version: '0'
|
|
179
|
+
type: :development
|
|
180
|
+
prerelease: false
|
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0'
|
|
172
186
|
description: A IIIF image server
|
|
173
187
|
email:
|
|
174
188
|
- jcoyne85@stanford.edu
|
|
@@ -176,6 +190,7 @@ executables: []
|
|
|
176
190
|
extensions: []
|
|
177
191
|
extra_rdoc_files: []
|
|
178
192
|
files:
|
|
193
|
+
- ".github/dependabot.yml"
|
|
179
194
|
- ".github/workflows/ruby.yml"
|
|
180
195
|
- ".gitignore"
|
|
181
196
|
- ".rspec"
|
|
@@ -257,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
257
272
|
- !ruby/object:Gem::Version
|
|
258
273
|
version: '0'
|
|
259
274
|
requirements: []
|
|
260
|
-
rubygems_version:
|
|
275
|
+
rubygems_version: 4.0.22
|
|
261
276
|
specification_version: 4
|
|
262
277
|
summary: A Rails engine that support IIIF requests
|
|
263
278
|
test_files:
|