assembly-image 1.8.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab0138b7a2f4b92d23428f192efd67f9db79e588849411265079c7dafbd8d44b
4
- data.tar.gz: 6d87bd7214d36684259de8d082b75494f67602947df1bfbb992ae7d4178a339c
3
+ metadata.gz: '088a4b9c59b50f893f7b50c16898321770006b4ab22dc08a8ddd70cdba9a15da'
4
+ data.tar.gz: f22bf6d6acbd4d6885e2102526e7c5e0ac76b93af71eff0d2237d32334afd223
5
5
  SHA512:
6
- metadata.gz: a1afdaef9ca647be48084fd50ea18adcb69383b42e5cccea155f5dbb5ed072709ca6061f0b0f352df738ff2a0a4d55388a5e2288f6fbb8eab97c166a3f5ed6f0
7
- data.tar.gz: e4310e4e33f402cefd3443173b47510ae6b1bb767be766f88edf934c802da7778866ad0e4b557254d6599a82b48f8e4f52fd50d9baf01ed0df430ad99cb8993f
6
+ metadata.gz: 91f0be3622982ad69823a45eca8111d05756e0442cd7d7aa16cb8099e71ee2e95c21f17c7f14b7ccab04c11724233c9a9739e24f8b8302f07f42b16738c6400e
7
+ data.tar.gz: d1ab206c475413496a6add9376cb246705df18a3142bdc32189b202e31af698b8cfded84464d00e94357fc08396ab142270043b3b862cc0d68cd57834863b649
data/.circleci/config.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  version: 2.1
2
2
  orbs:
3
- ruby-rails: sul-dlss/ruby-rails@3.0.1
3
+ ruby-rails: sul-dlss/ruby-rails@3.1.2
4
4
  workflows:
5
5
  build:
6
6
  jobs:
@@ -12,6 +12,9 @@ workflows:
12
12
  - run:
13
13
  name: Install exiftool
14
14
  command: curl -L http://cpanmin.us | perl - --sudo Image::ExifTool
15
+ - run:
16
+ name: Install libvips
17
+ command: sudo apt-get update && sudo apt-get install -y libvips
15
18
  - setup_remote_docker
16
19
  - run:
17
20
  name: Install Kakadu
data/.gitignore CHANGED
@@ -2,7 +2,6 @@
2
2
  *.gem
3
3
  .DS_Store
4
4
  .bundle
