assembly-image 1.8.0 → 2.1.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/.circleci/config.yml +4 -1
- data/.gitignore +2 -1
- data/.rubocop.yml +23 -5
- data/.rubocop_todo.yml +11 -51
- data/.rvmrc.example +1 -1
- data/Gemfile.lock +105 -0
- data/README.md +15 -58
- data/assembly-image.gemspec +4 -5
- data/bin/console +1 -1
- data/config/boot.rb +2 -2
- data/lib/assembly/image/jp2_creator.rb +127 -0
- data/lib/assembly/image.rb +58 -0
- data/lib/assembly-image.rb +5 -3
- data/profiles/cmyk.icc +0 -0
- data/spec/assembly/image/jp2_creator_spec.rb +327 -38
- data/spec/assembly/image_spec.rb +25 -0
- data/spec/spec_helper.rb +115 -29
- data/spec/test_data/color_rgb_srgb_rot90cw.tif +0 -0
- metadata +39 -38
- data/bin/run_all_tests +0 -3
- data/lib/assembly-image/image.rb +0 -162
- data/lib/assembly-image/images.rb +0 -107
- data/lib/assembly-image/jp2_creator.rb +0 -182
- data/lib/assembly-image/version.rb +0 -10
- data/spec/image_spec.rb +0 -279
- data/spec/images_spec.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '088a4b9c59b50f893f7b50c16898321770006b4ab22dc08a8ddd70cdba9a15da'
|
4
|
+
data.tar.gz: f22bf6d6acbd4d6885e2102526e7c5e0ac76b93af71eff0d2237d32334afd223
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91f0be3622982ad69823a45eca8111d05756e0442cd7d7aa16cb8099e71ee2e95c21f17c7f14b7ccab04c11724233c9a9739e24f8b8302f07f42b16738c6400e
|
7
|
+
data.tar.gz: d1ab206c475413496a6add9376cb246705df18a3142bdc32189b202e31af698b8cfded84464d00e94357fc08396ab142270043b3b862cc0d68cd57834863b649
|
data/.circleci/config.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
version: 2.1
|
2
2
|
orbs:
|
3
|
-
ruby-rails: sul-dlss/ruby-rails@3.
|
3
|
+
ruby-rails: sul-dlss/ruby-rails@3.1.2
|
4
4
|
workflows:
|
5
5
|
build:
|
6
6
|
jobs:
|
@@ -12,6 +12,9 @@ workflows:
|
|
12
12
|
- run:
|
13
13
|
name: Install exiftool
|
14
14
|
command: curl -L http://cpanmin.us | perl - --sudo Image::ExifTool
|
15
|
+
- run:
|
16
|
+
name: Install libvips
|
17
|
+
command: sudo apt-get update && sudo apt-get install -y libvips
|
15
18
|
- setup_remote_docker
|
16
19
|
- run:
|
17
20
|
name: Install Kakadu
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -22,14 +22,16 @@ Naming/FileName:
|
|
22
22
|
Exclude:
|
23
23
|
- lib/assembly-image.rb
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
Naming/PredicateName:
|
26
|
+
ForbiddenPrefixes:
|
27
|
+
- is_
|
28
|
+
|
29
|
+
RSpec/MultipleMemoizedHelpers:
|
30
|
+
Enabled: false
|
27
31
|
|
28
32
|
Style/WordArray:
|
29
33
|
Enabled: false
|
30
34
|
|
31
|
-
Gemspec/DateAssignment: # new in 1.10
|
32
|
-
Enabled: true
|
33
35
|
Gemspec/RequireMFA: # new in 1.23
|
34
36
|
Enabled: true
|
35
37
|
Layout/LineEndStringConcatenationIndentation: # new in 1.18
|
@@ -144,7 +146,7 @@ RSpec/SubjectDeclaration: # new in 2.5
|
|
144
146
|
RSpec/FactoryBot/SyntaxMethods: # new in 2.7
|
145
147
|
Enabled: true
|
146
148
|
RSpec/Rails/AvoidSetupHook: # new in 2.4
|
147
|
-
Enabled:
|
149
|
+
Enabled: false
|
148
150
|
|
149
151
|
Lint/RefinementImportMethods: # new in 1.27
|
150
152
|
Enabled: true
|
@@ -166,3 +168,19 @@ RSpec/ChangeByZero: # new in 2.11.0
|
|
166
168
|
Enabled: true
|
167
169
|
RSpec/VerifiedDoubleReference: # new in 2.10.0
|
168
170
|
Enabled: true
|
171
|
+
|
172
|
+
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
173
|
+
Enabled: true
|
174
|
+
Layout/LineContinuationLeadingSpace: # new in 1.31
|
175
|
+
Enabled: true
|
176
|
+
Layout/LineContinuationSpacing: # new in 1.31
|
177
|
+
Enabled: true
|
178
|
+
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
179
|
+
Enabled: true
|
180
|
+
Lint/NonAtomicFileOperation: # new in 1.31
|
181
|
+
Enabled: true
|
182
|
+
|
183
|
+
RSpec/Capybara/SpecificMatcher: # new in 2.12
|
184
|
+
Enabled: true
|
185
|
+
RSpec/Rails/HaveHttpStatus: # new in 2.12
|
186
|
+
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2022-
|
3
|
+
# on 2022-07-19 17:18:47 UTC using RuboCop version 1.31.2.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -13,56 +13,16 @@ Gemspec/RequiredRubyVersion:
|
|
13
13
|
Exclude:
|
14
14
|
- 'assembly-image.gemspec'
|
15
15
|
|
16
|
-
# Offense count: 3
|
17
|
-
# Cop supports --auto-correct.
|
18
|
-
Lint/RedundantCopDisableDirective:
|
19
|
-
Exclude:
|
20
|
-
- 'lib/assembly-image/image.rb'
|
21
|
-
- 'lib/assembly-image/images.rb'
|
22
|
-
|
23
16
|
# Offense count: 2
|
24
|
-
# Configuration parameters:
|
25
|
-
|
26
|
-
|
27
|
-
Exclude:
|
28
|
-
- 'spec/image_spec.rb'
|
29
|
-
- 'spec/images_spec.rb'
|
30
|
-
|
31
|
-
# Offense count: 21
|
32
|
-
RSpec/MultipleExpectations:
|
33
|
-
Max: 10
|
34
|
-
|
35
|
-
# Offense count: 5
|
36
|
-
RSpec/UnspecifiedException:
|
37
|
-
Exclude:
|
38
|
-
- 'spec/image_spec.rb'
|
39
|
-
- 'spec/images_spec.rb'
|
40
|
-
|
41
|
-
# Offense count: 3
|
42
|
-
Style/CombinableLoops:
|
43
|
-
Exclude:
|
44
|
-
- 'spec/images_spec.rb'
|
45
|
-
|
46
|
-
# Offense count: 1
|
47
|
-
# Cop supports --auto-correct.
|
48
|
-
Style/GlobalStdStream:
|
49
|
-
Exclude:
|
50
|
-
- 'lib/assembly-image/images.rb'
|
17
|
+
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
18
|
+
Metrics/AbcSize:
|
19
|
+
Max: 20
|
51
20
|
|
52
|
-
# Offense count:
|
53
|
-
# Configuration parameters:
|
54
|
-
|
55
|
-
|
56
|
-
Exclude:
|
57
|
-
- 'lib/assembly-image/image.rb'
|
21
|
+
# Offense count: 11
|
22
|
+
# Configuration parameters: CountAsOne.
|
23
|
+
RSpec/ExampleLength:
|
24
|
+
Max: 13
|
58
25
|
|
59
|
-
# Offense count:
|
60
|
-
|
61
|
-
|
62
|
-
Style/StringConcatenation:
|
63
|
-
Exclude:
|
64
|
-
- 'bin/console'
|
65
|
-
- 'config/boot.rb'
|
66
|
-
- 'lib/assembly-image.rb'
|
67
|
-
- 'lib/assembly-image/images.rb'
|
68
|
-
- 'spec/spec_helper.rb'
|
26
|
+
# Offense count: 15
|
27
|
+
RSpec/MultipleExpectations:
|
28
|
+
Max: 11
|
data/.rvmrc.example
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use 1.
|
1
|
+
rvm use 3.1.0@assembly-image --create
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
assembly-image (2.1.0)
|
5
|
+
activesupport (> 6.1)
|
6
|
+
assembly-objectfile (>= 1.6.4)
|
7
|
+
ruby-vips (>= 2.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (7.0.3.1)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
assembly-objectfile (2.1.0)
|
18
|
+
activesupport (>= 5.2.0)
|
19
|
+
mime-types (> 3)
|
20
|
+
mini_exiftool
|
21
|
+
ast (2.4.2)
|
22
|
+
byebug (11.1.3)
|
23
|
+
coderay (1.1.3)
|
24
|
+
concurrent-ruby (1.1.10)
|
25
|
+
diff-lcs (1.5.0)
|
26
|
+
docile (1.4.0)
|
27
|
+
ffi (1.15.5)
|
28
|
+
i18n (1.12.0)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
json (2.6.2)
|
31
|
+
method_source (1.0.0)
|
32
|
+
mime-types (3.4.1)
|
33
|
+
mime-types-data (~> 3.2015)
|
34
|
+
mime-types-data (3.2022.0105)
|
35
|
+
mini_exiftool (2.10.2)
|
36
|
+
minitest (5.16.2)
|
37
|
+
parallel (1.22.1)
|
38
|
+
parser (3.1.2.0)
|
39
|
+
ast (~> 2.4.1)
|
40
|
+
pry (0.13.1)
|
41
|
+
coderay (~> 1.1)
|
42
|
+
method_source (~> 1.0)
|
43
|
+
pry-byebug (3.9.0)
|
44
|
+
byebug (~> 11.0)
|
45
|
+
pry (~> 0.13.0)
|
46
|
+
rainbow (3.1.1)
|
47
|
+
rake (13.0.6)
|
48
|
+
regexp_parser (2.5.0)
|
49
|
+
rexml (3.2.5)
|
50
|
+
rspec (3.11.0)
|
51
|
+
rspec-core (~> 3.11.0)
|
52
|
+
rspec-expectations (~> 3.11.0)
|
53
|
+
rspec-mocks (~> 3.11.0)
|
54
|
+
rspec-core (3.11.0)
|
55
|
+
rspec-support (~> 3.11.0)
|
56
|
+
rspec-expectations (3.11.0)
|
57
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
58
|
+
rspec-support (~> 3.11.0)
|
59
|
+
rspec-mocks (3.11.1)
|
60
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
61
|
+
rspec-support (~> 3.11.0)
|
62
|
+
rspec-support (3.11.0)
|
63
|
+
rubocop (1.31.2)
|
64
|
+
json (~> 2.3)
|
65
|
+
parallel (~> 1.10)
|
66
|
+
parser (>= 3.1.0.0)
|
67
|
+
rainbow (>= 2.2.2, < 4.0)
|
68
|
+
regexp_parser (>= 1.8, < 3.0)
|
69
|
+
rexml (>= 3.2.5, < 4.0)
|
70
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
71
|
+
ruby-progressbar (~> 1.7)
|
72
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
73
|
+
rubocop-ast (1.19.1)
|
74
|
+
parser (>= 3.1.1.0)
|
75
|
+
rubocop-rspec (2.12.1)
|
76
|
+
rubocop (~> 1.31)
|
77
|
+
ruby-progressbar (1.11.0)
|
78
|
+
ruby-vips (2.1.4)
|
79
|
+
ffi (~> 1.12)
|
80
|
+
simplecov (0.21.2)
|
81
|
+
docile (~> 1.1)
|
82
|
+
simplecov-html (~> 0.11)
|
83
|
+
simplecov_json_formatter (~> 0.1)
|
84
|
+
simplecov-html (0.12.3)
|
85
|
+
simplecov_json_formatter (0.1.4)
|
86
|
+
tzinfo (2.0.5)
|
87
|
+
concurrent-ruby (~> 1.0)
|
88
|
+
unicode-display_width (2.2.0)
|
89
|
+
|
90
|
+
PLATFORMS
|
91
|
+
x86_64-darwin-19
|
92
|
+
x86_64-darwin-21
|
93
|
+
x86_64-linux
|
94
|
+
|
95
|
+
DEPENDENCIES
|
96
|
+
assembly-image!
|
97
|
+
pry-byebug
|
98
|
+
rake
|
99
|
+
rspec (~> 3.0)
|
100
|
+
rubocop
|
101
|
+
rubocop-rspec
|
102
|
+
simplecov
|
103
|
+
|
104
|
+
BUNDLED WITH
|
105
|
+
2.3.17
|
data/README.md
CHANGED
@@ -6,22 +6,16 @@
|
|
6
6
|
# Assembly Image Gem
|
7
7
|
|
8
8
|
## Overview
|
9
|
-
This gem contains classes used by the Stanford University Digital Library to
|
10
|
-
|
9
|
+
This gem contains classes used by the Stanford University Digital Library to create JP2 image derivatives.
|
10
|
+
|
11
|
+
Requires image processing software - see [prerequisites section](#prerequisites) below.
|
11
12
|
|
12
13
|
## Notes
|
13
14
|
|
14
15
|
1. The gem assumes that the user context in which it is executed has write access to the 'tmp' folder.
|
15
|
-
This is
|
16
|
-
|
17
|
-
is
|
18
|
-
If you know there are color profiles which are commonly used, it is better to
|
19
|
-
capture them in the gem itself in the profile folder so they can be re-used
|
20
|
-
and do not need to be extracted.
|
21
|
-
1. If any errors occur during JP2 generation for any reason, a runtime exception will be thrown with a description of the error.
|
22
|
-
2. If an image is passed in with a color profile that cannot be determined by examining the exif header data, an exception will be thrown.
|
23
|
-
|
24
|
-
This can commonly occur in basic test TIFs that are black/white and have no profile, so beware during testing.
|
16
|
+
This is to create the temporary tiffs used; we need temporary tiffs to reliably compress the image using KDUcompress, which doesn’t support arbitrary image types
|
17
|
+
2. If any errors occur during JP2 generation for any reason, a runtime exception will be thrown with a description of the error.
|
18
|
+
3. If an image is passed in with a color profile that cannot be determined, an exception will be thrown. This can commonly occur in basic test TIFs that are black/white and have no profile, so beware during testing.
|
25
19
|
|
26
20
|
## Usage
|
27
21
|
|
@@ -29,76 +23,39 @@ To use the JP2 creation method, you first instantiate the image object with an i
|
|
29
23
|
|
30
24
|
```ruby
|
31
25
|
require 'assembly-image'
|
32
|
-
|
33
|
-
|
34
|
-
output = input.create_jp2(:output=>'/full/path/to/output.jp2') # generate a new JP2 in the specified location
|
35
|
-
puts output.exif # show exif header information for the JP2
|
26
|
+
input_image = Assembly::Image.new('/full/path/to/file.tif')
|
27
|
+
output = input_image.create_jp2(output: '/full/path/to/output.jp2') # generate a new JP2 in the specified location
|
36
28
|
```
|
37
29
|
|
38
30
|
## Running tests
|
39
31
|
|
40
32
|
```bash
|
41
|
-
bundle exec
|
42
|
-
```
|
43
|
-
|
44
|
-
## Generate documentation
|
45
|
-
To generate documentation into the "doc" folder:
|
46
|
-
|
47
|
-
```bash
|
48
|
-
yard
|
49
|
-
```
|
50
|
-
|
51
|
-
To keep a local server running with up to date code documentation that you can view in your browser:
|
52
|
-
|
53
|
-
```bash
|
54
|
-
yard server --reload
|
33
|
+
bundle exec rspec
|
55
34
|
```
|
56
35
|
|
57
36
|
## Prerequisites
|
58
37
|
|
59
38
|
1. Kakadu Proprietary Software Binaries - for JP2 generation
|
60
|
-
1.
|
61
|
-
1. Exiftool
|
39
|
+
1. Libvips
|
40
|
+
1. Exiftool - upstream dependency of assembly-objectfile (used by specs to check mimetype of produced jp2, and because there is no libvips package available for circleci that speaks jp2)
|
62
41
|
|
63
42
|
### Kakadu
|
64
43
|
|
65
44
|
Download and install demonstration binaries from Kakadu:
|
66
45
|
http://kakadusoftware.com/downloads/
|
67
46
|
|
68
|
-
|
69
|
-
|
70
|
-
### Imagemagick
|
71
|
-
|
72
|
-
#### RHEL 6
|
73
|
-
|
74
|
-
The version of ImageMagick included with RHEL 6 has all of the dependency libraries included:
|
75
|
-
|
76
|
-
```bash
|
77
|
-
yum install ImageMagick
|
78
|
-
```
|
79
|
-
#### RHEL 5
|
80
|
-
|
81
|
-
The version of ImageMagick included with RHEL 5 is too old and does not have all the proper binaries included/built:
|
82
|
-
|
83
|
-
```bash
|
84
|
-
yum install lcms lcms-devel libjpeg libjpeg-devel libpng libpng-devel
|
85
|
-
```
|
86
|
-
Required libraries from source:
|
87
|
-
* libtiff (version 3.9.4 or higher)
|
88
|
-
|
89
|
-
Build Imagemagick from source:
|
90
|
-
http://www.imagemagick.org/download/ImageMagick.tar.gz
|
47
|
+
### Libvips
|
48
|
+
Note: libvips may require a significant amount of space for temporary files. The location for this can be controlled by the TMPDIR environment variable.
|
91
49
|
|
92
50
|
#### Mac
|
93
51
|
|
94
52
|
```bash
|
95
|
-
brew install
|
96
|
-
brew install imagemagick --use-tiff --use-jpeg2000
|
53
|
+
brew install libvips
|
97
54
|
```
|
98
55
|
|
99
56
|
### Exiftool
|
100
57
|
|
101
|
-
####
|
58
|
+
#### Linux
|
102
59
|
Download latest version from: http://www.sno.phy.queensu.ca/~phil/exiftool
|
103
60
|
|
104
61
|
```bash
|
data/assembly-image.gemspec
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
|
-
require 'assembly-image/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
6
|
s.name = 'assembly-image'
|
8
|
-
s.version =
|
7
|
+
s.version = '2.1.0'
|
9
8
|
s.authors = ['Peter Mangiafico', 'Renzo Sanchez-Silva', 'Monty Hindman', 'Tony Calavano']
|
10
9
|
s.email = ['pmangiafico@stanford.edu']
|
11
10
|
s.homepage = ''
|
@@ -14,18 +13,18 @@ Gem::Specification.new do |s|
|
|
14
13
|
s.metadata['rubygems_mfa_required'] = 'true'
|
15
14
|
|
16
15
|
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
16
|
s.bindir = 'exe'
|
19
17
|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
18
|
s.require_paths = ['lib']
|
21
19
|
|
20
|
+
s.add_dependency 'activesupport', '> 6.1'
|
22
21
|
s.add_dependency 'assembly-objectfile', '>= 1.6.4'
|
23
|
-
s.add_dependency '
|
22
|
+
s.add_dependency 'ruby-vips', '>= 2.0'
|
24
23
|
|
24
|
+
s.add_development_dependency 'pry-byebug'
|
25
25
|
s.add_development_dependency 'rake'
|
26
26
|
s.add_development_dependency 'rspec', '~> 3.0'
|
27
27
|
s.add_development_dependency 'rubocop'
|
28
28
|
s.add_development_dependency 'rubocop-rspec'
|
29
29
|
s.add_development_dependency 'simplecov'
|
30
|
-
s.add_development_dependency 'yard'
|
31
30
|
end
|
data/bin/console
CHANGED
data/config/boot.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
|
5
|
-
project_root = File.expand_path(File.dirname(__FILE__)
|
5
|
+
project_root = File.expand_path("#{File.dirname(__FILE__)}/..")
|
6
6
|
|
7
7
|
# Load config for current environment.
|
8
|
-
$LOAD_PATH.unshift(project_root
|
8
|
+
$LOAD_PATH.unshift("#{project_root}/lib")
|
9
9
|
|
10
10
|
require 'assembly-image'
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'assembly-objectfile'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'English' # see https://github.com/rubocop-hq/rubocop/issues/1747 (not #MAGA related)
|
6
|
+
require 'active_support/core_ext/module/delegation'
|
7
|
+
|
8
|
+
module Assembly
|
9
|
+
class Image < Assembly::ObjectFile
|
10
|
+
# Creates jp2 derivatives
|
11
|
+
class Jp2Creator
|
12
|
+
# Create a JP2 file for the current image.
|
13
|
+
# Important note: this will not work for multipage TIFFs.
|
14
|
+
#
|
15
|
+
# @return [Assembly::Image] object containing the generated JP2 file
|
16
|
+
#
|
17
|
+
# @param [Assembly::Image] the image file
|
18
|
+
# @param [String] output path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
|
19
|
+
# @param [Boolean] overwrite if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
20
|
+
# @param [Dir] tmp_folder the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# source_img = Assembly::Image.new('/input/path_to_file.tif')
|
24
|
+
# derivative_img = source_img.create_jp2(overwrite: true)
|
25
|
+
# puts derivative_img.mimetype # 'image/jp2'
|
26
|
+
# puts derivative_image.path # '/input/path_to_file.jp2'
|
27
|
+
def self.create(image, **args)
|
28
|
+
new(image, **args).create
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(image, overwrite: false, output: image.jp2_filename, tmp_folder: Dir.tmpdir)
|
32
|
+
@image = image
|
33
|
+
@output_path = output
|
34
|
+
@tmp_folder = tmp_folder
|
35
|
+
@overwrite = overwrite
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :image, :output_path, :tmp_folder, :tmp_tiff_path
|
39
|
+
|
40
|
+
delegate :vips_image, to: :image
|
41
|
+
|
42
|
+
# @return [Assembly::Image] object containing the generated JP2 file
|
43
|
+
def create
|
44
|
+
create_jp2_checks
|
45
|
+
|
46
|
+
# KDUcompress doesn’t support arbitrary image types, so we make a temporary tiff
|
47
|
+
@tmp_tiff_path = make_tmp_tiff
|
48
|
+
|
49
|
+
jp2_command = jp2_create_command(source_path: tmp_tiff_path, output: output_path)
|
50
|
+
result = `#{jp2_command}`
|
51
|
+
unless $CHILD_STATUS.success?
|
52
|
+
# Clean up any partial result
|
53
|
+
FileUtils.rm_rf(output_path)
|
54
|
+
raise "JP2 creation command failed: #{jp2_command} with result #{result}"
|
55
|
+
end
|
56
|
+
|
57
|
+
File.delete(tmp_tiff_path) unless tmp_tiff_path.nil?
|
58
|
+
|
59
|
+
# create output response object, which is an Assembly::Image type object
|
60
|
+
Image.new(output_path)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def overwrite?
|
66
|
+
@overwrite
|
67
|
+
end
|
68
|
+
|
69
|
+
def jp2_create_command(source_path:, output:)
|
70
|
+
options = []
|
71
|
+
# CMYK becomes sRGB in make_tmp_tiff, so jp2_space option will be set for sRGB and CMYK
|
72
|
+
# TODO: we're not sure at this time what happens for grayscale (or what Tony C. wants for grayscale)
|
73
|
+
# see https://github.com/sul-dlss/assembly-image/issues/98
|
74
|
+
options << '-jp2_space sRGB' if image.srgb?
|
75
|
+
options += KDU_COMPRESS_DEFAULT_OPTIONS
|
76
|
+
options << "Clayers=#{layers}"
|
77
|
+
"kdu_compress #{options.join(' ')} -i '#{source_path}' -o '#{output}' 2>&1"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the number of JP2 layers to generate
|
81
|
+
def layers
|
82
|
+
pixdem = [image.width, image.height].max
|
83
|
+
((Math.log(pixdem) / Math.log(2)) - (Math.log(96) / Math.log(2))).ceil + 1
|
84
|
+
end
|
85
|
+
|
86
|
+
KDU_COMPRESS_DEFAULT_OPTIONS = [
|
87
|
+
'-num_threads 2', # forces Kakadu to only use 2 threads
|
88
|
+
'-quiet', # suppress informative messages.
|
89
|
+
'Creversible=no', # Disable reversible compression
|
90
|
+
'Corder=RPCL', # R=resolution P=position C=component L=layer
|
91
|
+
'Cblk=\\{64,64\\}', # code-block dimensions; 64x64 happens to also be the default
|
92
|
+
'Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\}', # Precinct dimensions; 256x256 for the 2 highest resolution levels, defaults to 128x128 for the rest
|
93
|
+
'-rate -', # Ratio of compressed bits to the image size
|
94
|
+
'Clevels=5' # Number of wavelet decomposition levels, or stages
|
95
|
+
].freeze
|
96
|
+
|
97
|
+
def create_jp2_checks
|
98
|
+
image.send(:check_for_file)
|
99
|
+
raise 'input file is not a valid image, or is the wrong mimetype' unless image.jp2able?
|
100
|
+
|
101
|
+
raise SecurityError, "output #{output_path} exists, cannot overwrite" if !overwrite? && File.exist?(output_path)
|
102
|
+
raise SecurityError, 'cannot recreate jp2 over itself' if overwrite? && image.mimetype == 'image/jp2' && output_path == image.path
|
103
|
+
end
|
104
|
+
|
105
|
+
# We do this because we need to reliably compress the tiff and KDUcompress doesn’t support arbitrary image types
|
106
|
+
# rubocop:disable Metrics/MethodLength
|
107
|
+
def make_tmp_tiff
|
108
|
+
raise "tmp_folder #{tmp_folder} does not exist" unless File.exist?(tmp_folder)
|
109
|
+
|
110
|
+
# make temp tiff filename
|
111
|
+
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
|
112
|
+
result_path = tmp_tiff_file.path
|
113
|
+
tmp_tiff_image = if vips_image.interpretation.eql?(:cmyk)
|
114
|
+
vips_image.icc_transform(SRGB_ICC, input_profile: CMYK_ICC)
|
115
|
+
elsif image.has_profile?
|
116
|
+
vips_image.icc_transform(SRGB_ICC, embedded: true)
|
117
|
+
else
|
118
|
+
vips_image
|
119
|
+
end
|
120
|
+
|
121
|
+
tmp_tiff_image.tiffsave(result_path, bigtiff: true) # Use bigtiff so we can support images > 4GB
|
122
|
+
result_path
|
123
|
+
end
|
124
|
+
# rubocop:enable Metrics/MethodLength
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
require 'assembly-objectfile'
|
5
|
+
require_relative 'image/jp2_creator'
|
6
|
+
|
7
|
+
module Assembly
|
8
|
+
# The Image class contains methods to operate on an image.
|
9
|
+
class Image < Assembly::ObjectFile
|
10
|
+
# @return [integer] image height in pixels
|
11
|
+
def height
|
12
|
+
vips_image.height
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [integer] image width in pixels
|
16
|
+
def width
|
17
|
+
vips_image.width
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [string] full default jp2 path and filename that will be created from the given image
|
21
|
+
# Example: given original file of '/dir/path_to_file.tif', gives '/dir/path_to_file.jp2'
|
22
|
+
def jp2_filename
|
23
|
+
# path is a property on Assembly::ObjectFile
|
24
|
+
File.extname(path).empty? ? "#{path}.jp2" : path.gsub(File.extname(path), '.jp2')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a JP2 file for the current image.
|
28
|
+
# Important note: this will not work for multipage TIFFs.
|
29
|
+
#
|
30
|
+
# @param [String] output path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
|
31
|
+
# @param [Boolean] overwrite if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
32
|
+
# @param [Dir] tmp_folder the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
|
33
|
+
# @return [Assembly::Image] object containing the generated JP2 file
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# source_img = Assembly::Image.new('/dir/path_to_file.tif')
|
37
|
+
# jp2_img = source_img.create_jp2(overwrite: true)
|
38
|
+
# jp2_img.mimetype # 'image/jp2'
|
39
|
+
# jp2_img.path # '/dir/path_to_file.jp2'
|
40
|
+
def create_jp2(**params)
|
41
|
+
Jp2Creator.create(self, **params)
|
42
|
+
end
|
43
|
+
|
44
|
+
def vips_image
|
45
|
+
# autorot will only affect images that need rotation: https://www.libvips.org/API/current/libvips-conversion.html#vips-autorot
|
46
|
+
@vips_image ||= Vips::Image.new_from_file(path).autorot
|
47
|
+
end
|
48
|
+
|
49
|
+
def srgb?
|
50
|
+
vips_image.interpretation == :srgb
|
51
|
+
end
|
52
|
+
|
53
|
+
# Does the image include an ICC profile?
|
54
|
+
def has_profile?
|
55
|
+
vips_image.get_fields.include?('icc-profile-data')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/assembly-image.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module Assembly
|
4
4
|
# the path to the gem, used to access profiles stored with the gem
|
5
|
-
PATH_TO_IMAGE_GEM = File.expand_path(File.dirname(__FILE__)
|
5
|
+
PATH_TO_IMAGE_GEM = File.expand_path("#{File.dirname(__FILE__)}/..")
|
6
|
+
PATH_TO_PROFILES = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
|
7
|
+
SRGB_ICC = File.join(PATH_TO_PROFILES, 'sRGBIEC6196621.icc')
|
8
|
+
CMYK_ICC = File.join(PATH_TO_PROFILES, 'cmyk.icc')
|
6
9
|
end
|
7
10
|
|
8
|
-
require 'assembly
|
9
|
-
require 'assembly-image/images'
|
11
|
+
require 'assembly/image'
|
data/profiles/cmyk.icc
ADDED
Binary file
|