assembly-image 1.8.0 → 2.1.0

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 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