libis-format 1.3.7.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) 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 -12
  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/bin/{pdf_tool → pdf_copy} +2 -3
  13. data/data/PDFA_def.ps +3 -3
  14. data/data/eciRGB_v2.icc +0 -0
  15. data/data/types.yml +4 -17
  16. data/docker_cfg.yml +1 -0
  17. data/lib/libis/format/cli/convert.rb +4 -4
  18. data/lib/libis/format/cli/prompt_helper.rb +24 -32
  19. data/lib/libis/format/command_line.rb +3 -2
  20. data/lib/libis/format/config.rb +23 -19
  21. data/lib/libis/format/converter/audio_converter.rb +31 -56
  22. data/lib/libis/format/converter/base.rb +36 -16
  23. data/lib/libis/format/converter/chain.rb +32 -62
  24. data/lib/libis/format/converter/fop_pdf_converter.rb +8 -4
  25. data/lib/libis/format/converter/image_assembler.rb +82 -0
  26. data/lib/libis/format/converter/image_converter.rb +45 -248
  27. data/lib/libis/format/converter/image_splitter.rb +80 -0
  28. data/lib/libis/format/converter/image_watermarker.rb +261 -0
  29. data/lib/libis/format/converter/jp2_converter.rb +38 -36
  30. data/lib/libis/format/converter/office_converter.rb +28 -22
  31. data/lib/libis/format/converter/pdf_assembler.rb +66 -0
  32. data/lib/libis/format/converter/pdf_converter.rb +52 -200
  33. data/lib/libis/format/converter/pdf_optimizer.rb +70 -0
  34. data/lib/libis/format/converter/pdf_splitter.rb +65 -0
  35. data/lib/libis/format/converter/pdf_watermarker.rb +110 -0
  36. data/lib/libis/format/converter/repository.rb +13 -7
  37. data/lib/libis/format/converter/spreadsheet_converter.rb +16 -10
  38. data/lib/libis/format/converter/video_converter.rb +73 -109
  39. data/lib/libis/format/converter/xslt_converter.rb +11 -13
  40. data/lib/libis/format/converter.rb +1 -1
  41. data/lib/libis/format/identifier.rb +46 -44
  42. data/lib/libis/format/info.rb +27 -0
  43. data/lib/libis/format/library.rb +147 -0
  44. data/lib/libis/format/tool/droid.rb +30 -29
  45. data/lib/libis/format/tool/extension_identification.rb +26 -24
  46. data/lib/libis/format/tool/{ff_mpeg.rb → ffmpeg.rb} +10 -17
  47. data/lib/libis/format/tool/fido.rb +27 -22
  48. data/lib/libis/format/tool/file_tool.rb +24 -11
  49. data/lib/libis/format/tool/fop_pdf.rb +14 -25
  50. data/lib/libis/format/tool/identification_tool.rb +40 -38
  51. data/lib/libis/format/tool/office_to_pdf.rb +18 -30
  52. data/lib/libis/format/tool/pdf_copy.rb +47 -0
  53. data/lib/libis/format/tool/pdf_merge.rb +19 -25
  54. data/lib/libis/format/tool/pdf_optimizer.rb +19 -22
  55. data/lib/libis/format/tool/pdf_split.rb +33 -6
  56. data/lib/libis/format/tool/pdf_to_pdfa.rb +31 -45
  57. data/lib/libis/format/tool/pdfa_validator.rb +30 -24
  58. data/lib/libis/format/tool/spreadsheet_to_ods.rb +18 -29
  59. data/lib/libis/format/tool.rb +3 -4
  60. data/lib/libis/format/version.rb +1 -3
  61. data/lib/libis/format/yaml_loader.rb +71 -0
  62. data/lib/libis/format.rb +7 -5
  63. data/lib/libis-format.rb +0 -2
  64. data/libis-format.gemspec +18 -24
  65. data/tools/PdfTool.jar +0 -0
  66. data/tools/pdfbox/pdfbox-app-2.0.13.jar +0 -0
  67. data/tools/pdfbox/{preflight-app-3.0.3.jar → preflight-app-2.0.13.jar} +0 -0
  68. metadata +86 -128
  69. data/data/AdobeRGB1998.icc +0 -0
  70. data/lib/libis/format/converter/email_converter.rb +0 -36
  71. data/lib/libis/format/tool/msg_to_pdf.rb +0 -270
  72. data/lib/libis/format/tool/pdf_tool.rb +0 -52
  73. data/lib/libis/format/type_database.rb +0 -156
  74. data/lib/libis/format/type_database_impl.rb +0 -153
  75. data/tools/pdf2pdfa +0 -395
  76. data/tools/pdfbox/pdfbox-app-3.0.3.jar +0 -0
  77. /data/bin/{droid_tool → droid} +0 -0
  78. /data/bin/{fido_tool → fido} +0 -0
