hydra-derivatives 3.1.3 → 3.1.4

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +66 -0
  3. data/.rubocop_todo.yml +29 -0
  4. data/Gemfile +2 -0
  5. data/Rakefile +19 -4
  6. data/VERSION +1 -1
  7. data/lib/hydra/derivatives.rb +5 -5
  8. data/lib/hydra/derivatives/config.rb +7 -8
  9. data/lib/hydra/derivatives/logger.rb +2 -5
  10. data/lib/hydra/derivatives/processors/audio.rb +0 -1
  11. data/lib/hydra/derivatives/processors/document.rb +33 -18
  12. data/lib/hydra/derivatives/processors/ffmpeg.rb +2 -3
  13. data/lib/hydra/derivatives/processors/full_text.rb +1 -1
  14. data/lib/hydra/derivatives/processors/image.rb +39 -36
  15. data/lib/hydra/derivatives/processors/jpeg2k_image.rb +91 -89
  16. data/lib/hydra/derivatives/processors/processor.rb +1 -1
  17. data/lib/hydra/derivatives/processors/raw_image.rb +25 -25
  18. data/lib/hydra/derivatives/processors/shell_based_processor.rb +24 -32
  19. data/lib/hydra/derivatives/processors/video.rb +0 -2
  20. data/lib/hydra/derivatives/processors/video/config.rb +2 -4
  21. data/lib/hydra/derivatives/processors/video/processor.rb +24 -24
  22. data/lib/hydra/derivatives/runners/full_text_extract.rb +0 -1
  23. data/lib/hydra/derivatives/runners/image_derivatives.rb +0 -1
  24. data/lib/hydra/derivatives/runners/runner.rb +4 -7
  25. data/lib/hydra/derivatives/services/persist_basic_contained_output_file_service.rb +0 -1
  26. data/lib/hydra/derivatives/services/persist_output_file_service.rb +11 -13
  27. data/lib/hydra/derivatives/services/retrieve_source_file_service.rb +0 -1
  28. data/lib/hydra/derivatives/services/tempfile_service.rb +4 -5
  29. data/spec/processors/document_spec.rb +41 -0
  30. data/spec/processors/{full_text.rb → full_text_spec.rb} +10 -19
  31. data/spec/processors/image_spec.rb +28 -21
  32. data/spec/processors/jpeg2k_spec.rb +1 -2
  33. data/spec/processors/processor_spec.rb +2 -3
  34. data/spec/processors/shell_based_processor_spec.rb +1 -1
  35. data/spec/processors/video_spec.rb +4 -4
  36. data/spec/services/audio_derivatives_spec.rb +5 -5
  37. data/spec/services/persist_basic_contained_output_file_service_spec.rb +4 -6
  38. data/spec/services/retrieve_source_file_service_spec.rb +7 -7
  39. data/spec/services/tempfile_service_spec.rb +4 -2
  40. data/spec/spec_helper.rb +5 -3
  41. data/spec/units/config_spec.rb +5 -7
  42. data/spec/units/derivatives_spec.rb +8 -21
  43. data/spec/units/logger_spec.rb +7 -10
  44. data/spec/units/transcoding_spec.rb +111 -61
  45. metadata +9 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e78f564d56a0e670ce4366f69e9a2b5ddbdca96e
4
- data.tar.gz: 35205d1fcf5de953eee1d0a7e065dcf766f24dbf
3
+ metadata.gz: f9fe68ff09c49cf6061b2ef193ad428302dfac25
4
+ data.tar.gz: 1c0d21de93c9616a4d97cf4b8f6c46f68a66d96e
5
5
  SHA512:
