libis-format 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +20 -0
  4. data/.travis.yml +70 -0
  5. data/Gemfile +0 -10
  6. data/README.md +2 -2
  7. data/Rakefile +8 -0
  8. data/base/Dockerfile +35 -0
  9. data/base/Dockerfile.alpine +20 -0
  10. data/base/Dockerfile.rvm +56 -0
  11. data/base/rework_path +20 -0
  12. data/data/PDFA_def.ps +3 -3
  13. data/data/eciRGB_v2.icc +0 -0
  14. data/data/types.yml +4 -17
  15. data/docker_cfg.yml +1 -0
  16. data/lib/libis/format/cli/convert.rb +4 -4
  17. data/lib/libis/format/cli/prompt_helper.rb +24 -32
  18. data/lib/libis/format/command_line.rb +3 -2
  19. data/lib/libis/format/config.rb +22 -20
  20. data/lib/libis/format/converter/audio_converter.rb +31 -56
  21. data/lib/libis/format/converter/base.rb +36 -16
  22. data/lib/libis/format/converter/chain.rb +32 -52
  23. data/lib/libis/format/converter/fop_pdf_converter.rb +8 -4
  24. data/lib/libis/format/converter/image_assembler.rb +82 -0
  25. data/lib/libis/format/converter/image_converter.rb +40 -153
  26. data/lib/libis/format/converter/image_splitter.rb +80 -0
  27. data/lib/libis/format/converter/image_watermarker.rb +261 -0
  28. data/lib/libis/format/converter/jp2_converter.rb +38 -36
  29. data/lib/libis/format/converter/office_converter.rb +28 -22
  30. data/lib/libis/format/converter/pdf_assembler.rb +66 -0
  31. data/lib/libis/format/converter/pdf_converter.rb +50 -111
  32. data/lib/libis/format/converter/pdf_optimizer.rb +70 -0
  33. data/lib/libis/format/converter/pdf_splitter.rb +65 -0
  34. data/lib/libis/format/converter/pdf_watermarker.rb +110 -0
  35. data/lib/libis/format/converter/repository.rb +13 -7
  36. data/lib/libis/format/converter/spreadsheet_converter.rb +16 -10
  37. data/lib/libis/format/converter/video_converter.rb +58 -47
  38. data/lib/libis/format/converter/xslt_converter.rb +11 -13
  39. data/lib/libis/format/converter.rb +1 -1
  40. data/lib/libis/format/identifier.rb +46 -44
  41. data/lib/libis/format/info.rb +27 -0
  42. data/lib/libis/format/library.rb +147 -0
  43. data/lib/libis/format/tool/droid.rb +30 -29
  44. data/lib/libis/format/tool/extension_identification.rb +26 -24
  45. data/lib/libis/format/tool/{ff_mpeg.rb → ffmpeg.rb} +10 -17
  46. data/lib/libis/format/tool/fido.rb +27 -22
  47. data/lib/libis/format/tool/file_tool.rb +24 -11
  48. data/lib/libis/format/tool/fop_pdf.rb +14 -25
  49. data/lib/libis/format/tool/identification_tool.rb +40 -38
  50. data/lib/libis/format/tool/office_to_pdf.rb +18 -30
  51. data/lib/libis/format/tool/pdf_copy.rb +15 -24
  52. data/lib/libis/format/tool/pdf_merge.rb +14 -24
  53. data/lib/libis/format/tool/pdf_optimizer.rb +17 -24
  54. data/lib/libis/format/tool/pdf_split.rb +16 -25
  55. data/lib/libis/format/tool/pdf_to_pdfa.rb +32 -50
  56. data/lib/libis/format/tool/pdfa_validator.rb +30 -25
  57. data/lib/libis/format/tool/spreadsheet_to_ods.rb +18 -29
  58. data/lib/libis/format/tool.rb +3 -4
  59. data/lib/libis/format/version.rb +1 -3
  60. data/lib/libis/format/yaml_loader.rb +71 -0
  61. data/lib/libis/format.rb +7 -5
  62. data/lib/libis-format.rb +0 -2
  63. data/libis-format.gemspec +18 -24
  64. metadata +78 -120
  65. data/data/AdobeRGB1998.icc +0 -0
  66. data/lib/libis/format/converter/email_converter.rb +0 -35
  67. data/lib/libis/format/tool/msg_to_pdf.rb +0 -270
  68. data/lib/libis/format/type_database.rb +0 -156
  69. data/lib/libis/format/type_database_impl.rb +0 -153
  70. data/tools/pdf2pdfa +0 -395
  71. /data/bin/{droid_tool → droid} +0 -0
  72. /data/bin/{fido_tool → fido} +0 -0
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative 'base'
4
2
  require 'libis/format/identifier'
