assembly-image 1.7.6 → 1.8.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 +22 -0
- data/.github/pull_request_template.md +10 -0
- data/.gitignore +4 -1
- data/.rubocop.yml +150 -3
- data/.rubocop_todo.yml +68 -0
- data/README.md +4 -48
- data/assembly-image.gemspec +3 -2
- data/lib/assembly-image/image.rb +11 -156
- data/lib/assembly-image/jp2_creator.rb +182 -0
- data/lib/assembly-image/version.rb +2 -2
- data/spec/assembly/image/jp2_creator_spec.rb +58 -0
- data/spec/image_spec.rb +248 -244
- data/spec/images_spec.rb +20 -22
- data/spec/spec_helper.rb +89 -0
- metadata +48 -10
- data/.travis.yml +0 -28
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ab0138b7a2f4b92d23428f192efd67f9db79e588849411265079c7dafbd8d44b
|
|
4
|
+
data.tar.gz: 6d87bd7214d36684259de8d082b75494f67602947df1bfbb992ae7d4178a339c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a1afdaef9ca647be48084fd50ea18adcb69383b42e5cccea155f5dbb5ed072709ca6061f0b0f352df738ff2a0a4d55388a5e2288f6fbb8eab97c166a3f5ed6f0
|
|
7
|
+
data.tar.gz: e4310e4e33f402cefd3443173b47510ae6b1bb767be766f88edf934c802da7778866ad0e4b557254d6599a82b48f8e4f52fd50d9baf01ed0df430ad99cb8993f
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
orbs:
|
|
3
|
+
ruby-rails: sul-dlss/ruby-rails@3.0.1
|
|
4
|
+
workflows:
|
|
5
|
+
build:
|
|
6
|
+
jobs:
|
|
7
|
+
- ruby-rails/lint-gem:
|
|
8
|
+
name: lint
|
|
9
|
+
- ruby-rails/test-gem:
|
|
10
|
+
name: test
|
|
11
|
+
before-test:
|
|
12
|
+
- run:
|
|
13
|
+
name: Install exiftool
|
|
14
|
+
command: curl -L http://cpanmin.us | perl - --sudo Image::ExifTool
|
|
15
|
+
- setup_remote_docker
|
|
16
|
+
- run:
|
|
17
|
+
name: Install Kakadu
|
|
18
|
+
command: |
|
|
19
|
+
docker create --name kakadu josejuansanchez/kakadu:1.0
|
|
20
|
+
docker cp kakadu:/kakadu kakadu
|
|
21
|
+
sudo cp kakadu/*.so /usr/lib
|
|
22
|
+
sudo cp kakadu/* /usr/bin
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Why was this change made? 🤔
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## How was this change tested? 🤨
|
|
6
|
+
|
|
7
|
+
⚡ ⚠ If this change has cross service impact, ***run [integration tests](https://github.com/sul-dlss/infrastructure-integration-test) that do IMAGE ACCESSIONING*** (e.g. create_preassembly_image_spec) and/or test in [stage|qa] environment, in addition to specs. ⚡
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
require: rubocop-rspec
|
|
4
|
+
|
|
5
|
+
AllCops:
|
|
6
|
+
TargetRubyVersion: 3.0
|
|
7
|
+
SuggestExtensions: false
|
|
8
|
+
|
|
1
9
|
# rspec expect{...} is conventional
|
|
2
10
|
Layout/SpaceBeforeBlockBraces:
|
|
3
11
|
Exclude:
|
|
@@ -7,15 +15,154 @@ Layout/EmptyLineBetweenDefs:
|
|
|
7
15
|
AllowAdjacentOneLineDefs: true
|
|
8
16
|
|
|
9
17
|
# Configuration parameters: AllowURI, URISchemes.
|
|
10
|
-
|
|
18
|
+
Layout/LineLength:
|
|
11
19
|
Max: 200
|
|
12
20
|
|
|
13
21
|
Naming/FileName:
|
|
14
22
|
Exclude:
|
|
15
23
|
- lib/assembly-image.rb
|
|
16
24
|
|
|
25
|
+
RSpec/ExampleLength:
|
|
26
|
+
Max: 12
|
|
27
|
+
|
|
17
28
|
Style/WordArray:
|
|
18
29
|
Enabled: false
|
|
19
30
|
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
Gemspec/DateAssignment: # new in 1.10
|
|
32
|
+
Enabled: true
|
|
33
|
+
Gemspec/RequireMFA: # new in 1.23
|
|
34
|
+
Enabled: true
|
|
35
|
+
Layout/LineEndStringConcatenationIndentation: # new in 1.18
|
|
36
|
+
Enabled: true
|
|
37
|
+
Layout/SpaceBeforeBrackets: # new in 1.7
|
|
38
|
+
Enabled: true
|
|
39
|
+
Lint/AmbiguousAssignment: # new in 1.7
|
|
40
|
+
Enabled: true
|
|
41
|
+
Lint/AmbiguousOperatorPrecedence: # new in 1.21
|
|
42
|
+
Enabled: true
|
|
43
|
+
Lint/AmbiguousRange: # new in 1.19
|
|
44
|
+
Enabled: true
|
|
45
|
+
Lint/DeprecatedConstants: # new in 1.8
|
|
46
|
+
Enabled: true
|
|
47
|
+
Lint/DuplicateBranch: # new in 1.3
|
|
48
|
+
Enabled: true
|
|
49
|
+
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
|
|
50
|
+
Enabled: true
|
|
51
|
+
Lint/EmptyBlock: # new in 1.1
|
|
52
|
+
Enabled: true
|
|
53
|
+
Lint/EmptyClass: # new in 1.3
|
|
54
|
+
Enabled: true
|
|
55
|
+
Lint/EmptyInPattern: # new in 1.16
|
|
56
|
+
Enabled: true
|
|
57
|
+
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
|
|
58
|
+
Enabled: true
|
|
59
|
+
Lint/LambdaWithoutLiteralBlock: # new in 1.8
|
|
60
|
+
Enabled: true
|
|
61
|
+
Lint/NoReturnInBeginEndBlocks: # new in 1.2
|
|
62
|
+
Enabled: true
|
|
63
|
+
Lint/NumberedParameterAssignment: # new in 1.9
|
|
64
|
+
Enabled: true
|
|
65
|
+
Lint/OrAssignmentToConstant: # new in 1.9
|
|
66
|
+
Enabled: true
|
|
67
|
+
Lint/RedundantDirGlobSort: # new in 1.8
|
|
68
|
+
Enabled: true
|
|
69
|
+
Lint/RequireRelativeSelfPath: # new in 1.22
|
|
70
|
+
Enabled: true
|
|
71
|
+
Lint/SymbolConversion: # new in 1.9
|
|
72
|
+
Enabled: true
|
|
73
|
+
Lint/ToEnumArguments: # new in 1.1
|
|
74
|
+
Enabled: true
|
|
75
|
+
Lint/TripleQuotes: # new in 1.9
|
|
76
|
+
Enabled: true
|
|
77
|
+
Lint/UnexpectedBlockArity: # new in 1.5
|
|
78
|
+
Enabled: true
|
|
79
|
+
Lint/UnmodifiedReduceAccumulator: # new in 1.1
|
|
80
|
+
Enabled: true
|
|
81
|
+
Lint/UselessRuby2Keywords: # new in 1.23
|
|
82
|
+
Enabled: true
|
|
83
|
+
Naming/BlockForwarding: # new in 1.24
|
|
84
|
+
Enabled: true
|
|
85
|
+
Security/IoMethods: # new in 1.22
|
|
86
|
+
Enabled: true
|
|
87
|
+
Style/ArgumentsForwarding: # new in 1.1
|
|
88
|
+
Enabled: true
|
|
89
|
+
Style/CollectionCompact: # new in 1.2
|
|
90
|
+
Enabled: true
|
|
91
|
+
Style/DocumentDynamicEvalDefinition: # new in 1.1
|
|
92
|
+
Enabled: true
|
|
93
|
+
Style/EndlessMethod: # new in 1.8
|
|
94
|
+
Enabled: true
|
|
95
|
+
Style/FileRead: # new in 1.24
|
|
96
|
+
Enabled: true
|
|
97
|
+
Style/FileWrite: # new in 1.24
|
|
98
|
+
Enabled: true
|
|
99
|
+
Style/HashConversion: # new in 1.10
|
|
100
|
+
Enabled: true
|
|
101
|
+
Style/HashExcept: # new in 1.7
|
|
102
|
+
Enabled: true
|
|
103
|
+
Style/IfWithBooleanLiteralBranches: # new in 1.9
|
|
104
|
+
Enabled: true
|
|
105
|
+
Style/InPatternThen: # new in 1.16
|
|
106
|
+
Enabled: true
|
|
107
|
+
Style/MapToHash: # new in 1.24
|
|
108
|
+
Enabled: true
|
|
109
|
+
Style/MultilineInPatternThen: # new in 1.16
|
|
110
|
+
Enabled: true
|
|
111
|
+
Style/NegatedIfElseCondition: # new in 1.2
|
|
112
|
+
Enabled: true
|
|
113
|
+
Style/NilLambda: # new in 1.3
|
|
114
|
+
Enabled: true
|
|
115
|
+
Style/NumberedParameters: # new in 1.22
|
|
116
|
+
Enabled: true
|
|
117
|
+
Style/NumberedParametersLimit: # new in 1.22
|
|
118
|
+
Enabled: true
|
|
119
|
+
Style/OpenStructUse: # new in 1.23
|
|
120
|
+
Enabled: true
|
|
121
|
+
Style/QuotedSymbols: # new in 1.16
|
|
122
|
+
Enabled: true
|
|
123
|
+
Style/RedundantArgument: # new in 1.4
|
|
124
|
+
Enabled: true
|
|
125
|
+
Style/RedundantSelfAssignmentBranch: # new in 1.19
|
|
126
|
+
Enabled: true
|
|
127
|
+
Style/SelectByRegexp: # new in 1.22
|
|
128
|
+
Enabled: true
|
|
129
|
+
Style/StringChars: # new in 1.12
|
|
130
|
+
Enabled: true
|
|
131
|
+
Style/SwapValues: # new in 1.1
|
|
132
|
+
Enabled: true
|
|
133
|
+
|
|
134
|
+
RSpec/BeEq: # new in 2.9.0
|
|
135
|
+
Enabled: true
|
|
136
|
+
RSpec/BeNil: # new in 2.9.0
|
|
137
|
+
Enabled: true
|
|
138
|
+
RSpec/ExcessiveDocstringSpacing: # new in 2.5
|
|
139
|
+
Enabled: true
|
|
140
|
+
RSpec/IdenticalEqualityAssertion: # new in 2.4
|
|
141
|
+
Enabled: true
|
|
142
|
+
RSpec/SubjectDeclaration: # new in 2.5
|
|
143
|
+
Enabled: true
|
|
144
|
+
RSpec/FactoryBot/SyntaxMethods: # new in 2.7
|
|
145
|
+
Enabled: true
|
|
146
|
+
RSpec/Rails/AvoidSetupHook: # new in 2.4
|
|
147
|
+
Enabled: true
|
|
148
|
+
|
|
149
|
+
Lint/RefinementImportMethods: # new in 1.27
|
|
150
|
+
Enabled: true
|
|
151
|
+
Security/CompoundHash: # new in 1.28
|
|
152
|
+
Enabled: true
|
|
153
|
+
Style/EnvHome: # new in 1.29
|
|
154
|
+
Enabled: true
|
|
155
|
+
Style/FetchEnvVar: # new in 1.28
|
|
156
|
+
Enabled: true
|
|
157
|
+
Style/MapCompactWithConditionalBlock: # new in 1.30
|
|
158
|
+
Enabled: true
|
|
159
|
+
Style/NestedFileDirname: # new in 1.26
|
|
160
|
+
Enabled: true
|
|
161
|
+
Style/ObjectThen: # new in 1.28
|
|
162
|
+
Enabled: true
|
|
163
|
+
Style/RedundantInitialize: # new in 1.27
|
|
164
|
+
Enabled: true
|
|
165
|
+
RSpec/ChangeByZero: # new in 2.11.0
|
|
166
|
+
Enabled: true
|
|
167
|
+
RSpec/VerifiedDoubleReference: # new in 2.10.0
|
|
168
|
+
Enabled: true
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2022-02-28 19:49:08 UTC using RuboCop version 1.25.1.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: Include.
|
|
11
|
+
# Include: **/*.gemspec
|
|
12
|
+
Gemspec/RequiredRubyVersion:
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'assembly-image.gemspec'
|
|
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
|
+
# Offense count: 2
|
|
24
|
+
# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
|
|
25
|
+
# Include: **/*_spec*rb*, **/spec/**/*
|
|
26
|
+
RSpec/FilePath:
|
|
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'
|
|
51
|
+
|
|
52
|
+
# Offense count: 1
|
|
53
|
+
# Configuration parameters: AllowedMethods.
|
|
54
|
+
# AllowedMethods: respond_to_missing?
|
|
55
|
+
Style/OptionalBooleanParameter:
|
|
56
|
+
Exclude:
|
|
57
|
+
- 'lib/assembly-image/image.rb'
|
|
58
|
+
|
|
59
|
+
# Offense count: 8
|
|
60
|
+
# Cop supports --auto-correct-all.
|
|
61
|
+
# Configuration parameters: Mode.
|
|
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'
|
data/README.md
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
[](https://circleci.com/gh/sul-dlss/assembly-image/tree/main)
|
|
2
|
+
[](https://codeclimate.com/github/sul-dlss/assembly-image/test_coverage)
|
|
3
|
+
[](https://codeclimate.com/github/sul-dlss/assembly-image/maintainability)
|
|
4
|
+
[](https://badge.fury.io/rb/assembly-image)
|
|
2
5
|
|
|
3
6
|
# Assembly Image Gem
|
|
4
7
|
|
|
@@ -6,53 +9,6 @@
|
|
|
6
9
|
This gem contains classes used by the Stanford University Digital Library to
|
|
7
10
|
perform image operations necessary for accessioning of content.
|
|
8
11
|
|
|
9
|
-
## Releases
|
|
10
|
-
|
|
11
|
-
* 0.0.1 initial release
|
|
12
|
-
* 0.0.2 small bug fixes
|
|
13
|
-
* 0.0.3 more bug fixes
|
|
14
|
-
* 0.0.4 update jp2 creation method to restrict allowed input types and improve color profile handling
|
|
15
|
-
* 0.0.5 updated documentation to yard format
|
|
16
|
-
* 0.0.6 updated dependency declarations
|
|
17
|
-
* 0.1.0 move color profile extraction to tmp folder instead of gem profiles folder
|
|
18
|
-
* 0.1.1 fix problem with digest require statement
|
|
19
|
-
* 0.1.2 move check for file existence to when an action occurs instead of object initialization; more error checking and messages on command execution
|
|
20
|
-
* 0.1.3 added a filesize attribute to the file object to allow easy access to filesize in bytes
|
|
21
|
-
* 0.1.4 added a new images class that allows you batch create jp2s from an input TIFF directory
|
|
22
|
-
* 0.2.0 added a new method to the image class to handle TIFF "sanity-check" -- can be used to ensure TIFFs are valid before JP2 generation
|
|
23
|
-
* 1.0.0 bump the version number up to an official production level release
|
|
24
|
-
* 1.1.0 remove common object file behaviors to a separate gem and use that gem as a dependency
|
|
25
|
-
* 1.1.1 minor changes to spec tests
|
|
26
|
-
* 1.1.2 remove the addition of 'format' node to file types in content metadata generation
|
|
27
|
-
* 1.1.3 changes to content metadata generation method: change md5 and sha1 computations so that they come from the assembly-objectfile gem,
|
|
28
|
-
and set preserve/publish/shelve attributes using mimetype defaults
|
|
29
|
-
* 1.2.0 support tiffs that have embedded thumbnails when creating jp2
|
|
30
|
-
* 1.2.1 raise a SecurityError if the user attempts to overwrite an existing jp2 when creating it, to make it easier to catch in assembly
|
|
31
|
-
* 1.2.2 add height and width methods for an image that gets it from exif
|
|
32
|
-
* 1.2.4 prepare for release listing on DLSS release board
|
|
33
|
-
* 1.2.5 small change to use the jp2able method instead of the valid? method when creating jp2s
|
|
34
|
-
* 1.2.6 update how version number is set to make it easier to show
|
|
35
|
-
* 1.3.0 added a new method to the Assembly::Images class to allow for batch adding of color profiles to all tiffs in a directory; allow batch methods to run recursively
|
|
36
|
-
* 1.3.1 remove content metadata generation method and add to assembly-objectfile gem instead
|
|
37
|
-
* 1.3.3 update gemspec to force use of latest assembly-objectfile gem to allow gem to work in Ruby 1.9 projects
|
|
38
|
-
* 1.3.4 update to latest version of lyberteam gems
|
|
39
|
-
* 1.3.5 fix a problem that could occur if there were spaces in input filenames
|
|
40
|
-
* 1.3.6 add new attribute to give you default jp2 filename that will be used
|
|
41
|
-
* 1.3.7 add new attribute to give you default dpg jp2 filename
|
|
42
|
-
* 1.3.8 allow for batch processing of image extensions other than tif
|
|
43
|
-
* 1.3.9 create new methods for getting a color profile from exif and for force adding color profile to a single image
|
|
44
|
-
* 1.4.0 and 1.4.1 set the imagemagick tmp folder location environment variable when creating jp2
|
|
45
|
-
* 1.5.0 allow images with a color profile to have jp2 derivatives generated
|
|
46
|
-
* 1.5.1 relax nokogiri version requirement
|
|
47
|
-
* 1.6.1 bump version number of assembly-objectfile required to fix UTF-8 errors during JP2-create
|
|
48
|
-
* 1.6.2-1.6.3 small change to jp2 generation to try and fix bug with tiffs that have multiple input profile layers
|
|
49
|
-
* 1.6.4 added in some additional checks to try and create jp2s with mismatching exif data
|
|
50
|
-
* 1.6.5 fix problem with lack of extension in incoming tif causing a problem when creating jp2
|
|
51
|
-
* 1.6.7 release to github/rubygems
|
|
52
|
-
* 1.6.9 update mini_exiftool
|
|
53
|
-
* 1.7.1 for jp2, only transcode to tiff if not a tiff
|
|
54
|
-
* 1.7.3 for jp2, only transcode to tiff if not an uncompressed tiff
|
|
55
|
-
|
|
56
12
|
## Notes
|
|
57
13
|
|
|
58
14
|
1. The gem assumes that the user context in which it is executed has write access to the 'tmp' folder.
|
data/assembly-image.gemspec
CHANGED
|
@@ -11,8 +11,7 @@ Gem::Specification.new do |s|
|
|
|
11
11
|
s.homepage = ''
|
|
12
12
|
s.summary = 'Ruby immplementation of image services needed to prepare objects to be accessioned in SULAIR digital library'
|
|
13
13
|
s.description = 'Contains classes to create derivative image files and perform other image operations'
|
|
14
|
-
|
|
15
|
-
s.rubyforge_project = 'assembly-image'
|
|
14
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
|
16
15
|
|
|
17
16
|
s.files = `git ls-files`.split("\n")
|
|
18
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -26,5 +25,7 @@ Gem::Specification.new do |s|
|
|
|
26
25
|
s.add_development_dependency 'rake'
|
|
27
26
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
28
27
|
s.add_development_dependency 'rubocop'
|
|
28
|
+
s.add_development_dependency 'rubocop-rspec'
|
|
29
|
+
s.add_development_dependency 'simplecov'
|
|
29
30
|
s.add_development_dependency 'yard'
|
|
30
31
|
end
|
data/lib/assembly-image/image.rb
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'assembly-objectfile'
|
|
4
|
-
|
|
5
|
-
require 'English' # see https://github.com/rubocop-hq/rubocop/issues/1747 (not #MAGA related)
|
|
4
|
+
require_relative 'jp2_creator'
|
|
6
5
|
|
|
7
6
|
module Assembly
|
|
8
7
|
# The Image class contains methods to operate on an image.
|
|
9
|
-
# rubocop:disable Metrics/ClassLength
|
|
10
8
|
class Image
|
|
11
9
|
# include common behaviors from assembly-objectfile gem
|
|
12
10
|
include Assembly::ObjectFileable
|
|
13
11
|
|
|
14
|
-
# stores the path to the tmp file generated during the JP2 creation process
|
|
15
|
-
attr_accessor :tmp_path
|
|
16
|
-
|
|
17
12
|
# Examines the input image for validity. Used to determine if image is correct and if JP2 generation is likely to succeed.
|
|
18
13
|
# This method is automatically called before you create a jp2 but it can be called separately earlier as a sanity check.
|
|
19
14
|
#
|
|
@@ -99,7 +94,7 @@ module Assembly
|
|
|
99
94
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
|
100
95
|
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
|
101
96
|
def jp2_filename
|
|
102
|
-
File.extname(
|
|
97
|
+
File.extname(path).empty? ? "#{path}.jp2" : path.gsub(File.extname(path), '.jp2')
|
|
103
98
|
end
|
|
104
99
|
|
|
105
100
|
# Returns the full DPG equivalent jp2 path and filename that would match with the given image
|
|
@@ -121,7 +116,6 @@ module Assembly
|
|
|
121
116
|
# * :output => path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
|
|
122
117
|
# * :overwrite => if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
|
123
118
|
# * :tmp_folder => the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
|
|
124
|
-
# * :preserve_tmp_source => if set to true, preserve the temporary file generated during the creation process and store path in 'tmp_path' attribute (default: false)
|
|
125
119
|
#
|
|
126
120
|
# Example:
|
|
127
121
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
|
@@ -130,64 +124,8 @@ module Assembly
|
|
|
130
124
|
# puts derivative_image.path # '/input/path_to_file.jp2'
|
|
131
125
|
# rubocop:disable Metrics/CyclomaticComplexity:
|
|
132
126
|
def create_jp2(params = {})
|
|
133
|
-
|
|
134
|
-
create_jp2_checks(output: output, overwrite: params[:overwrite])
|
|
135
|
-
|
|
136
|
-
# Using instance variable so that can check in tests.
|
|
137
|
-
@tmp_path = make_tmp_tiff(tmp_folder: params[:tmp_folder])
|
|
138
|
-
|
|
139
|
-
jp2_command = jp2_create_command(source_path: @tmp_path, output: output)
|
|
140
|
-
result = `#{jp2_command}`
|
|
141
|
-
raise "JP2 creation command failed: #{jp2_command} with result #{result}" unless $CHILD_STATUS.success?
|
|
142
|
-
|
|
143
|
-
File.delete(@tmp_path) unless @tmp_path.nil? || params[:preserve_tmp_source]
|
|
144
|
-
|
|
145
|
-
# create output response object, which is an Assembly::Image type object
|
|
146
|
-
Assembly::Image.new(output)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
private
|
|
150
|
-
|
|
151
|
-
# def create_temp_tiff?
|
|
152
|
-
# mimetype != 'image/tiff' || compressed?
|
|
153
|
-
# end
|
|
154
|
-
|
|
155
|
-
def create_jp2_checks(output:, overwrite:)
|
|
156
|
-
check_for_file
|
|
157
|
-
raise 'input file is not a valid image, or is the wrong mimetype' unless jp2able?
|
|
158
|
-
|
|
159
|
-
raise SecurityError, "output #{output} exists, cannot overwrite" if !overwrite && File.exist?(output)
|
|
160
|
-
raise SecurityError, 'cannot recreate jp2 over itself' if overwrite && mimetype == 'image/jp2' && output == @path
|
|
161
|
-
end
|
|
162
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
163
|
-
|
|
164
|
-
def jp2_create_command(source_path:, output:)
|
|
165
|
-
kdu_bin = 'kdu_compress'
|
|
166
|
-
options = []
|
|
167
|
-
options << '-jp2_space sRGB' if samples_per_pixel == 3
|
|
168
|
-
options += kdu_compress_default_options
|
|
169
|
-
options << "Clayers=#{layers}"
|
|
170
|
-
"#{kdu_bin} #{options.join(' ')} -i '#{source_path}' -o '#{output}' 2>&1"
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# rubocop:disable Metrics/MethodLength
|
|
174
|
-
def kdu_compress_default_options
|
|
175
|
-
[
|
|
176
|
-
'-num_threads 2', # forces Kakadu to only use 2 threads
|
|
177
|
-
'-precise', # forces the use of 32-bit representations
|
|
178
|
-
'-no_weights', # minimization of the MSE over all reconstructed colour components
|
|
179
|
-
'-quiet', # suppress informative messages.
|
|
180
|
-
'Creversible=no', # Disable reversible compression
|
|
181
|
-
'Cmodes=BYPASS', #
|
|
182
|
-
'Corder=RPCL', # R=resolution P=position C=component L=layer
|
|
183
|
-
'Cblk=\\{64,64\\}', # code-block dimensions; 64x64 happens to also be the default
|
|
184
|
-
'Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\}', # Precinct dimensions; 256x256 for the 2 highest resolution levels, defaults to 128x128 for the rest
|
|
185
|
-
'ORGgen_plt=yes', # Insert packet length information
|
|
186
|
-
'-rate 1.5', # Ratio of compressed bits to the image size
|
|
187
|
-
'Clevels=5' # Number of wavelet decomposition levels, or stages
|
|
188
|
-
]
|
|
127
|
+
Jp2Creator.create(self, params)
|
|
189
128
|
end
|
|
190
|
-
# rubocop:enable Metrics/MethodLength
|
|
191
129
|
|
|
192
130
|
def samples_per_pixel
|
|
193
131
|
if exif['samplesperpixel']
|
|
@@ -202,6 +140,14 @@ module Assembly
|
|
|
202
140
|
end
|
|
203
141
|
end
|
|
204
142
|
|
|
143
|
+
# Get size of image data in bytes
|
|
144
|
+
def image_data_size
|
|
145
|
+
(samples_per_pixel * height * width * bits_per_sample) / 8
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
205
151
|
def bits_per_sample
|
|
206
152
|
if exif['bitspersample']
|
|
207
153
|
exif['bitspersample'].to_i
|
|
@@ -212,96 +158,5 @@ module Assembly
|
|
|
212
158
|
end
|
|
213
159
|
end
|
|
214
160
|
end
|
|
215
|
-
|
|
216
|
-
# Get size of image data in bytes
|
|
217
|
-
def image_data_size
|
|
218
|
-
(samples_per_pixel * height * width * bits_per_sample) / 8
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
# Bigtiff needs to be used if size of image exceeds 2^32 bytes.
|
|
222
|
-
def need_bigtiff?
|
|
223
|
-
image_data_size >= 2**32
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
# Get the number of JP2 layers to generate
|
|
227
|
-
def layers
|
|
228
|
-
pixdem = [width, height].max
|
|
229
|
-
((Math.log(pixdem) / Math.log(2)) - (Math.log(96) / Math.log(2))).ceil + 1
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
# rubocop:disable Metrics/MethodLength
|
|
233
|
-
# rubocop:disable Metrics/AbcSize
|
|
234
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
235
|
-
def profile_conversion_switch(profile, tmp_folder:)
|
|
236
|
-
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
|
|
237
|
-
# eventually we may allow the user to specify the output_profile...when we do, you can just uncomment this code
|
|
238
|
-
# and update the tests that check for this
|
|
239
|
-
output_profile = 'sRGBIEC6196621' # params[:output_profile] || 'sRGBIEC6196621'
|
|
240
|
-
output_profile_file = File.join(path_to_profiles, "#{output_profile}.icc")
|
|
241
|
-
|
|
242
|
-
raise "output profile #{output_profile} invalid" unless File.exist?(output_profile_file)
|
|
243
|
-
|
|
244
|
-
return '' if profile.nil?
|
|
245
|
-
|
|
246
|
-
# if the input color profile exists, contract paths to the profile and setup the command
|
|
247
|
-
|
|
248
|
-
input_profile = profile.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
|
249
|
-
|
|
250
|
-
# construct a path to the input profile, which might exist either in the gem itself or in the tmp folder
|
|
251
|
-
input_profile_file_gem = File.join(path_to_profiles, "#{input_profile}.icc")
|
|
252
|
-
input_profile_file_tmp = File.join(tmp_folder, "#{input_profile}.icc")
|
|
253
|
-
input_profile_file = File.exist?(input_profile_file_gem) ? input_profile_file_gem : input_profile_file_tmp
|
|
254
|
-
|
|
255
|
-
# if input profile was extracted and does not matches an existing known profile either in the gem or in the tmp folder,
|
|
256
|
-
# we'll issue an imagicmagick command to extract the profile to the tmp folder
|
|
257
|
-
unless File.exist?(input_profile_file)
|
|
258
|
-
input_profile_extract_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert '#{@path}'[0] #{input_profile_file}" # extract profile from input image
|
|
259
|
-
result = `#{input_profile_extract_command} 2>&1`
|
|
260
|
-
raise "input profile extraction command failed: #{input_profile_extract_command} with result #{result}" unless $CHILD_STATUS.success?
|
|
261
|
-
# if extraction failed or we cannot write the file, throw exception
|
|
262
|
-
raise 'input profile is not a known profile and could not be extracted from input file' unless File.exist?(input_profile_file)
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
"-profile #{input_profile_file} -profile #{output_profile_file}"
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
def make_tmp_tiff(tmp_folder: nil)
|
|
269
|
-
tmp_folder ||= Dir.tmpdir
|
|
270
|
-
raise "tmp_folder #{tmp_folder} does not exists" unless File.exist?(tmp_folder)
|
|
271
|
-
|
|
272
|
-
# make temp tiff filename
|
|
273
|
-
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
|
|
274
|
-
tmp_path = tmp_tiff_file.path
|
|
275
|
-
|
|
276
|
-
options = []
|
|
277
|
-
|
|
278
|
-
# Limit the amount of memory ImageMagick is able to use.
|
|
279
|
-
options << '-limit memory 1GiB -limit map 1GiB'
|
|
280
|
-
|
|
281
|
-
case samples_per_pixel
|
|
282
|
-
when 3
|
|
283
|
-
options << '-type TrueColor'
|
|
284
|
-
when 1
|
|
285
|
-
options << '-depth 8' # force the production of a grayscale access derivative
|
|
286
|
-
options << '-type Grayscale'
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
options << profile_conversion_switch(profile, tmp_folder: tmp_folder)
|
|
290
|
-
|
|
291
|
-
# The output in the covnert command needs to be prefixed by the image type. By default ImageMagick
|
|
292
|
-
# will assume TIFF: when the file extension is .tif/.tiff. TIFF64: Needs to be forced when image will
|
|
293
|
-
# exceed 2^32 bytes in size
|
|
294
|
-
tiff_type = need_bigtiff? ? 'TIFF64:' : ''
|
|
295
|
-
|
|
296
|
-
tiff_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert -quiet -compress none #{options.join(' ')} '#{@path}[0]' #{tiff_type}'#{tmp_path}'"
|
|
297
|
-
result = `#{tiff_command} 2>&1`
|
|
298
|
-
raise "tiff convert command failed: #{tiff_command} with result #{result}" unless $CHILD_STATUS.success?
|
|
299
|
-
|
|
300
|
-
tmp_path
|
|
301
|
-
end
|
|
302
|
-
# rubocop:enable Metrics/MethodLength
|
|
303
|
-
# rubocop:enable Metrics/AbcSize
|
|
304
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
305
161
|
end
|
|
306
|
-
# rubocop:enable Metrics/ClassLength
|
|
307
162
|
end
|