6
- metadata.gz: 7843da96087847b8215e3bcfc3840596cd94cc4d96cc1e7bd798d13a12ea21ae2c797c8a2e0a0e94127b4e5ea3abeb07dbbac51e7731b4768d85043a56599ecb
7
- data.tar.gz: c2e424d665c7f5b3a3feabc82d1b4c8970280cc5f6a8e9dfcc2d5d42493aac176ea3ae3d39e4d340ff15bf2555e4d62b0f17bc6ac0897765adab4fa3c5f12f04
6
+ metadata.gz: 62bc8d5e8265a6f85214a530af6a6d36469473db17485b36a1cd622822ae591208ea5fa994ff2b23b4c1f5ab31d20131deb98061348941c47599be0ca403a2ee
7
+ data.tar.gz: d74669b4b6ec7c9b713ee33b72f35e7d43f4acfbc44a675ef162b6e8194c2df0363f17d9da958441209587118cdaa34b2d7c35688752a489acc6d563a1b76994
@@ -0,0 +1,66 @@
1
+ require: rubocop-rspec
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ AllCops:
5
+ DisplayCopNames: true
6
+ Include:
7
+ - '**/Rakefile'
8
+ Exclude:
9
+ - 'vendor/**/*'
10
+ - 'spec/internal/bin/*'
11
+ - 'spec/internal/db/schema.rb'
12
+
13
+ Metrics/LineLength:
14
+ Enabled: false
15
+
16
+ Style/CollectionMethods:
17
+ PreferredMethods:
18
+ collect: 'map'
19
+ collect!: 'map!'
20
+ inject: 'reduce'
21
+ detect: 'find'
22
+ find_all: 'select'
23
+
24
+ Style/ClassAndModuleChildren:
25
+ Enabled: false
26
+
27
+ Style/Documentation:
28
+ Enabled: false
29
+
30
+ Style/StringLiterals:
31
+ Enabled: false
32
+
33
+ Style/SignalException:
34
+ Enabled: false
35
+
36
+ Style/IndentationConsistency:
37
+ EnforcedStyle: rails
38
+
39
+ Style/PredicateName:
40
+ Exclude:
41
+ - spec/services/tempfile_service_spec.rb
42
+
43
+ RSpec/ExampleWording:
44
+ CustomTransform:
45
+ be: is
46
+ have: has
47
+ not: does not
48
+ NOT: does NOT
49
+ IgnoredWords:
50
+ - only
51
+
52
+ RSpec/FilePath:
53
+ Enabled: false
54
+
55
+ RSpec/InstanceVariable:
56
+ Enabled: false
57
+
58
+ RSpec/DescribeClass:
59
+ Exclude:
60
+ - spec/units/config_spec.rb
61
+ - spec/units/transcoding_spec.rb
62
+
63
+ RSpec/AnyInstance:
64
+ Exclude:
65
+ - spec/processors/image_spec.rb
66
+ - spec/units/transcoding_spec.rb
@@ -0,0 +1,29 @@
1
+ # List of files that we ought to fix based on what Rubocop is complaining about them
2
+
3
+ Metrics/CyclomaticComplexity:
4
+ Exclude:
5
+ - spec/units/transcoding_spec.rb
6
+
7
+ Metrics/MethodLength:
8
+ Exclude:
9
+ - lib/hydra/derivatives/config.rb
10
+ - lib/hydra/derivatives/processors/document.rb
11
+ - lib/hydra/derivatives/processors/jpeg2k_image.rb
12
+ - lib/hydra/derivatives/processors/shell_based_processor.rb
13
+ - lib/hydra/derivatives/processors/video/processor.rb
14
+ - lib/hydra/derivatives/services/tempfile_service.rb
15
+ - spec/units/transcoding_spec.rb
16
+
17
+ Metrics/ClassLength:
18
+ Exclude:
19
+ - lib/hydra/derivatives/processors/jpeg2k_image.rb
20
+
21
+ Metrics/AbcSize:
22
+ Exclude:
23
+ - lib/hydra/derivatives/processors/document.rb
24
+ - lib/hydra/derivatives/processors/full_text.rb
25
+ - lib/hydra/derivatives/processors/jpeg2k_image.rb
26
+ - lib/hydra/derivatives/processors/shell_based_processor.rb
27
+ - lib/hydra/derivatives/services/persist_basic_contained_output_file_service.rb
28
+ - lib/hydra/derivatives/services/tempfile_service.rb
29
+ - spec/units/transcoding_spec.rb
data/Gemfile CHANGED
@@ -5,4 +5,6 @@ gemspec
5
5
 
6
6
  group :development, :test do
7
7
  gem 'byebug' unless ENV['TRAVIS']
8
+ gem 'rubocop', '~> 0.37.2', require: false
9
+ gem 'rubocop-rspec', require: false
8
10
  end
data/Rakefile CHANGED
@@ -10,11 +10,26 @@ RSpec::Core::RakeTask.new(:spec)
10
10
  require 'solr_wrapper/rake_task'
11
11
  require 'fcrepo_wrapper'
