libis-format 1.3.4 → 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 -52
  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 -250
  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 +58 -47
  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 -35
  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,160 +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 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
- # - rotation: rotation of the watermark text (in degrees; integer number)
94
- # - size: font size of the watermark text
95
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0)
96
- # - gap: size of the gap between watermark instances. Integer value is absolute size in points (1/72 inch).
97
- # Fractions are percentage of widht/height.
98
- # If both options are given, the file will be used as-is if it exists and is a valid image file. Otherwise the
99
- # file will be created or overwritten with a newly created watermark image.
100
- #
101
- # The created watermark file will be a PNG image with transparent background containing the supplied text
102
- # slanted by 30 degrees counter-clockwise.
103
- #
104
- # @param [Hash] options Hash of options for watermark creation.
105
-
106
- def watermark(options = {})
107
- options.key_strings_to_symbols!
108
- if options[:file] || options[:image]
109
- watermark_image(options)
110
- elsif options[:text]
111
- watermark_text(options)
112
- elsif options[:banner]
113
- watermark_banner(options)
114
- end
115
- end
116
-
117
- # Use an image as watermark
118
- #
119
- # Next to the :file or :image option, this enables the following options:
120
- # - tiles: number of tiles of the watermark - default 4
121
- # 0: no tiling, so only 1 watermark will be placed with the original size
122
- # 1: 1 tile, so the watermark will be scaled up to fill the image
123
- # n > 1: minimum n tiles in both directions
124
- # n < 0: tile without scaling the watermark
125
- # - size: same as tiles - for backwards compatibility
126
- # - resize: fraction 0.0 - 1.0
127
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
128
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
129
- # - gravity: center point of the overlay - default 'center'
130
- # - composition: algorithm to use to compose both images - default modulate
131
- def watermark_image(options = {})
132
- options.key_strings_to_symbols!
133
- @options[:watermark] = {command: 'image'}
134
- @options[:watermark][:data] = options[:file] || options[:image]
135
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
136
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
137
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
138
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
139
- @options[:watermark][:gravity] = options[:gravity] || 'center'
140
- @options[:watermark][:composition] = options[:composition] || 'modulate'
141
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
142
- end
143
-
144
- # Use text as watermark
145
- #
146
- # Next to the :text option, this enables the following options:
147
- # - tiles: number of tiles of the watermark - default 4
148
- # 0: no tiling, so only 1 watermark will be placed with the original size
149
- # 1: 1 tile, so the watermark will be scaled up to fill the image
150
- # n > 1: minimum n tiles in both directions
151
- # n < 0: tile without scaling the watermark
152
- # - size: same as tiles - for backwards compatibility
153
- # - resize: fraction 0.0 - 1.0
154
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
155
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
156
- # - gravity: center point of the overlay - default 'center'
157
- # - composition: algorithm to use to compose both images - default modulate
158
- # - rotation: rotation of the text
159
- def watermark_text(options = {})
160
- options.key_strings_to_symbols!
161
- @options[:watermark] = {command: 'text'}
162
- @options[:watermark][:data] = options[:text] || '© LIBIS'
163
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
164
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
165
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
166
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
167
- @options[:watermark][:gravity] = options[:gravity] || 'center'
168
- @options[:watermark][:composition] = options[:composition] || 'modulate'
169
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
170
- end
171
-
172
- # Create a vertical banner to the right side of each page
173
- #
174
- # The banner options are:
175
- # - banner: text to put in the banner
176
- # - add_filename: append filename to the text (use any value to enable)
177
- # - fontsize: size of the font (in points) (default: autoscale)
178
- # - width: width of the banner (default: 3% of image height). Not including a border of 30% of the banner width
179
- # - background_color_(red|green|blue): color components of background (default: rgb(84,190,233))
180
- # - text_color_(red|green|blue): color components of background (default: rgb(255,255,255))
181
- def watermark_banner(options = {})
182
- options.key_strings_to_symbols!
183
- @options[:watermark] = {command: 'banner'}
184
- @options[:watermark][:data] = options[:banner] || '© LIBIS'
185
- @options[:watermark][:add_filename] = !!options[:add_filename]
186
- @options[:watermark][:size] = options[:fontsize] if options[:fontsize]
187
- @options[:watermark][:width] = options[:width] if options[:width]
188
- @options[:watermark][:background_red] = options[:background_color_red] || 84
189
- @options[:watermark][:background_green] = options[:background_color_green] || 190
190
- @options[:watermark][:background_blue] = options[:background_color_blue] || 233
191
- @options[:watermark][:text_red] = options[:text_color_red] || 255
192
- @options[:watermark][:text_green] = options[:text_color_green] || 255
193
- @options[:watermark][:text_blue] = options[:text_color_blue] || 255
98
+ self
194
99
  end
195
100
 
196
101
  def convert(source, target, format, opts = {})
@@ -198,147 +103,34 @@ module Libis
198
103
 
199
104
  FileUtils.mkpath(File.dirname(target))
200
105
 
201
- if source.is_a? Array
202
-
203
- assemble_and_convert(source, target, format)
204
-
205
- elsif File.directory?(source)
206
- source_list = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
207
-
208
- assemble_and_convert(source_list, target, format)
106
+ convert_image(source, target, format)
209
107
 