5
- Gemfile.lock
6
5
  config/certs/*
7
6
  config/environments/*
8
7
  doc/*
@@ -14,3 +13,5 @@ tmp
14
13
 
15
14
  coverage
16
15
  spec/examples.txt
16
+ spec/test_data/input/*
17
+ spec/test_data/output/*
data/.rubocop.yml CHANGED
@@ -22,14 +22,16 @@ Naming/FileName:
22
22
  Exclude:
23
23
  - lib/assembly-image.rb
24
24
 
25
- RSpec/ExampleLength:
26
- Max: 12
25
+ Naming/PredicateName:
26
+ ForbiddenPrefixes:
27
+ - is_
28
+
29
+ RSpec/MultipleMemoizedHelpers:
30
+ Enabled: false
27
31
 
28
32
  Style/WordArray:
29
33
  Enabled: false
30
34
 
31
- Gemspec/DateAssignment: # new in 1.10
32
- Enabled: true
33
35
  Gemspec/RequireMFA: # new in 1.23
34
36
  Enabled: true
35
37
  Layout/LineEndStringConcatenationIndentation: # new in 1.18
@@ -144,7 +146,7 @@ RSpec/SubjectDeclaration: # new in 2.5
144
146
  RSpec/FactoryBot/SyntaxMethods: # new in 2.7
145
147
  Enabled: true
146
148
  RSpec/Rails/AvoidSetupHook: # new in 2.4
147
- Enabled: true
149
+ Enabled: false
148
150
 
149
151
  Lint/RefinementImportMethods: # new in 1.27
150
152
  Enabled: true
@@ -166,3 +168,19 @@ RSpec/ChangeByZero: # new in 2.11.0
166
168
  Enabled: true
167
169
  RSpec/VerifiedDoubleReference: # new in 2.10.0
168
170
  Enabled: true
171
+
172
+ Gemspec/DeprecatedAttributeAssignment: # new in 1.30
173
+ Enabled: true
174
+ Layout/LineContinuationLeadingSpace: # new in 1.31
175
+ Enabled: true
176
+ Layout/LineContinuationSpacing: # new in 1.31
177
+ Enabled: true
178
+ Lint/ConstantOverwrittenInRescue: # new in 1.31
179
+ Enabled: true
180
+ Lint/NonAtomicFileOperation: # new in 1.31
181
+ Enabled: true
182
+
183
+ RSpec/Capybara/SpecificMatcher: # new in 2.12
184
+ Enabled: true
185
+ RSpec/Rails/HaveHttpStatus: # new in 2.12
186
+ Enabled: false
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2022-02-28 19:49:08 UTC using RuboCop version 1.25.1.
3
+ # on 2022-07-19 17:18:47 UTC using RuboCop version 1.31.2.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -13,56 +13,16 @@ Gemspec/RequiredRubyVersion:
13
13
  Exclude:
14
14
  - 'assembly-image.gemspec'
15
15
 
16
- # Offense count: 3
17
- # Cop supports --auto-correct.
18
- Lint/RedundantCopDisableDirective:
19
- Exclude:
20
- - 'lib/assembly-image/image.rb'
21
- - 'lib/assembly-image/images.rb'
22
-
23
16
  # Offense count: 2
24
- # Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
25
- # Include: **/*_spec*rb*, **/spec/**/*
26
- RSpec/FilePath:
27
- Exclude:
28
- - 'spec/image_spec.rb'
29
- - 'spec/images_spec.rb'
30
-
31
- # Offense count: 21
32
- RSpec/MultipleExpectations:
33
- Max: 10
34
-
35
- # Offense count: 5
36
- RSpec/UnspecifiedException:
37
- Exclude:
38
- - 'spec/image_spec.rb'
39
- - 'spec/images_spec.rb'
40
-
41
- # Offense count: 3
42
- Style/CombinableLoops:
43
- Exclude:
44
- - 'spec/images_spec.rb'
45
-
46
- # Offense count: 1
47
- # Cop supports --auto-correct.
48
- Style/GlobalStdStream:
49
- Exclude:
50
- - 'lib/assembly-image/images.rb'
17
+ # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
18
+ Metrics/AbcSize:
19
+ Max: 20
51
20
 
52
- # Offense count: 1
53
- # Configuration parameters: AllowedMethods.
54
- # AllowedMethods: respond_to_missing?
55
- Style/OptionalBooleanParameter:
56
- Exclude:
57
- - 'lib/assembly-image/image.rb'
21
+ # Offense count: 11
22
+ # Configuration parameters: CountAsOne.
23
+ RSpec/ExampleLength:
24
+ Max: 13
58
25
 