12
12
  require 'active_fedora/rake_support'
13
+ require 'rubocop/rake_task'
13
14
 
14
- desc 'Start Fedora and Solr and run specs'
15
- task :ci do
16
- with_test_server do
17
- Rake::Task['spec'].invoke
15
+ namespace :derivatives do
16
+ desc 'Run style checker'
17
+ RuboCop::RakeTask.new(:rubocop) do |task|
18
+ task.requires << 'rubocop-rspec'
19
+ task.fail_on_error = true
20
+ end
21
+
22
+ RSpec::Core::RakeTask.new(:rspec)
23
+
24
+ desc 'Start up Solr & Fedora and run tests'
25
+ task :spec do
26
+ with_test_server do
27
+ Rake::Task['derivatives:rspec'].invoke
28
+ end
18
29
  end
19
30
  end
31
+
32
+ desc 'Run continuous integration build'
33
+ task ci: ['derivatives:rubocop', 'derivatives:spec']
34
+
20
35
  task default: :ci
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.3
1
+ 3.1.4
@@ -47,13 +47,13 @@ module Hydra
47
47
  end
48
48
 
49
49
  [:ffmpeg_path, :libreoffice_path, :temp_file_base, :fits_path, :kdu_compress_path,
50
- :kdu_compress_recipes, :enable_ffmpeg, :source_file_service, :output_file_service].each do |method|
50
+ :kdu_compress_recipes, :enable_ffmpeg, :source_file_service, :output_file_service].each do |method|
51
51
  module_eval <<-RUBY
52
- def self.#{method.to_s}
53
- config.#{method.to_s}
52
+ def self.#{method}
53
+ config.#{method}
54
54
  end
55
- def self.#{method.to_s}= val
56
- config.#{method.to_s}= val
55
+ def self.#{method}= val
56
+ config.#{method}= val
57
57
  end
58
58
  RUBY
59
59
  end
@@ -3,9 +3,9 @@ require 'tmpdir'
3
3
  module Hydra
4
4
  module Derivatives
5
5
  class Config
6
- attr_writer :ffmpeg_path, :libreoffice_path, :temp_file_base,
7
- :source_file_service, :output_file_service, :fits_path,
8
- :enable_ffmpeg, :kdu_compress_path, :kdu_compress_recipes
6
+ attr_writer :ffmpeg_path, :libreoffice_path, :temp_file_base,
7
+ :source_file_service, :output_file_service, :fits_path,
8
+ :enable_ffmpeg, :kdu_compress_path, :kdu_compress_recipes
9
9
 
10
10
  def ffmpeg_path
11
11
  @ffmpeg_path ||= 'ffmpeg'
@@ -41,7 +41,7 @@ module Hydra
41
41
 
42
42
  def kdu_compress_recipes
43
43
  @kdu_compress_recipes ||= {
44
- default_color: %Q{-rate 2.4,1.48331273,.91673033,.56657224,.35016049,.21641118,.13374944,.08266171
44
+ default_color: %(-rate 2.4,1.48331273,.91673033,.56657224,.35016049,.21641118,.13374944,.08266171
45
45
  -jp2_space sRGB
46
46
  -double_buffering 10
47
47
  -num_threads 4
@@ -54,8 +54,8 @@ module Hydra
54
54
  Corder=RPCL
55
55
  ORGgen_plt=yes
56
56
  ORGtparts=R
57
- "Stiles={1024,1024}" }.gsub(/\s+/, " ").strip,
58
- default_grey: %Q{-rate 2.4,1.48331273,.91673033,.56657224,.35016049,.21641118,.13374944,.08266171
57
+ "Stiles={1024,1024}" ).gsub(/\s+/, " ").strip,
58
+ default_grey: %(-rate 2.4,1.48331273,.91673033,.56657224,.35016049,.21641118,.13374944,.08266171
59
59
  -jp2_space sLUM
60
60
  -double_buffering 10
61
61
  -num_threads 4
@@ -68,10 +68,9 @@ module Hydra
68
68
  Corder=RPCL
69
69
  ORGgen_plt=yes
70
70
  ORGtparts=R
71
- "Stiles={1024,1024}" }.gsub(/\s+/, " ").strip
71
+ "Stiles={1024,1024}" ).gsub(/\s+/, " ").strip
72
72
  }
73
73
  end
74
-
75
74
  end
