assembly-image 1.6.9 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/assembly-image.gemspec +0 -1
- data/lib/assembly-image.rb +2 -2
- data/lib/assembly-image/image.rb +97 -59
- data/lib/assembly-image/version.rb +1 -1
- metadata +3 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 693f1de3f3da7705f8920609b33300286a2bee43
|
4
|
+
data.tar.gz: dd91d143c8cb63df32576df88e8faaf99f75ef6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7a36d09fa0326861718e9c99495ce0ffc79ee4cb08b5fe1d9ed4d9eebb5fbf4527b3a0905434dadc4683f6c674f828e85f0dd10dde5a5b486a8a58fdac8da0f
|
7
|
+
data.tar.gz: 11e5bcee0606f7696f0d984b09a8c4aad7a558e2db1aabf2f0d2fdbd55c204c06ebaafde06e72673f5f7668975d99803bb8382699faaa07b4778a50ee324ab67
|
data/.travis.yml
CHANGED
data/assembly-image.gemspec
CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
s.add_dependency 'uuidtools'
|
22
21
|
s.add_dependency 'assembly-objectfile', '>= 1.6.4'
|
23
22
|
s.add_dependency 'mini_exiftool', '>= 1.6', '< 3'
|
24
23
|
|
data/lib/assembly-image.rb
CHANGED
data/lib/assembly-image/image.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'uuidtools'
|
2
1
|
require 'assembly-objectfile'
|
2
|
+
require 'tempfile'
|
3
3
|
|
4
4
|
module Assembly
|
5
5
|
|
@@ -131,86 +131,124 @@ module Assembly
|
|
131
131
|
|
132
132
|
raise SecurityError,'cannot recreate jp2 over itself' if overwrite && mimetype=='image/jp2' && output == @path
|
133
133
|
|
134
|
-
tmp_folder = params[:tmp_folder] ||
|
134
|
+
tmp_folder = params[:tmp_folder] || Dir.tmpdir
|
135
135
|
raise "tmp_folder #{tmp_folder} does not exists" unless File.exists?(tmp_folder)
|
136
136
|
|
137
|
-
output_profile = 'sRGBIEC6196621' # params[:output_profile] || 'sRGBIEC6196621' # eventually we may allow the user to specify the output_profile...when we do, you can just uncomment this code and update the tests that check for this
|
138
137
|
preserve_tmp_source = params[:preserve_tmp_source] || false
|
139
|
-
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM,'profiles')
|
140
|
-
output_profile_file = File.join(path_to_profiles,"#{output_profile}.icc")
|
141
138
|
|
142
|
-
|
139
|
+
# make temp tiff filename
|
140
|
+
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
|
141
|
+
@tmp_path = tmp_tiff_file.path
|
143
142
|
|
144
|
-
|
145
|
-
|
143
|
+
options = []
|
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
|
146
155
|
|
147
|
-
|
156
|
+
options << profile_conversion_switch(profile, tmp_folder: tmp_folder)
|
148
157
|
|
149
|
-
|
158
|
+
tiff_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert -quiet -compress none #{options.join(' ')} '#{@path}[0]' '#{@tmp_path}'"
|
159
|
+
result=`#{tiff_command} 2>&1`
|
160
|
+
raise "tiff convert command failed: #{tiff_command} with result #{result}" unless $?.success?
|
150
161
|
|
151
|
-
|
162
|
+
# jp2 creation command
|
163
|
+
kdu_bin = 'kdu_compress'
|
164
|
+
options = []
|
165
|
+
options << '-jp2_space sRGB' if samples_per_pixel == 3
|
166
|
+
options += kdu_compress_default_options
|
167
|
+
options << "Clayers=#{layers.to_s}"
|
168
|
+
jp2_command = "#{kdu_bin} #{options.join(' ')} -i '#{@tmp_path}' -o '#{output}'"
|
169
|
+
result=`#{jp2_command} 2>&1`
|
170
|
+
raise "JP2 creation command failed: #{jp2_command} with result #{result}" unless $?.success?
|
152
171
|
|
153
|
-
|
154
|
-
input_profile_file_gem = File.join(path_to_profiles,"#{input_profile}.icc")
|
155
|
-
input_profile_file_tmp = File.join(tmp_folder,"#{input_profile}.icc")
|
156
|
-
input_profile_file = File.exists?(input_profile_file_gem) ? input_profile_file_gem : input_profile_file_tmp
|
172
|
+
tmp_tiff_file.delete unless preserve_tmp_source
|
157
173
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
input_profile_extraction_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert '#{@path}'[0] #{input_profile_file}" # extract profile from input image
|
162
|
-
result=`#{input_profile_extraction_command} 2>&1`
|
163
|
-
raise "input profile extraction command failed: #{input_profile_extraction_command} with result #{result}" unless $?.success?
|
164
|
-
raise 'input profile is not a known profile and could not be extracted from input file' unless File.exists?(input_profile_file) # if extraction failed or we cannot write the file, throw exception
|
165
|
-
end
|
174
|
+
# create output response object, which is an Assembly::Image type object
|
175
|
+
Assembly::Image.new(output)
|
176
|
+
end
|
166
177
|
|
167
|
-
|
178
|
+
private
|
179
|
+
|
180
|
+
def kdu_compress_default_options
|
181
|
+
[
|
182
|
+
'-precise', # forces the use of 32-bit representations
|
183
|
+
'-no_weights', # minimization of the MSE over all reconstructed colour components
|
184
|
+
'-quiet', # suppress informative messages.
|
185
|
+
'Creversible=no', # Disable reversible compression
|
186
|
+
'Cmodes=BYPASS', #
|
187
|
+
'Corder=RPCL', # R=resolution P=position C=component L=layer
|
188
|
+
'Cblk=\\{64,64\\}', # code-block dimensions; 64x64 happens to also be the default
|
189
|
+
'Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\}', # Precinct dimensions; 256x256 for the 2 highest resolution levels, defaults to 128x128 for the rest
|
190
|
+
'ORGgen_plt=yes', # Insert packet length information
|
191
|
+
'-rate 1.5', # Ratio of compressed bits to the image size
|
192
|
+
'Clevels=5' # Number of wavelet decomposition levels, or stages
|
193
|
+
]
|
194
|
+
end
|
168
195
|
|
196
|
+
def samples_per_pixel
|
197
|
+
if exif['samplesperpixel']
|
198
|
+
exif['samplesperpixel'].to_i
|
169
199
|
else
|
200
|
+
case mimetype
|
201
|
+
when 'image/tiff'
|
202
|
+
1
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
170
206
|
|
171
|
-
|
172
|
-
|
207
|
+
def bits_per_sample
|
208
|
+
if exif['bitspersample']
|
209
|
+
exif['bitspersample'].to_i
|
210
|
+
else
|
211
|
+
case mimetype
|
212
|
+
when 'image/tiff'
|
213
|
+
1
|
214
|
+
end
|
173
215
|
end
|
216
|
+
end
|
174
217
|
|
175
|
-
|
176
|
-
|
218
|
+
# Get the number of JP2 layers to generate
|
219
|
+
def layers
|
220
|
+
pixdem = [width, height].max
|
221
|
+
(( Math.log(pixdem) / Math.log(2) ) - ( Math.log(96) / Math.log(2) )).ceil + 1
|
222
|
+
end
|
177
223
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
when '1'
|
183
|
-
if bits_per_sample.to_i == 1
|
184
|
-
options += '-type Bilevel'
|
185
|
-
elsif bits_per_sample.to_i > 1
|
186
|
-
options += '-type Grayscale'
|
187
|
-
end
|
188
|
-
end
|
189
|
-
tiff_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert -quiet -compress none #{profile_conversion_switch} #{options} '#{@path}[0]' '#{@tmp_path}'"
|
190
|
-
result=`#{tiff_command} 2>&1`
|
191
|
-
raise "tiff convert command failed: #{tiff_command} with result #{result}" unless $?.success?
|
224
|
+
def profile_conversion_switch(profile, tmp_folder:)
|
225
|
+
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM,'profiles')
|
226
|
+
output_profile = 'sRGBIEC6196621' # params[:output_profile] || 'sRGBIEC6196621' # eventually we may allow the user to specify the output_profile...when we do, you can just uncomment this code and update the tests that check for this
|
227
|
+
output_profile_file = File.join(path_to_profiles,"#{output_profile}.icc")
|
192
228
|
|
193
|
-
|
194
|
-
layers = (( Math.log(pixdem) / Math.log(2) ) - ( Math.log(96) / Math.log(2) )).ceil + 1
|
229
|
+
raise "output profile #{output_profile} invalid" unless File.exists?(output_profile_file)
|
195
230
|
|
196
|
-
|
197
|
-
kdu_bin = 'kdu_compress '
|
198
|
-
options = ''
|
199
|
-
options += ' -jp2_space sRGB ' if samples_per_pixel == '3'
|
200
|
-
options += ' -precise -no_weights -quiet Creversible=no Cmodes=BYPASS Corder=RPCL ' +
|
201
|
-
'Cblk=\\{64,64\\} Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\} ' +
|
202
|
-
'ORGgen_plt=yes -rate 1.5 Clevels=5 '
|
203
|
-
jp2_command = "#{kdu_bin} #{options} Clayers=#{layers.to_s} -i '#{@tmp_path}' -o '#{output}'"
|
204
|
-
result=`#{jp2_command} 2>&1`
|
205
|
-
raise "JP2 creation command failed: #{jp2_command} with result #{result}" unless $?.success?
|
231
|
+
return '' if profile.nil?
|
206
232
|
|
207
|
-
|
233
|
+
# if the input color profile exists, contract paths to the profile and setup the command
|
208
234
|
|
209
|
-
#
|
210
|
-
Assembly::Image.new(output)
|
235
|
+
input_profile = profile.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
211
236
|
|
212
|
-
|
237
|
+
# 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.exists?(input_profile_file_gem) ? input_profile_file_gem : input_profile_file_tmp
|
213
241
|
|
214
|
-
|
242
|
+
# if input profile was extracted and does not matches an existing known profile either in the gem or in the tmp folder,
|
243
|
+
# we'll issue an imagicmagick command to extract the profile to the tmp folder
|
244
|
+
unless File.exists?(input_profile_file)
|
245
|
+
input_profile_extraction_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert '#{@path}'[0] #{input_profile_file}" # extract profile from input image
|
246
|
+
result=`#{input_profile_extraction_command} 2>&1`
|
247
|
+
raise "input profile extraction command failed: #{input_profile_extraction_command} with result #{result}" unless $?.success?
|
248
|
+
raise 'input profile is not a known profile and could not be extracted from input file' unless File.exists?(input_profile_file) # if extraction failed or we cannot write the file, throw exception
|
249
|
+
end
|
215
250
|
|
251
|
+
"-profile #{input_profile_file} -profile #{output_profile_file}"
|
252
|
+
end
|
253
|
+
end
|
216
254
|
end
|
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.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Mangiafico
|
@@ -11,22 +11,8 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2018-03-19 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
17
|
-
name: uuidtools
|
18
|
-
requirement: !ruby/object:Gem::Requirement
|
19
|
-
requirements:
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '0'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
16
|
- !ruby/object:Gem::Dependency
|
31
17
|
name: assembly-objectfile
|
32
18
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
142
|
version: '0'
|
157
143
|
requirements: []
|
158
144
|
rubyforge_project: assembly-image
|
159
|
-
rubygems_version: 2.6.
|
145
|
+
rubygems_version: 2.6.11
|
160
146
|
signing_key:
|
161
147
|
specification_version: 4
|
162
148
|
summary: Ruby immplementation of image services needed to prepare objects to be accessioned
|
@@ -167,4 +153,3 @@ test_files:
|
|
167
153
|
- spec/spec_helper.rb
|
168
154
|
- spec/test_data/input/.empty
|
169
155
|
- spec/test_data/output/.empty
|
170
|
-
has_rdoc:
|