@@ -1,34 +1,37 @@
1
- # frozen_string_literal: true
1
+ # encoding: utf-8
2
2
 
3
3
  require_relative 'base'
4
4
  require 'libis/format/identifier'
5
5
 
6
6
  require 'mini_magick'
7
- require 'fileutils'
8
7
 
9
8
  MiniMagick.logger.level = ::Logger::UNKNOWN
10
9
 
11
10
  MiniMagick.configure do |config|
12
- config.tmpdir = Libis::Format::Config[:tempdir] || Dir.tmpdir
11
+ # config.cli = :graphicsmagick
12
+ config.validate_on_create = false
13
+ config.validate_on_write = false
14
+ config.whiny = false
13
15
  end
14
16
 
15
17
  module Libis
16
18
  module Format
17
19
  module Converter
20
+
18
21
  # noinspection RubyTooManyInstanceVariablesInspection
19
22
  class ImageConverter < Libis::Format::Converter::Base
23
+
20
24
  def self.input_types
21
- %i[TIFF JPG PNG BMP GIF PDF JP2]
25
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2, :PBM, :PGM, :PPM]
22
26
  end
23
27
 
24
28
  def self.output_types(format = nil)
25
- return [] unless input_types.include?(format)
26
-
27
- %i[TIFF JPG PNG BMP GIF PDF JP2]
29
+ return [] unless input_types.include?(format) if format
30
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
28
31
  end
29
32
 
30
33
  def self.multipage?(format)
31
- %i[PDF TIFF GIF PBM PGM PPM].include?(format)
34
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
32
35
  end
33
36
 
34
37
  def initialize
@@ -37,153 +40,62 @@ module Libis
37
40
  end
38
41
 
39
42
  def image_convert(_)
40
- # force usage of this converter
43
+ #force usage of this converter
41
44
  end
42
45
 
43
- def quiet(value)
44
- @quiet = !!value
46
+ def quiet(v)
47
+ @quiet = !!v
48
+ self
45
49
  end
46
50
 
47
- def page(number)
48
- @page = number
51
+ def page(nr)
52
+ @page = nr
53
+ self
49
54
  end
50
55
 
51
56
  def scale(percent)
52
57
  @options[:scale] = percent
58
+ self
53
59
  end
54
60
 
55
61
  def resize(geometry)
56
62
  @options[:resize] = geometry
63
+ self
57
64
  end
58
65
 
59
66
  def quality(value)
60
67
  @options[:quality] = value
68
+ self
61
69
  end
62
70
 
63
71
  def dpi(value)
64
72
  @options[:density] = value
73
+ self
65
74
  end
66
75
 
67
76
  def resample(value)
68
77
  @options[:resample] = value
78
+ self
69
79
  end
70
80
 
71
81
  def flatten(value = true)
72
- @options[:flatten] = !!value
82
+ @options[:flatten] = value
83
+ self
73
84
  end
74
85
 
75
86
  def colorspace(value)
76
87
  @options[:colorspace] = value
88
+ self
77
89
  end
78
90
 
79
91
  def delete_date(value = true)
80
- @delete_date = !!value
92
+ @delete_date = value
93
+ self
81
94
  end
82
95
 
83
96
  def profile(icc)
84
97
  @profile = icc