5
3
  require 'chromaprint'
@@ -9,19 +7,24 @@ require 'fileutils'
9
7
  module Libis
10
8
  module Format
11
9
  module Converter
10
+
12
11
  class AudioConverter < Libis::Format::Converter::Base
12
+
13
13
  def self.input_types
14
- %i[MP3 FLAC AC3 AAC WMA ALAC WAV AIFF AMR AU M4A]
14
+ [:MP3, :FLAC, :AC3, :AAC, :WMA, :ALAC, :WAV, :AIFF, :AMR, :AU, :M4A]
15
15
  end
16
16
 
17
17
  def self.output_types(format = nil)
18
- return [] unless input_types.include?(format)
18
+ return [] unless format.nil? || input_types.include?(format)
19
+ [:MP3, :FLAC, :AC3, :AAC, :WMA, :ALAC, :WAV, :AIFF, :AMR, :AU, :M4A]
20
+ end
19
21
 
20
- %i[MP3 FLAC AC3 AAC WMA ALAC WAV AIFF AMR AU M4A]
22
+ def initialize
23
+ super
21
24
  end
22
25
 
23
- def quiet(value)
24
- @flags[:quiet] = !!value
26
+ def quiet(v)
27
+ @flags[:quiet] = !!v
25
28
  end
26
29
 
27
30
  def format(format)
@@ -57,70 +60,38 @@ module Libis
57
60
  end
58
61
 
59
62
  def web_stream(value)
60
- return unless value
61
-
62
- @options[:codec] = 'mp3'
63
+ if value
64
+ @options[:codec] = 'mp3'
65
+ end
63
66
  end
64
67
 
65
68
  def preset(stream, name)
66
69
  (@options[:preset] ||= {})[stream] = name
67
70
  end
68
71
 
69
- # def encoder(value)
70
- # @options[:encoder] = value
71
- # end
72
- #
73
- # def encoder_options(value)
74
- # @options[:encoder_options] = value
75
- # end
76
-
77
72
  def convert(source, target, _format, opts = {})
78
73
  super
79
74
 
80
75
  FileUtils.mkpath(File.dirname(target))
81
76
 
82
- if source.is_a? Array
83
-
84
- assemble_and_convert(source, target)
85
-
86
- elsif File.directory?(source)
87
-
88
- sources = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
89
- assemble_and_convert(sources, target)
90
-
91
- else
77
+ convert_file(source, target)
92
78
 
93
- convert_file(source, target)
94
-
95
- end
96
- end
97
-
98
- def assemble_and_convert(sources, target)
99
- result = {}
100
- Tempfile.create(%w[list .txt]) do |f|
101
- sources.each { |src| f.puts src }
102
- opts[:global] ||= []
103
- opts[:global] += %w[-f concat]
104
- f.close
105
- result = convert_file(f.to_path, target)
106
- end
107
- result
108
79
  end
109
80
 
110
81
  def self.sounds_like(file1, file2, threshold, rate, channels)
111
- rate ||= 96_000
82
+ rate ||= 96000
112
83
  channels ||= 2
113
84
  threshold ||= 0.85
114
85
 
115
- if File.exist?(file1) && File.exist?(file2)
86
+ if File.exists?(file1) && File.exists?(file2)
116
87
  # Convert input files into raw 16-bit signed audio (WAV) to process with Chramaprint
117
- file1_raw = File.join('', 'tmp', "#{File.basename(file1)}.wav")
118
- file2_raw = File.join('', 'tmp', "#{File.basename(file2)}.wav")
88
+ file1_raw = File.join('', 'tmp', File.basename(file1) + '.wav')
89
+ file2_raw = File.join('', 'tmp', File.basename(file2) + '.wav')
119
90
  FileUtils.rm(file1_raw, force: true)
120
91
  FileUtils.rm(file2_raw, force: true)
121
92
  cvt_cmd = Libis::Format::Config[:raw_audio_convert_cmd]
