assembly-image 1.7.0 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +12 -4
- data/.travis.yml +1 -0
- data/Gemfile +2 -0
- data/README.md +4 -4
- data/Rakefile +14 -3
- data/assembly-image.gemspec +8 -6
- data/bin/console +1 -0
- data/config/boot.rb +2 -1
- data/lib/assembly-image/image.rb +101 -75
- data/lib/assembly-image/images.rb +42 -32
- data/lib/assembly-image/version.rb +3 -1
- data/lib/assembly-image.rb +2 -2
- data/spec/image_spec.rb +75 -54
- data/spec/images_spec.rb +21 -20
- data/spec/spec_helper.rb +25 -19
- metadata +19 -6
- data/.rubocop_todo.yml +0 -263
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 37d19061d4cdbcf04b0a9dfa0702d9ae68eda22a248daba5284327d4a0a6586b
|
4
|
+
data.tar.gz: 77961e8b421063939c636e20d32ccfc74e7fa334e2229903d3a9da2a37dfcfa2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e129b0e5549da1e7c3925cded0ad977bd537a4da8492be152738b26fecd18445c3c29e72a5040865cdabca5ce8fe1e3951805abbc2734b2bc38a1d52831ad75
|
7
|
+
data.tar.gz: 848bdfc0b96d1257371fd8b51589eef953020b5dae43c98068206c96b22472ae27bab0b72fcb51e89a2786f5cbd3cec831ebcf2571a0da737cdad10b8b5cbd78
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,21 @@
|
|
1
|
-
inherit_from: .rubocop_todo.yml
|
2
|
-
|
3
1
|
# rspec expect{...} is conventional
|
4
|
-
|
2
|
+
Layout/SpaceBeforeBlockBraces:
|
5
3
|
Exclude:
|
6
4
|
- 'spec/**/*_spec.rb'
|
7
5
|
|
8
|
-
|
6
|
+
Layout/EmptyLineBetweenDefs:
|
9
7
|
AllowAdjacentOneLineDefs: true
|
10
8
|
|
11
9
|
# Configuration parameters: AllowURI, URISchemes.
|
12
10
|
Metrics/LineLength:
|
13
11
|
Max: 200
|
12
|
+
|
13
|
+
Naming/FileName:
|
14
|
+
Exclude:
|
15
|
+
- lib/assembly-image.rb
|
16
|
+
|
17
|
+
Style/WordArray:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
AllCops:
|
21
|
+
TargetRubyVersion: 2.5.3
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -50,6 +50,7 @@ perform image operations necessary for accessioning of content.
|
|
50
50
|
* 1.6.5 fix problem with lack of extension in incoming tif causing a problem when creating jp2
|
51
51
|
* 1.6.7 release to github/rubygems
|
52
52
|
* 1.6.9 update mini_exiftool
|
53
|
+
* 1.7.1 for jp2, only transcode to tiff if not a tiff
|
53
54
|
|
54
55
|
## Notes
|
55
56
|
|
@@ -98,10 +99,9 @@ yard server --reload
|
|
98
99
|
|
99
100
|
## Prerequisites
|
100
101
|
|
101
|
-
1.
|
102
|
-
|
103
|
-
|
104
|
-
4. Exiftool
|
102
|
+
1. Kakadu Proprietary Software Binaries - for JP2 generation
|
103
|
+
1. ImageMagick 6.5.4 or higher
|
104
|
+
1. Exiftool
|
105
105
|
|
106
106
|
### Kakadu
|
107
107
|
|
data/Rakefile
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
3
4
|
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
require 'bundler/gem_tasks'
|
7
|
+
|
8
|
+
desc 'Run style checker'
|
9
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
10
|
+
task.fail_on_error = true
|
11
|
+
end
|
4
12
|
|
5
|
-
desc 'Run specs'
|
6
13
|
RSpec::Core::RakeTask.new(:spec)
|
7
14
|
|
8
|
-
task :
|
15
|
+
task ci: [:rubocop] do
|
16
|
+
Rake::Task['spec'].invoke
|
17
|
+
end
|
18
|
+
|
19
|
+
task default: :ci
|
data/assembly-image.gemspec
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
2
4
|
require 'assembly-image/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |s|
|
5
7
|
s.name = 'assembly-image'
|
6
8
|
s.version = Assembly::Image::VERSION
|
7
|
-
s.authors = ['Peter Mangiafico', 'Renzo Sanchez-Silva','Monty Hindman','Tony Calavano']
|
9
|
+
s.authors = ['Peter Mangiafico', 'Renzo Sanchez-Silva', 'Monty Hindman', 'Tony Calavano']
|
8
10
|
s.email = ['pmangiafico@stanford.edu']
|
9
11
|
s.homepage = ''
|
10
|
-
s.summary =
|
11
|
-
s.description =
|
12
|
+
s.summary = 'Ruby immplementation of image services needed to prepare objects to be accessioned in SULAIR digital library'
|
13
|
+
s.description = 'Contains classes to create derivative image files and perform other image operations'
|
12
14
|
|
13
15
|
s.rubyforge_project = 'assembly-image'
|
14
16
|
|
@@ -21,8 +23,8 @@ Gem::Specification.new do |s|
|
|
21
23
|
s.add_dependency 'assembly-objectfile', '>= 1.6.4'
|
22
24
|
s.add_dependency 'mini_exiftool', '>= 1.6', '< 3'
|
23
25
|
|
26
|
+
s.add_development_dependency 'rake'
|
24
27
|
s.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
s.add_development_dependency 'rubocop'
|
25
29
|
s.add_development_dependency 'yard'
|
26
|
-
s.add_development_dependency 'rake'
|
27
|
-
|
28
30
|
end
|
data/bin/console
CHANGED
data/config/boot.rb
CHANGED
data/lib/assembly-image/image.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'assembly-objectfile'
|
2
4
|
require 'tempfile'
|
3
5
|
|
4
6
|
module Assembly
|
5
|
-
|
6
7
|
# The Image class contains methods to operate on an image.
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
7
9
|
class Image
|
8
|
-
|
9
10
|
# include common behaviors from assembly-objectfile gem
|
10
11
|
include Assembly::ObjectFileable
|
11
12
|
|
@@ -45,7 +46,6 @@ module Assembly
|
|
45
46
|
end
|
46
47
|
|
47
48
|
# Get the image width from exif data
|
48
|
-
#
|
49
49
|
# @return [integer] image height in pixels
|
50
50
|
# Example:
|
51
51
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
@@ -67,19 +67,17 @@ module Assembly
|
|
67
67
|
# Example:
|
68
68
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
69
69
|
# source_img.add_exif_profile_description('Adobe RGB 1998')
|
70
|
-
def add_exif_profile_description(profile_name,force=false)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
raise "profile addition command failed: #{command} with result #{result}" unless $?.success?
|
79
|
-
end
|
80
|
-
rescue Exception => e
|
81
|
-
puts "** Error for #{filename}: #{e.message}"
|
70
|
+
def add_exif_profile_description(profile_name, force = false)
|
71
|
+
if profile.nil? || force
|
72
|
+
input_profile = profile_name.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
73
|
+
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
|
74
|
+
input_profile_file = File.join(path_to_profiles, "#{input_profile}.icc")
|
75
|
+
command = "exiftool '-icc_profile<=#{input_profile_file}' #{path}"
|
76
|
+
result = `#{command} 2>&1`
|
77
|
+
raise "profile addition command failed: #{command} with result #{result}" unless $CHILD_STATUS.success?
|
82
78
|
end
|
79
|
+
rescue StandardError => e
|
80
|
+
puts "** Error for #{filename}: #{e.message}"
|
83
81
|
end
|
84
82
|
|
85
83
|
# Returns the full default jp2 path and filename that will be created from the given image
|
@@ -89,7 +87,7 @@ module Assembly
|
|
89
87
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
90
88
|
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
91
89
|
def jp2_filename
|
92
|
-
File.extname(@path).empty? ? "#{@path}.jp2" : @path.gsub(File.extname(@path),'.jp2')
|
90
|
+
File.extname(@path).empty? ? "#{@path}.jp2" : @path.gsub(File.extname(@path), '.jp2')
|
93
91
|
end
|
94
92
|
|
95
93
|
# Returns the full DPG equivalent jp2 path and filename that would match with the given image
|
@@ -99,7 +97,7 @@ module Assembly
|
|
99
97
|
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
100
98
|
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
101
99
|
def dpg_jp2_filename
|
102
|
-
jp2_filename.gsub('_00_','_05_')
|
100
|
+
jp2_filename.gsub('_00_', '_05_')
|
103
101
|
end
|
104
102
|
|
105
103
|
# Create a JP2 file for the current image.
|
@@ -118,65 +116,52 @@ module Assembly
|
|
118
116
|
# derivative_img=source_img.create_jp2(:overwrite=>true)
|
119
117
|
# puts derivative_img.mimetype # 'image/jp2'
|
120
118
|
# puts derivative_image.path # '/input/path_to_file.jp2'
|
119
|
+
# rubocop:disable Metrics/AbcSize
|
120
|
+
# rubocop:disable Metrics/MethodLength
|
121
121
|
def create_jp2(params = {})
|
122
|
+
output = params[:output] || jp2_filename
|
123
|
+
create_jp2_checks(output: output, overwrite: params[:overwrite])
|
122
124
|
|
123
|
-
|
125
|
+
# Using instance variable so that can check in tests.
|
126
|
+
source_path = if mimetype != 'image/tiff'
|
127
|
+
@tmp_path = make_tmp_tiff(tmp_folder: params[:tmp_folder])
|
128
|
+
else
|
129
|
+
@path
|
130
|
+
end
|
124
131
|
|
125
|
-
|
132
|
+
result = `#{jp2_create_command(source_path: source_path, output: output)}`
|
133
|
+
raise "JP2 creation command failed: #{jp2_command} with result #{result}" unless $CHILD_STATUS.success?
|
126
134
|
|
127
|
-
|
128
|
-
overwrite = params[:overwrite] || false
|
135
|
+
File.delete(source_path) unless @tmp_path.nil? || params[:preserve_tmp_source]
|
129
136
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
raise "tmp_folder #{tmp_folder} does not exists" unless File.exists?(tmp_folder)
|
136
|
-
|
137
|
-
preserve_tmp_source = params[:preserve_tmp_source] || false
|
138
|
-
|
139
|
-
# make temp tiff filename
|
140
|
-
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
|
141
|
-
@tmp_path = tmp_tiff_file.path
|
137
|
+
# create output response object, which is an Assembly::Image type object
|
138
|
+
Assembly::Image.new(output)
|
139
|
+
end
|
140
|
+
# rubocop:enable Metrics/AbcSize
|
141
|
+
# rubocop:enable Metrics/MethodLength
|
142
142
|
|
143
|
-
|
144
|
-
case samples_per_pixel
|
145
|
-
when 3
|
146
|
-
options << '-type TrueColor'
|
147
|
-
when 1
|
148
|
-
if bits_per_sample == 1
|
149
|
-
options << '-type Bilevel'
|
150
|
-
options << '-depth 8' # force the production of a grayscale access derivative
|
151
|
-
elsif bits_per_sample > 1
|
152
|
-
options << '-type Grayscale'
|
153
|
-
end
|
154
|
-
end
|
143
|
+
private
|
155
144
|
|
156
|
-
|
145
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
146
|
+
def create_jp2_checks(output:, overwrite:)
|
147
|
+
check_for_file
|
148
|
+
raise 'input file is not a valid image, or is the wrong mimetype' unless jp2able?
|
157
149
|
|
158
|
-
|
159
|
-
|
160
|
-
|
150
|
+
raise SecurityError, "output #{output} exists, cannot overwrite" if !overwrite && File.exist?(output)
|
151
|
+
raise SecurityError, 'cannot recreate jp2 over itself' if overwrite && mimetype == 'image/jp2' && output == @path
|
152
|
+
end
|
153
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
161
154
|
|
162
|
-
|
155
|
+
def jp2_create_command(source_path:, output:)
|
163
156
|
kdu_bin = 'kdu_compress'
|
164
157
|
options = []
|
165
158
|
options << '-jp2_space sRGB' if samples_per_pixel == 3
|
166
159
|
options += kdu_compress_default_options
|
167
|
-
options << "Clayers=#{layers
|
168
|
-
|
169
|
-
result=`#{jp2_command} 2>&1`
|
170
|
-
raise "JP2 creation command failed: #{jp2_command} with result #{result}" unless $?.success?
|
171
|
-
|
172
|
-
tmp_tiff_file.delete unless preserve_tmp_source
|
173
|
-
|
174
|
-
# create output response object, which is an Assembly::Image type object
|
175
|
-
Assembly::Image.new(output)
|
160
|
+
options << "Clayers=#{layers}"
|
161
|
+
"#{kdu_bin} #{options.join(' ')} -i '#{source_path}' -o '#{output}' 2>&1"
|
176
162
|
end
|
177
163
|
|
178
|
-
|
179
|
-
|
164
|
+
# rubocop:disable Metrics/MethodLength
|
180
165
|
def kdu_compress_default_options
|
181
166
|
[
|
182
167
|
'-precise', # forces the use of 32-bit representations
|
@@ -192,6 +177,7 @@ module Assembly
|
|
192
177
|
'Clevels=5' # Number of wavelet decomposition levels, or stages
|
193
178
|
]
|
194
179
|
end
|
180
|
+
# rubocop:enable Metrics/MethodLength
|
195
181
|
|
196
182
|
def samples_per_pixel
|
197
183
|
if exif['samplesperpixel']
|
@@ -218,37 +204,77 @@ module Assembly
|
|
218
204
|
# Get the number of JP2 layers to generate
|
219
205
|
def layers
|
220
206
|
pixdem = [width, height].max
|
221
|
-
((
|
207
|
+
((Math.log(pixdem) / Math.log(2)) - (Math.log(96) / Math.log(2))).ceil + 1
|
222
208
|
end
|
223
209
|
|
210
|
+
# rubocop:disable Metrics/MethodLength
|
211
|
+
# rubocop:disable Metrics/AbcSize
|
212
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
224
213
|
def profile_conversion_switch(profile, tmp_folder:)
|
225
|
-
path_to_profiles
|
226
|
-
|
227
|
-
|
214
|
+
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
|
215
|
+
# eventually we may allow the user to specify the output_profile...when we do, you can just uncomment this code
|
216
|
+
# and update the tests that check for this
|
217
|
+
output_profile = 'sRGBIEC6196621' # params[:output_profile] || 'sRGBIEC6196621'
|
218
|
+
output_profile_file = File.join(path_to_profiles, "#{output_profile}.icc")
|
228
219
|
|
229
|
-
raise "output profile #{output_profile} invalid" unless File.
|
220
|
+
raise "output profile #{output_profile} invalid" unless File.exist?(output_profile_file)
|
230
221
|
|
231
222
|
return '' if profile.nil?
|
232
223
|
|
233
224
|
# if the input color profile exists, contract paths to the profile and setup the command
|
234
225
|
|
235
|
-
input_profile = profile.gsub(/[^[:alnum:]]/, '')
|
226
|
+
input_profile = profile.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
236
227
|
|
237
228
|
# construct a path to the input profile, which might exist either in the gem itself or in the tmp folder
|
238
|
-
input_profile_file_gem = File.join(path_to_profiles,"#{input_profile}.icc")
|
239
|
-
input_profile_file_tmp = File.join(tmp_folder,"#{input_profile}.icc")
|
240
|
-
input_profile_file = File.
|
229
|
+
input_profile_file_gem = File.join(path_to_profiles, "#{input_profile}.icc")
|
230
|
+
input_profile_file_tmp = File.join(tmp_folder, "#{input_profile}.icc")
|
231
|
+
input_profile_file = File.exist?(input_profile_file_gem) ? input_profile_file_gem : input_profile_file_tmp
|
241
232
|
|
242
233
|
# if input profile was extracted and does not matches an existing known profile either in the gem or in the tmp folder,
|
243
234
|
# we'll issue an imagicmagick command to extract the profile to the tmp folder
|
244
|
-
unless File.
|
245
|
-
|
246
|
-
result
|
247
|
-
raise "input profile extraction command failed: #{
|
248
|
-
|
235
|
+
unless File.exist?(input_profile_file)
|
236
|
+
input_profile_extract_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert '#{@path}'[0] #{input_profile_file}" # extract profile from input image
|
237
|
+
result = `#{input_profile_extract_command} 2>&1`
|
238
|
+
raise "input profile extraction command failed: #{input_profile_extract_command} with result #{result}" unless $CHILD_STATUS.success?
|
239
|
+
# if extraction failed or we cannot write the file, throw exception
|
240
|
+
raise 'input profile is not a known profile and could not be extracted from input file' unless File.exist?(input_profile_file)
|
249
241
|
end
|
250
242
|
|
251
243
|
"-profile #{input_profile_file} -profile #{output_profile_file}"
|
252
244
|
end
|
245
|
+
|
246
|
+
def make_tmp_tiff(tmp_folder: nil)
|
247
|
+
tmp_folder ||= Dir.tmpdir
|
248
|
+
raise "tmp_folder #{tmp_folder} does not exists" unless File.exist?(tmp_folder)
|
249
|
+
|
250
|
+
# make temp tiff filename
|
251
|
+
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
|
252
|
+
tmp_path = tmp_tiff_file.path
|
253
|
+
|
254
|
+
options = []
|
255
|
+
case samples_per_pixel
|
256
|
+
when 3
|
257
|
+
options << '-type TrueColor'
|
258
|
+
when 1
|
259
|
+
if bits_per_sample == 1
|
260
|
+
options << '-type Bilevel'
|
261
|
+
options << '-depth 8' # force the production of a grayscale access derivative
|
262
|
+
elsif bits_per_sample > 1
|
263
|
+
options << '-type Grayscale'
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
options << profile_conversion_switch(profile, tmp_folder: tmp_folder)
|
268
|
+
|
269
|
+
tiff_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert -quiet -compress none #{options.join(' ')} '#{@path}[0]' '#{tmp_path}'"
|
270
|
+
result = `#{tiff_command} 2>&1`
|
271
|
+
raise "tiff convert command failed: #{tiff_command} with result #{result}" unless $CHILD_STATUS.success?
|
272
|
+
|
273
|
+
tmp_path
|
274
|
+
end
|
275
|
+
# rubocop:enable Metrics/MethodLength
|
276
|
+
# rubocop:enable Metrics/AbcSize
|
277
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
253
278
|
end
|
279
|
+
# rubocop:enable Metrics/ClassLength
|
254
280
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
2
4
|
module Assembly
|
3
|
-
|
4
5
|
# The Images class contains methods to operate on multiple images in batch.
|
5
6
|
class Images
|
6
|
-
|
7
7
|
def self.logger
|
8
8
|
@logger ||= Logger.new(STDERR)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
class << self
|
12
|
+
attr_writer :logger
|
13
13
|
end
|
14
14
|
|
15
15
|
# Pass in a source path and have exif color profile descriptions added to all images contained.
|
@@ -28,8 +28,9 @@ module Assembly
|
|
28
28
|
#
|
29
29
|
# Example:
|
30
30
|
# Assembly::Images.batch_add_exif_profile_description('/full_path_to_tifs','Adobe RGB 1998')
|
31
|
-
|
32
|
-
|
31
|
+
# rubocop:disable Metrics/MethodLength
|
32
|
+
# rubocop:disable Metrics/AbcSize
|
33
|
+
def self.batch_add_exif_profile_descr(source, profile_name, params = {})
|
33
34
|
extension = params[:extension] || 'tif'
|
34
35
|
recursive = params[:recursive] || false
|
35
36
|
force = params[:force] || false
|
@@ -40,13 +41,15 @@ module Assembly
|
|
40
41
|
|
41
42
|
# iterate over input directory looking for tifs
|
42
43
|
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
43
|
-
Dir.glob(File.join(source,pattern)).each do |file|
|
44
|
-
img=Assembly::Image.new(file)
|
44
|
+
Dir.glob(File.join(source, pattern)).each do |file|
|
45
|
+
img = Assembly::Image.new(file)
|
45
46
|
logger.debug "Processing #{file}"
|
46
|
-
img.add_exif_profile_description(profile_name,force)
|
47
|
+
img.add_exif_profile_description(profile_name, force)
|
47
48
|
end
|
48
49
|
'Complete'
|
49
50
|
end
|
51
|
+
# rubocop:enable Metrics/MethodLength
|
52
|
+
# rubocop:enable Metrics/AbcSize
|
50
53
|
|
51
54
|
# Pass in a source path and get JP2s generate for each tiff that is in the source path
|
52
55
|
#
|
@@ -63,35 +66,42 @@ module Assembly
|
|
63
66
|
#
|
64
67
|
# Example:
|
65
68
|
# Assembly::Images.batch_generate_jp2('/full_path_to_tifs')
|
66
|
-
|
69
|
+
# rubocop:disable Metrics/MethodLength
|
70
|
+
# rubocop:disable Metrics/AbcSize
|
71
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
72
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
73
|
+
def self.batch_generate_jp2(source, params = {})
|
74
|
+
raise 'Input path does not exist' unless File.directory?(source)
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
recursive = params[:recursive] || false
|
76
|
+
output = params[:output] || File.join(source, 'jp2') # default output directgory is jp2 sub-directory from source
|
77
|
+
extension = params[:extension] || 'tif'
|
78
|
+
overwrite = params[:overwrite] || false
|
79
|
+
recursive = params[:recursive] || false
|
73
80
|
|
74
|
-
|
75
|
-
|
81
|
+
Dir.mkdir(output) unless File.directory?(output) # attemp to make output directory
|
82
|
+
raise 'Output path does not exist or could not be created' unless File.directory?(output)
|
76
83
|
|
77
|
-
|
78
|
-
|
84
|
+
logger.debug "Source: #{source}"
|
85
|
+
logger.debug "Destination: #{output}"
|
79
86
|
|
80
|
-
|
87
|
+
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
81
88
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
89
|
+
# iterate over input directory looking for tifs
|
90
|
+
Dir.glob(File.join(source, pattern)).each do |file|
|
91
|
+
source_img = Assembly::Image.new(file)
|
92
|
+
output_img = File.join(output, File.basename(file, File.extname(file)) + '.jp2') # output image gets same file name as source, but with a jp2 extension and in the correct output directory
|
93
|
+
begin
|
94
|
+
source_img.create_jp2(overwrite: overwrite, output: output_img)
|
95
|
+
logger.debug "Generated jp2 for #{File.basename(file)}"
|
96
|
+
rescue StandardError => e
|
97
|
+
logger.debug "** Error for #{File.basename(file)}: #{e.message}"
|
92
98
|
end
|
93
|
-
|
94
|
-
|
99
|
+
end
|
100
|
+
'Complete'
|
95
101
|
end
|
102
|
+
# rubocop:enable Metrics/MethodLength
|
103
|
+
# rubocop:enable Metrics/AbcSize
|
104
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
105
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
96
106
|
end
|
97
107
|
end
|
data/lib/assembly-image.rb
CHANGED
data/spec/image_spec.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
3
6
|
describe Assembly::Image do
|
4
|
-
|
5
7
|
it 'should not run if no input file is passed in' do
|
6
|
-
@ai=Assembly::Image.new('')
|
7
|
-
expect{@ai.create_jp2}.to raise_error
|
8
|
+
@ai = Assembly::Image.new('')
|
9
|
+
expect{ @ai.create_jp2 }.to raise_error
|
8
10
|
end
|
9
11
|
|
10
12
|
it 'should indicate the default jp2 filename' do
|
11
13
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
12
|
-
expect(@ai.jp2_filename).to eq TEST_TIF_INPUT_FILE.gsub('.tif','.jp2')
|
14
|
+
expect(@ai.jp2_filename).to eq TEST_TIF_INPUT_FILE.gsub('.tif', '.jp2')
|
13
15
|
end
|
14
16
|
|
15
17
|
it 'should indicate the default jp2 filename' do
|
@@ -19,7 +21,7 @@ describe Assembly::Image do
|
|
19
21
|
|
20
22
|
it 'should indicate the default DPG jp2 filename' do
|
21
23
|
@ai = Assembly::Image.new(TEST_DPG_TIF_INPUT_FILE)
|
22
|
-
expect(@ai.dpg_jp2_filename).to eq TEST_DPG_TIF_INPUT_FILE.gsub('.tif','.jp2').gsub('_00_','_05_')
|
24
|
+
expect(@ai.dpg_jp2_filename).to eq TEST_DPG_TIF_INPUT_FILE.gsub('.tif', '.jp2').gsub('_00_', '_05_')
|
23
25
|
end
|
24
26
|
|
25
27
|
it 'should indicate the default jp2 filename' do
|
@@ -32,77 +34,92 @@ describe Assembly::Image do
|
|
32
34
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
33
35
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
34
36
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
35
|
-
result
|
37
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
38
|
+
# Indicates a temp tiff was not created.
|
39
|
+
expect(@ai.tmp_path).to be_nil
|
36
40
|
expect(result).to be_a_kind_of Assembly::Image
|
37
41
|
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
38
42
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
39
43
|
expect(result.exif.colorspace).to eq 'sRGB'
|
40
|
-
@jp2=Assembly::Image.new(TEST_JP2_OUTPUT_FILE)
|
44
|
+
@jp2 = Assembly::Image.new(TEST_JP2_OUTPUT_FILE)
|
41
45
|
expect(@jp2.height).to eq 100
|
42
46
|
expect(@jp2.width).to eq 100
|
43
47
|
end
|
44
48
|
|
45
49
|
it 'should create grayscale jp2 when given a bitonal tif' do
|
46
50
|
skip 'The latest version of Kakadu may require some changes for this work correctly'
|
47
|
-
# error message is
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
# error message is
|
52
|
+
# JP2 creation command failed: kdu_compress -precise -no_weights -quiet Creversible=no Cmodes=BYPASS
|
53
|
+
# Corder=RPCL Cblk=\{64,64\} Cprecincts=\{256,256\},\{256,256\},\{128,128\} ORGgen_plt=yes -rate 1.5 Clevels=5
|
54
|
+
# Clayers=2 -i '/tmp/408d3740-e25f-4c1b-889f-3f138d088fe4.tif' -o '/home/travis/build/sul-dlss/assembly-image/spec/test_data/output/test.jp2'
|
55
|
+
# with result Kakadu Error:
|
56
|
+
# The number of colours associated with the colour space identified by the source
|
57
|
+
# file (possible from an embedded ICC profile) is not consistent with the number
|
58
|
+
# of supplied image components and/or colour palette. You can address this
|
59
|
+
# problem by supplying a `-jp2_space' or `-jpx_space' argument to explicitly
|
60
|
+
# identify a colour space that has anywhere from 1 to 1 colour components.
|
61
|
+
generate_test_image(TEST_TIF_INPUT_FILE, color: 'white', image_type: 'Bilevel')
|
55
62
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
56
63
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
57
64
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
58
65
|
expect(@ai).to have_color_profile
|
59
|
-
result
|
66
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
67
|
+
# Indicates a temp tiff was not created.
|
68
|
+
expect(@ai.tmp_path).to be_nil
|
60
69
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
61
70
|
expect(result.exif.colorspace).to eq 'Grayscale'
|
62
71
|
end
|
63
72
|
|
64
73
|
it 'should create color jp2 when given a color tif but bitonal image data (1 channels and 1 bits per pixel)' do
|
65
|
-
generate_test_image(TEST_TIF_INPUT_FILE
|
74
|
+
generate_test_image(TEST_TIF_INPUT_FILE, color: 'white', image_type: 'TrueColor', profile: '')
|
66
75
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
67
76
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
68
77
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
69
78
|
expect(@ai).to_not have_color_profile
|
70
|
-
result
|
79
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
80
|
+
# Indicates a temp tiff was not created.
|
81
|
+
expect(@ai.tmp_path).to be_nil
|
71
82
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
72
83
|
expect(result.exif.colorspace).to eq 'sRGB'
|
73
84
|
end
|
74
85
|
|
75
86
|
it 'should create grayscale jp2 when given a graycale tif but with bitonal image data (1 channel and 1 bits per pixel)' do
|
76
|
-
generate_test_image(TEST_TIF_INPUT_FILE
|
87
|
+
generate_test_image(TEST_TIF_INPUT_FILE, color: 'white', image_type: 'Grayscale', profile: '')
|
77
88
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
78
89
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
79
90
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
91
|
+
# Indicates a temp tiff was not created.
|
92
|
+
expect(@ai.tmp_path).to be_nil
|
80
93
|
expect(@ai).to_not have_color_profile
|
81
|
-
result
|
94
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
82
95
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
83
96
|
expect(result.exif.colorspace).to eq 'Grayscale'
|
84
97
|
end
|
85
98
|
|
86
99
|
it 'should create color jp2 when given a color tif but with greyscale image data (1 channel and 8 bits per pixel)' do
|
87
|
-
generate_test_image(TEST_TIF_INPUT_FILE
|
100
|
+
generate_test_image(TEST_TIF_INPUT_FILE, color: 'gray', image_type: 'TrueColor', profile: '')
|
88
101
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
89
102
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
90
103
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
104
|
+
# Indicates a temp tiff was not created.
|
105
|
+
expect(@ai.tmp_path).to be_nil
|
91
106
|
expect(@ai).to_not have_color_profile
|
92
|
-
result
|
107
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
93
108
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
94
109
|
expect(result.exif.colorspace).to eq 'sRGB'
|
95
110
|
end
|
96
111
|
|
97
112
|
it 'should create a jp2 when the source image has no profile' do
|
98
|
-
generate_test_image(TEST_TIF_INPUT_FILE
|
113
|
+
generate_test_image(TEST_TIF_INPUT_FILE, profile: '') # generate a test input with no profile
|
99
114
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
100
115
|
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
101
116
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
117
|
+
# Indicates a temp tiff was not created.
|
118
|
+
expect(@ai.tmp_path).to be_nil
|
102
119
|
expect(@ai).to_not have_color_profile
|
103
120
|
expect(@ai).to be_a_valid_image
|
104
121
|
expect(@ai).to be_jp2able
|
105
|
-
@ai.create_jp2(:
|
122
|
+
@ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
106
123
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
107
124
|
end
|
108
125
|
|
@@ -112,7 +129,7 @@ describe Assembly::Image do
|
|
112
129
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
113
130
|
expect(File).to exist TEST_JP2_OUTPUT_FILE
|
114
131
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
115
|
-
expect{@ai.create_jp2(:
|
132
|
+
expect{ @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE) }.to raise_error(SecurityError)
|
116
133
|
end
|
117
134
|
|
118
135
|
it 'should get the correct image height and width' do
|
@@ -135,57 +152,61 @@ describe Assembly::Image do
|
|
135
152
|
generate_test_image(TEST_TIF_INPUT_FILE)
|
136
153
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
137
154
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
138
|
-
result
|
155
|
+
result = @ai.create_jp2(output_profile: 'bogusness')
|
139
156
|
expect(result).to be_a_kind_of Assembly::Image
|
140
157
|
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
141
158
|
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
142
159
|
expect(result.exif.colorspace).to eq 'sRGB'
|
143
160
|
end
|
144
161
|
|
162
|
+
it 'should create jp2 when given a JPEG' do
|
163
|
+
generate_test_image(TEST_JPEG_INPUT_FILE)
|
164
|
+
expect(File).to exist TEST_JPEG_INPUT_FILE
|
165
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
166
|
+
@ai = Assembly::Image.new(TEST_JPEG_INPUT_FILE)
|
167
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE)
|
168
|
+
# Indicates a temp tiff was created.
|
169
|
+
expect(@ai.tmp_path).not_to be_nil
|
170
|
+
expect(File).not_to exist @ai.tmp_path
|
171
|
+
expect(result).to be_a_kind_of Assembly::Image
|
172
|
+
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
173
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
174
|
+
end
|
175
|
+
|
145
176
|
it 'should not run if you specify a bogus tmp folder' do
|
146
|
-
generate_test_image(
|
147
|
-
bogus_folder='/crapsticks'
|
148
|
-
expect(File).to exist
|
177
|
+
generate_test_image(TEST_JPEG_INPUT_FILE)
|
178
|
+
bogus_folder = '/crapsticks'
|
179
|
+
expect(File).to exist TEST_JPEG_INPUT_FILE
|
149
180
|
expect(File).to_not exist bogus_folder
|
150
|
-
@ai = Assembly::Image.new(
|
151
|
-
expect { @ai.create_jp2(:
|
181
|
+
@ai = Assembly::Image.new(TEST_JPEG_INPUT_FILE)
|
182
|
+
expect { @ai.create_jp2(tmp_folder: bogus_folder) }.to raise_error
|
152
183
|
end
|
153
184
|
|
154
185
|
it 'should create a jp2 and preserve the temporary file if specified' do
|
155
|
-
generate_test_image(
|
156
|
-
expect(File).to exist
|
157
|
-
@ai = Assembly::Image.new(
|
158
|
-
result
|
186
|
+
generate_test_image(TEST_JPEG_INPUT_FILE)
|
187
|
+
expect(File).to exist TEST_JPEG_INPUT_FILE
|
188
|
+
@ai = Assembly::Image.new(TEST_JPEG_INPUT_FILE)
|
189
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE, preserve_tmp_source: true)
|
190
|
+
# Indicates a temp tiff was created.
|
191
|
+
expect(@ai.tmp_path).not_to be_nil
|
192
|
+
expect(File).to exist @ai.tmp_path
|
159
193
|
expect(result).to be_a_kind_of Assembly::Image
|
160
194
|
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
161
195
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
162
|
-
expect(
|
163
|
-
expect(File.exists?(@ai.tmp_path)).to be true
|
196
|
+
expect(File.exist?(@ai.tmp_path)).to be true
|
164
197
|
end
|
165
198
|
|
166
199
|
it 'should create jp2 of the same filename and in the same location as the input if no output file is specified, and should cleanup tmp file' do
|
167
200
|
generate_test_image(TEST_TIF_INPUT_FILE)
|
168
201
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
169
|
-
expect(File.
|
202
|
+
expect(File.exist?(TEST_JP2_INPUT_FILE)).to be false
|
170
203
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
171
|
-
result
|
204
|
+
result = @ai.create_jp2
|
172
205
|
expect(result).to be_a_kind_of Assembly::Image
|
173
206
|
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
174
207
|
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
175
208
|
expect(result.exif.colorspace).to eq 'sRGB'
|
176
|
-
expect(
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'should create jp2 from input JPEG of the same filename and in the same location as the input if no output file is specified, and should cleanup tmp file' do
|
180
|
-
generate_test_image(TEST_JPEG_INPUT_FILE)
|
181
|
-
expect(File).to exist TEST_JPEG_INPUT_FILE
|
182
|
-
expect(File).to_not exist TEST_JP2_INPUT_FILE
|
183
|
-
@ai = Assembly::Image.new(TEST_JPEG_INPUT_FILE)
|
184
|
-
result=@ai.create_jp2
|
185
|
-
expect(result).to be_a_kind_of Assembly::Image
|
186
|
-
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
187
|
-
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
188
|
-
expect(File.exists?(@ai.tmp_path)).to be false
|
209
|
+
expect(@ai.tmp_path).to be_nil
|
189
210
|
end
|
190
211
|
|
191
212
|
it 'should recreate jp2 if the output file exists and if you allow overwriting' do
|
@@ -194,7 +215,7 @@ describe Assembly::Image do
|
|
194
215
|
expect(File).to exist TEST_TIF_INPUT_FILE
|
195
216
|
expect(File).to exist TEST_JP2_OUTPUT_FILE
|
196
217
|
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
197
|
-
result
|
218
|
+
result = @ai.create_jp2(output: TEST_JP2_OUTPUT_FILE, overwrite: true)
|
198
219
|
expect(result).to be_a_kind_of Assembly::Image
|
199
220
|
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
200
221
|
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
@@ -206,5 +227,5 @@ describe Assembly::Image do
|
|
206
227
|
remove_files(TEST_INPUT_DIR)
|
207
228
|
remove_files(TEST_OUTPUT_DIR)
|
208
229
|
end
|
209
|
-
|
210
230
|
end
|
231
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/images_spec.rb
CHANGED
@@ -1,48 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
3
6
|
describe Assembly::Images do
|
4
|
-
|
5
7
|
it 'should not run if no input folder is passed in' do
|
6
|
-
expect{Assembly::Images.batch_generate_jp2('')}.to raise_error
|
8
|
+
expect{ Assembly::Images.batch_generate_jp2('') }.to raise_error
|
7
9
|
end
|
8
10
|
|
9
11
|
it 'should not run if a non-existent input folder is passed in' do
|
10
|
-
expect{Assembly::Images.batch_generate_jp2('/junk/path')}.to raise_error
|
12
|
+
expect{ Assembly::Images.batch_generate_jp2('/junk/path') }.to raise_error
|
11
13
|
end
|
12
14
|
|
13
15
|
it 'should run and batch produe jp2s from input tiffs' do
|
14
|
-
['test1','test2','test3'].each {|image| generate_test_image(File.join(TEST_INPUT_DIR,"#{image}.tif")) }
|
15
|
-
Assembly::Images.batch_generate_jp2(TEST_INPUT_DIR
|
16
|
+
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif")) }
|
17
|
+
Assembly::Images.batch_generate_jp2(TEST_INPUT_DIR, output: TEST_OUTPUT_DIR)
|
16
18
|
expect(File.directory?(TEST_OUTPUT_DIR)).to be true
|
17
|
-
['test1','test2','test3'].each {|image| expect(File.join(TEST_OUTPUT_DIR,"#{image}.jp2")).to be_a_jp2 }
|
19
|
+
['test1', 'test2', 'test3'].each { |image| expect(File.join(TEST_OUTPUT_DIR, "#{image}.jp2")).to be_a_jp2 }
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'should run and batch add color profile descriptions input tiffs with no color profile descriptions' do
|
21
|
-
['test1','test2','test3'].each {|image| generate_test_image(File.join(TEST_INPUT_DIR,"#{image}.tif")
|
22
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to be nil}
|
23
|
-
Assembly::Images.
|
24
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)'}
|
23
|
+
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif"), profile: '') }
|
24
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to be nil }
|
25
|
+
Assembly::Images.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998')
|
26
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)' }
|
25
27
|
end
|
26
28
|
|
27
29
|
it 'should run and batch add color profile descriptions input tiffs, forcing over existing color profile descriptions' do
|
28
|
-
['test1','test2','test3'].each {|image| generate_test_image(File.join(TEST_INPUT_DIR,"#{image}.tif")) }
|
29
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq
|
30
|
-
Assembly::Images.
|
31
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq
|
30
|
+
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif")) }
|
31
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
32
|
+
Assembly::Images.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998', force: true) # force overwrite
|
33
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)' }
|
32
34
|
end
|
33
35
|
|
34
36
|
it 'should run and batch add color profile descriptions input tiffs, not overwriting existing color profile descriptions' do
|
35
|
-
['test1','test2','test3'].each {|image| generate_test_image(File.join(TEST_INPUT_DIR,"#{image}.tif")) }
|
36
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq
|
37
|
-
Assembly::Images.
|
38
|
-
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq
|
37
|
+
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif")) }
|
38
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
39
|
+
Assembly::Images.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998') # do not force overwrite
|
40
|
+
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
39
41
|
end
|
40
42
|
|
41
|
-
|
42
43
|
after(:each) do
|
43
44
|
# after each test, empty out the input and output test directories
|
44
45
|
remove_files(TEST_INPUT_DIR)
|
45
46
|
remove_files(TEST_OUTPUT_DIR)
|
46
47
|
end
|
47
|
-
|
48
48
|
end
|
49
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/spec_helper.rb
CHANGED
@@ -1,38 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
bootfile = File.expand_path(File.dirname(__FILE__) + '/../config/boot')
|
2
4
|
require bootfile
|
5
|
+
require 'English'
|
3
6
|
|
4
|
-
TEST_INPUT_DIR = File.join(Assembly::PATH_TO_IMAGE_GEM,'spec','test_data','input')
|
5
|
-
TEST_OUTPUT_DIR = File.join(Assembly::PATH_TO_IMAGE_GEM,'spec','test_data','output')
|
6
|
-
TEST_TIF_INPUT_FILE = File.join(TEST_INPUT_DIR,'test.tif')
|
7
|
-
TEST_DPG_TIF_INPUT_FILE
|
8
|
-
TEST_JPEG_INPUT_FILE
|
9
|
-
TEST_JP2_INPUT_FILE = File.join(TEST_INPUT_DIR,'test.jp2')
|
10
|
-
TEST_JP2_OUTPUT_FILE = File.join(TEST_OUTPUT_DIR,'test.jp2')
|
7
|
+
TEST_INPUT_DIR = File.join(Assembly::PATH_TO_IMAGE_GEM, 'spec', 'test_data', 'input')
|
8
|
+
TEST_OUTPUT_DIR = File.join(Assembly::PATH_TO_IMAGE_GEM, 'spec', 'test_data', 'output')
|
9
|
+
TEST_TIF_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.tif')
|
10
|
+
TEST_DPG_TIF_INPUT_FILE = File.join(TEST_INPUT_DIR, 'oo000oo0001_00_01.tif')
|
11
|
+
TEST_JPEG_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jpg')
|
12
|
+
TEST_JP2_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jp2')
|
13
|
+
TEST_JP2_OUTPUT_FILE = File.join(TEST_OUTPUT_DIR, 'test.jp2')
|
11
14
|
TEST_DRUID = 'nx288wh8889'
|
12
15
|
|
13
16
|
# generate a sample image file with a specified profile
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
create_command
|
17
|
+
# rubocop:disable Metrics/AbcSize
|
18
|
+
def generate_test_image(file, params = {})
|
19
|
+
color = params[:color] || 'red'
|
20
|
+
profile = params[:profile] || 'sRGBIEC6196621'
|
21
|
+
image_type = params[:image_type]
|
22
|
+
create_command = "convert -size 100x100 xc:#{color} "
|
23
|
+
create_command += ' -profile ' + File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles', profile + '.icc') + ' ' unless profile == ''
|
20
24
|
create_command += " -type #{image_type} " if image_type
|
21
25
|
create_command += file
|
22
26
|
create_command += ' 2>&1'
|
23
|
-
output = `#{create_command}`
|
24
|
-
unless
|
25
|
-
raise "Failed to create test image #{file} (#{params}): \n#{output}"
|
26
|
-
end
|
27
|
+
output = `#{ create_command }`
|
28
|
+
raise "Failed to create test image #{file} (#{params}): \n#{output}" unless $CHILD_STATUS.success?
|
27
29
|
end
|
30
|
+
# rubocop:enable Metrics/AbcSize
|
28
31
|
|
29
32
|
def remove_files(dir)
|
30
|
-
Dir.foreach(dir)
|
33
|
+
Dir.foreach(dir) do |f|
|
34
|
+
fn = File.join(dir, f)
|
35
|
+
File.delete(fn) if !File.directory?(fn) && File.basename(fn) != '.empty'
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
RSpec::Matchers.define :be_a_jp2 do
|
34
40
|
match do |actual|
|
35
|
-
if File.
|
41
|
+
if File.exist?(actual)
|
36
42
|
exif = MiniExiftool.new actual
|
37
43
|
exif['mimetype'] == 'image/jp2'
|
38
44
|
else
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: assembly-image
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.
|
4
|
+
version: 1.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Mangiafico
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2019-01-25 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: assembly-objectfile
|
@@ -47,6 +47,20 @@ dependencies:
|
|
47
47
|
- - "<"
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '3'
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
50
64
|
- !ruby/object:Gem::Dependency
|
51
65
|
name: rspec
|
52
66
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,7 +76,7 @@ dependencies:
|
|
62
76
|
- !ruby/object:Gem::Version
|
63
77
|
version: '3.0'
|
64
78
|
- !ruby/object:Gem::Dependency
|
65
|
-
name:
|
79
|
+
name: rubocop
|
66
80
|
requirement: !ruby/object:Gem::Requirement
|
67
81
|
requirements:
|
68
82
|
- - ">="
|
@@ -76,7 +90,7 @@ dependencies:
|
|
76
90
|
- !ruby/object:Gem::Version
|
77
91
|
version: '0'
|
78
92
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
93
|
+
name: yard
|
80
94
|
requirement: !ruby/object:Gem::Requirement
|
81
95
|
requirements:
|
82
96
|
- - ">="
|
@@ -100,7 +114,6 @@ files:
|
|
100
114
|
- ".gitignore"
|
101
115
|
- ".rspec"
|
102
116
|
- ".rubocop.yml"
|
103
|
-
- ".rubocop_todo.yml"
|
104
117
|
- ".rvmrc.example"
|
105
118
|
- ".travis.yml"
|
106
119
|
- Gemfile
|
@@ -142,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
155
|
version: '0'
|
143
156
|
requirements: []
|
144
157
|
rubyforge_project: assembly-image
|
145
|
-
rubygems_version: 2.6
|
158
|
+
rubygems_version: 2.7.6
|
146
159
|
signing_key:
|
147
160
|
specification_version: 4
|
148
161
|
summary: Ruby immplementation of image services needed to prepare objects to be accessioned
|
data/.rubocop_todo.yml
DELETED
@@ -1,263 +0,0 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
# `rubocop --auto-gen-config`
|
3
|
-
# on 2015-12-15 16:19:20 -0800 using RuboCop version 0.35.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: 11
|
10
|
-
# Cop supports --auto-correct.
|
11
|
-
Lint/DeprecatedClassMethods:
|
12
|
-
Exclude:
|
13
|
-
- 'lib/assembly-image/image.rb'
|
14
|
-
- 'spec/image_spec.rb'
|
15
|
-
- 'spec/spec_helper.rb'
|
16
|
-
|
17
|
-
# Offense count: 2
|
18
|
-
Lint/RescueException:
|
19
|
-
Exclude:
|
20
|
-
- 'lib/assembly-image/image.rb'
|
21
|
-
- 'lib/assembly-image/images.rb'
|
22
|
-
|
23
|
-
# Offense count: 2
|
24
|
-
# Cop supports --auto-correct.
|
25
|
-
Lint/StringConversionInInterpolation:
|
26
|
-
Exclude:
|
27
|
-
- 'lib/assembly-image/image.rb'
|
28
|
-
|
29
|
-
# Offense count: 2
|
30
|
-
Lint/UselessAssignment:
|
31
|
-
Exclude:
|
32
|
-
- 'config/boot.rb'
|
33
|
-
- 'lib/assembly-image/images.rb'
|
34
|
-
|
35
|
-
# Offense count: 4
|
36
|
-
Metrics/AbcSize:
|
37
|
-
Max: 87
|
38
|
-
|
39
|
-
# Offense count: 2
|
40
|
-
Metrics/CyclomaticComplexity:
|
41
|
-
Max: 29
|
42
|
-
|
43
|
-
# Offense count: 2
|
44
|
-
# Configuration parameters: AllowURI, URISchemes.
|
45
|
-
Metrics/LineLength:
|
46
|
-
Max: 244
|
47
|
-
|
48
|
-
# Offense count: 5
|
49
|
-
# Configuration parameters: CountComments.
|
50
|
-
Metrics/MethodLength:
|
51
|
-
Max: 59
|
52
|
-
|
53
|
-
# Offense count: 2
|
54
|
-
Metrics/PerceivedComplexity:
|
55
|
-
Max: 30
|
56
|
-
|
57
|
-
# Offense count: 2
|
58
|
-
# Cop supports --auto-correct.
|
59
|
-
# Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep.
|
60
|
-
Style/CaseIndentation:
|
61
|
-
Enabled: false
|
62
|
-
|
63
|
-
# Offense count: 1
|
64
|
-
# Configuration parameters: Exclude.
|
65
|
-
Style/Documentation:
|
66
|
-
Exclude:
|
67
|
-
- 'spec/**/*'
|
68
|
-
- 'test/**/*'
|
69
|
-
- 'lib/assembly-image.rb'
|
70
|
-
|
71
|
-
# Offense count: 1
|
72
|
-
# Cop supports --auto-correct.
|
73
|
-
Style/EmptyLines:
|
74
|
-
Exclude:
|
75
|
-
- 'spec/images_spec.rb'
|
76
|
-
|
77
|
-
# Offense count: 4
|
78
|
-
# Cop supports --auto-correct.
|
79
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
80
|
-
Style/EmptyLinesAroundBlockBody:
|
81
|
-
Exclude:
|
82
|
-
- 'spec/image_spec.rb'
|
83
|
-
- 'spec/images_spec.rb'
|
84
|
-
|
85
|
-
# Offense count: 2
|
86
|
-
# Cop supports --auto-correct.
|
87
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
88
|
-
Style/EmptyLinesAroundClassBody:
|
89
|
-
Exclude:
|
90
|
-
- 'lib/assembly-image/image.rb'
|
91
|
-
|
92
|
-
# Offense count: 2
|
93
|
-
# Cop supports --auto-correct.
|
94
|
-
Style/EmptyLinesAroundMethodBody:
|
95
|
-
Exclude:
|
96
|
-
- 'lib/assembly-image/image.rb'
|
97
|
-
- 'lib/assembly-image/images.rb'
|
98
|
-
|
99
|
-
# Offense count: 13
|
100
|
-
# Cop supports --auto-correct.
|
101
|
-
# Configuration parameters: AllowForAlignment.
|
102
|
-
Style/ExtraSpacing:
|
103
|
-
Exclude:
|
104
|
-
- 'lib/assembly-image/image.rb'
|
105
|
-
- 'spec/images_spec.rb'
|
106
|
-
- 'spec/spec_helper.rb'
|
107
|
-
|
108
|
-
# Offense count: 1
|
109
|
-
# Configuration parameters: Exclude.
|
110
|
-
Style/FileName:
|
111
|
-
Exclude:
|
112
|
-
- 'lib/assembly-image.rb'
|
113
|
-
|
114
|
-
# Offense count: 1
|
115
|
-
# Configuration parameters: MinBodyLength.
|
116
|
-
Style/GuardClause:
|
117
|
-
Exclude:
|
118
|
-
- 'spec/spec_helper.rb'
|
119
|
-
|
120
|
-
# Offense count: 31
|
121
|
-
# Cop supports --auto-correct.
|
122
|
-
# Configuration parameters: SupportedStyles, UseHashRocketsWithSymbolValues.
|
123
|
-
Style/HashSyntax:
|
124
|
-
EnforcedStyle: hash_rockets
|
125
|
-
|
126
|
-
# Offense count: 1
|
127
|
-
# Cop supports --auto-correct.
|
128
|
-
# Configuration parameters: Width.
|
129
|
-
Style/IndentationWidth:
|
130
|
-
Exclude:
|
131
|
-
- 'lib/assembly-image/images.rb'
|
132
|
-
|
133
|
-
# Offense count: 2
|
134
|
-
# Cop supports --auto-correct.
|
135
|
-
Style/LineEndConcatenation:
|
136
|
-
Exclude:
|
137
|
-
- 'lib/assembly-image/image.rb'
|
138
|
-
|
139
|
-
# Offense count: 1
|
140
|
-
# Cop supports --auto-correct.
|
141
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
142
|
-
Style/MethodDefParentheses:
|
143
|
-
Enabled: false
|
144
|
-
|
145
|
-
# Offense count: 2
|
146
|
-
# Cop supports --auto-correct.
|
147
|
-
Style/NegatedIf:
|
148
|
-
Exclude:
|
149
|
-
- 'lib/assembly-image/image.rb'
|
150
|
-
|
151
|
-
# Offense count: 2
|
152
|
-
# Cop supports --auto-correct.
|
153
|
-
# Configuration parameters: PreferredDelimiters.
|
154
|
-
Style/PercentLiteralDelimiters:
|
155
|
-
Exclude:
|
156
|
-
- 'assembly-image.gemspec'
|
157
|
-
|
158
|
-
# Offense count: 1
|
159
|
-
# Cop supports --auto-correct.
|
160
|
-
Style/RedundantBegin:
|
161
|
-
Exclude:
|
162
|
-
- 'lib/assembly-image/image.rb'
|
163
|
-
|
164
|
-
# Offense count: 1
|
165
|
-
# Cop supports --auto-correct.
|
166
|
-
# Configuration parameters: AllowAsExpressionSeparator.
|
167
|
-
Style/Semicolon:
|
168
|
-
Exclude:
|
169
|
-
- 'spec/spec_helper.rb'
|
170
|
-
|
171
|
-
# Offense count: 14
|
172
|
-
# Cop supports --auto-correct.
|
173
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
174
|
-
Style/SignalException:
|
175
|
-
Exclude:
|
176
|
-
- 'lib/assembly-image/image.rb'
|
177
|
-
- 'lib/assembly-image/images.rb'
|
178
|
-
- 'spec/spec_helper.rb'
|
179
|
-
|
180
|
-
# Offense count: 4
|
181
|
-
# Cop supports --auto-correct.
|
182
|
-
Style/SingleSpaceBeforeFirstArg:
|
183
|
-
Exclude:
|
184
|
-
- 'spec/images_spec.rb'
|
185
|
-
|
186
|
-
# Offense count: 93
|
187
|
-
# Cop supports --auto-correct.
|
188
|
-
Style/SpaceAfterComma:
|
189
|
-
Exclude:
|
190
|
-
- 'assembly-image.gemspec'
|
191
|
-
- 'lib/assembly-image/image.rb'
|
192
|
-
- 'lib/assembly-image/images.rb'
|
193
|
-
- 'spec/image_spec.rb'
|
194
|
-
- 'spec/images_spec.rb'
|
195
|
-
- 'spec/spec_helper.rb'
|
196
|
-
|
197
|
-
# Offense count: 4
|
198
|
-
# Cop supports --auto-correct.
|
199
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
200
|
-
Style/SpaceAroundEqualsInParameterDefault:
|
201
|
-
Enabled: false
|
202
|
-
|
203
|
-
# Offense count: 54
|
204
|
-
# Cop supports --auto-correct.
|
205
|
-
# Configuration parameters: MultiSpaceAllowedForOperators.
|
206
|
-
Style/SpaceAroundOperators:
|
207
|
-
Exclude:
|
208
|
-
- 'lib/assembly-image.rb'
|
209
|
-
- 'lib/assembly-image/image.rb'
|
210
|
-
- 'lib/assembly-image/images.rb'
|
211
|
-
- 'spec/image_spec.rb'
|
212
|
-
- 'spec/images_spec.rb'
|
213
|
-
- 'spec/spec_helper.rb'
|
214
|
-
|
215
|
-
# Offense count: 1
|
216
|
-
# Cop supports --auto-correct.
|
217
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
218
|
-
Style/SpaceBeforeBlockBraces:
|
219
|
-
Enabled: false
|
220
|
-
|
221
|
-
# Offense count: 29
|
222
|
-
# Cop supports --auto-correct.
|
223
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
|
224
|
-
Style/SpaceInsideBlockBraces:
|
225
|
-
Enabled: false
|
226
|
-
|
227
|
-
# Offense count: 4
|
228
|
-
# Cop supports --auto-correct.
|
229
|
-
Style/SpaceInsideParens:
|
230
|
-
Exclude:
|
231
|
-
- 'lib/assembly-image/image.rb'
|
232
|
-
|
233
|
-
# Offense count: 5
|
234
|
-
# Cop supports --auto-correct.
|
235
|
-
Style/SpecialGlobalVars:
|
236
|
-
Exclude:
|
237
|
-
- 'lib/assembly-image/image.rb'
|
238
|
-
- 'spec/spec_helper.rb'
|
239
|
-
|
240
|
-
# Offense count: 87
|
241
|
-
# Cop supports --auto-correct.
|
242
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
243
|
-
Style/StringLiterals:
|
244
|
-
Enabled: false
|
245
|
-
|
246
|
-
# Offense count: 1
|
247
|
-
# Cop supports --auto-correct.
|
248
|
-
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
|
249
|
-
Style/TrivialAccessors:
|
250
|
-
Exclude:
|
251
|
-
- 'lib/assembly-image/images.rb'
|
252
|
-
|
253
|
-
# Offense count: 2
|
254
|
-
# Cop supports --auto-correct.
|
255
|
-
Style/UnneededPercentQ:
|
256
|
-
Exclude:
|
257
|
-
- 'assembly-image.gemspec'
|
258
|
-
|
259
|
-
# Offense count: 11
|
260
|
-
# Cop supports --auto-correct.
|
261
|
-
# Configuration parameters: WordRegex.
|
262
|
-
Style/WordArray:
|
263
|
-
MinSize: 3
|