riiif 2.8.1 → 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/workflows/ruby.yml +5 -2
- 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 +16 -37
- 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 +16 -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
|
@@ -22,8 +22,11 @@ jobs:
|
|
|
22
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/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) }
|
|
9
|
+
let(:image) { double(has_alpha?: false, width: 500, height: 376) }
|
|
10
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
|
|
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,45 +25,30 @@ RSpec.describe Riiif::VipsInfoExtractor do
|
|
|
31
25
|
end
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
context '
|
|
35
|
-
let(:
|
|
28
|
+
context 'when autorotate is enabled' do
|
|
29
|
+
let(:oriented) { double(has_alpha?: false, width: 376, height: 500) }
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
interpretation: srgb
|
|
41
|
-
filename: spec/fixtures/test.tif
|
|
42
|
-
vips-loader: pngload"
|
|
31
|
+
before do
|
|
32
|
+
allow(Riiif).to receive(:autorotate?).and_return(true)
|
|
33
|
+
allow(image).to receive(:autorot).and_return(oriented)
|
|
43
34
|
end
|
|
44
35
|
|
|
45
|
-
it '
|
|
46
|
-
expect(described_class.new(image).extract).to
|
|
47
|
-
height: 50,
|
|
48
|
-
width: 50,
|
|
49
|
-
format: "PNG",
|
|
50
|
-
channels: "srgba"
|
|
51
|
-
})
|
|
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)
|
|
52
38
|
end
|
|
53
39
|
end
|
|
54
40
|
|
|
55
|
-
context 'on a
|
|
56
|
-
let(:image) { double(has_alpha?:
|
|
41
|
+
context 'on a file with transparency' do
|
|
42
|
+
let(:image) { double(has_alpha?: true, width: 50, height: 50) }
|
|
57
43
|
|
|
58
|
-
let(:fake_info)
|
|
59
|
-
"width: 150
|
|
60
|
-
height: 150
|
|
61
|
-
interpretation: srgb
|
|
62
|
-
filename: spec/fixtures/test.jpeg
|
|
63
|
-
vips-loader: jpegload
|
|
64
|
-
exif-ifd0-Artist: University Library (Digital Object: Digital Media Group)"
|
|
65
|
-
end
|
|
44
|
+
let(:fake_info) { "pngload" }
|
|
66
45
|
|
|
67
46
|
it 'returns the extracted attributes' do
|
|
68
47
|
expect(described_class.new(image).extract).to eq({
|
|
69
|
-
height:
|
|
70
|
-
width:
|
|
71
|
-
format: "
|
|
72
|
-
channels: "
|
|
48
|
+
height: 50,
|
|
49
|
+
width: 50,
|
|
50
|
+
format: "PNG",
|
|
51
|
+
channels: "srgba"
|
|
73
52
|
})
|
|
74
53
|
end
|
|
75
54
|
end
|
|
@@ -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
|
|
@@ -258,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
258
272
|
- !ruby/object:Gem::Version
|
|
259
273
|
version: '0'
|
|
260
274
|
requirements: []
|
|
261
|
-
rubygems_version: 4.0.
|
|
275
|
+
rubygems_version: 4.0.22
|
|
262
276
|
specification_version: 4
|
|
263
277
|
summary: A Rails engine that support IIIF requests
|
|
264
278
|
test_files:
|