122
- `#{format(cvt_cmd, file1, file1_raw, rate, channels)}`
123
- `#{format(cvt_cmd, file2, file2_raw, rate, channels)}`
93
+ %x"#{cvt_cmd % [file1, file1_raw, rate, channels]}"
94
+ %x"#{cvt_cmd % [file2, file2_raw, rate, channels]}"
124
95
  file1_audio = File.binread(file1_raw)
125
96
  file2_audio = File.binread(file2_raw)
126
97
 
@@ -140,33 +111,37 @@ module Libis
140
111
  else
141
112
  false
142
113
  end
114
+
143
115
  rescue Exception => e
144
- puts "Error comparing sound file #{file1} and #{file2}: #{e.message} @ #{e.backtrace.first}"
116
+ error "Error comparing sound file #{file1} and #{file2}: #{e.message} @ #{e.backtrace.first}"
145
117
  false
146
118
  end
147
119
 
148
120
  protected
149
121
 
150
122
  def convert_file(source, target)
151
- opts = { global: [], input: [], filter: [], output: [] }
152
-
123
+ opts = {global: [], input: [], filter: [], output: []}
153
124
  opts[:global] << '-hide_banner'
154
125
  opts[:global] << '-loglevel' << (@options[:quiet] ? 'fatal' : 'warning')
155
126
  opts[:output] << '-vn' # disable input video stream in case it exists
156
127
  opts[:output] << '-codec:a' << @options[:codec] if @options[:codec]
157
128
  opts[:output] << '-map_metadata:g' << '0:g' # Copy global metadata
158
129
  opts[:output] << '-map_metadata:s:a' << '0:s:a' # Copy audio metadata
159
- opts[:input] << '-accurate_seek' << (@options[:start].to_i.negative? ? '-sseof' : '-ss') << @options[:start] if @options[:start]
130
+ opts[:input] << '-accurate_seek' << (@options[:start].to_i < 0 ? '-sseof' : '-ss') << @options[:start] if @options[:start]
160
131
  opts[:input] << '-t' << @options[:duration] if @options[:duration]
161
132
  opts[:output] << '-q:a' << @options[:quality] if @options[:quality]
162
133
  opts[:output] << '-b:a' << @options[:bit_rate] if @options[:bit_rate]
163
134
  opts[:output] << '-ar' << @options[:sampling_freq] if @options[:sampling_freq]
164
135
  opts[:output] << '-ac' << @options[:channels] if @options[:channels]
165
136
  opts[:output] << '-f' << @options[:format] if @options[:format]
166
-
167
- Libis::Format::Tool::FFMpeg.run(source, target, opts)
137
+ result = Libis::Format::Tool::FFMpeg.run(source, target, opts)
138
+ info "FFMpeg output: #{result}"
139
+ result
140
+ target
168
141
  end
142
+
169
143
  end
144
+
170
145
  end
171
146
  end
172
- end
147
+ end
@@ -1,16 +1,17 @@
1
- # frozen_string_literal: true
1
+ # coding: utf-8
2
2
 
3
3
  ### require 'tools/string'
4
4
  require 'tmpdir'
5
5
  require 'libis/tools/logger'
6
6
  require 'libis/tools/temp_file'
7
- require 'libis/format/type_database'
7
+ require 'libis/format/library'
8
8
 
9
9
  require_relative 'repository'
10
10
 
11
11
  module Libis
12
12
  module Format
13
13
  module Converter
14
+
14
15
  class Base
15
16
  include Libis::Tools::Logger
16
17
 
@@ -21,43 +22,58 @@ module Libis
21
22
  @flags = {}
22
23
  end
23
24
 
24
- def convert(source, _target, _format, opts = {})
25
- unless File.exist? source
26
- error "Cannot find file '#{source}'."
27
- return nil
25
+ def self.category
26
+ :converter
27
+ end
28
+
29
+ def check_file_exist(file)
30
+ unless File.exist? file
31
+ error "Cannot find file '#{file}'."
32
+ return false
33
+ end
34
+ true
35
+ end
36
+
37
+ def convert(source, target, format, opts = {})
38
+ if source.is_a?(Array)
39
+ return nil unless source.map { |f| check_file_exist(f) }.reduce(:&)
40
+ else
41
+ return nil unless check_file_exist(source)
28
42
  end
29
43
  @options.merge!(opts[:options]) if opts[:options]