59
- # Offense count: 8
60
- # Cop supports --auto-correct-all.
61
- # Configuration parameters: Mode.
62
- Style/StringConcatenation:
63
- Exclude:
64
- - 'bin/console'
65
- - 'config/boot.rb'
66
- - 'lib/assembly-image.rb'
67
- - 'lib/assembly-image/images.rb'
68
- - 'spec/spec_helper.rb'
26
+ # Offense count: 15
27
+ RSpec/MultipleExpectations:
28
+ Max: 11
data/.rvmrc.example CHANGED
@@ -1 +1 @@
1
- rvm use 1.9.3@assembly-image --create
1
+ rvm use 3.1.0@assembly-image --create
data/Gemfile.lock ADDED
@@ -0,0 +1,105 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ assembly-image (2.1.0)
5
+ activesupport (> 6.1)
6
+ assembly-objectfile (>= 1.6.4)
7
+ ruby-vips (>= 2.0)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (7.0.3.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ assembly-objectfile (2.1.0)
18
+ activesupport (>= 5.2.0)
19
+ mime-types (> 3)
20
+ mini_exiftool
21
+ ast (2.4.2)
22
+ byebug (11.1.3)
23
+ coderay (1.1.3)
24
+ concurrent-ruby (1.1.10)
25
+ diff-lcs (1.5.0)
26
+ docile (1.4.0)
27
+ ffi (1.15.5)
28
+ i18n (1.12.0)
29
+ concurrent-ruby (~> 1.0)
30
+ json (2.6.2)
31
+ method_source (1.0.0)
32
+ mime-types (3.4.1)
33
+ mime-types-data (~> 3.2015)
34
+ mime-types-data (3.2022.0105)
35
+ mini_exiftool (2.10.2)
36
+ minitest (5.16.2)
37
+ parallel (1.22.1)
38
+ parser (3.1.2.0)
39
+ ast (~> 2.4.1)
40
+ pry (0.13.1)
41
+ coderay (~> 1.1)
42
+ method_source (~> 1.0)
43
+ pry-byebug (3.9.0)
44
+ byebug (~> 11.0)
45
+ pry (~> 0.13.0)
46
+ rainbow (3.1.1)
47
+ rake (13.0.6)
48
+ regexp_parser (2.5.0)
49
+ rexml (3.2.5)
50
+ rspec (3.11.0)
51
+ rspec-core (~> 3.11.0)
52
+ rspec-expectations (~> 3.11.0)
53
+ rspec-mocks (~> 3.11.0)
54
+ rspec-core (3.11.0)
55
+ rspec-support (~> 3.11.0)
56
+ rspec-expectations (3.11.0)
57
+ diff-lcs (>= 1.2.0, < 2.0)
58
+ rspec-support (~> 3.11.0)
59
+ rspec-mocks (3.11.1)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.11.0)
62
+ rspec-support (3.11.0)
63
+ rubocop (1.31.2)
64
+ json (~> 2.3)
65
+ parallel (~> 1.10)
66
+ parser (>= 3.1.0.0)
67
+ rainbow (>= 2.2.2, < 4.0)
68
+ regexp_parser (>= 1.8, < 3.0)
69
+ rexml (>= 3.2.5, < 4.0)
70
+ rubocop-ast (>= 1.18.0, < 2.0)
71
+ ruby-progressbar (~> 1.7)
72
+ unicode-display_width (>= 1.4.0, < 3.0)
73
+ rubocop-ast (1.19.1)
74
+ parser (>= 3.1.1.0)
75
+ rubocop-rspec (2.12.1)
76
+ rubocop (~> 1.31)
77
+ ruby-progressbar (1.11.0)
78
+ ruby-vips (2.1.4)
79
+ ffi (~> 1.12)
80
+ simplecov (0.21.2)
81
+ docile (~> 1.1)
82
+ simplecov-html (~> 0.11)
83
+ simplecov_json_formatter (~> 0.1)
84
+ simplecov-html (0.12.3)
85
+ simplecov_json_formatter (0.1.4)
86
+ tzinfo (2.0.5)
87
+ concurrent-ruby (~> 1.0)
88
+ unicode-display_width (2.2.0)
89
+
90
+ PLATFORMS
91
+ x86_64-darwin-19
92
+ x86_64-darwin-21
93
+ x86_64-linux
94
+
95
+ DEPENDENCIES
96
+ assembly-image!
97
+ pry-byebug
98
+ rake
99
+ rspec (~> 3.0)
100
+ rubocop
101
+ rubocop-rspec
102
+ simplecov
103
+
104
+ BUNDLED WITH
105
+ 2.3.17
data/README.md CHANGED
@@ -6,22 +6,16 @@
6
6
  # Assembly Image Gem
7
7
 
8
8
  ## Overview
