hydra-derivatives 3.1.3 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.
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