lib/assembly-image/jp2_creator.rb in assembly-image-1.9.0 vs lib/assembly-image/jp2_creator.rb in assembly-image-2.0.0
- old
+ new
@@ -5,11 +5,11 @@
require 'English' # see https://github.com/rubocop-hq/rubocop/issues/1747 (not #MAGA related)
module Assembly
class Image < Assembly::ObjectFile
# Creates jp2 derivatives
- class Jp2Creator # rubocop:disable Metrics/ClassLength
+ class Jp2Creator
# Create a JP2 file for the current image.
# Important note: this will not work for multipage TIFFs.
#
# @return [Assembly::Image] object containing the generated JP2 file
#
@@ -66,10 +66,11 @@
@overwrite
end
def jp2_create_command(source_path:, output:)
options = []
+ # TODO: Consider using ruby-vips to determine the colorspace instead of relying on exif (which is done below)
options << '-jp2_space sRGB' if image.samples_per_pixel == 3
options += KDU_COMPRESS_DEFAULT_OPTIONS
options << "Clayers=#{layers}"
"kdu_compress #{options.join(' ')} -i '#{source_path}' -o '#{output}' 2>&1"
end
@@ -80,106 +81,53 @@
((Math.log(pixdem) / Math.log(2)) - (Math.log(96) / Math.log(2))).ceil + 1
end
KDU_COMPRESS_DEFAULT_OPTIONS = [
'-num_threads 2', # forces Kakadu to only use 2 threads
- '-precise', # forces the use of 32-bit representations
- '-no_weights', # minimization of the MSE over all reconstructed colour components
'-quiet', # suppress informative messages.
'Creversible=no', # Disable reversible compression
- 'Cmodes=BYPASS', #
'Corder=RPCL', # R=resolution P=position C=component L=layer
'Cblk=\\{64,64\\}', # code-block dimensions; 64x64 happens to also be the default
'Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\}', # Precinct dimensions; 256x256 for the 2 highest resolution levels, defaults to 128x128 for the rest
- 'ORGgen_plt=yes', # Insert packet length information
- '-rate 1.5', # Ratio of compressed bits to the image size
+ '-rate -', # Ratio of compressed bits to the image size
'Clevels=5' # Number of wavelet decomposition levels, or stages
].freeze
- # rubocop:disable Metrics/AbcSize
def create_jp2_checks
image.send(:check_for_file)
raise 'input file is not a valid image, or is the wrong mimetype' unless image.jp2able?
raise SecurityError, "output #{output_path} exists, cannot overwrite" if !overwrite? && File.exist?(output_path)
raise SecurityError, 'cannot recreate jp2 over itself' if overwrite? && image.mimetype == 'image/jp2' && output_path == image.path
end
- # rubocop:disable Metrics/MethodLength
- def profile_conversion_switch(profile, tmp_folder:)
- path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
- # 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
- output_profile = 'sRGBIEC6196621' # params[:output_profile] || 'sRGBIEC6196621'
- output_profile_file = File.join(path_to_profiles, "#{output_profile}.icc")
-
- raise "output profile #{output_profile} invalid" unless File.exist?(output_profile_file)
-
- return '' if image.profile.nil?
-
- # if the input color profile exists, contract paths to the profile and setup the command
-
- input_profile = profile.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
-
- # construct a path to the input profile, which might exist either in the gem itself or in the tmp folder
- input_profile_file_gem = File.join(path_to_profiles, "#{input_profile}.icc")
- input_profile_file_tmp = File.join(tmp_folder, "#{input_profile}.icc")
- input_profile_file = File.exist?(input_profile_file_gem) ? input_profile_file_gem : input_profile_file_tmp
-
- # if input profile was extracted and does not matches an existing known profile either in the gem or in the tmp folder,
- # we'll issue an imagicmagick command to extract the profile to the tmp folder
- unless File.exist?(input_profile_file)
- input_profile_extract_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert '#{image.path}'[0] #{input_profile_file}" # extract profile from input image
- result = `#{input_profile_extract_command} 2>&1`
- raise "input profile extraction command failed: #{input_profile_extract_command} with result #{result}" unless $CHILD_STATUS.success?
- # if extraction failed or we cannot write the file, throw exception
- raise 'input profile is not a known profile and could not be extracted from input file' unless File.exist?(input_profile_file)
- end
-
- "-profile #{input_profile_file} -profile #{output_profile_file}"
- end
-
# Bigtiff needs to be used if size of image exceeds 2^32 bytes.
def need_bigtiff?
image.image_data_size >= 2**32
end
# We do this because we need to reliably compress the tiff and KDUcompress doesn’t support arbitrary image types
+ # rubocop:disable Metrics/MethodLength
def make_tmp_tiff(tmp_folder: nil)
tmp_folder ||= Dir.tmpdir
raise "tmp_folder #{tmp_folder} does not exists" unless File.exist?(tmp_folder)
# make temp tiff filename
tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
tmp_path = tmp_tiff_file.path
+ vips_image = Vips::Image.new_from_file image.path
- options = []
+ vips_image = if vips_image.interpretation.eql?(:cmyk)
+ vips_image.icc_transform(SRGB_ICC, input_profile: CMYK_ICC)
+ elsif !image.profile.nil?
+ vips_image.icc_transform(SRGB_ICC, embedded: true)
+ else
+ vips_image
+ end
- # Limit the amount of memory ImageMagick is able to use.
- options << '-limit memory 1GiB -limit map 1GiB'
-
- case image.samples_per_pixel
- when 3
- options << '-type TrueColor'
- when 1
- options << '-depth 8' # force the production of a grayscale access derivative
- options << '-type Grayscale'
- end
-
- options << profile_conversion_switch(image.profile, tmp_folder: tmp_folder)
-
- # The output in the covnert command needs to be prefixed by the image type. By default ImageMagick
- # will assume TIFF: when the file extension is .tif/.tiff. TIFF64: Needs to be forced when image will
- # exceed 2^32 bytes in size
- tiff_type = need_bigtiff? ? 'TIFF64:' : ''
-
- tiff_command = "MAGICK_TEMPORARY_PATH=#{tmp_folder} convert -quiet -compress none #{options.join(' ')} '#{image.path}[0]' #{tiff_type}'#{tmp_path}'"
- result = `#{tiff_command} 2>&1`
- raise "tiff convert command failed: #{tiff_command} with result #{result}" unless $CHILD_STATUS.success?
-
+ vips_image.tiffsave(tmp_path, bigtiff: need_bigtiff?)
tmp_path
end
# rubocop:enable Metrics/MethodLength
- # rubocop:enable Metrics/AbcSize
end
end
end