assembly-image 1.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rvmrc.example +1 -0
- data/Gemfile +4 -0
- data/LICENSE +14 -0
- data/README.rdoc +139 -0
- data/Rakefile +8 -0
- data/assembly-image.gemspec +30 -0
- data/bin/console +8 -0
- data/bin/run_all_tests +3 -0
- data/config/boot.rb +9 -0
- data/lib/assembly-image/image.rb +216 -0
- data/lib/assembly-image/images.rb +97 -0
- data/lib/assembly-image/version.rb +8 -0
- data/lib/assembly-image.rb +9 -0
- data/profiles/AdobeRGB1998.icc +0 -0
- data/profiles/DotGain20.icc +0 -0
- data/profiles/sRGBIEC6196621.icc +0 -0
- data/spec/image_spec.rb +203 -0
- data/spec/images_spec.rb +48 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/test_data/input/.empty +0 -0
- data/spec/test_data/output/.empty +0 -0
- metadata +190 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b213d29d1bbd1206e9268adeff0d7eba4f9e8b26
|
4
|
+
data.tar.gz: 04d757adec2931a7ca42ac9f1cf7f29d6b7dbbc0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 84120410f44ab8fdbf8fe2f7e9943d6209058e6bc4ffc707e149ba134c65b3165e1839ec869bf40b33a823ab395ed7ddfbbb22582f8aee53c2a5befaf8d31b62
|
7
|
+
data.tar.gz: fb93f15796aacf0500337b0afe7997cec9d832edb39f23f6078cacaef061c36efb5e85b48b4f40607f2b7d86bd3d58afdd569f33f3babfe1c980de90179b89d6
|
data/.gitignore
ADDED
data/.rvmrc.example
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@assembly-image --create
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#############################################################################################################
|
2
|
+
# Copyright (c) 2012-2014 by The Board of Trustees of the Leland Stanford Junior University. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
data/README.rdoc
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
= Assembly Image Gem
|
2
|
+
|
3
|
+
==Overview
|
4
|
+
This gem contains classes used by the Stanford University Digital Library to perform
|
5
|
+
image operations necessary for accessioning of content.
|
6
|
+
|
7
|
+
==Releases
|
8
|
+
|
9
|
+
- 0.0.1 initial release
|
10
|
+
- 0.0.2 small bug fixes
|
11
|
+
- 0.0.3 more bug fixes
|
12
|
+
- 0.0.4 update jp2 creation method to restrict allowed input types and improve color profile handling
|
13
|
+
- 0.0.5 updated documentation to yard format
|
14
|
+
- 0.0.6 updated dependency declarations
|
15
|
+
- 0.1.0 move color profile extraction to tmp folder instead of gem profiles folder
|
16
|
+
- 0.1.1 fix problem with digest require statement
|
17
|
+
- 0.1.2 move check for file existence to when an action occurs instead of object initialization; more error checking and messages on command execution
|
18
|
+
- 0.1.3 added a filesize attribute to the file object to allow easy access to filesize in bytes
|
19
|
+
- 0.1.4 added a new images class that allows you batch create jp2s from an input TIFF directory
|
20
|
+
- 0.2.0 added a new method to the image class to handle TIFF "sanity-check" -- can be used to ensure TIFFs are valid before JP2 generation
|
21
|
+
- 1.0.0 bump the version number up to an official production level release
|
22
|
+
- 1.1.0 remove common object file behaviors to a separate gem and use that gem as a dependency
|
23
|
+
- 1.1.1 minor changes to spec tests
|
24
|
+
- 1.1.2 remove the addition of 'format' node to file types in content metadata generation
|
25
|
+
- 1.1.3 changes to content metadata generation method: change md5 and sha1 computations so that they come from the assembly-objectfile gem, and set preserve/publish/shelve attributes using mimetype defaults
|
26
|
+
- 1.2.0 support tiffs that have embedded thumbnails when creating jp2
|
27
|
+
- 1.2.1 raise a SecurityError if the user attempts to overwrite an existing jp2 when creating it, to make it easier to catch in assembly
|
28
|
+
- 1.2.2 add height and width methods for an image that gets it from exif
|
29
|
+
- 1.2.4 prepare for release listing on DLSS release board
|
30
|
+
- 1.2.5 small change to use the jp2able method instead of the valid? method when creating jp2s
|
31
|
+
- 1.2.6 update how version number is set to make it easier to show
|
32
|
+
- 1.3.0 added a new method to the Assembly::Images class to allow for batch adding of color profiles to all tiffs in a directory; allow batch methods to run recursively
|
33
|
+
- 1.3.1 remove content metadata generation method and add to assembly-objectfile gem instead
|
34
|
+
- 1.3.3 update gemspec to force use of latest assembly-objectfile gem to allow gem to work in Ruby 1.9 projects
|
35
|
+
- 1.3.4 update to latest version of lyberteam gems
|
36
|
+
- 1.3.5 fix a problem that could occur if there were spaces in input filenames
|
37
|
+
- 1.3.6 add new attribute to give you default jp2 filename that will be used
|
38
|
+
- 1.3.7 add new attribute to give you default dpg jp2 filename
|
39
|
+
- 1.3.8 allow for batch processing of image extensions other than tif
|
40
|
+
- 1.3.9 create new methods for getting a color profile from exif and for force adding color profile to a single image
|
41
|
+
- 1.4.0 and 1.4.1 set the imagemagick tmp folder location environment variable when creating jp2
|
42
|
+
- 1.5.0 allow images with a color profile to have jp2 derivatives generated
|
43
|
+
- 1.5.1 relax nokogiri version requirement
|
44
|
+
- 1.6.1 bump version number of assembly-objectfile required to fix UTF-8 errors during JP2-create
|
45
|
+
- 1.6.2-1.6.3 small change to jp2 generation to try and fix bug with tiffs that have multiple input profile layers
|
46
|
+
- 1.6.4 added in some additional checks to try and create jp2s with mismatching exif data
|
47
|
+
- 1.6.5 fix problem with lack of extension in incoming tif causing a problem when creating jp2
|
48
|
+
- 1.6.7 release to github/rubygems
|
49
|
+
==Notes
|
50
|
+
|
51
|
+
1. The gem assumes that the user context in which it is executed has write access to the 'tmp' folder.
|
52
|
+
This is because color profiles can be extracted from images during the JP2 creation process, and these profiles need to
|
53
|
+
be stored as local files, and it is beneficial to cache them for later usage by images with the same color profile.
|
54
|
+
If you know there are color profiles which are commonly used, it is better to capture them in the gem itself in the profile
|
55
|
+
folder so they can be re-used and do not need to be extracted.
|
56
|
+
|
57
|
+
2. If any errors occur during JP2 generation for any reason, a runtime exception will be thrown with a description of the error.
|
58
|
+
|
59
|
+
3. If an image is passed in with a color profile that cannot be determined by examining the exif header data, an exception will be thrown.
|
60
|
+
This can commonally occur in basic test TIFs that are black/white and have no profile, so beware during testing.
|
61
|
+
|
62
|
+
==Usage
|
63
|
+
|
64
|
+
To use the JP2 creation method, you first instantiate the image object with an input image and then operate on it.
|
65
|
+
|
66
|
+
require 'assembly-image'
|
67
|
+
input=Assembly::Image.new('/full/path/to/file.tif')
|
68
|
+
puts input.exif # this will show you exif header information for the TIF
|
69
|
+
output=input.create_jp2(:output=>'/full/path/to/output.jp2') # this will generate a new JP2 in the output location specified
|
70
|
+
puts output.exif # this will show you exif header information for the JP2
|
71
|
+
|
72
|
+
==Running tests
|
73
|
+
|
74
|
+
bundle exec rspec spec
|
75
|
+
|
76
|
+
==Generate documentation
|
77
|
+
To generate documentation into the "doc" folder:
|
78
|
+
|
79
|
+
yard
|
80
|
+
|
81
|
+
To keep a local server running with up to date code documentation that you can view in your browser:
|
82
|
+
|
83
|
+
yard server --reload
|
84
|
+
|
85
|
+
==Prerequisites
|
86
|
+
|
87
|
+
1. Perl
|
88
|
+
|
89
|
+
2. Kakadu Software Binaries - for JP2 generation
|
90
|
+
|
91
|
+
Download and install demonstration binaries from Kakadu:
|
92
|
+
http://www.kakadusoftware.com/index.php?option=com_content&task=view&id=26&Itemid=22
|
93
|
+
|
94
|
+
Note: The binaries will not work with RHEL 5.x; an RPM for RHEL 5 with
|
95
|
+
compatible binaries coming soon.
|
96
|
+
|
97
|
+
3. Imagemagick 6.5.4 or higher
|
98
|
+
|
99
|
+
RHEL 6
|
100
|
+
|
101
|
+
The version of ImageMagick included with RHEL 6 has all of the dependency libraries included:
|
102
|
+
|
103
|
+
yum install ImageMagick
|
104
|
+
|
105
|
+
RHEL 5: (RPM to install with included binaries comming soon)
|
106
|
+
|
107
|
+
The version of ImageMagic included with RHEL 5 is too old and does not have all the proper binaries included/built
|
108
|
+
|
109
|
+
Required libraries are:
|
110
|
+
|
111
|
+
yum install lcms lcms-devel libjpeg \
|
112
|
+
libjpeg-devel libpng libpng-devel
|
113
|
+
|
114
|
+
Required libraries from source:
|
115
|
+
* libtiff (version 3.9.4 or higher)
|
116
|
+
|
117
|
+
Build Imagemagick from source:
|
118
|
+
http://www.imagemagick.org/download/ImageMagick.tar.gz
|
119
|
+
|
120
|
+
Mac users:
|
121
|
+
|
122
|
+
brew install jasper
|
123
|
+
brew install libtiff
|
124
|
+
brew install imagemagick --use-tiff --use-jpeg2000
|
125
|
+
|
126
|
+
4. Exiftool
|
127
|
+
|
128
|
+
RHEL: (RPM to install comming soon)
|
129
|
+
Download latest version from: http://www.sno.phy.queensu.ca/~phil/exiftool
|
130
|
+
|
131
|
+
tar -xf Image-ExifTool-#.##.tar.gz
|
132
|
+
cd Image-ExifTool-#.##
|
133
|
+
perl Makefile.PL
|
134
|
+
make test
|
135
|
+
sudo make install
|
136
|
+
|
137
|
+
Mac users:
|
138
|
+
|
139
|
+
brew install exiftool
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'assembly-image/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'assembly-image'
|
6
|
+
s.version = Assembly::Image::VERSION
|
7
|
+
s.authors = ["Peter Mangiafico", "Renzo Sanchez-Silva","Monty Hindman","Tony Calavano"]
|
8
|
+
s.email = ["pmangiafico@stanford.edu"]
|
9
|
+
s.homepage = ""
|
10
|
+
s.summary = %q{Ruby immplementation of image services needed to prepare objects to be accessioned in SULAIR digital library}
|
11
|
+
s.description = %q{Contains classes to create derivative image files and perform other image operations}
|
12
|
+
|
13
|
+
s.rubyforge_project = 'assembly-image'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
|
20
|
+
s.add_dependency 'uuidtools'
|
21
|
+
s.add_dependency 'assembly-objectfile', ">= 1.6.4"
|
22
|
+
s.add_dependency 'mini_exiftool', "~> 1.6"
|
23
|
+
s.add_dependency 'activesupport'
|
24
|
+
s.add_dependency 'nokogiri'
|
25
|
+
|
26
|
+
s.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
s.add_development_dependency "yard"
|
28
|
+
s.add_development_dependency "rake"
|
29
|
+
|
30
|
+
end
|
data/bin/console
ADDED
data/bin/run_all_tests
ADDED
data/config/boot.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'uuidtools'
|
2
|
+
require 'assembly-objectfile'
|
3
|
+
|
4
|
+
module Assembly
|
5
|
+
|
6
|
+
# The Image class contains methods to operate on an image.
|
7
|
+
class Image
|
8
|
+
|
9
|
+
# include common behaviors from assembly-objectfile gem
|
10
|
+
include Assembly::ObjectFileable
|
11
|
+
|
12
|
+
# stores the path to the tmp file generated during the JP2 creation process
|
13
|
+
attr_accessor :tmp_path
|
14
|
+
|
15
|
+
# Examines the input image for validity. Used to determine if image is correct and if JP2 generation is likely to succeed.
|
16
|
+
# This method is automatically called before you create a jp2 but it can be called separately earlier as a sanity check.
|
17
|
+
#
|
18
|
+
# @return [boolean] true if image is valid, false if not.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# source_img=Assembly::ObjectFile.new('/input/path_to_file.tif')
|
22
|
+
# puts source_img.valid? # gives true
|
23
|
+
def valid?
|
24
|
+
valid_image? # behavior is defined in assembly-objectfile gem
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get the image color profile
|
28
|
+
#
|
29
|
+
# @return [string] image color profile
|
30
|
+
# Example:
|
31
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
32
|
+
# puts source_img.profile # gives 'Adobe RGB 1998'
|
33
|
+
def profile
|
34
|
+
exif.nil? ? nil : exif['profiledescription']
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get the image height from exif data
|
38
|
+
#
|
39
|
+
# @return [integer] image height in pixels
|
40
|
+
# Example:
|
41
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
42
|
+
# puts source_img.height # gives 100
|
43
|
+
def height
|
44
|
+
exif.imageheight
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the image width from exif data
|
48
|
+
#
|
49
|
+
# @return [integer] image height in pixels
|
50
|
+
# Example:
|
51
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
52
|
+
# puts source_img.width # gives 100
|
53
|
+
def width
|
54
|
+
exif.imagewidth
|
55
|
+
end
|
56
|
+
|
57
|
+
# Add an exif color profile descriptions to the image.
|
58
|
+
# This is useful if your source TIFFs do not have color profile descriptions in the EXIF data, but you know what it should be.
|
59
|
+
# This will allow the images to pass the validaty check and have JP2s created successfully.
|
60
|
+
#
|
61
|
+
# Note you will need full read/write access to the source path so that new EXIF data can be saved.
|
62
|
+
#
|
63
|
+
# @param [String] profile_name profile name to be added, current options are 'Adobe RBG 1998','Dot Gain 20%','sRGB IEC61966-2.1'
|
64
|
+
#
|
65
|
+
# @param [String] force if set to true, force overwrite a color profile description even if it already exists (default: false)
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
69
|
+
# source_img.add_exif_profile_description('Adobe RGB 1998')
|
70
|
+
def add_exif_profile_description(profile_name,force=false)
|
71
|
+
begin
|
72
|
+
if profile.nil? || force
|
73
|
+
input_profile = profile_name.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
74
|
+
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM,'profiles')
|
75
|
+
input_profile_file = File.join(path_to_profiles,"#{input_profile}.icc")
|
76
|
+
command="exiftool '-icc_profile<=#{input_profile_file}' #{path}"
|
77
|
+
result=`#{command} 2>&1`
|
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}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the full default jp2 path and filename that will be created from the given image
|
86
|
+
#
|
87
|
+
# @return [string] full default jp2 path and filename that will be created from the given image
|
88
|
+
# Example:
|
89
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
90
|
+
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
91
|
+
def jp2_filename
|
92
|
+
File.extname(@path).empty? ? "#{@path}.jp2" : @path.gsub(File.extname(@path),'.jp2')
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the full DPG equivalent jp2 path and filename that would match with the given image
|
96
|
+
#
|
97
|
+
# @return [string] full DPG equivalent jp2 path and filename
|
98
|
+
# Example:
|
99
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
100
|
+
# puts source_img.jp2_filename # gives /input/path_to_file.jp2
|
101
|
+
def dpg_jp2_filename
|
102
|
+
jp2_filename.gsub('_00_','_05_')
|
103
|
+
end
|
104
|
+
|
105
|
+
# Create a JP2 file for the current image.
|
106
|
+
# Important note: this will not work for multipage TIFFs.
|
107
|
+
#
|
108
|
+
# @return [Assembly::Image] object containing the generated JP2 file
|
109
|
+
#
|
110
|
+
# @param [Hash] params Optional parameters specified as a hash, using symbols for options:
|
111
|
+
# * :output => path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
|
112
|
+
# * :overwrite => if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
113
|
+
# * :tmp_folder => the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
|
114
|
+
# * :preserve_tmp_source => if set to true, preserve the temporary file generated during the creation process and store path in 'tmp_path' attribute (default: false)
|
115
|
+
#
|
116
|
+
# Example:
|
117
|
+
# source_img=Assembly::Image.new('/input/path_to_file.tif')
|
118
|
+
# derivative_img=source_img.create_jp2(:overwrite=>true)
|
119
|
+
# puts derivative_img.mimetype # 'image/jp2'
|
120
|
+
# puts derivative_image.path # '/input/path_to_file.jp2'
|
121
|
+
def create_jp2(params = {})
|
122
|
+
|
123
|
+
check_for_file
|
124
|
+
|
125
|
+
raise "input file is not a valid image, or is the wrong mimetype" if !self.jp2able?
|
126
|
+
|
127
|
+
output = params[:output] || jp2_filename
|
128
|
+
overwrite = params[:overwrite] || false
|
129
|
+
|
130
|
+
raise SecurityError,"output #{output} exists, cannot overwrite" if !overwrite && File.exists?(output)
|
131
|
+
|
132
|
+
raise SecurityError,"cannot recreate jp2 over itself" if overwrite && mimetype=='image/jp2' && output == @path
|
133
|
+
|
134
|
+
tmp_folder = params[:tmp_folder] || '/tmp'
|
135
|
+
raise "tmp_folder #{tmp_folder} does not exists" unless File.exists?(tmp_folder)
|
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
|
+
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
|
+
|
142
|
+
raise "output profile #{output_profile} invalid" if !File.exists?(output_profile_file)
|
143
|
+
|
144
|
+
samples_per_pixel=exif['samplesperpixel'].to_s || ""
|
145
|
+
bits_per_sample=exif['bitspersample'] || ""
|
146
|
+
|
147
|
+
path_to_profiles = File.join(Assembly::PATH_TO_IMAGE_GEM,'profiles')
|
148
|
+
|
149
|
+
if !profile.nil? # if the input color profile exists, contract paths to the profile and setup the command
|
150
|
+
|
151
|
+
input_profile = profile.gsub(/[^[:alnum:]]/, '') # remove all non alpha-numeric characters, so we can get to a filename
|
152
|
+
|
153
|
+
# construct a path to the input profile, which might exist either in the gem itself or in the tmp folder
|
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
|
157
|
+
|
158
|
+
# if input profile was extracted and does not matches an existing known profile either in the gem or in the tmp folder,
|
159
|
+
# we'll issue an imagicmagick command to extract the profile to the tmp folder
|
160
|
+
unless File.exists?(input_profile_file)
|
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
|
166
|
+
|
167
|
+
profile_conversion_switch = "-profile #{input_profile_file} -profile #{output_profile_file}"
|
168
|
+
|
169
|
+
else
|
170
|
+
|
171
|
+
profile_conversion_switch = "" # no conversion needed if input color profile does not exist
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
# make temp tiff filename
|
176
|
+
@tmp_path = "#{tmp_folder}/#{UUIDTools::UUID.random_create.to_s}.tif"
|
177
|
+
|
178
|
+
options = ""
|
179
|
+
case samples_per_pixel
|
180
|
+
when "3"
|
181
|
+
options += "-type TrueColor"
|
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?
|
192
|
+
|
193
|
+
pixdem = width > height ? width : height
|
194
|
+
layers = (( Math.log(pixdem) / Math.log(2) ) - ( Math.log(96) / Math.log(2) )).ceil + 1
|
195
|
+
|
196
|
+
# jp2 creation command
|
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?
|
206
|
+
|
207
|
+
File.delete(@tmp_path) unless preserve_tmp_source
|
208
|
+
|
209
|
+
# create output response object, which is an Assembly::Image type object
|
210
|
+
return Assembly::Image.new(output)
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Assembly
|
3
|
+
|
4
|
+
# The Images class contains methods to operate on multiple images in batch.
|
5
|
+
class Images
|
6
|
+
|
7
|
+
def self.logger
|
8
|
+
@logger ||= Logger.new(STDERR)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logger= logger
|
12
|
+
@logger = 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
|
+
def self.batch_add_exif_profile_description(source,profile_name,params={})
|
32
|
+
|
33
|
+
extension = params[:extension] || 'tif'
|
34
|
+
recursive = params[:recursive] || false
|
35
|
+
force = params[:force] || false
|
36
|
+
|
37
|
+
raise "Input path does not exist" unless File.directory?(source)
|
38
|
+
|
39
|
+
logger.debug "Source: #{source}"
|
40
|
+
|
41
|
+
# iterate over input directory looking for tifs
|
42
|
+
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
43
|
+
Dir.glob(File.join(source,pattern)).each do |file|
|
44
|
+
img=Assembly::Image.new(file)
|
45
|
+
logger.debug "Processing #{file}"
|
46
|
+
img.add_exif_profile_description(profile_name,force)
|
47
|
+
end
|
48
|
+
return "Complete"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Pass in a source path and get JP2s generate for each tiff that is in the source path
|
52
|
+
#
|
53
|
+
# If not passed in, the destination will be a "jp2" subfolder within the source folder.
|
54
|
+
# Note you will need read access to the source path, and write access to the destination path.
|
55
|
+
#
|
56
|
+
# @param [String] source path full path to the directory containing TIFFs to be converted to JP2
|
57
|
+
#
|
58
|
+
# @param [Hash] params Optional parameters specified as a hash, using symbols for options:
|
59
|
+
# * :output=>'/full/path_to_jp2' # specifies full path to folder where jp2s will be created (default: jp2 subdirectory from source path)
|
60
|
+
# * :overwrite => if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
|
61
|
+
# * :recursive => if set to true, directories will be searched recursively for TIFFs from the source specified, false searches the top level only (default: false)
|
62
|
+
# * :extension => defines the types of files that will be processed (default '.tif')
|
63
|
+
#
|
64
|
+
# Example:
|
65
|
+
# Assembly::Images.batch_generate_jp2('/full_path_to_tifs')
|
66
|
+
def self.batch_generate_jp2(source,params={})
|
67
|
+
|
68
|
+
raise "Input path does not exist" unless File.directory?(source)
|
69
|
+
output = params[:output] || File.join(source,'jp2') # default output directgory is jp2 sub-directory from source
|
70
|
+
extension = params[:extension] || 'tif'
|
71
|
+
overwrite = params[:overwrite] || false
|
72
|
+
recursive = params[:recursive] || false
|
73
|
+
|
74
|
+
Dir.mkdir(output) unless File.directory?(output) # attemp to make output directory
|
75
|
+
raise "Output path does not exist or could not be created" unless File.directory?(output)
|
76
|
+
|
77
|
+
logger.debug "Source: #{source}"
|
78
|
+
logger.debug "Destination: #{output}"
|
79
|
+
|
80
|
+
pattern = recursive ? "**/*.#{extension}" : "*.#{extension}*"
|
81
|
+
|
82
|
+
# iterate over input directory looking for tifs
|
83
|
+
Dir.glob(File.join(source,pattern)).each do |file|
|
84
|
+
source_img=Assembly::Image.new(file)
|
85
|
+
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
|
86
|
+
begin
|
87
|
+
derivative_img=source_img.create_jp2(:overwrite=>overwrite,:output=>output_img)
|
88
|
+
logger.debug "Generated jp2 for #{File.basename(file)}"
|
89
|
+
rescue Exception => e
|
90
|
+
logger.debug "** Error for #{File.basename(file)}: #{e.message}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
return 'Complete'
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Assembly
|
2
|
+
|
3
|
+
# the path to the gem, used to access profiles stored with the gem
|
4
|
+
PATH_TO_IMAGE_GEM = File.expand_path(File.dirname(__FILE__) + '/..')
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
# auto-include all files in the lib sub-directory directory
|
9
|
+
Dir[File.dirname(__FILE__) + '/assembly-image/*.rb'].each {|file| require file unless file=='version.rb'}
|
Binary file
|
Binary file
|
Binary file
|
data/spec/image_spec.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Assembly::Image do
|
4
|
+
|
5
|
+
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
|
+
end
|
9
|
+
|
10
|
+
it "should indicate the default jp2 filename" do
|
11
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
12
|
+
expect(@ai.jp2_filename).to eq TEST_TIF_INPUT_FILE.gsub('.tif','.jp2')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should indicate the default jp2 filename" do
|
16
|
+
@ai = Assembly::Image.new("/path/to/a/file_with_no_extension")
|
17
|
+
expect(@ai.jp2_filename).to eq "/path/to/a/file_with_no_extension.jp2"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should indicate the default DPG jp2 filename" do
|
21
|
+
@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_')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should indicate the default jp2 filename" do
|
26
|
+
@ai = Assembly::Image.new("/path/to/a/file_with_no_00_extension")
|
27
|
+
expect(@ai.dpg_jp2_filename).to eq "/path/to/a/file_with_no_05_extension.jp2"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should create jp2 when given an RGB tif" do
|
31
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
32
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
33
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
34
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
35
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
36
|
+
expect(result).to be_a_kind_of Assembly::Image
|
37
|
+
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
38
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
39
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
40
|
+
@jp2=Assembly::Image.new(TEST_JP2_OUTPUT_FILE)
|
41
|
+
expect(@jp2.height).to eq 100
|
42
|
+
expect(@jp2.width).to eq 100
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should create grayscale jp2 when given a bitonal tif" do
|
46
|
+
generate_test_image(TEST_TIF_INPUT_FILE,:color=>'white',:image_type=>"Bilevel")
|
47
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
48
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
49
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
50
|
+
expect(@ai).to have_color_profile
|
51
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
52
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
53
|
+
expect(result.exif.colorspace).to eq "Grayscale"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should create color jp2 when given a color tif but bitonal image data (1 channels and 1 bits per pixel)" do
|
57
|
+
generate_test_image(TEST_TIF_INPUT_FILE,:color=>'white',:image_type=>"TrueColor",:profile=>'')
|
58
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
59
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
60
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
61
|
+
expect(@ai).to_not have_color_profile
|
62
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
63
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
64
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create grayscale jp2 when given a graycale tif but with bitonal image data (1 channel and 1 bits per pixel)" do
|
68
|
+
generate_test_image(TEST_TIF_INPUT_FILE,:color=>'white',:image_type=>"Grayscale",:profile=>'')
|
69
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
70
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
71
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
72
|
+
expect(@ai).to_not have_color_profile
|
73
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
74
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
75
|
+
expect(result.exif.colorspace).to eq "Grayscale"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should create color jp2 when given a color tif but with greyscale image data (1 channel and 8 bits per pixel)" do
|
79
|
+
generate_test_image(TEST_TIF_INPUT_FILE,:color=>'gray',:image_type=>"TrueColor",:profile=>'')
|
80
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
81
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
82
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
83
|
+
expect(@ai).to_not have_color_profile
|
84
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
85
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
86
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should create a jp2 when the source image has no profile" do
|
90
|
+
generate_test_image(TEST_TIF_INPUT_FILE,:profile=>'') # generate a test input with no profile
|
91
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
92
|
+
expect(File).to_not exist TEST_JP2_OUTPUT_FILE
|
93
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
94
|
+
expect(@ai).to_not have_color_profile
|
95
|
+
expect(@ai).to be_a_valid_image
|
96
|
+
expect(@ai).to be_jp2able
|
97
|
+
@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)
|
98
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should not run if the output file exists and you don't allow overwriting" do
|
102
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
103
|
+
generate_test_image(TEST_JP2_OUTPUT_FILE)
|
104
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
105
|
+
expect(File).to exist TEST_JP2_OUTPUT_FILE
|
106
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
107
|
+
expect{@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE)}.to raise_error(SecurityError)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should get the correct image height and width" do
|
111
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
112
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
113
|
+
expect(@ai.height).to eq 100
|
114
|
+
expect(@ai.width).to eq 100
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not run if the input file is a jp2" do
|
118
|
+
generate_test_image(TEST_JP2_OUTPUT_FILE)
|
119
|
+
expect(File).to exist TEST_JP2_OUTPUT_FILE
|
120
|
+
@ai = Assembly::Image.new(TEST_JP2_OUTPUT_FILE)
|
121
|
+
expect(@ai).to be_valid_image
|
122
|
+
expect(@ai).to_not be_jp2able
|
123
|
+
expect { @ai.create_jp2 }.to raise_error
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should run if you specify a bogus output profile, because this is not currently an option" do
|
127
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
128
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
129
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
130
|
+
result=@ai.create_jp2(:output_profile=>'bogusness')
|
131
|
+
expect(result).to be_a_kind_of Assembly::Image
|
132
|
+
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
133
|
+
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
134
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not run if you specify a bogus tmp folder" do
|
138
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
139
|
+
bogus_folder='/crapsticks'
|
140
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
141
|
+
expect(File).to_not exist bogus_folder
|
142
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
143
|
+
expect { @ai.create_jp2(:tmp_folder=>bogus_folder) }.to raise_error
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should create a jp2 and preserve the temporary file if specified" do
|
147
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
148
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
149
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
150
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE, :preserve_tmp_source=>true)
|
151
|
+
expect(result).to be_a_kind_of Assembly::Image
|
152
|
+
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
153
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
154
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
155
|
+
expect(File.exists?(@ai.tmp_path)).to be true
|
156
|
+
end
|
157
|
+
|
158
|
+
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
|
159
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
160
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
161
|
+
expect(File.exists?(TEST_JP2_INPUT_FILE)).to be false
|
162
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
163
|
+
result=@ai.create_jp2
|
164
|
+
expect(result).to be_a_kind_of Assembly::Image
|
165
|
+
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
166
|
+
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
167
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
168
|
+
expect(File.exists?(@ai.tmp_path)).to be false
|
169
|
+
end
|
170
|
+
|
171
|
+
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
|
172
|
+
generate_test_image(TEST_JPEG_INPUT_FILE)
|
173
|
+
expect(File).to exist TEST_JPEG_INPUT_FILE
|
174
|
+
expect(File).to_not exist TEST_JP2_INPUT_FILE
|
175
|
+
@ai = Assembly::Image.new(TEST_JPEG_INPUT_FILE)
|
176
|
+
result=@ai.create_jp2
|
177
|
+
expect(result).to be_a_kind_of Assembly::Image
|
178
|
+
expect(result.path).to eq TEST_JP2_INPUT_FILE
|
179
|
+
expect(TEST_JP2_INPUT_FILE).to be_a_jp2
|
180
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
181
|
+
expect(File.exists?(@ai.tmp_path)).to be false
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should recreate jp2 if the output file exists and if you allow overwriting" do
|
185
|
+
generate_test_image(TEST_TIF_INPUT_FILE)
|
186
|
+
generate_test_image(TEST_JP2_OUTPUT_FILE)
|
187
|
+
expect(File).to exist TEST_TIF_INPUT_FILE
|
188
|
+
expect(File).to exist TEST_JP2_OUTPUT_FILE
|
189
|
+
@ai = Assembly::Image.new(TEST_TIF_INPUT_FILE)
|
190
|
+
result=@ai.create_jp2(:output => TEST_JP2_OUTPUT_FILE,:overwrite => true)
|
191
|
+
expect(result).to be_a_kind_of Assembly::Image
|
192
|
+
expect(result.path).to eq TEST_JP2_OUTPUT_FILE
|
193
|
+
expect(TEST_JP2_OUTPUT_FILE).to be_a_jp2
|
194
|
+
expect(result.exif.colorspace).to eq "sRGB"
|
195
|
+
end
|
196
|
+
|
197
|
+
after(:each) do
|
198
|
+
# after each test, empty out the input and output test directories
|
199
|
+
remove_files(TEST_INPUT_DIR)
|
200
|
+
remove_files(TEST_OUTPUT_DIR)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
data/spec/images_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Assembly::Images do
|
4
|
+
|
5
|
+
it "should not run if no input folder is passed in" do
|
6
|
+
expect{Assembly::Images.batch_generate_jp2('')}.to raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
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
|
11
|
+
end
|
12
|
+
|
13
|
+
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,:output=>TEST_OUTPUT_DIR)
|
16
|
+
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 }
|
18
|
+
end
|
19
|
+
|
20
|
+
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"),:profile=>'') }
|
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.batch_add_exif_profile_description(TEST_INPUT_DIR,'Adobe RGB 1998')
|
24
|
+
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)'}
|
25
|
+
end
|
26
|
+
|
27
|
+
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 'sRGB IEC61966-2.1'}
|
30
|
+
Assembly::Images.batch_add_exif_profile_description(TEST_INPUT_DIR,'Adobe RGB 1998',:force=>true) # force overwrite
|
31
|
+
['test1','test2','test3'].each {|image| expect(Assembly::Image.new(File.join(TEST_INPUT_DIR,"#{image}.tif")).exif.profiledescription).to eq 'Adobe RGB (1998)'}
|
32
|
+
end
|
33
|
+
|
34
|
+
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 'sRGB IEC61966-2.1'}
|
37
|
+
Assembly::Images.batch_add_exif_profile_description(TEST_INPUT_DIR,'Adobe RGB 1998') # do not force overwrite
|
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
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
after(:each) do
|
43
|
+
# after each test, empty out the input and output test directories
|
44
|
+
remove_files(TEST_INPUT_DIR)
|
45
|
+
remove_files(TEST_OUTPUT_DIR)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
bootfile = File.expand_path(File.dirname(__FILE__) + '/../config/boot')
|
2
|
+
require bootfile
|
3
|
+
|
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 = File.join(TEST_INPUT_DIR,'oo000oo0001_00_01.tif')
|
8
|
+
TEST_JPEG_INPUT_FILE = File.join(TEST_INPUT_DIR,'test.jpg')
|
9
|
+
TEST_JP2_INPUT_FILE = File.join(TEST_INPUT_DIR,'test.jp2')
|
10
|
+
TEST_JP2_OUTPUT_FILE = File.join(TEST_OUTPUT_DIR,'test.jp2')
|
11
|
+
TEST_DRUID = "nx288wh8889"
|
12
|
+
|
13
|
+
# generate a sample image file with a specified profile
|
14
|
+
def generate_test_image(file,params={})
|
15
|
+
color=params[:color] || 'red'
|
16
|
+
profile=params[:profile] || 'sRGBIEC6196621'
|
17
|
+
image_type=params[:image_type]
|
18
|
+
create_command="convert -size 100x100 xc:#{color} "
|
19
|
+
create_command += " -profile " + File.join(Assembly::PATH_TO_IMAGE_GEM,'profiles',profile+'.icc') + " " unless profile == ''
|
20
|
+
create_command += " -type #{image_type} " if image_type
|
21
|
+
create_command += file
|
22
|
+
create_command += " 2>&1"
|
23
|
+
output = `#{create_command}`
|
24
|
+
unless $?.success?
|
25
|
+
raise "Failed to create test image #{file} (#{params}): \n#{output}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_files(dir)
|
30
|
+
Dir.foreach(dir) {|f| fn = File.join(dir, f); File.delete(fn) if !File.directory?(fn) && File.basename(fn) != '.empty'}
|
31
|
+
end
|
32
|
+
|
33
|
+
RSpec::Matchers.define :be_a_jp2 do
|
34
|
+
match do |actual|
|
35
|
+
if File.exists?(actual)
|
36
|
+
exif = MiniExiftool.new actual
|
37
|
+
exif['mimetype'] == 'image/jp2'
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
File without changes
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: assembly-image
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.6.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Mangiafico
|
8
|
+
- Renzo Sanchez-Silva
|
9
|
+
- Monty Hindman
|
10
|
+
- Tony Calavano
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2014-07-25 00:00:00.000000000 Z
|
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
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: assembly-objectfile
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.6.4
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.6.4
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: mini_exiftool
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '1.6'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '1.6'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: activesupport
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
type: :runtime
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: nokogiri
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :runtime
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: rspec
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - "~>"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '3.0'
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '3.0'
|
100
|
+
- !ruby/object:Gem::Dependency
|
101
|
+
name: yard
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
type: :development
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
name: rake
|
116
|
+
requirement: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
description: Contains classes to create derivative image files and perform other image
|
129
|
+
operations
|
130
|
+
email:
|
131
|
+
- pmangiafico@stanford.edu
|
132
|
+
executables:
|
133
|
+
- console
|
134
|
+
- run_all_tests
|
135
|
+
extensions: []
|
136
|
+
extra_rdoc_files: []
|
137
|
+
files:
|
138
|
+
- ".gitignore"
|
139
|
+
- ".rvmrc.example"
|
140
|
+
- Gemfile
|
141
|
+
- LICENSE
|
142
|
+
- README.rdoc
|
143
|
+
- Rakefile
|
144
|
+
- assembly-image.gemspec
|
145
|
+
- bin/console
|
146
|
+
- bin/run_all_tests
|
147
|
+
- config/boot.rb
|
148
|
+
- lib/assembly-image.rb
|
149
|
+
- lib/assembly-image/image.rb
|
150
|
+
- lib/assembly-image/images.rb
|
151
|
+
- lib/assembly-image/version.rb
|
152
|
+
- profiles/AdobeRGB1998.icc
|
153
|
+
- profiles/DotGain20.icc
|
154
|
+
- profiles/sRGBIEC6196621.icc
|
155
|
+
- spec/image_spec.rb
|
156
|
+
- spec/images_spec.rb
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
- spec/test_data/input/.empty
|
159
|
+
- spec/test_data/output/.empty
|
160
|
+
homepage: ''
|
161
|
+
licenses: []
|
162
|
+
metadata: {}
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
requirements: []
|
178
|
+
rubyforge_project: assembly-image
|
179
|
+
rubygems_version: 2.2.2
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: Ruby immplementation of image services needed to prepare objects to be accessioned
|
183
|
+
in SULAIR digital library
|
184
|
+
test_files:
|
185
|
+
- spec/image_spec.rb
|
186
|
+
- spec/images_spec.rb
|
187
|
+
- spec/spec_helper.rb
|
188
|
+
- spec/test_data/input/.empty
|
189
|
+
- spec/test_data/output/.empty
|
190
|
+
has_rdoc:
|