76
75
  end
77
76
  end
@@ -1,15 +1,13 @@
1
1
  module Hydra::Derivatives
2
2
  class Logger
3
-
4
3
  class << self
5
-
6
- def method_missing method_name, *arguments, &block
4
+ def method_missing(method_name, *arguments, &block)
7
5
  logger.send(method_name, *arguments, &block)
8
6
  rescue
9
7
  super
10
8
  end
11
9
 
12
- def respond_to?(method_name, include_private = false)
10
+ def respond_to?(method_name, _include_private = false)
13
11
  logger.respond_to? method_name
14
12
  end
15
13
 
@@ -18,7 +16,6 @@ module Hydra::Derivatives
18
16
  def logger
19
17
  ActiveFedora::Base.logger || ::Logger.new(STDOUT)
20
18
  end
21
-
22
19
  end
23
20
  end
24
21
  end
@@ -3,4 +3,3 @@ module Hydra::Derivatives::Processors
3
3
  include Ffmpeg
4
4
  end
5
5
  end
6
-
@@ -2,27 +2,42 @@ module Hydra::Derivatives::Processors
2
2
  class Document < Processor
3
3
  include ShellBasedProcessor
4
4
 
5
- def self.encode(path, options, output_file)
6
- format = File.extname(output_file).sub('.', '')
7
- outdir = File.dirname(output_file)
5
+ def self.encode(path, format, outdir)
8
6
  execute "#{Hydra::Derivatives.libreoffice_path} --invisible --headless --convert-to #{format} --outdir #{outdir} #{path}"
9
7
  end
10
8
 
11
- def encode_file(file_suffix, options = { })
12
- new_output = ''
13
- if file_suffix == 'jpg'
14
- temp_file = File.join(Hydra::Derivatives.temp_file_base, [directives.fetch(:label).to_s, 'pdf'].join('.'))
15
- new_output = File.join(Hydra::Derivatives.temp_file_base, [File.basename(temp_file).sub(File.extname(temp_file), ''), file_suffix].join('.'))
16
- self.class.encode(source_path, options, temp_file)
17
- self.class.encode(temp_file, options, output_file(file_suffix))
18
- File.unlink(temp_file)
19
- else
20
- self.class.encode(source_path, options, output_file(file_suffix))
21
- new_output = File.join(Hydra::Derivatives.temp_file_base, [directives.fetch(:label).to_s, file_suffix].join('.'))
22
- end
23
- out_file = File.open(new_output, "rb")
24
- output_file_service.call(out_file, directives)
25
- File.unlink(out_file)
9
+ # Converts the document to the format specified in the directives hash.
10
+ # TODO: file_suffix and options are passed from ShellBasedProcessor.process but are not needed.
11
+ # A refactor could simplify this.
12
+ def encode_file(_file_suffix, _options = {})
13
+ convert_to_format
14
+ ensure
15
+ FileUtils.rm_f(converted_file)
26
16
  end
17
+
18
+ private
19
+
20
+ # For jpeg files, a pdf is created from the original source and then passed to the Image processor class
21
+ # so we can get a better conversion with resizing options. Otherwise, the ::encode method is used.
22
+ def convert_to_format
23
+ if directives.fetch(:format) == "jpg"
24
+ Hydra::Derivatives::Processors::Image.new(converted_file, directives).process
25
+ else
26
+ output_file_service.call(File.read(converted_file), directives)
27
+ end
28
+ end
29
+
30
+ def converted_file
31
+ @converted_file ||= if directives.fetch(:format) == "jpg"
32
+ convert_to("pdf")
33
+ else
34
+ convert_to(directives.fetch(:format))
35
+ end
36
+ end
37
+
38
+ def convert_to(format)
39
+ self.class.encode(source_path, format, Hydra::Derivatives.temp_file_base)
40
+ File.join(Hydra::Derivatives.temp_file_base, [File.basename(source_path, ".*"), format].join('.'))
41
+ end
27
42
  end
28
43
  end
@@ -3,14 +3,13 @@ module Hydra::Derivatives::Processors
3
3
  module Ffmpeg
4
4
  extend ActiveSupport::Concern
5
5
 
6
- INPUT_OPTIONS=:input_options
7
- OUTPUT_OPTIONS=:output_options
6
+ INPUT_OPTIONS = :input_options
7
+ OUTPUT_OPTIONS = :output_options
8
8
 