9
- This gem contains classes used by the Stanford University Digital Library to
10
- perform image operations necessary for accessioning of content.
9
+ This gem contains classes used by the Stanford University Digital Library to create JP2 image derivatives.
10
+
11
+ Requires image processing software - see [prerequisites section](#prerequisites) below.
11
12
 
12
13
  ## Notes
13
14
 
14
15
  1. The gem assumes that the user context in which it is executed has write access to the 'tmp' folder.
15
- This is because color profiles can be extracted from images during the JP2
16
- creation process, and these profiles need to be stored as local files, and it
17
- is beneficial to cache them for later usage by images with the same color profile.
18
- If you know there are color profiles which are commonly used, it is better to
19
- capture them in the gem itself in the profile folder so they can be re-used
20
- and do not need to be extracted.
21
- 1. If any errors occur during JP2 generation for any reason, a runtime exception will be thrown with a description of the error.
22
- 2. 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.
23
-
24
- This can commonly occur in basic test TIFs that are black/white and have no profile, so beware during testing.
16
+ This is to create the temporary tiffs used; we need temporary tiffs to reliably compress the image using KDUcompress, which doesn’t support arbitrary image types
17
+ 2. If any errors occur during JP2 generation for any reason, a runtime exception will be thrown with a description of the error.
18
+ 3. If an image is passed in with a color profile that cannot be determined, an exception will be thrown. This can commonly occur in basic test TIFs that are black/white and have no profile, so beware during testing.
25
19
 
26
20
  ## Usage
27
21
 
@@ -29,76 +23,39 @@ To use the JP2 creation method, you first instantiate the image object with an i
29
23
 
30
24
  ```ruby
31
25
  require 'assembly-image'
32
- input = Assembly::Image.new('/full/path/to/file.tif')
33
- puts input.exif # show exif header information for the TIF
34
- output = input.create_jp2(:output=>'/full/path/to/output.jp2') # generate a new JP2 in the specified location
35
- puts output.exif # show exif header information for the JP2
26
+ input_image = Assembly::Image.new('/full/path/to/file.tif')
27
+ output = input_image.create_jp2(output: '/full/path/to/output.jp2') # generate a new JP2 in the specified location
36
28
  ```
37
29
 
38
30
  ## Running tests
39
31
 
40
32
  ```bash
41
- bundle exec rake
42
- ```
43
-
44
- ## Generate documentation
45
- To generate documentation into the "doc" folder:
46
-
47
- ```bash
48
- yard
49
- ```
50
-
51
- To keep a local server running with up to date code documentation that you can view in your browser:
52
-
53
- ```bash
54
- yard server --reload
33
+ bundle exec rspec
55
34
  ```
56
35
 
57
36
  ## Prerequisites
58
37
 
59
38
  1. Kakadu Proprietary Software Binaries - for JP2 generation
60
- 1. ImageMagick 6.5.4 or higher
61
- 1. Exiftool
39
+ 1. Libvips
40
+ 1. Exiftool - upstream dependency of assembly-objectfile (used by specs to check mimetype of produced jp2, and because there is no libvips package available for circleci that speaks jp2)
62
41
 
63
42
  ### Kakadu
64
43
 
65
44
  Download and install demonstration binaries from Kakadu:
66
45
  http://kakadusoftware.com/downloads/
67
46
 
68
- NOTE: If you have upgrade to El Capitan on OS X, you will need to donwload and re-install the latest version of Kakadu, due to changes made with SIP. These changes moved the old executable binaries to an inaccessible location.
69
-
70
- ### Imagemagick
71
-
72
- #### RHEL 6
73
-
74
- The version of ImageMagick included with RHEL 6 has all of the dependency libraries included:
75
-
76
- ```bash
77
- yum install ImageMagick
78
- ```
79
- #### RHEL 5
80
-
81
- The version of ImageMagick included with RHEL 5 is too old and does not have all the proper binaries included/built:
82
-
83
- ```bash
84
- yum install lcms lcms-devel libjpeg libjpeg-devel libpng libpng-devel
85
- ```
86
- Required libraries from source:
87
- * libtiff (version 3.9.4 or higher)
88
-
89
- Build Imagemagick from source:
90
- http://www.imagemagick.org/download/ImageMagick.tar.gz
47
+ ### Libvips
48
+ Note: libvips may require a significant amount of space for temporary files. The location for this can be controlled by the TMPDIR environment variable.
91
49
 
92
50
  #### Mac
93
51
 
94
52
  ```bash
95
- brew install jasper libtiff
96
- brew install imagemagick --use-tiff --use-jpeg2000
53
+ brew install libvips
97
54
  ```
98
55
 
99
56
  ### Exiftool
100
57
 
101
- #### RHEL
58
+ #### Linux
102
59
  Download latest version from: http://www.sno.phy.queensu.ca/~phil/exiftool
103
60
 
104
61
  ```bash
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  $LOAD_PATH.push File.expand_path('lib', __dir__)
4
- require 'assembly-image/version'
5
4
 
6
5
  Gem::Specification.new do |s|
7
6
  s.name = 'assembly-image'
8
- s.version = Assembly::Image::VERSION
7
+ s.version = '2.1.0'
9
8
  s.authors = ['Peter Mangiafico', 'Renzo Sanchez-Silva', 'Monty Hindman', 'Tony Calavano']
10
9
  s.email = ['pmangiafico@stanford.edu']
11
10
  s.homepage = ''
@@ -14,18 +13,18 @@ Gem::Specification.new do |s|
14
13
  s.metadata['rubygems_mfa_required'] = 'true'
15
14
 
16
15
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
16
  s.bindir = 'exe'
19
17
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
18
  s.require_paths = ['lib']
21
19
 
20
+ s.add_dependency 'activesupport', '> 6.1'
22
21
  s.add_dependency 'assembly-objectfile', '>= 1.6.4'
23
- s.add_dependency 'mini_exiftool', '>= 1.6', '< 3'
22
+ s.add_dependency 'ruby-vips', '>= 2.0'
24
23
 
24
+ s.add_development_dependency 'pry-byebug'
25
25
  s.add_development_dependency 'rake'
26
26
  s.add_development_dependency 'rspec', '~> 3.0'
27
27
  s.add_development_dependency 'rubocop'
28
28
  s.add_development_dependency 'rubocop-rspec'
29
29
  s.add_development_dependency 'simplecov'
30
- s.add_development_dependency 'yard'
31
30
  end
data/bin/console CHANGED
@@ -4,6 +4,6 @@
4
4
  require 'rubygems'
5
5
  require 'irb'
6
6
 
7
- require File.expand_path(File.dirname(__FILE__) + '/../config/boot')
7
+ require File.expand_path("#{File.dirname(__FILE__)}/../config/boot")
8
8
 
9
9
  IRB.start
data/config/boot.rb CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
 
5
- project_root = File.expand_path(File.dirname(__FILE__) + '/..')
5
+ project_root = File.expand_path("#{File.dirname(__FILE__)}/..")
6
6
 
7
7
  # Load config for current environment.
8
- $LOAD_PATH.unshift(project_root + '/lib')
8
+ $LOAD_PATH.unshift("#{project_root}/lib")
9
9
 
10
10
  require 'assembly-image'
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'assembly-objectfile'
4
+ require 'tempfile'
5
+ require 'English' # see https://github.com/rubocop-hq/rubocop/issues/1747 (not #MAGA related)
6
+ require 'active_support/core_ext/module/delegation'
7
+
8
+ module Assembly
9
+ class Image < Assembly::ObjectFile
10
+ # Creates jp2 derivatives
11
+ class Jp2Creator
12
+ # Create a JP2 file for the current image.
13
+ # Important note: this will not work for multipage TIFFs.
14
+ #
15
+ # @return [Assembly::Image] object containing the generated JP2 file
16
+ #
17
+ # @param [Assembly::Image] the image file
18
+ # @param [String] output path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
19
+ # @param [Boolean] overwrite if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
20
+ # @param [Dir] tmp_folder the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
21
+ #
22
+ # Example:
23
+ # source_img = Assembly::Image.new('/input/path_to_file.tif')
24
+ # derivative_img = source_img.create_jp2(overwrite: true)
25
+ # puts derivative_img.mimetype # 'image/jp2'
26
+ # puts derivative_image.path # '/input/path_to_file.jp2'
27
+ def self.create(image, **args)
28
+ new(image, **args).create
29
+ end
30
+
31
+ def initialize(image, overwrite: false, output: image.jp2_filename, tmp_folder: Dir.tmpdir)
32
+ @image = image
33
+ @output_path = output
34
+ @tmp_folder = tmp_folder
35
+ @overwrite = overwrite
36
+ end
37
+
38
+ attr_reader :image, :output_path, :tmp_folder, :tmp_tiff_path
39
+
40
+ delegate :vips_image, to: :image
41
+
42
+ # @return [Assembly::Image] object containing the generated JP2 file
43
+ def create
44
+ create_jp2_checks
45
+
46
+ # KDUcompress doesn’t support arbitrary image types, so we make a temporary tiff
47
+ @tmp_tiff_path = make_tmp_tiff
48
+
49
+ jp2_command = jp2_create_command(source_path: tmp_tiff_path, output: output_path)
50
+ result = `#{jp2_command}`
51
+ unless $CHILD_STATUS.success?
52
+ # Clean up any partial result
53
+ FileUtils.rm_rf(output_path)
54
+ raise "JP2 creation command failed: #{jp2_command} with result #{result}"
55
+ end
56
+
57
+ File.delete(tmp_tiff_path) unless tmp_tiff_path.nil?
58
+
59
+ # create output response object, which is an Assembly::Image type object
60
+ Image.new(output_path)
61
+ end
62
+
63
+ private
64
+
65
+ def overwrite?
66
+ @overwrite
67
+ end
68
+
69
+ def jp2_create_command(source_path:, output:)
70
+ options = []
71
+ # CMYK becomes sRGB in make_tmp_tiff, so jp2_space option will be set for sRGB and CMYK
72
+ # TODO: we're not sure at this time what happens for grayscale (or what Tony C. wants for grayscale)
73
+ # see https://github.com/sul-dlss/assembly-image/issues/98
74
+ options << '-jp2_space sRGB' if image.srgb?
75
+ options += KDU_COMPRESS_DEFAULT_OPTIONS
76
+ options << "Clayers=#{layers}"
77
+ "kdu_compress #{options.join(' ')} -i '#{source_path}' -o '#{output}' 2>&1"
78
+ end
79
+
80
+ # Get the number of JP2 layers to generate
81
+ def layers
82
+ pixdem = [image.width, image.height].max
83
+ ((Math.log(pixdem) / Math.log(2)) - (Math.log(96) / Math.log(2))).ceil + 1
84
+ end
85
+
86
+ KDU_COMPRESS_DEFAULT_OPTIONS = [
87
+ '-num_threads 2', # forces Kakadu to only use 2 threads
88
+ '-quiet', # suppress informative messages.
89
+ 'Creversible=no', # Disable reversible compression
90
+ 'Corder=RPCL', # R=resolution P=position C=component L=layer
91
+ 'Cblk=\\{64,64\\}', # code-block dimensions; 64x64 happens to also be the default
92
+ 'Cprecincts=\\{256,256\\},\\{256,256\\},\\{128,128\\}', # Precinct dimensions; 256x256 for the 2 highest resolution levels, defaults to 128x128 for the rest
93
+ '-rate -', # Ratio of compressed bits to the image size
94
+ 'Clevels=5' # Number of wavelet decomposition levels, or stages
95
+ ].freeze
96
+
97
+ def create_jp2_checks
98
+ image.send(:check_for_file)
99
+ raise 'input file is not a valid image, or is the wrong mimetype' unless image.jp2able?
100
+
101
+ raise SecurityError, "output #{output_path} exists, cannot overwrite" if !overwrite? && File.exist?(output_path)
102
+ raise SecurityError, 'cannot recreate jp2 over itself' if overwrite? && image.mimetype == 'image/jp2' && output_path == image.path
103
+ end
104
+
105
+ # We do this because we need to reliably compress the tiff and KDUcompress doesn’t support arbitrary image types
106
+ # rubocop:disable Metrics/MethodLength
107
+ def make_tmp_tiff
108
+ raise "tmp_folder #{tmp_folder} does not exist" unless File.exist?(tmp_folder)
109
+
110
+ # make temp tiff filename
111
+ tmp_tiff_file = Tempfile.new(['assembly-image', '.tif'], tmp_folder)
112
+ result_path = tmp_tiff_file.path
113
+ tmp_tiff_image = if vips_image.interpretation.eql?(:cmyk)
114
+ vips_image.icc_transform(SRGB_ICC, input_profile: CMYK_ICC)
115
+ elsif image.has_profile?
116
+ vips_image.icc_transform(SRGB_ICC, embedded: true)
117
+ else
118
+ vips_image
119
+ end
120
+
121
+ tmp_tiff_image.tiffsave(result_path, bigtiff: true) # Use bigtiff so we can support images > 4GB
122
+ result_path
123
+ end
124
+ # rubocop:enable Metrics/MethodLength
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vips'
4
+ require 'assembly-objectfile'
5
+ require_relative 'image/jp2_creator'
6
+
7
+ module Assembly
8
+ # The Image class contains methods to operate on an image.
9
+ class Image < Assembly::ObjectFile
10
+ # @return [integer] image height in pixels
11
+ def height
12
+ vips_image.height
13
+ end
14
+
15
+ # @return [integer] image width in pixels
16
+ def width
17
+ vips_image.width
18
+ end
19
+
20
+ # @return [string] full default jp2 path and filename that will be created from the given image
21
+ # Example: given original file of '/dir/path_to_file.tif', gives '/dir/path_to_file.jp2'
22
+ def jp2_filename
23
+ # path is a property on Assembly::ObjectFile
24
+ File.extname(path).empty? ? "#{path}.jp2" : path.gsub(File.extname(path), '.jp2')
25
+ end
26
+
27
+ # Create a JP2 file for the current image.
28
+ # Important note: this will not work for multipage TIFFs.
29
+ #
30
+ # @param [String] output path to the output JP2 file (default: mirrors the source file name and path, but with a .jp2 extension)
31
+ # @param [Boolean] overwrite if set to false, an existing JP2 file with the same name won't be overwritten (default: false)
32
+ # @param [Dir] tmp_folder the temporary folder to use when creating the jp2 (default: '/tmp'); also used by imagemagick
33
+ # @return [Assembly::Image] object containing the generated JP2 file
34
+ #
35
+ # Example:
36
+ # source_img = Assembly::Image.new('/dir/path_to_file.tif')
37
+ # jp2_img = source_img.create_jp2(overwrite: true)
38
+ # jp2_img.mimetype # 'image/jp2'
39
+ # jp2_img.path # '/dir/path_to_file.jp2'
40
+ def create_jp2(**params)
41
+ Jp2Creator.create(self, **params)
42
+ end
43
+
44
+ def vips_image
45
+ # autorot will only affect images that need rotation: https://www.libvips.org/API/current/libvips-conversion.html#vips-autorot
46
+ @vips_image ||= Vips::Image.new_from_file(path).autorot
47
+ end
48
+
49
+ def srgb?
50
+ vips_image.interpretation == :srgb
51
+ end
52
+
53
+ # Does the image include an ICC profile?
54
+ def has_profile?
55
+ vips_image.get_fields.include?('icc-profile-data')
56
+ end
57
+ end
58
+ end
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Assembly
4
4
  # the path to the gem, used to access profiles stored with the gem
5
- PATH_TO_IMAGE_GEM = File.expand_path(File.dirname(__FILE__) + '/..')
5
+ PATH_TO_IMAGE_GEM = File.expand_path("#{File.dirname(__FILE__)}/..")
6
+ PATH_TO_PROFILES = File.join(Assembly::PATH_TO_IMAGE_GEM, 'profiles')
7
+ SRGB_ICC = File.join(PATH_TO_PROFILES, 'sRGBIEC6196621.icc')
8
+ CMYK_ICC = File.join(PATH_TO_PROFILES, 'cmyk.icc')
6
9
  end
7
10
 
8
- require 'assembly-image/image'
9
- require 'assembly-image/images'
11
+ require 'assembly/image'
data/profiles/cmyk.icc ADDED
Binary file