210
- else
211
-
212
- image = MiniMagick::Image.open(source) { |b| b.quiet } # rubocop:disable Style/SymbolProc
213
-
214
- if image.pages.size > 1
215
- if @page
216
- convert_image(image.pages[@page].path, target, format)
217
- else
218
- # noinspection RubyBlockToMethodReference
219
- assemble_and_convert(image.pages.map(&:path), target, format)
220
- end
221
- else
222
- convert_image(source, target, format)
223
- end
224
- end
108
+ target
225
109
 
226
- {
227
- files: [target],
228
- converter: self.class.name
229
- }
230
- end
231
-
232
- def assemble_and_convert(sources, target, format)
233
- warn 'Received multiple images as input and single page format as target.' unless self.class.multipage?(format)
234
- converted_pages = sources.inject([]) do |list, path|
235
- # noinspection RubyArgCount
236
- converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
237
- convert_image(path, converted.path, format)
238
- list << converted
239
- end
240
- MiniMagick.convert do |b|
241
- b.append unless self.class.multipage?(format)
242
- converted_pages.each { |page| b << page.path }
243
- b << target
244
- end
245
- converted_pages.each do |temp_file|
246
- temp_file.close
247
- temp_file.unlink
248
- end
249
110
  end
250
111
 
251
112
  protected
252
113
 
253
114
  def convert_image(source, target, format)
254
- image_info = nil
255
-
256
- MiniMagick.convert do |convert|
257
- # Make converter silent
258
- convert.quiet if @quiet
259
115
 
260
- # Build watermark image in buffer
261
- wm = @options.delete(:watermark)
262
- if wm
263
- image_info = MiniMagick::Image::Info.new(source) { |b| b.quiet }
264
- case wm[:command]
265
- when 'text'
266
- convert.background 'transparent'
267
- convert.size('2000x2000')
268
- convert.gravity 'Center'
269
- convert.font('Helvetica').fill('black').pointsize(72) # .stroke('black').strokewidth(1)
270
- convert << "label:#{wm[:data]}"
271
- convert.rotate wm[:rotation]
272
- convert.trim.repage.+ # rubocop:disable Lint/Void
273
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
274
- convert.filter('Lagrange')
275
- convert.resize("#{image_info['width'] / wm[:tiles]}x#{image_info['height'] / wm[:tiles]}") if wm[:tiles].positive?
276
- convert.resize("#{wm[:resize]}%") if wm[:resize]
277
- when 'image'
278
- convert << wm[:data]
279
- convert.background 'transparent'
280
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
281
- convert.rotate wm[:rotation]
282
- convert.filter('Lagrange')
283
- convert.resize("#{image_info['width'] / wm[:tiles]}x#{image_info['height'] / wm[:tiles]}") if wm[:tiles].positive?
284
- convert.resize("#{wm[:resize]}%") if wm[:resize]
285
- when 'banner'
286
- banner_width = wm[:width] || [0.03 * image_info['height'], 20].max.round(0)
287
- banner_border = banner_width / 3
288
- convert.background "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
289
- convert.size("#{image_info['height']}x#{banner_width}")
290
- convert.bordercolor "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
291
- convert.border "0x#{banner_border}"
292
- convert.fill "rgb(#{wm[:text_red]},#{wm[:text_green]},#{wm[:text_blue]})"
293
- convert.font "Liberation-Sans"
294
- convert.pointsize wm[:size] if wm[:size]
295
- convert.gravity 'Center'
296
- convert << "label:#{wm[:data]}#{wm[:add_filename] ? File.basename(source, '.*') : ''}"
297
- end
298
-
299
- # Save watermark image to buffer
300
- convert.write('mpr:watermark').delete.+
301
- 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
302
120
 
303
- # load source image
121
+ MiniMagick::Tool::Convert.new do |convert|
122
+ convert.quiet if @quiet
304
123
  convert << source
305
-
306
- # force flatten image if necessary
307
124
  convert.flatten if @options[:flatten].nil? && format == :JPG
308
-
309
- # add watermark image
310
- if wm
311
- if wm[:command] == 'banner'
312
- convert.rotate '-90'
313
- convert << 'mpr:watermark'
314
- convert.rotate '180'
315
- convert.append
316
- convert.rotate '-90'
317
- else
318
- if (0..1).include? wm[:tiles]
319
- convert << 'mpr:watermark'
320
- else
321
- convert.stack do |stack|
322
- stack.size("#{image_info['width']}x#{image_info['height']}")
323
- stack << 'xc:transparent'
324
- stack.tile('mpr:watermark')
325
- stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
326
- end
327
- convert.compose(wm[:composition])
328
- convert.gravity(wm[:gravity])
329
- convert.define("compose:args=#{wm[:opacity]}%")
330
- convert.composite
331
- end
332
- 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'
333
128
  end
334
129
 
335
- @flags.each { |f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f) }
336
- convert << '+set' << 'modify-date' << '+set' << 'create-date' if @delete_date
337
-
338
130
  colorspace = @options.delete(:colorspace) || 'sRGB'
339
131
  unless @options.empty?
340
132
  convert.colorspace('RGB')
341
- @options.each { |o, v| convert.send(o, v) }
133
+ @options.each {|o, v| convert.send(o, v)}
342
134
  end
343
135
  convert.colorspace(colorspace)
344
136
  convert.profile @profile if @profile
@@ -350,8 +142,11 @@ module Libis
350
142
  end
351
143
 
352
144
  target
145
+
353
146
  end
147
+
354
148
  end
149
+
355
150
  end
356
151
  end
357
- 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