9
9
  included do
10
10
  include ShellBasedProcessor
11
11
  end
12
12
 
13
-
14
13
  module ClassMethods
15
14
  def encode(path, options, output_file)
16
15
  inopts = options[INPUT_OPTIONS] ||= "-y"
@@ -36,7 +36,7 @@ module Hydra::Derivatives::Processors
36
36
 
37
37
  # @return [Hash] the request headers to send to the Solr extract service
38
38
  def request_headers
39
- { Faraday::Request::UrlEncoded::CONTENT_TYPE => "#{mime_type}",
39
+ { Faraday::Request::UrlEncoded::CONTENT_TYPE => mime_type.to_s,
40
40
  Faraday::Adapter::CONTENT_LENGTH => original_size.to_s }
41
41
  end
42
42
 
@@ -5,54 +5,57 @@ module Hydra::Derivatives::Processors
5
5
  class_attribute :timeout
6
6
 
7
7
  def process
8
- timeout ? process_with_timeout : process_without_timeout
8
+ timeout ? process_with_timeout : create_resized_image
9
9
  end
10
10
 
11
11
  def process_with_timeout
12
- status = Timeout::timeout(timeout) do
13
- process_without_timeout
14
- end
15
- rescue Timeout::Error => ex
12
+ Timeout.timeout(timeout) { create_resized_image }
13
+ rescue Timeout::Error
16
14
  raise Hydra::Derivatives::TimeoutError, "Unable to process image derivative\nThe command took longer than #{timeout} seconds to execute"
17
15
  end
18
16
 
19
- def process_without_timeout
20
- format = directives.fetch(:format)
21
- name = directives.fetch(:label, format)
22
- destination_name = output_filename_for(name)
23
- size = directives.fetch(:size, nil)
24
- quality = directives.fetch(:quality, nil)
25
- create_resized_image(destination_name, size, format, quality)
26
- end
27
-
28
17
  protected
29
18
 
30
- def create_resized_image(destination_name, size, format, quality=nil)
31
- create_image(destination_name, format, quality) do |xfrm|
32
- xfrm.resize(size) if size.present?
19
+ # When resizing images, it is necessary to flatten any layers, otherwise the background
20
+ # may be completely black. This happens especially with PDFs. See #110
21
+ def create_resized_image
22
+ create_image do |xfrm|
23
+ if size
24
+ xfrm.flatten
25
+ xfrm.resize(size)
26
+ end
27
+ end
33
28
  end
34
- end
35
29
 
36
- def create_image(destination_name, format, quality=nil)
37
- xfrm = load_image_transformer
38
- yield(xfrm) if block_given?
39
- xfrm.format(format)
40
- xfrm.quality(quality.to_s) if quality
41
- write_image(destination_name, format, xfrm)
42
- end
30
+ def create_image
31
+ xfrm = load_image_transformer
32
+ yield(xfrm) if block_given?
33
+ xfrm.format(directives.fetch(:format))
34
+ xfrm.quality(quality.to_s) if quality
35
+ write_image(xfrm)
36
+ end
37
+
38
+ def write_image(xfrm)
39
+ output_io = StringIO.new
40
+ xfrm.write(output_io)
41
+ output_io.rewind
42
+ output_file_service.call(output_io, directives)
43
+ end
43
44
 
44
- def write_image(destination_name, format, xfrm)
45
- output_io = StringIO.new
46
- xfrm.write(output_io)
47
- output_io.rewind
45
+ # Override this method if you want a different transformer, or need to load the
46
+ # raw image from a different source (e.g. external file)
47
+ def load_image_transformer
48
+ MiniMagick::Image.open(source_path)
49
+ end
48
50
 
49
- output_file_service.call(output_io, directives)
50
- end
51
+ private
51
52
 
52
- # Override this method if you want a different transformer, or need to load the
53
- # raw image from a different source (e.g. external file)
54
- def load_image_transformer
55
- MiniMagick::Image.open(source_path)
56
- end
53
+ def size
54
+ directives.fetch(:size, nil)
55
+ end
56
+
57
+ def quality
58
+ directives.fetch(:quality, nil)
59
+ end
57
60
  end
58
61
  end
@@ -1,15 +1,97 @@
1
1
  require 'mini_magick'
2
2
  require 'nokogiri'
3
3
 
4
-
5
4
  module Hydra::Derivatives::Processors
6
5
  class Jpeg2kImage < Processor
7
6
  include ShellBasedProcessor
8
7
 
8
+ class << self
9
+ def srgb_profile_path
10
+ File.join [
11
+ File.expand_path('../../../../', __FILE__),
12
+ 'color_profiles',
13
+ 'sRGB_IEC61966-2-1_no_black_scaling.icc'
14
+ ]
15
+ end
16
+
17
+ def kdu_compress_recipe(args, quality, long_dim)
18
+ if args[:recipe].is_a? Symbol
19
+ recipe = [args[:recipe].to_s, quality].join('_').to_sym
20
+ if Hydra::Derivatives.kdu_compress_recipes.key? recipe
21
+ return Hydra::Derivatives.kdu_compress_recipes[recipe]
22
+ else
23
+ ActiveFedora::Base.logger.warn "No JP2 recipe for :#{args[:recipe]} ('#{recipe}') found in configuration. Using best guess."
24
+ return calculate_recipe(args, quality, long_dim)
25
+ end
26
+ elsif args[:recipe].is_a? String
27
+ return args[:recipe]
28
+ else
29
+ return calculate_recipe(args, quality, long_dim)
30
+ end
31
+ end
32
+
33
+ def calculate_recipe(args, quality, long_dim)
34
+ levels_arg = args.fetch(:levels, level_count_for_size(long_dim))
35
+ rates_arg = layer_rates(args.fetch(:layers, 8), args.fetch(:compression, 10))
36
+ tile_size = args.fetch(:tile_size, 1024)
37
+ tiles_arg = "#{tile_size},#{tile_size}"
38
+ jp2_space_arg = quality == 'gray' ? 'sLUM' : 'sRGB'
39
+
40
+ %(-rate #{rates_arg}
41
+ -jp2_space #{jp2_space_arg}
42
+ -double_buffering 10
43
+ -num_threads 4
44
+ -no_weights
45
+ Clevels=#{levels_arg}
46
+ "Stiles={#{tiles_arg}}"
47
+ "Cblk={64,64}"
48
+ Cuse_sop=yes
49
+ Cuse_eph=yes
50
+ Corder=RPCL
51
+ ORGgen_plt=yes
52
+ ORGtparts=R ).gsub(/\s+/, " ").strip
53
+ end
54
+
55
+ def level_count_for_size(long_dim)
56
+ levels = 0
57
+ level_size = long_dim
58
+ while level_size >= 96
59
+ level_size /= 2
60
+ levels += 1
61
+ end
62
+ levels - 1
63
+ end
64
+
65
+ def layer_rates(layer_count, compression_numerator)
66
+ # e.g. if compression_numerator = 10 then compression is 10:1
67
+ rates = []
68
+ cmp = 24.0 / compression_numerator
69
+ layer_count.times do
70
+ rates << cmp
71
+ cmp = (cmp / 1.618).round(8)
72
+ end
73
+ rates.map(&:to_s).join(',')
74
+ end
75
+
76
+ protected
77
+
78
+ def encode(path, recipe, output_file)
79
+ kdu_compress = Hydra::Derivatives.kdu_compress_path
80
+ execute "#{kdu_compress} -quiet -i #{path} -o #{output_file} #{recipe}"
81
+ end
82
+
83
+ def tmp_file(ext)
84
+ Dir::Tmpname.create(['sufia', ext], Hydra::Derivatives.temp_file_base) {}
85
+ end
86
+
87
+ def long_dim(image)
88
+ [image[:width], image[:height]].max
89
+ end
90
+ end
91
+
9
92
  def process
10
93
  image = MiniMagick::Image.open(source_path)
11
94
  quality = image['%[channels]'] == 'gray' ? 'gray' : 'color'
12
- name = directives.fetch(:label)
13
95
  long_dim = self.class.long_dim(image)
14
96
  file_path = self.class.tmp_file('.tif')
15
97
  to_srgb = directives.fetch(:to_srgb, true)
@@ -22,7 +104,7 @@ module Hydra::Derivatives::Processors
22
104
  File.unlink(file_path) unless file_path.nil?
23
105
  end
24
106
 
25
- def encode_file(recipe, opts={})
107
+ def encode_file(recipe, opts = {})
26
108
  output_file = self.class.tmp_file('.jp2')
27
109
  if opts[:file_path]
28
110
  self.class.encode(opts[:file_path], recipe, output_file)
@@ -36,94 +118,14 @@ module Hydra::Derivatives::Processors
36
118
  end
37
119
 
38
120
  protected
39
- def preprocess(image, opts={})
40
- # resize: <geometry>, to_srgb: <bool>, src_quality: 'color'|'gray'
41
- image.combine_options do |c|
42
- c.resize(opts[:resize]) if opts[:resize]
43
- c.profile self.class.srgb_profile_path if opts[:src_quality] == 'color' && opts[:to_srgb]
44
- end
45
- image
46
- end
47
-
48
- def self.encode(path, recipe, output_file)
49
- kdu_compress = Hydra::Derivatives.kdu_compress_path
50
- execute "#{kdu_compress} -quiet -i #{path} -o #{output_file} #{recipe}"
51
- end
52
-
53
- def self.srgb_profile_path
54
- File.join [
55
- File.expand_path('../../../../', __FILE__),
56
- 'color_profiles',
57
- 'sRGB_IEC61966-2-1_no_black_scaling.icc'
58
- ]
59
- end
60
121
 
61
- def self.tmp_file(ext)
62
- Dir::Tmpname.create(['sufia', ext], Hydra::Derivatives.temp_file_base){}
63
- end
64
-
65
- def self.long_dim(image)
66
- [image[:width], image[:height]].max
67
- end
68
-
69
- def self.kdu_compress_recipe(args, quality, long_dim)
70
- if args[:recipe].is_a? Symbol
71
- recipe = [args[:recipe].to_s, quality].join('_').to_sym
72
- if Hydra::Derivatives.kdu_compress_recipes.has_key? recipe
73
- return Hydra::Derivatives.kdu_compress_recipes[recipe]
74
- else
75
- ActiveFedora::Base.logger.warn "No JP2 recipe for :#{args[:recipe].to_s} ('#{recipe}') found in configuration. Using best guess."
76
- return calculate_recipe(args,quality,long_dim)
122
+ def preprocess(image, opts = {})
123
+ # resize: <geometry>, to_srgb: <bool>, src_quality: 'color'|'gray'
124
+ image.combine_options do |c|
125
+ c.resize(opts[:resize]) if opts[:resize]
126
+ c.profile self.class.srgb_profile_path if opts[:src_quality] == 'color' && opts[:to_srgb]
77
127
  end
78
- elsif args[:recipe].is_a? String
79
- return args[:recipe]
80
- else
81
- return calculate_recipe(args, quality, long_dim)
128
+ image
82
129
  end
83
- end
84
-
85
- def self.calculate_recipe(args, quality, long_dim)
86
- levels_arg = args.fetch(:levels, level_count_for_size(long_dim))
87
- rates_arg = layer_rates(args.fetch(:layers, 8), args.fetch(:compression, 10))
88
- tile_size = args.fetch(:tile_size, 1024)
89
- tiles_arg = "#{tile_size},#{tile_size}"
90
- jp2_space_arg = quality == 'gray' ? 'sLUM' : 'sRGB'
91
-
92
- %Q{-rate #{rates_arg}
93
- -jp2_space #{jp2_space_arg}
94
- -double_buffering 10
95
- -num_threads 4
96
- -no_weights
97
- Clevels=#{levels_arg}
98
- "Stiles={#{tiles_arg}}"
99
- "Cblk={64,64}"
100
- Cuse_sop=yes
101
- Cuse_eph=yes
102
- Corder=RPCL
103
- ORGgen_plt=yes
104
- ORGtparts=R }.gsub(/\s+/, " ").strip
105
- end
106
-
107
- def self.level_count_for_size(long_dim)
108
- levels = 0
109
- level_size = long_dim
110
- while level_size >= 96
111
- level_size = level_size/2
112
- levels+=1
113
- end
114
- levels-1
115
- end
116
-
117
- def self.layer_rates(layer_count,compression_numerator)
118
- #e.g. if compression_numerator = 10 then compression is 10:1
119
- rates = []
120
- cmp = 24.0/compression_numerator
121
- layer_count.times do
122
- rates << cmp
123
- cmp = (cmp/1.618).round(8)
124
- end
125
- rates.map(&:to_s ).join(',')
126
- end
127
-
128
130
  end
129
131
  end