Class: Hydra::Derivatives::Processors::Jpeg2kImage

Inherits:
Processor
  • Object
show all
Includes:
ShellBasedProcessor
Defined in:
lib/hydra/derivatives/processors/jpeg2k_image.rb

Constant Summary

Constants included from ShellBasedProcessor

ShellBasedProcessor::BLOCK_SIZE

Instance Attribute Summary

Attributes inherited from Processor

#directives, #output_file_service, #source_path

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ShellBasedProcessor

#options_for, #output_file

Methods inherited from Processor

#initialize, #output_file, #output_file_id, #output_filename_for

Constructor Details

This class inherits a constructor from Hydra::Derivatives::Processors::Processor

Class Method Details

.calculate_recipe(args, quality, long_dim) ⇒ Object


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 30

def calculate_recipe(args, quality, long_dim)
  levels_arg = args.fetch(:levels, level_count_for_size(long_dim))
  rates_arg = layer_rates(args.fetch(:layers, 8), args.fetch(:compression, 10))
  tile_size = args.fetch(:tile_size, 1024)
  tiles_arg = "#{tile_size},#{tile_size}"
  jp2_space_arg = quality == 'gray' ? 'sLUM' : 'sRGB'

  %(-rate #{rates_arg}
      -jp2_space #{jp2_space_arg}
      -double_buffering 10
      -num_threads 4
      -no_weights
      Clevels=#{levels_arg}
      "Stiles={#{tiles_arg}}"
      "Cblk={64,64}"
      Cuse_sop=yes
      Cuse_eph=yes
      Corder=RPCL
      ORGgen_plt=yes
      ORGtparts=R  ).gsub(/\s+/, " ").strip
end

.encode(path, recipe, output_file) ⇒ Object


73
74
75
76
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 73

def encode(path, recipe, output_file)
  kdu_compress = Hydra::Derivatives.kdu_compress_path
  execute "#{kdu_compress} -quiet -i #{Shellwords.escape(path)} -o #{output_file} #{recipe}"
end

.kdu_compress_recipe(args, quality, long_dim) ⇒ Object


17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 17

def kdu_compress_recipe(args, quality, long_dim)
  if args[:recipe].is_a? Symbol
    recipe = [args[:recipe].to_s, quality].join('_').to_sym
    return Hydra::Derivatives.kdu_compress_recipes[recipe] if Hydra::Derivatives.kdu_compress_recipes.key? recipe
    ActiveFedora::Base.logger.warn "No JP2 recipe for :#{args[:recipe]} ('#{recipe}') found in configuration. Using best guess."
    calculate_recipe(args, quality, long_dim)
  elsif args[:recipe].is_a? String
    args[:recipe]
  else
    calculate_recipe(args, quality, long_dim)
  end
end

.layer_rates(layer_count, compression_numerator) ⇒ Object


62
63
64
65
66
67
68
69
70
71
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 62

def layer_rates(layer_count, compression_numerator)
  # e.g. if compression_numerator = 10 then compression is 10:1
  rates = []
  cmp = 24.0 / compression_numerator
  layer_count.times do
    rates << cmp
    cmp = (cmp / 1.618).round(8)
  end
  rates.map(&:to_s).join(',')
end

.level_count_for_size(long_dim) ⇒ Object


52
53
54
55
56
57
58
59
60
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 52

def level_count_for_size(long_dim)
  levels = 0
  level_size = long_dim
  while level_size >= 96
    level_size /= 2
    levels += 1
  end
  levels - 1
end

.long_dim(image) ⇒ Object


82
83
84
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 82

def long_dim(image)
  [image[:width], image[:height]].max
end

.srgb_profile_pathObject


9
10
11
12
13
14
15
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 9

def srgb_profile_path
  File.join [
    File.expand_path('../../../../', __FILE__),
    'color_profiles',
    'sRGB_IEC61966-2-1_no_black_scaling.icc'
  ]
end

.tmp_file(ext) ⇒ Object


78
79
80
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 78

def tmp_file(ext)
  Dir::Tmpname.create(['sufia', ext], Hydra::Derivatives.temp_file_base) {}
end

Instance Method Details

#encode_file(recipe, opts = {}) ⇒ Object


102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 102

def encode_file(recipe, opts = {})
  output_file = self.class.tmp_file('.jp2')
  if opts[:file_path]
    self.class.encode(opts[:file_path], recipe, output_file)
  else
    Hydra::Derivatives::TempfileService.create(source_file) do |f|
      self.class.encode(f.path, recipe, output_file)
    end
  end
  output_file_service.call(File.open(output_file, 'rb'), directives)
  File.unlink(output_file)
end

#processObject


87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/hydra/derivatives/processors/jpeg2k_image.rb', line 87

def process
  image = MiniMagick::Image.open(source_path)
  quality = image['%[channels]'] == 'gray' ? 'gray' : 'color'
  long_dim = self.class.long_dim(image)
  file_path = self.class.tmp_file('.tif')
  to_srgb = directives.fetch(:to_srgb, true)
  if directives[:resize] || to_srgb
    preprocess(image, resize: directives[:resize], to_srgb: to_srgb, src_quality: quality)
  end
  image.write file_path
  recipe = self.class.kdu_compress_recipe(directives, quality, long_dim)
  encode_file(recipe, file_path: file_path)
  File.unlink(file_path) unless file_path.nil?
end