30
44
  @flags.merge!(opts[:flags]) if opts[:flags]
31
45
  end
32
46
 
33
47
  def self.input_types
34
- raise 'Method #input_types needs to be overridden in converter'
48
+ raise RuntimeError, 'Method #input_types needs to be overridden in converter'
35
49
  end
36
50
 
37
51
  def self.output_types(_format = nil)
38
- raise 'Method #output_types needs to be overridden in converter'
52
+ raise RuntimeError, 'Method #output_types needs to be overridden in converter'
39
53
  end
40
54
 
41
55
  def using_temp(target, &block)
42
56
  self.class.using_temp(target, &block)
43
57
  end
44
58
 
45
- def self.using_temp(target)
59
+ def Base.using_temp(target)
46
60
  tempfile = Tools::TempFile.name("convert-#{File.basename(target, '.*').gsub(/\s/, '_')}", File.extname(target))
47
61
  result = yield tempfile
48
62
  return nil unless result
49
-
50
63
  FileUtils.move result, target
51
64
  target
52
65
  end
53
66
 
54
- def self.inherited(klass) # rubocop:disable Lint/MissingSuper
67
+ def Base.inherited(klass)
68
+
55
69
  Repository.register klass
56
70
 
57
71
  class << self
72
+
58
73
  def conversions
59
- input_types.each_with_object({}) do |input_type, hash|
74
+ input_types.inject({}) do |hash, input_type|
60
75
  hash[input_type] = output_types
76
+ hash
61
77
  end
62
78
  end
63
79
 
@@ -70,17 +86,17 @@ module Libis
70
86
  end
71
87
 
72
88
  def input_mimetype?(mimetype)
73
- type_id = TypeDatabase.instance.mime_types(mimetype).first
89
+ type_id = Libis::Format::Library.get_field_by(:mimetype, mimetype, :format)
74
90
  input_type? type_id
75
91
  end
76
92
 
77
93
  def output_mimetype?(mimetype)
78
- type_id = TypeDatabase.instance.mime_types(mimetype).first
94
+ type_id = Libis::Format::Library.get_field_by(:mimetype, mimetype, :format)
79
95
  output_type? type_id
80
96
  end
81
97
 
82
98
  def conversion?(input_type, output_type)
83
- conversions[input_type]&.any? { |t| t == output_type }
99
+ conversions[input_type] and conversions[input_type].any? { |t| t == output_type }
84
100
  end
85
101
 
86
102
  def output_for(input_type)
@@ -88,11 +104,15 @@ module Libis
88
104
  end
89
105
 
90
106
  def extension?(extension)
91
- !TypeDatabase.ext_types(extension).first.nil?
107
+ !Libis::Format::Library.get_field_by(:extension, extension, :format).nil?
92
108
  end
109
+
93
110
  end
111
+
94
112
  end
113
+
95
114
  end
115
+
96
116
  end
97
117
  end
98
118
  end
@@ -1,15 +1,16 @@
1
- # frozen_string_literal: true
1
+ # coding: utf-8
2
2
 
3
3
  require 'fileutils'
4
4
  require 'deep_dive'
5
5
 
6
6
  require 'libis/tools/logger'
7
7
  require 'libis/tools/extend/hash'
8
- require 'libis/format/type_database'
8
+ require 'libis/format/library'
9
9
 
10
10
  module Libis
11
11
  module Format
12
12
  module Converter
13
+
13
14
  class Chain
14
15
  include ::Libis::Tools::Logger
15
16
  include DeepDive
@@ -25,16 +26,15 @@ module Libis
25
26
  # @return [Array[Hash]]
26
27
  def append(converter)
27
28
  return [] unless converter
28
-
29
29
  valid_chain_nodes(converter).map do |node|
30
- ddup.add_chain_node(node)
30
+ self.ddup.add_chain_node(node)
31
31
  end.compact
32
32
  end
33
33
 
34
34
  def closed?
35
35
  !@converter_chain.empty? &&
36
- @converter_chain.first[:input].to_sym == @source_format &&
37
- @converter_chain.last[:output].to_sym == @target_format
36
+ @converter_chain.first[:input].to_sym == @source_format &&
37
+ @converter_chain.last[:output].to_sym == @target_format
38
38
  end
39
39
 
40
40
  def valid?
@@ -49,76 +49,68 @@ module Libis
49
49
  @converter_chain.size
