assembly-image 1.6.7
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 +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:
|