assembly-image 2.0.0 → 2.1.1
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 +1 -1
- data/.gitignore +0 -1
- data/.rubocop.yml +121 -4
- data/.rubocop_todo.yml +7 -57
- data/.rvmrc.example +1 -1
- data/Gemfile.lock +118 -0
- data/README.md +12 -36
- data/assembly-image.gemspec +2 -3
- data/bin/console +1 -1
- data/config/boot.rb +2 -2
- data/lib/{assembly-image → assembly/image}/jp2_creator.rb +36 -42
- data/lib/assembly/image.rb +60 -0
- data/lib/assembly-image.rb +2 -3
- data/spec/assembly/image/jp2_creator_spec.rb +327 -34
- data/spec/assembly/image_spec.rb +25 -0
- data/spec/spec_helper.rb +4 -21
- metadata +15 -43
- data/lib/assembly-image/image.rb +0 -149
- data/lib/assembly-image/images.rb +0 -102
- data/spec/image_spec.rb +0 -324
- data/spec/images_spec.rb +0 -47
- data/spec/test_data/color_cmyk_tagged.tif +0 -0
- data/spec/test_data/color_cmyk_untagged.tif +0 -0
- data/spec/test_data/color_rgb_adobergb1998_lzw.tif +0 -0
- data/spec/test_data/color_rgb_srgb.jpg +0 -0
- data/spec/test_data/color_rgb_srgb.tif +0 -0
- data/spec/test_data/color_rgb_untagged.tif +0 -0
- data/spec/test_data/gray_gray_untagged.tif +0 -0
data/lib/assembly-image/image.rb
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby-vips'
|
4
|
-
require 'assembly-objectfile'
|
5
|
-
require_relative 'jp2_creator'
|
6
|
-
|
7
|
-
module Assembly
|
8
|
-
# The Image class contains methods to operate on an image.
|
9
|
-
class Image < Assembly::ObjectFile
|
10
|
-
# Examines the input image for validity. Used to determine if image is correct and if JP2 generation is likely to succeed.
|
11
|
-
# This method is automatically called before you create a jp2 but it can be called separately earlier as a sanity check.
|
12
|
-
#
|
13
|
-
# @return [boolean] true if image is valid, false if not.
|
14
|
-
#
|
15
|
-
# Example:
|
16
|
-
# source_img=Assembly::ObjectFile.new('/input/path_to_file.tif')
|
17
|
-
# puts source_img.valid? # gives true
|
18
|
-
def valid?
|
19
|
-
valid_image? # behavior is defined in assembly-objectfile gem
|
20
|
-
end
|
21
|
-
|
22
|
-
# Get the image color profile
|
23
|
-
#
|
24
|
-
# @return [string] image color profile
|
25
|
-
# Example:
|
26
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
27
|
-
# puts source_img.profile # gives 'Adobe RGB 1998'
|
28
|
-
def profile
|
29
|
-
exif.nil? ? nil : exif['profiledescription']
|
30
|
-
end
|
31
|
-
|
32
|
-
# Get the image height from exif data
|
33
|
-
#
|
34
|
-
# @return [integer] image height in pixels
|
35
|
-
# Example:
|
36
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
37
|
-
# puts source_img.height # gives 100
|
38
|
-
def height
|
39
|
-
exif.imageheight
|
40
|
-
end
|
41
|
-
|
42
|
-
# Get the image width from exif data
|
43
|
-
# @return [integer] image height in pixels
|
44
|
-
# Example:
|
45
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
46
|
-
# puts source_img.width # gives 100
|
47
|
-
def width
|
48
|
-
exif.imagewidth
|
49
|
-
end
|
50
|
-
|
51
|
-
# Examines the input image to determine if it is compressed.
|
52
|
-
#
|
53
|
-
# @return [boolean] true if image is compressed, false if not.
|
54
|
-
#
|
55
|
-
# Example:
|
56
|
-
# source_img=Assembly::ObjectFile.new('/input/path_to_file.tif')
|
57
|
-
# puts source_img.compressed? # gives true
|
58
|
-
# def compressed?
|
59
|
-
# exif.compression != 'Uncompressed'
|
60
|
-
# end
|
61
|
-
|
62
|
-
# Add an exif color profile descriptions to the image.
|
63
|
-
# This is useful if your source TIFFs do not have color profile descriptions in the EXIF data, but you know what it should be.
|
64
|
-
# This will allow the images to pass the validaty check and have JP2s created successfully.
|
65
|
-
#
|
66
|
-
# Note you will need full read/write access to the source path so that new EXIF data can be saved.
|
67
|
-
#
|
68
|
-
# @param [String] profile_name profile name to be added, current options are 'Adobe RBG 1998','Dot Gain 20%','sRGB IEC61966-2.1'
|
69
|
-
#
|
70
|
-
# @param [String] force if set to true, force overwrite a color profile description even if it already exists (default: false)
|
71
|
-
#
|
72
|
-
# Example:
|
73
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
74
|
-
# source_img.add_exif_profile_description('Adobe RGB 1998')
|
75
|
-
def add_exif_profile_description(profile_name, force = false)
|
76
|
-
if profile.nil? || force
|
77
|
-
input_profile = profile_name.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
78
|
-
input_profile_file = File.join(PATH_TO_PROFILES, "#{input_profile}.icc")
|
79
|
-
command = "exiftool '-icc_profile<=#{input_profile_file}' #{path}"
|
80
|
-
result = `#{command} 2>&1`
|
81
|
-
raise "profile addition command failed: #{command} with result #{result}" unless $CHILD_STATUS.success?
|
82
|
-
end
|
83
|
-
rescue StandardError => e
|
84
|
-
puts "** Error for #{filename}: #{e.message}"
|
85
|
-
end
|
86
|
-
|
87
|
-
# Returns the full default jp2 path and filename that will be created from the given image
|
88
|
-
#
|
89
|
-
# @return [string] full default jp2 path and filename that will be created from the given image
|
90
|
-
# Example:
|
91
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
92
|
-
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
93
|
-
def jp2_filename
|
94
|
-
File.extname(path).empty? ? "#{path}.jp2" : path.gsub(File.extname(path), '.jp2')
|
95
|
-
end
|
96
|
-
|
97
|
-
# Create a JP2 file for the current image.
|
98
|
-
# Important note: this will not work for multipage TIFFs.
|
99
|
-
#
|
100
|
-
# @return [Assembly::Image] object containing the generated JP2 file
|
101
|
-
#
|
102
|
-
# @param [Hash] params Optional parameters specified as a hash, using symbols for options:
|
103
|
-
# * :output => path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
|
104
|
-
# * :overwrite => if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
105
|
-
# * :tmp_folder => the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
|
106
|
-
#
|
107
|
-
# Example:
|
108
|
-
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
109
|
-
# derivative_img=source_img.create_jp2(:overwrite=>true)
|
110
|
-
# puts derivative_img.mimetype # 'image/jp2'
|
111
|
-
# puts derivative_image.path # '/input/path_to_file.jp2'
|
112
|
-
# rubocop:disable Metrics/CyclomaticComplexity:
|
113
|
-
def create_jp2(params = {})
|
114
|
-
Jp2Creator.create(self, params)
|
115
|
-
end
|
116
|
-
|
117
|
-
def samples_per_pixel
|
118
|
-
if exif['samplesperpixel']
|
119
|
-
exif['samplesperpixel'].to_i
|
120
|
-
else
|
121
|
-
case mimetype
|
122
|
-
when 'image/tiff'
|
123
|
-
1
|
124
|
-
when 'image/jpeg'
|
125
|
-
3
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# Get size of image data in bytes
|
131
|
-
def image_data_size
|
132
|
-
(samples_per_pixel * height * width * bits_per_sample) / 8
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
138
|
-
def bits_per_sample
|
139
|
-
if exif['bitspersample']
|
140
|
-
exif['bitspersample'].to_i
|
141
|
-
else
|
142
|
-
case mimetype
|
143
|
-
when 'image/tiff'
|
144
|
-
1
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'logger'
|
4
|
-
module Assembly
|
5
|
-
# The Images class contains methods to operate on multiple images in batch.
|
6
|
-
class Images
|
7
|
-
def self.logger
|
8
|
-
@logger ||= Logger.new(STDERR)
|
9
|
-
end
|
10
|
-
|
11
|
-
class << self
|
12
|
-
attr_writer :logger
|
13
|
-
end
|
14
|
-
|
15
|
-
# Pass in a source path and have exif color profile descriptions added to all images contained.
|
16
|
-
# This is useful if your source TIFFs do not have color profile descriptions in the EXIF data, but you know what it should be.
|
17
|
-
# This will allow the images to pass the validty check and have JP2s created successfully.
|
18
|
-
#
|
19
|
-
# Note you will need full read/write access to the source path so that new EXIF data can be saved.
|
20
|
-
#
|
21
|
-
# @param [String] source path full path to the directory containing TIFFs
|
22
|
-
# @param [String] profile_name profile name to be added, current options are 'Adobe RBG 1998','Dot Gain 20%','sRGB IEC61966-2.1'
|
23
|
-
#
|
24
|
-
# @param [Hash] params Optional parameters specified as a hash, using symbols for options:
|
25
|
-
# * :force => if set to true, force overwrite a color profile description even if it already exists (default: false)
|
26
|
-
# * :recusrive => if set to true, directories will be searched recursively for TIFFs from the source specified, false searches the top level only (default: false)
|
27
|
-
# * :extension => defines the types of files that will be processed (default '.tif')
|
28
|
-
#
|
29
|
-
# Example:
|
30
|
-
# Assembly::Images.batch_add_exif_profile_description('/full_path_to_tifs','Adobe RGB 1998')
|
31
|
-
# rubocop:disable Metrics/MethodLength
|
32
|
-
# rubocop:disable Metrics/AbcSize
|
33
|
-
def self.batch_add_exif_profile_descr(source, profile_name, params = {})
|
34
|
-
extension = params[:extension] || 'tif'
|
35
|
-
recursive = params[:recursive] || false
|
36
|
-
force = params[:force] || false
|
37
|
-
|
38
|
-
raise 'Input path does not exist' unless File.directory?(source)
|
39
|
-
|
40
|
-
# iterate over input directory looking for tifs
|
41
|
-
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
42
|
-
Dir.glob(File.join(source, pattern)).each do |file|
|
43
|
-
img = Assembly::Image.new(file)
|
44
|
-
logger.debug "Processing #{file}"
|
45
|
-
img.add_exif_profile_description(profile_name, force)
|
46
|
-
end
|
47
|
-
'Complete'
|
48
|
-
end
|
49
|
-
# rubocop:enable Metrics/MethodLength
|
50
|
-
# rubocop:enable Metrics/AbcSize
|
51
|
-
|
52
|
-
# Pass in a source path and get JP2s generate for each tiff that is in the source path
|
53
|
-
#
|
54
|
-
# If not passed in, the destination will be a "jp2" subfolder within the source folder.
|
55
|
-
# Note you will need read access to the source path, and write access to the destination path.
|
56
|
-
#
|
57
|
-
# @param [String] source path full path to the directory containing TIFFs to be converted to JP2
|
58
|
-
#
|
59
|
-
# @param [Hash] params Optional parameters specified as a hash, using symbols for options:
|
60
|
-
# * :output=>'/full/path_to_jp2' # specifies full path to folder where jp2s will be created (default: jp2 subdirectory from source path)
|
61
|
-
# * :overwrite => if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
62
|
-
# * :recursive => if set to true, directories will be searched recursively for TIFFs from the source specified, false searches the top level only (default: false)
|
63
|
-
# * :extension => defines the types of files that will be processed (default '.tif')
|
64
|
-
#
|
65
|
-
# Example:
|
66
|
-
# Assembly::Images.batch_generate_jp2('/full_path_to_tifs')
|
67
|
-
# rubocop:disable Metrics/MethodLength
|
68
|
-
# rubocop:disable Metrics/AbcSize
|
69
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
70
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
71
|
-
def self.batch_generate_jp2(source, params = {})
|
72
|
-
raise 'Input path does not exist' unless File.directory?(source)
|
73
|
-
|
74
|
-
output = params[:output] || File.join(source, 'jp2') # default output directgory is jp2 sub-directory from source
|
75
|
-
extension = params[:extension] || 'tif'
|
76
|
-
overwrite = params[:overwrite] || false
|
77
|
-
recursive = params[:recursive] || false
|
78
|
-
|
79
|
-
Dir.mkdir(output) unless File.directory?(output) # attemp to make output directory
|
80
|
-
raise 'Output path does not exist or could not be created' unless File.directory?(output)
|
81
|
-
|
82
|
-
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
83
|
-
|
84
|
-
# iterate over input directory looking for tifs
|
85
|
-
Dir.glob(File.join(source, pattern)).each do |file|
|
86
|
-
source_img = Assembly::Image.new(file)
|
87
|
-
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
|
88
|
-
begin
|
89
|
-
source_img.create_jp2(overwrite: overwrite, output: output_img)
|
90
|
-
logger.debug "Generated jp2 for #{File.basename(file)}"
|
91
|
-
rescue StandardError => e
|
92
|
-
logger.debug "** Error for #{File.basename(file)}: #{e.message}"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
'Complete'
|
96
|
-
end
|
97
|
-
# rubocop:enable Metrics/MethodLength
|
98
|
-
# rubocop:enable Metrics/AbcSize
|
99
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
100
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
101
|
-
end
|
102
|
-
end
|
data/spec/image_spec.rb
DELETED
@@ -1,324 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'fileutils'
|
5
|
-
|
6
|
-
RSpec.describe Assembly::Image do
|
7
|
-
let(:assembly_image) { described_class.new(input_path) }
|
8
|
-
let(:input_path) { TEST_TIF_INPUT_FILE }
|
9
|
-
let(:jp2_output_file) { File.join(TEST_OUTPUT_DIR, File.basename(input_path).gsub('.tif', '.jp2')) }
|
10
|
-
|
11
|
-
before { cleanup }
|
12
|
-
|
13
|
-
describe '#jp2_filename' do
|
14
|
-
it 'indicates the default jp2 filename' do
|
15
|
-
expect(assembly_image.jp2_filename).to eq input_path.gsub('.tif', '.jp2')
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'with a file with no extension' do
|
19
|
-
let(:input_path) { '/path/to/a/file_with_no_extension' }
|
20
|
-
|
21
|
-
it 'indicates the default jp2 filename' do
|
22
|
-
expect(assembly_image.jp2_filename).to eq '/path/to/a/file_with_no_extension.jp2'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe '#create_jp2' do
|
28
|
-
context 'when input path is blank' do
|
29
|
-
let(:input_path) { '' }
|
30
|
-
|
31
|
-
it 'does not run if no input file is passed in' do
|
32
|
-
expect { assembly_image.create_jp2 }.to raise_error(RuntimeError)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'when given an uncompressed compressed RGB tif with more than 4GB of image data', skip: 'This test will create a 4GB test image and a 4GB temporary image, so skipping by default.' do
|
37
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'rgb.tif') }
|
38
|
-
|
39
|
-
before do
|
40
|
-
generate_test_image(input_path, compress: 'none', width: '37838', height: '37838')
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'creates the jp2 with a temp file' do
|
44
|
-
expect(File).to exist input_path
|
45
|
-
expect(File).not_to exist jp2_output_file
|
46
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
47
|
-
expect(assembly_image.tmp_path).not_to be_nil
|
48
|
-
expect(result).to be_a_kind_of described_class
|
49
|
-
expect(result.path).to eq jp2_output_file
|
50
|
-
expect(jp2_output_file).to be_a_jp2
|
51
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
52
|
-
expect(result.height).to eq 37_838
|
53
|
-
expect(result.width).to eq 37_838
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'when given an LZW compressed RGB tif with more than 4GB of image data', skip: 'This test will create a 4GB temporary image, so skipping by default.' do
|
58
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'lzw.tif') }
|
59
|
-
|
60
|
-
before do
|
61
|
-
generate_test_image(input_path, compress: 'lzw', width: '37838', height: '37838')
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'creates the jp2 with a temp file' do
|
65
|
-
expect(File).to exist input_path
|
66
|
-
expect(File).not_to exist jp2_output_file
|
67
|
-
expect(assembly_image.exif.samplesperpixel).to be 3
|
68
|
-
expect(assembly_image.exif.bitspersample).to eql '8 8 8'
|
69
|
-
expect(assembly_image).to be_a_valid_image
|
70
|
-
expect(assembly_image).to be_jp2abl
|
71
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
72
|
-
expect(assembly_image.tmp_path).not_to be_nil
|
73
|
-
expect(result).to be_a_kind_of described_class
|
74
|
-
expect(result.path).to eq jp2_output_file
|
75
|
-
expect(jp2_output_file).to be_a_jp2
|
76
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
77
|
-
expect(result.height).to eq 37_838
|
78
|
-
expect(result.width).to eq 37_838
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context 'when given a bitonal tif' do
|
83
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'bitonal.tif') }
|
84
|
-
|
85
|
-
before do
|
86
|
-
generate_test_image(input_path, color: 'bin', bands: 1, depth: 1)
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'creates valid jp2' do
|
90
|
-
expect(File).to exist input_path
|
91
|
-
expect(File).not_to exist jp2_output_file
|
92
|
-
expect(assembly_image.exif.samplesperpixel).to be 1
|
93
|
-
expect(assembly_image.exif.bitspersample).to be 1
|
94
|
-
expect(assembly_image).not_to have_color_profile
|
95
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
96
|
-
expect(result).to be_a_kind_of described_class
|
97
|
-
expect(result.path).to eq jp2_output_file
|
98
|
-
expect(jp2_output_file).to be_a_jp2
|
99
|
-
expect(result.exif.colorspace).to eq 'Grayscale'
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context 'when given a color tif but bitonal image data (1 channels and 1 bits per pixel)' do
|
104
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'color.tif') }
|
105
|
-
|
106
|
-
before do
|
107
|
-
generate_test_image(input_path, color: 'bin', bands: 3)
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'creates color jp2' do
|
111
|
-
expect(File).to exist input_path
|
112
|
-
expect(File).not_to exist jp2_output_file
|
113
|
-
expect(assembly_image).not_to have_color_profile
|
114
|
-
expect(assembly_image.exif.samplesperpixel).to be 3
|
115
|
-
expect(assembly_image.exif.bitspersample).to eql '8 8 8'
|
116
|
-
expect(assembly_image).to be_a_valid_image
|
117
|
-
expect(assembly_image).to be_jp2able
|
118
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
119
|
-
expect(result).to be_a_kind_of described_class
|
120
|
-
expect(result.path).to eq jp2_output_file
|
121
|
-
expect(jp2_output_file).to be_a_jp2
|
122
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'when given a graycale tif but with bitonal image data (1 channel and 1 bits per pixel)' do
|
127
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'gray.tif') }
|
128
|
-
|
129
|
-
before do
|
130
|
-
generate_test_image(input_path, color: 'grey', bands: 1)
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'creates grayscale jp2' do
|
134
|
-
expect(File).to exist input_path
|
135
|
-
expect(File).not_to exist jp2_output_file
|
136
|
-
expect(assembly_image).not_to have_color_profile
|
137
|
-
expect(assembly_image.exif.samplesperpixel).to be 1
|
138
|
-
expect(assembly_image.exif.bitspersample).to be 8
|
139
|
-
expect(assembly_image).to be_a_valid_image
|
140
|
-
expect(assembly_image).to be_jp2able
|
141
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
142
|
-
expect(jp2_output_file).to be_a_jp2
|
143
|
-
expect(result).to be_a_kind_of described_class
|
144
|
-
expect(result.path).to eq jp2_output_file
|
145
|
-
expect(result.exif.colorspace).to eq 'Grayscale'
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context 'when given a color tif but with greyscale image data (1 channel and 8 bits per pixel)' do
|
150
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'color_gray.tif') }
|
151
|
-
|
152
|
-
before do
|
153
|
-
generate_test_image(input_path, color: 'grey')
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'creates color jp2' do
|
157
|
-
expect(File).to exist input_path
|
158
|
-
expect(File).not_to exist jp2_output_file
|
159
|
-
expect(assembly_image.exif.samplesperpixel).to be 3
|
160
|
-
expect(assembly_image.exif.bitspersample).to eql '8 8 8'
|
161
|
-
expect(assembly_image).to be_a_valid_image
|
162
|
-
expect(assembly_image).to be_jp2able
|
163
|
-
expect(assembly_image).not_to have_color_profile
|
164
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
165
|
-
expect(result).to be_a_kind_of described_class
|
166
|
-
expect(result.path).to eq jp2_output_file
|
167
|
-
expect(jp2_output_file).to be_a_jp2
|
168
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
context 'when given a cmyk tif' do
|
173
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'cmky.tif') }
|
174
|
-
|
175
|
-
before do
|
176
|
-
generate_test_image(input_path, color: 'cmyk', cg_type: 'cmyk', profile: 'cmyk', bands: 4)
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'creates an srgb jp2', skip: 'Need to verify the color space is correct in jp2' do
|
180
|
-
expect(File).to exist input_path
|
181
|
-
expect(File).not_to exist jp2_output_file
|
182
|
-
expect(assembly_image.exif.samplesperpixel).to be 4
|
183
|
-
expect(assembly_image.exif.bitspersample).to eql '8 8 8 8'
|
184
|
-
expect(assembly_image).to be_a_valid_image
|
185
|
-
expect(assembly_image).to be_jp2able
|
186
|
-
expect(assembly_image).to have_color_profile
|
187
|
-
result = assembly_image.create_jp2(output: jp2_output_file)
|
188
|
-
expect(result).to be_a_kind_of described_class
|
189
|
-
expect(result.path).to eq jp2_output_file
|
190
|
-
expect(jp2_output_file).to be_a_jp2
|
191
|
-
# note, we verify the CMYK has been converted to an SRGB JP2 correctly by using ruby-vips instead of exif, since exif does not correctly
|
192
|
-
# identify the color space...note: this line current does not work in circleci, potentially due to libvips version differences
|
193
|
-
expect(Vips::Image.new_from_file(jp2_output_file).get_value('interpretation')).to eq :srgb
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
context 'when the source image has no profile' do
|
198
|
-
let(:input_path) { File.join(TEST_INPUT_DIR, 'no_profile.tif') }
|
199
|
-
|
200
|
-
before do
|
201
|
-
generate_test_image(input_path)
|
202
|
-
end
|
203
|
-
|
204
|
-
it 'creates a jp2' do
|
205
|
-
expect(File).to exist input_path
|
206
|
-
expect(File).not_to exist jp2_output_file
|
207
|
-
expect(assembly_image.exif.samplesperpixel).to be 3
|
208
|
-
expect(assembly_image.exif.bitspersample).to eql '8 8 8'
|
209
|
-
expect(assembly_image).not_to have_color_profile
|
210
|
-
expect(assembly_image).to be_a_valid_image
|
211
|
-
expect(assembly_image).to be_jp2able
|
212
|
-
assembly_image.create_jp2(output: jp2_output_file)
|
213
|
-
expect(jp2_output_file).to be_a_jp2
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
context "when the output file exists and you don't allow overwriting" do
|
218
|
-
before do
|
219
|
-
generate_test_image(input_path)
|
220
|
-
FileUtils.touch(jp2_output_file) # just need a file with this name, don't care what
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'does not run' do
|
224
|
-
expect(File).to exist input_path
|
225
|
-
expect(File).to exist jp2_output_file
|
226
|
-
expect { assembly_image.create_jp2(output: jp2_output_file) }.to raise_error(SecurityError)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
context 'when given a test tiff' do
|
231
|
-
before do
|
232
|
-
generate_test_image(input_path)
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'gets the correct image height and width' do
|
236
|
-
expect(assembly_image.height).to eq 36
|
237
|
-
expect(assembly_image.width).to eq 43
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context 'when the input file is a jp2' do
|
242
|
-
before do
|
243
|
-
generate_test_image(input_path)
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'does not run' do
|
247
|
-
expect(File).to exist input_path
|
248
|
-
expect(File).not_to exist jp2_output_file
|
249
|
-
expect(assembly_image).not_to have_color_profile
|
250
|
-
expect(assembly_image).to be_a_valid_image
|
251
|
-
expect(assembly_image).to be_jp2able
|
252
|
-
assembly_image.create_jp2(output: jp2_output_file)
|
253
|
-
expect(jp2_output_file).to be_a_jp2
|
254
|
-
jp2_file = described_class.new(jp2_output_file)
|
255
|
-
expect(jp2_file).to be_valid_image
|
256
|
-
expect(jp2_file).not_to be_jp2able
|
257
|
-
expect { jp2_file.create_jp2 }.to raise_error(RuntimeError)
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
context 'when you specify a bogus output profile' do
|
262
|
-
before do
|
263
|
-
generate_test_image(input_path)
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'runs, because this is not currently an option' do
|
267
|
-
expect(File).to exist input_path
|
268
|
-
result = assembly_image.create_jp2(output_profile: 'bogusness')
|
269
|
-
expect(result).to be_a_kind_of described_class
|
270
|
-
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
271
|
-
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
272
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
context 'when an invalid tmp folder' do
|
277
|
-
before do
|
278
|
-
generate_test_image(TEST_JPEG_INPUT_FILE)
|
279
|
-
end
|
280
|
-
|
281
|
-
let(:input_path) { TEST_JPEG_INPUT_FILE }
|
282
|
-
|
283
|
-
it 'does not run' do
|
284
|
-
bogus_folder = '/crapsticks'
|
285
|
-
expect(File).to exist TEST_JPEG_INPUT_FILE
|
286
|
-
expect(File).not_to exist bogus_folder
|
287
|
-
expect { assembly_image.create_jp2(tmp_folder: bogus_folder) }.to raise_error(RuntimeError)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context 'when no output file is specified' do
|
292
|
-
before do
|
293
|
-
generate_test_image(input_path)
|
294
|
-
end
|
295
|
-
|
296
|
-
it 'creates a jp2 of the same filename and in the same location as the input and cleans up the tmp file' do
|
297
|
-
expect(File).to exist input_path
|
298
|
-
expect(File.exist?(TEST_JP2_INPUT_FILE)).to be false
|
299
|
-
result = assembly_image.create_jp2
|
300
|
-
expect(result).to be_a_kind_of described_class
|
301
|
-
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
302
|
-
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
303
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
context 'when the output file exists and you allow overwriting' do
|
308
|
-
before do
|
309
|
-
generate_test_image(input_path)
|
310
|
-
FileUtils.touch(jp2_output_file) # just need a file with this name, don't care what
|
311
|
-
end
|
312
|
-
|
313
|
-
it 'recreates jp2' do
|
314
|
-
expect(File).to exist input_path
|
315
|
-
expect(File).to exist jp2_output_file
|
316
|
-
result = assembly_image.create_jp2(output: jp2_output_file, overwrite: true)
|
317
|
-
expect(result).to be_a_kind_of described_class
|
318
|
-
expect(result.path).to eq jp2_output_file
|
319
|
-
expect(jp2_output_file).to be_a_jp2
|
320
|
-
expect(result.exif.colorspace).to eq 'sRGB'
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
data/spec/images_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe Assembly::Images do
|
6
|
-
before { cleanup }
|
7
|
-
|
8
|
-
describe '#batch_generate_jp2' do
|
9
|
-
it 'does not run if no input folder is passed in' do
|
10
|
-
expect{ described_class.batch_generate_jp2('') }.to raise_error(RuntimeError)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'does not run if a non-existent input folder is passed in' do
|
14
|
-
expect{ described_class.batch_generate_jp2('/junk/path') }.to raise_error(RuntimeError)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'runs and batch produces jp2s from input tiffs' do
|
18
|
-
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif"), profile: 'AdobeRGB1998') }
|
19
|
-
described_class.batch_generate_jp2(TEST_INPUT_DIR, output: TEST_OUTPUT_DIR)
|
20
|
-
expect(File.directory?(TEST_OUTPUT_DIR)).to be true
|
21
|
-
['test1', 'test2', 'test3'].each { |image| expect(File.join(TEST_OUTPUT_DIR, "#{image}.jp2")).to be_a_jp2 }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe '#batch_add_exif_profile_descr' do
|
26
|
-
it 'runs and batch adds color profile descriptions to input tiffs that had no color profile descriptions' do
|
27
|
-
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif")) }
|
28
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to be_nil }
|
29
|
-
described_class.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998')
|
30
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)' }
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'runs and batch adds color profile descriptions to input tiffs, forcing over existing color profile descriptions' do
|
34
|
-
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif"), profile: 'sRGBIEC6196621') }
|
35
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
36
|
-
described_class.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998', force: true) # force overwrite
|
37
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)' }
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'runs and batch adds color profile descriptions to input tiffs, not overwriting existing color profile descriptions' do
|
41
|
-
['test1', 'test2', 'test3'].each { |image| generate_test_image(File.join(TEST_INPUT_DIR, "#{image}.tif"), profile: 'sRGBIEC6196621') }
|
42
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
43
|
-
described_class.batch_add_exif_profile_descr(TEST_INPUT_DIR, 'Adobe RGB 1998') # do not force overwrite
|
44
|
-
['test1', 'test2', 'test3'].each { |image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR, "#{image}.tif")).exif.profiledescription).to eq 'sRGB IEC61966-2.1' }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|