50
50
  end
51
51
 
52
- alias length size
52
+ alias_method :length, :size
53
53
 
54
54
  def to_s
55
- result = @source_format.to_s
56
- result << @converter_chain.map { |node| node_to_s(node) }.join('->-')
55
+ "#{@source_format}->-#{@converter_chain.map do |node|
56
+ "#{node[:converter].name.gsub(/^.*::/, '')}#{node[:operations].empty? ? '' :
57
+ "(#{node[:operations].each do |operation|
58
+ "#{operation[:method]}:#{operation[:argument]}"
59
+ end.join(',')})"}->-#{node[:output]}"
60
+ end.join('->-')}"
57
61
  end
58
62
 
59
63
  def convert(src_file, target_file)
64
+
60
65
  unless valid?
61
66
  error 'Converter chain is not valid'
62
67
  return nil
63
68
  end
64
69
 
65
70
  temp_files = []
66
- xtra_files = []
67
-
68
- result = { commands: [] }
69
71
 
70
72
  # noinspection RubyParenthesesAroundConditionInspection
71
- conversion_success = @converter_chain.each_with_index do |node, i|
73
+ result = @converter_chain.each_with_index do |node, i|
74
+
72
75
  target_type = node[:output]
73
76
  converter_class = node[:converter]
74
77
  converter = converter_class.new
75
78
 
76
- node[:operations]&.each do |operation|
79
+ node[:operations].each do |operation|
77
80
  converter.send operation[:method], operation[:argument]
78
- end
81
+ end if node[:operations]
79
82
 
80
83
  target = target_file
81
84
 
82
85
  if i < size - 1
83
- target += ".temp.#{TypeDatabase.type_extentions(target_type).first}"
84
- target += ".#{TypeDatabase.type_extentions(target_type).first}" while File.exist? target
86
+ target += ".temp.#{Libis::Format::Library.get_field(target_type, :extensions).first}"
87
+ target += ".#{Libis::Format::Library.get_field(target_type, :extensions).first}" while File.exist? target
85
88
  temp_files << target
86
89
  end
87
90
 
88
91
  FileUtils.mkdir_p File.dirname(target)
89
92
 
90
- r = converter.convert(src_file, target, target_type)
93
+ src_file = converter.convert(src_file, target, target_type)
91
94
 
92
- src_file = r[:files].first
93
- xtra_files += r[:files][1..]
94
95
  break :failed unless src_file
95
96
 
96
- result[:commands] << r.merge(converter: converter_class.name)
97
-
98
- :success
99
97
  end
100
98
 
101
- result[:files] = [src_file] + xtra_files
102
-
103
99
  temp_files.each do |f|
104
100
  FileUtils.rm(f, force: true)
105
101
  end
106
102
 
107
- conversion_success == :failed ? nil : result
103
+ result == :failed ? nil : target_file
104
+
108
105
  end
109
106
 
110
107
  def valid_chain_nodes(converter)
111
- source_format = begin
112
- @converter_chain.last[:output]
113
- rescue StandardError
114
- @source_format
115
- end
108
+ source_format = @converter_chain.last[:output] rescue @source_format
116
109
  nodes = []
117
110
  if converter.input_types.include? source_format
118
111
  converter.output_types(source_format).each do |format|
119
- node = { converter:, input: source_format, output: format }
112
+ node = {converter: converter, input: source_format, output: format}
120
113
  next if node_exists?(node)
121
-
122
114
  nodes << node
123
115
  end
124
116
  end
@@ -133,7 +125,6 @@ module Libis
133
125
  return nil unless node[:output] && node[:converter].output_types(source_format).include?(node[:output])
134
126
  return nil unless node[:converter].input_types.include? source_format
135
127
  return nil if node_exists?(node)
136
-
137
128
  @converter_chain << node
138
129
  # debug "Chain: #{self}"
139
130
  self
@@ -142,16 +133,15 @@ module Libis
142
133
  def apply_operations
143
134
  temp_chain = @converter_chain.reverse.ddup
144
135
  applied = true
145
- operations = @operations&.ddup || {}
136
+ operations = @operations && @operations.ddup || {}
146
137
  while (operation = operations.shift)
147
138
  method = operation.first.to_s.to_sym
148
- applied &&= temp_chain.each do |node|
139
+ applied &&= :found == temp_chain.each do |node|
149
140
  next unless node[:converter].instance_methods.include?(method)