85
- end
86
-
87
- # Create or use a watermark image.
88
- #
89
- # The main watermark options are (use symbols):
90
- # - text: text to create a watermark from
91
- # - file: watermark image to use
92
- # - image: same as above
93
- # - banner: use side banner
94
- #
95
- # For each of these options above a dedicated option handler will be called
96
- #
97
- # @param [Hash] options Hash of options for watermark creation.
98
-
99
- def watermark(options = {})
100
- options.key_strings_to_symbols!
101
- if options[:file] || options[:image]
102
- watermark_image(options)
103
- elsif options[:text]
104
- watermark_text(options)
105
- elsif options[:banner]
106
- watermark_banner(options)
107
- end
108
- end
109
-
110
- # Use an image as watermark
111
- #
112
- # Next to the :file or :image option, this enables the following options:
113
- # - tiles: number of tiles of the watermark - default 4
114
- # 0: no tiling, so only 1 watermark will be placed with the original size
115
- # 1: 1 tile, so the watermark will be scaled up to fill the image
116
- # n > 1: minimum n tiles in both directions
117
- # n < 0: tile without scaling the watermark
118
- # - size: same as tiles - for backwards compatibility
119
- # - resize: fraction 0.0 - 1.0
120
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
121
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
122
- # - gravity: center point of the overlay - default 'center'
123
- # - composition: algorithm to use to compose both images - default modulate
124
- def watermark_image(options = {})
125
- options.key_strings_to_symbols!
126
- @options[:watermark] = {command: 'image'}
127
- @options[:watermark][:data] = options[:file] || options[:image]
128
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
129
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
130
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
131
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
132
- @options[:watermark][:gravity] = options[:gravity] || 'center'
133
- @options[:watermark][:composition] = options[:composition] || 'modulate'
134
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
135
- end
136
-
137
- # Use text as watermark
138
- #
139
- # Next to the :text option, this enables the following options:
140
- # - tiles: number of tiles of the watermark - default 4
141
- # 0: no tiling, so only 1 watermark will be placed with the original size
142
- # 1: 1 tile, so the watermark will be scaled up to fill the image
143
- # n > 1: minimum n tiles in both directions
144
- # n < 0: tile without scaling the watermark
145
- # - size: same as tiles - for backwards compatibility
146
- # - resize: fraction 0.0 - 1.0
147
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
148
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
149
- # - gravity: center point of the overlay - default 'center'
150
- # - composition: algorithm to use to compose both images - default modulate
151
- # - rotation: rotation of the text
152
- def watermark_text(options = {})
153
- options.key_strings_to_symbols!
154
- @options[:watermark] = {command: 'text'}
155
- @options[:watermark][:data] = options[:text] || '© LIBIS'
156
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
157
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
158
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
159
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
160
- @options[:watermark][:gravity] = options[:gravity] || 'center'
161
- @options[:watermark][:composition] = options[:composition] || 'modulate'
162
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
163
- end
164
-
165
- # Create a vertical banner to the right side of the image
166
- #
167
- # The banner options are:
168
- # - banner: text to put in the banner
169
- # - add_filename: append filename to the text (use any value to enable)
170
- # - fontsize: size of the font (in points) (default: autoscale)
171
- # - width: width of the banner (default: 3% of image height). Not including a border of 1/3 of the banner width
172
- # - background_color_(red|green|blue): color components of background (default: rgb(84,190,233))
173
- # - text_color_(red|green|blue): color components of background (default: rgb(255,255,255))
174
- def watermark_banner(options = {})
175
- options.key_strings_to_symbols!
176
- @options[:watermark] = {command: 'banner'}
177
- @options[:watermark][:data] = options[:banner] || '© LIBIS'
178
- @options[:watermark][:add_filename] = !!options[:add_filename]
179
- @options[:watermark][:size] = options[:fontsize] if options[:fontsize]
180
- @options[:watermark][:width] = options[:width] if options[:width]
181
- @options[:watermark][:background_red] = options[:background_color_red] || 84
182
- @options[:watermark][:background_green] = options[:background_color_green] || 190
183
- @options[:watermark][:background_blue] = options[:background_color_blue] || 233
184
- @options[:watermark][:text_red] = options[:text_color_red] || 255
185
- @options[:watermark][:text_green] = options[:text_color_green] || 255
186
- @options[:watermark][:text_blue] = options[:text_color_blue] || 255
98
+ self
187
99
  end
188
100
 
189
101
  def convert(source, target, format, opts = {})
@@ -191,152 +103,34 @@ module Libis
191
103
 
192
104
  FileUtils.mkpath(File.dirname(target))
193
105
 
194
- if source.is_a? Array
195
-
196
- assemble_and_convert(source, target, format)
197
-
198
- elsif File.directory?(source)
199
- source_list = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
200
-
201
- assemble_and_convert(source_list, target, format)
106
+ convert_image(source, target, format)
202
107
 
203
- else
204
-
205
- image = MiniMagick::Image.open(source) { |b| b.quiet } # rubocop:disable Style/SymbolProc
206
-
207
- if image.pages.size > 1
208
- if @page
209
- convert_image(image.pages[@page].path, target, format)
210
- else
211
- # noinspection RubyBlockToMethodReference
212
- assemble_and_convert(image.pages.map(&:path), target, format)
213
- end
214
- else
215
- convert_image(source, target, format)
216
- end
217
- end
108
+ target
218
109
 
219
- {
220
- files: [target],
221
- converter: self.class.name
222
- }
223
- end
224
-
225
- def assemble_and_convert(sources, target, format)
226
- warn 'Received multiple images as input and single page format as target.' unless self.class.multipage?(format)
227
- converted_pages = sources.inject([]) do |list, path|
228
- # noinspection RubyArgCount
229
- converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
230
- convert_image(path, converted.path, format)
231
- list << converted
232
- end
233
- MiniMagick.convert do |b|
234
- b.append unless self.class.multipage?(format)
235
- converted_pages.each { |page| b << page.path }
236
- b << target
237
- end
238
- converted_pages.each do |temp_file|
239
- temp_file.close
240
- temp_file.unlink
241
- end
242
110
  end
243
111
 
244
112
  protected
245
113
 
246
114
  def convert_image(source, target, format)
247
- image_info = nil
248
-
249
- MiniMagick.convert do |convert|
250
- # Make converter silent
251
- convert.quiet if @quiet
252
115
 
253
- # Build watermark image in buffer
254
- wm = @options.delete(:watermark)
255
- if wm
256
- image_info = MiniMagick::Image::Info.new(source) { |b| b.quiet }
257
- im_height = image_info['height']
258
- im_width = image_info['width']
259
- case wm[:command]
260
- when 'text'
261
- convert.background 'transparent'
262
- convert.size('2000x2000')
263
- convert.gravity 'Center'
264
- convert.font('Helvetica').fill('black').pointsize(72) # .stroke('black').strokewidth(1)
265
- convert << "label:#{wm[:data]}"
266
- convert.rotate wm[:rotation]
267
- convert.trim.repage.+ # rubocop:disable Lint/Void
268
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
269
- convert.filter('Lagrange')
270
- convert.resize("#{im_width / wm[:tiles]}x#{im_height / wm[:tiles]}") if wm[:tiles].positive?
271
- convert.resize("#{wm[:resize]}%") if wm[:resize]
272
- when 'image'
273
- convert << wm[:data]
274
- convert.background 'transparent'
275
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
276
- convert.rotate wm[:rotation]
277
- convert.filter('Lagrange')
278
- convert.resize("#{im_width / wm[:tiles]}x#{im_height / wm[:tiles]}") if wm[:tiles].positive?
279
- convert.resize("#{wm[:resize]}%") if wm[:resize]
280
- when 'banner'
281
- banner_width = wm[:width] || [0.03 * im_height, 20].max.round(0)
282
- banner_border = banner_width / 3
283
- convert.background "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
284
- convert.size("#{im_height}x#{banner_width}")
285
- convert.bordercolor "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
286
- convert.border "0x#{banner_border}"
287
- convert.fill "rgb(#{wm[:text_red]},#{wm[:text_green]},#{wm[:text_blue]})"
288
- convert.font "Liberation-Sans"
289
- convert.pointsize wm[:size] if wm[:size]
290
- convert.gravity 'Center'
291
- convert << "label:#{wm[:data]}#{wm[:add_filename] ? File.basename(source, '.*') : ''}"
292
- end
293
-
294
- # Save watermark image to buffer
295
- convert.write('mpr:watermark').delete.+
296
-
297
- # Restore canvas to source image size (workaround for IM bug when loading JP2K files)
298
- convert.size("#{im_width}x#{im_height}")
299
- end
116
+ if @page
117
+ image = MiniMagick::Image.open(source) { |b| b.quiet }
118
+ source = image.pages[@page].path if image.pages.size > 1
119
+ end
300
120
 