150
-
151
141
  node[:operations] ||= []
152
- node[:operations] << { method:, argument: operation.last }
142
+ node[:operations] << {method: method, argument: operation.last}
153
143
  break :found
154
- end == :found
144
+ end
155
145
  end
156
146
  if applied && operations.empty?
157
147
  @converter_chain = temp_chain.reverse
@@ -161,27 +151,17 @@ module Libis
161
151
  false
162
152
  end
163
153
 
164
- private
165
154
 
166
- def node_to_s(node)
167
- result = node[:converter].name.gsub(/^.*::/, '').to_s
168
- unless node[:operations].empty?
169
- result << '('
170
- result << node[:operations].map do |operation|
171
- "#{operation[:method]}:#{operation[:argument]}"
172
- end.join(',')
173
- result << ')'
174
- end
175
- result << '->-'
176
- result << node[:output].to_s
177
- end
155
+ private
178
156
 
179
157
  def node_exists?(node)
180
158
  @converter_chain.detect do |n|
181
159
  n[:converter] == node[:converter] && n[:input] == node[:input] && n[:output] == node[:output]
182
160
  end
183
161
  end
162
+
184
163
  end
164
+
185
165
  end
186
166
  end
187
167
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'nokogiri'
4
2
 
5
3
  require_relative 'base'
@@ -9,14 +7,15 @@ require 'libis/format/tool/fop_pdf'
9
7
  module Libis
10
8
  module Format
11
9
  module Converter
10
+
12
11
  class FopPdfConverter < Libis::Format::Converter::Base
12
+
13
13
  def self.input_types
14
14
  [:XML]
15
15
  end
16
16
 
17
17
  def self.output_types(format = nil)
18
- return [] if format && !input_types.include?(format)
19
-
18
+ return [] unless input_types.include?(format) if format
20
19
  [:PDF]
21
20
  end
22
21
 
@@ -31,8 +30,13 @@ module Libis
31
30
  FileUtils.mkpath(File.dirname(target))
32
31
 
33
32
  Libis::Format::Tool::FopPdf.run(source, target)
33
+
34
+ target
35
+
34
36
  end
37
+
35
38
  end
39
+
36
40
  end
37
41
  end
38
42
  end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'base'
4
+ require 'libis/format/identifier'
5
+
6
+ require 'mini_magick'
7
+
8
+ MiniMagick.logger.level = ::Logger::UNKNOWN
9
+
10
+ MiniMagick.configure do |config|
11
+ # config.cli = :graphicsmagick
12
+ config.validate_on_create = false
13
+ config.validate_on_write = false
14
+ config.whiny = false
15
+ end
16
+
17
+ module Libis
18
+ module Format
19
+ module Converter
20
+
21
+ # noinspection RubyTooManyInstanceVariablesInspection,DuplicatedCode
22
+ class ImageAssembler < Libis::Format::Converter::Base
23
+
24
+ def self.input_types
25
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
26
+ end
27
+
28
+ def self.output_types(format = nil)
29
+ return [] unless input_types.include?(format) if format
30
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM]
31
+ end
32
+
33
+ def self.category
34
+ :assembler
35
+ end
36
+
37
+ def image_assemble(_)
38
+ #force usage of this converter
39
+ end
40
+
41
+ def quiet(v)
42
+ @quiet = !!v
43
+ end
44
+
45
+ def convert(source, target, format, opts = {})
46
+ super
47
+
48
+ FileUtils.mkpath(File.dirname(target))
49
+
50
+ if source.is_a? Array
51
+ assemble(source, target, format)
52
+ elsif File.directory?(source)
53
+ source_list = Dir[File.join(source, '**', '*')].reject {|p| File.directory? p}
54
+ assemble(source_list, target, format)
55
+ else
56
+ image = MiniMagick::Image.open(source) {|b| b.quiet}
57
+ if image.pages.size > 1
58
+ assemble(image.pages.map {|page| page.path}, target, format)
59
+ else
60
+ assemble([source], target, format)
61
+ end
62
+ end
63
+
64
+ target
65
+
66
+ end
67
+
68
+ private
69
+
70
+ def assemble(sources, target, format)
71
+ MiniMagick::Tool::Convert.new do |b|
72
+ sources.each {|source| b << source}
73
+ convert.format(format)
74
+ b << target
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end