301
- # load source image
121
+ MiniMagick::Tool::Convert.new do |convert|
122
+ convert.quiet if @quiet
302
123
  convert << source
303
-
304
- # force flatten image if necessary
305
124
  convert.flatten if @options[:flatten].nil? && format == :JPG
306
-
307
- # add watermark image
308
- if wm
309
- if wm[:command] == 'banner'
310
- convert.rotate '-90'
311
- convert << 'mpr:watermark'
312
- convert.rotate '180'
313
- convert.append
314
- convert.rotate '-90'
315
- else
316
- if (0..1).include? wm[:tiles]
317
- convert << 'mpr:watermark'
318
- else
319
- convert.stack do |stack|
320
- stack.size("#{image_info['width']}x#{image_info['height']}")
321
- stack << 'xc:transparent'
322
- stack.tile('mpr:watermark')
323
- stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
324
- end
325
- convert.compose(wm[:composition])
326
- convert.gravity(wm[:gravity])
327
- convert.define("compose:args=#{wm[:opacity]}%")
328
- convert.composite
329
- end
330
- end
125
+ @flags.each {|f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f)}
126
+ if @delete_date
127
+ convert << '+set' << 'modify-date' << '+set' << 'create-date'
331
128
  end
332
129
 
333
- @flags.each { |f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f) }
334
- convert << '+set' << 'modify-date' << '+set' << 'create-date' if @delete_date
335
-
336
130
  colorspace = @options.delete(:colorspace) || 'sRGB'
337
131
  unless @options.empty?
338
132
  convert.colorspace('RGB')
339
- @options.each { |o, v| convert.send(o, v) }
133
+ @options.each {|o, v| convert.send(o, v)}
340
134
  end
341
135
  convert.colorspace(colorspace)
342
136
  convert.profile @profile if @profile
@@ -348,8 +142,11 @@ module Libis
348
142
  end
349
143
 
350
144
  target
145
+
351
146
  end
147
+
352
148
  end
149
+
353
150
  end
354
151
  end
355
- end
152
+ end
@@ -0,0 +1,80 @@
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
+ class ImageSplitter < Libis::Format::Converter::Base
22
+
23
+ def self.input_types
24
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM]
25
+ end
26
+
27
+ def self.output_types(format = nil)
28
+ return [] unless input_types.include?(format) if format
29
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
30
+ end
31
+
32
+ def self.multipage?(format)
33
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
34
+ end
35
+
36
+ def image_split(_)
37
+ #force usage of this converter
38
+ end
39
+
40
+ def quiet(v)
41
+ @quiet = !!v
42
+ end
43
+
44
+ def convert(source, target, format, opts = {})
45
+ super
46
+
47
+ FileUtils.mkpath(File.dirname(target))
48
+
49
+ if self.class.multipage?(format)
50
+ target = File.join(File.dirname(target), "#{File.basename(target, '.*')}-%d#{File.extname(target)}")
51
+ end
52
+
53
+ result = split_image(source, target, format)
54
+ return nil unless result
55
+ target
56
+
57
+ end
58
+
59
+ private
60
+
61
+ def split_image(source, target, format)
62
+
63
+ MiniMagick::Tool::Convert.new do |convert|
64
+ convert.quiet if @quiet
65
+ convert << source
66
+ convert.format(format)
67
+ convert << target
68
+
69
+ debug "ImageMagick command: '#{convert.command.join(' ')}'"
70
+ end
71
+
72
+ target
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
80
+ end