libis-format 1.3.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.gitignore +20 -0
- data/.travis.yml +70 -0
- data/Gemfile +0 -12
- data/README.md +2 -2
- data/Rakefile +8 -0
- data/base/Dockerfile +35 -0
- data/base/Dockerfile.alpine +20 -0
- data/base/Dockerfile.rvm +56 -0
- data/base/rework_path +20 -0
- data/bin/{pdf_tool → pdf_copy} +2 -3
- data/data/PDFA_def.ps +3 -3
- data/data/eciRGB_v2.icc +0 -0
- data/data/types.yml +4 -17
- data/docker_cfg.yml +1 -0
- data/lib/libis/format/cli/convert.rb +4 -4
- data/lib/libis/format/cli/prompt_helper.rb +24 -32
- data/lib/libis/format/command_line.rb +3 -2
- data/lib/libis/format/config.rb +23 -19
- data/lib/libis/format/converter/audio_converter.rb +31 -56
- data/lib/libis/format/converter/base.rb +36 -16
- data/lib/libis/format/converter/chain.rb +32 -52
- data/lib/libis/format/converter/fop_pdf_converter.rb +8 -4
- data/lib/libis/format/converter/image_assembler.rb +82 -0
- data/lib/libis/format/converter/image_converter.rb +45 -250
- data/lib/libis/format/converter/image_splitter.rb +80 -0
- data/lib/libis/format/converter/image_watermarker.rb +261 -0
- data/lib/libis/format/converter/jp2_converter.rb +38 -36
- data/lib/libis/format/converter/office_converter.rb +28 -22
- data/lib/libis/format/converter/pdf_assembler.rb +66 -0
- data/lib/libis/format/converter/pdf_converter.rb +52 -200
- data/lib/libis/format/converter/pdf_optimizer.rb +70 -0
- data/lib/libis/format/converter/pdf_splitter.rb +65 -0
- data/lib/libis/format/converter/pdf_watermarker.rb +110 -0
- data/lib/libis/format/converter/repository.rb +13 -7
- data/lib/libis/format/converter/spreadsheet_converter.rb +16 -10
- data/lib/libis/format/converter/video_converter.rb +58 -47
- data/lib/libis/format/converter/xslt_converter.rb +11 -13
- data/lib/libis/format/converter.rb +1 -1
- data/lib/libis/format/identifier.rb +46 -44
- data/lib/libis/format/info.rb +27 -0
- data/lib/libis/format/library.rb +147 -0
- data/lib/libis/format/tool/droid.rb +30 -29
- data/lib/libis/format/tool/extension_identification.rb +26 -24
- data/lib/libis/format/tool/{ff_mpeg.rb → ffmpeg.rb} +10 -17
- data/lib/libis/format/tool/fido.rb +27 -22
- data/lib/libis/format/tool/file_tool.rb +24 -11
- data/lib/libis/format/tool/fop_pdf.rb +14 -25
- data/lib/libis/format/tool/identification_tool.rb +40 -38
- data/lib/libis/format/tool/office_to_pdf.rb +18 -30
- data/lib/libis/format/tool/pdf_copy.rb +47 -0
- data/lib/libis/format/tool/pdf_merge.rb +19 -25
- data/lib/libis/format/tool/pdf_optimizer.rb +19 -22
- data/lib/libis/format/tool/pdf_split.rb +33 -6
- data/lib/libis/format/tool/pdf_to_pdfa.rb +31 -45
- data/lib/libis/format/tool/pdfa_validator.rb +30 -24
- data/lib/libis/format/tool/spreadsheet_to_ods.rb +18 -29
- data/lib/libis/format/tool.rb +3 -4
- data/lib/libis/format/version.rb +1 -3
- data/lib/libis/format/yaml_loader.rb +71 -0
- data/lib/libis/format.rb +7 -5
- data/lib/libis-format.rb +0 -2
- data/libis-format.gemspec +18 -24
- data/tools/PdfTool.jar +0 -0
- data/tools/pdfbox/pdfbox-app-2.0.13.jar +0 -0
- data/tools/pdfbox/{preflight-app-3.0.3.jar → preflight-app-2.0.13.jar} +0 -0
- metadata +86 -128
- data/data/AdobeRGB1998.icc +0 -0
- data/lib/libis/format/converter/email_converter.rb +0 -35
- data/lib/libis/format/tool/msg_to_pdf.rb +0 -270
- data/lib/libis/format/tool/pdf_tool.rb +0 -52
- data/lib/libis/format/type_database.rb +0 -156
- data/lib/libis/format/type_database_impl.rb +0 -153
- data/tools/pdf2pdfa +0 -395
- data/tools/pdfbox/pdfbox-app-3.0.3.jar +0 -0
- /data/bin/{droid_tool → droid} +0 -0
- /data/bin/{fido_tool → fido} +0 -0
@@ -0,0 +1,261 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require 'libis/format/identifier'
|
5
|
+
|
6
|
+
require 'mini_magick'
|
7
|
+
# noinspection RubyResolve
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
MiniMagick.logger.level = ::Logger::UNKNOWN
|
11
|
+
|
12
|
+
MiniMagick.configure do |config|
|
13
|
+
# config.cli = :graphicsmagick
|
14
|
+
config.validate_on_create = false
|
15
|
+
config.validate_on_write = false
|
16
|
+
config.whiny = false
|
17
|
+
end
|
18
|
+
|
19
|
+
module Libis
|
20
|
+
module Format
|
21
|
+
module Converter
|
22
|
+
|
23
|
+
# noinspection RubyTooManyInstanceVariablesInspection
|
24
|
+
class ImageWatermarker < Libis::Format::Converter::Base
|
25
|
+
|
26
|
+
def self.input_types
|
27
|
+
[:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.output_types(format = nil)
|
31
|
+
return [] unless input_types.include?(format) if format
|
32
|
+
[format]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.multipage?(format)
|
36
|
+
[:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
super
|
41
|
+
@quiet = true
|
42
|
+
@wm_image = nil
|
43
|
+
@wm_file = nil
|
44
|
+
@wm_text = '© LIBIS'
|
45
|
+
@wm_tiles = 4
|
46
|
+
@wm_resize = nil
|
47
|
+
@wm_gap = 20
|
48
|
+
@wm_gravity = 'Center'
|
49
|
+
@wm_rotation = 30
|
50
|
+
@wm_composition ='modulate'
|
51
|
+
@wm_composition_args = '10'
|
52
|
+
end
|
53
|
+
|
54
|
+
def image_watermark(_)
|
55
|
+
#force usage of this converter
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def quiet(v)
|
60
|
+
@quiet = !!v
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def page(v)
|
65
|
+
@page = v.to_i
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# watermark image to use
|
70
|
+
def file(v)
|
71
|
+
@wm_file = v.blank? ? nil : v
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# text to create a watermark from
|
76
|
+
def text(v)
|
77
|
+
@wm_text = v.blank? ? nil : v
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
# rotation of the watermark text (counter clockwise in degrees; integer number)
|
82
|
+
# default 30
|
83
|
+
def rotation(v)
|
84
|
+
@wm_rotation = v.to_i
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# number of tiles of the watermark
|
89
|
+
# default 4
|
90
|
+
# 0: no tiling, so only 1 watermark will be placed with the original size
|
91
|
+
# 1: 1 tile, so the watermark will be scaled up to fill the image
|
92
|
+
# n > 1: minimum n tiles in both directions
|
93
|
+
# n < 0: tile without scaling the watermark
|
94
|
+
def tiles(v)
|
95
|
+
@wm_tiles = v.to_i
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
# fraction 0.0 - 1.0
|
100
|
+
def resize(v)
|
101
|
+
@wm_resize = (v.to_f * 100).to_i
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# size of the gap between watermark instances. Fractions as percentage of widht/height
|
106
|
+
# default 0.2
|
107
|
+
def gap(v)
|
108
|
+
@wm_gap = (v.to_f * 100).to_i
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
# center point for the watermark overlay
|
113
|
+
# default 'center'
|
114
|
+
def gravity(v)
|
115
|
+
@wm_gravity = v.blank? ? nil : v
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
# the image composition method for merging the watermark image
|
120
|
+
# default 'modulate'
|
121
|
+
# See https://imagemagick.org/script/compose.php for more information
|
122
|
+
def composition(v)
|
123
|
+
@wm_composition = v.blank? ? nil : v
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
# arguments for the composition method
|
128
|
+
# default '10'
|
129
|
+
# See https://imagemagick.org/script/compose.php for more information
|
130
|
+
def composition_args(v)
|
131
|
+
@wm_composition_args = v.blank? ? nil : v
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def convert(source, target, format, opts = {})
|
137
|
+
super
|
138
|
+
|
139
|
+
FileUtils.mkpath(File.dirname(target))
|
140
|
+
|
141
|
+
if source.is_a?(Array) || File.directory?(source)
|
142
|
+
error 'Only a single image file is allowed for input'
|
143
|
+
else
|
144
|
+
image = MiniMagick::Image.open(source) { |b| b.quiet }
|
145
|
+
|
146
|
+
if image.pages.size > 1
|
147
|
+
if @page
|
148
|
+
convert_image(image.pages[@page].path, target, format)
|
149
|
+
else
|
150
|
+
error 'multipage input file detecte; you need to supply a page number'
|
151
|
+
end
|
152
|
+
else
|
153
|
+
convert_image(source, target, format)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
target
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
# noinspection DuplicatedCode
|
164
|
+
def convert_image(source, target, format)
|
165
|
+
|
166
|
+
wm_image = watermark_image
|
167
|
+
return nil unless wm_image
|
168
|
+
image_info = MiniMagick::Image::Info.new(source) {|b| b.quiet}
|
169
|
+
|
170
|
+
MiniMagick::Tool::Convert.new do |convert|
|
171
|
+
convert.quiet if @quiet
|
172
|
+
|
173
|
+
# adapt watermark image to tile size and apply gap and resize if necessary
|
174
|
+
convert << @wm_image.path
|
175
|
+
# noinspection RubyResolve
|
176
|
+
convert.bordercolor('transparent').border("#{@wm_gap}%") if @wm_gap > 0
|
177
|
+
convert.filter('Lagrange')
|
178
|
+
convert.resize("#{image_info['width'] / @wm_tiles}x#{image_info['height'] / @wm_tiles}") if @wm_tiles > 0
|
179
|
+
convert.resize("#{@wm_resize}%") if @wm_resize
|
180
|
+
convert.write('mpr:watermark').delete.+
|
181
|
+
|
182
|
+
# convert the source image
|
183
|
+
convert << source
|
184
|
+
if @wm_tiles >= 0 and @wm_tiles <= 1
|
185
|
+
# only 1 watermark required (tiles = 0/1 => scaled no/yes)
|
186
|
+
convert << 'mpr:watermark'
|
187
|
+
else
|
188
|
+
# fill the image size with a pattern of the watermark image
|
189
|
+
convert.stack do |stack|
|
190
|
+
stack.size("#{image_info['width']}x#{image_info['height']}")
|
191
|
+
stack << 'xc:transparent'
|
192
|
+
# noinspection RubyResolve
|
193
|
+
stack.tile('mpr:watermark')
|
194
|
+
# noinspection RubyResolve
|
195
|
+
stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
# perform the blending operation
|
199
|
+
convert.compose(@wm_composition).gravity(@wm_gravity).define("compose:args=#{@wm_composition_args}").composite
|
200
|
+
|
201
|
+
convert.format(format)
|
202
|
+
convert << target
|
203
|
+
|
204
|
+
debug "ImageMagick command: '#{convert.command.join(' ')}'"
|
205
|
+
end
|
206
|
+
|
207
|
+
target
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
# Create or use a watermark image.
|
214
|
+
#
|
215
|
+
# If both text and image are set, the file will be used as-is if it exists and is a valid image file. Otherwise the
|
216
|
+
# file will be created or overwritten with a newly created watermark image.
|
217
|
+
#
|
218
|
+
# The created watermark file will be a 2000x2000 pixels PNG image with transparent background
|
219
|
+
#
|
220
|
+
# The text will be slanted by given rotation degrees counter-clockwise
|
221
|
+
def watermark_image
|
222
|
+
rotation = 360 - @wm_rotation
|
223
|
+
@wm_image = MiniMagick::Image.new(@wm_file) if @wm_file
|
224
|
+
# only create image if file is not an image
|
225
|
+
unless @wm_image&.valid?
|
226
|
+
# noinspection RubyResolve
|
227
|
+
# Create image file (as given or temp file)
|
228
|
+
image = @wm_file || (Dir::Tmpname.create(%w(wm_image .png)) {|_|})
|
229
|
+
# noinspection RubyResolve
|
230
|
+
MiniMagick::Tool::Convert.new do |convert|
|
231
|
+
convert.quiet # allways quiet
|
232
|
+
convert.background 'transparent'
|
233
|
+
convert.size('2000x2000')
|
234
|
+
convert.gravity 'Center'
|
235
|
+
convert.font('Helvetica').fill('black').pointsize(72) #.stroke('black').strokewidth(1)
|
236
|
+
convert << "label:#{@wm_text}"
|
237
|
+
convert.rotate rotation
|
238
|
+
convert.trim.repage.+
|
239
|
+
convert << image
|
240
|
+
end
|
241
|
+
if @wm_file
|
242
|
+
@wm_image = MiniMagick::Image.new(image)
|
243
|
+
else # delete temp file
|
244
|
+
@wm_image = MiniMagick::Image.open(image)
|
245
|
+
File.delete(image)
|
246
|
+
end
|
247
|
+
# noinspection RubyResolve
|
248
|
+
unless @wm_image.valid?
|
249
|
+
error "Problem creating watermark image '#{image}'."
|
250
|
+
@wm_image = nil
|
251
|
+
end
|
252
|
+
@wm_image
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# encoding: utf-8
|
3
2
|
require 'libis-tools'
|
4
3
|
require 'fileutils'
|
5
4
|
require 'libis/format/config'
|
@@ -8,31 +7,32 @@ require_relative 'base'
|
|
8
7
|
module Libis
|
9
8
|
module Format
|
10
9
|
module Converter
|
10
|
+
|
11
11
|
class Jp2Converter < Libis::Format::Converter::Base
|
12
|
+
|
12
13
|
def self.input_types
|
13
|
-
|
14
|
+
[:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF]
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.output_types(format = nil)
|
17
|
-
return [] unless input_types.include?(format)
|
18
|
-
|
18
|
+
return [] unless input_types.include?(format) if format
|
19
19
|
[:JP2]
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize
|
23
23
|
super
|
24
24
|
@options = {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
color_xform: false,
|
26
|
+
error_resilience: :ALL,
|
27
|
+
lossless: true,
|
28
|
+
progression_order: 'RLCP',
|
29
|
+
tile_size: [1024, 1024],
|
30
|
+
codeblock_size: [6, 6],
|
31
31
|
}
|
32
32
|
end
|
33
33
|
|
34
34
|
def j2kdriver(_)
|
35
|
-
#
|
35
|
+
#force usage of this converter
|
36
36
|
end
|
37
37
|
|
38
38
|
def color_xform(flag = true)
|
@@ -68,36 +68,38 @@ module Libis
|
|
68
68
|
|
69
69
|
@options.each do |key, value|
|
70
70
|
case key
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
when :color_xform
|
72
|
+
options << '--set-output-j2k-color-xform' << (value ? 'YES' : 'NO')
|
73
|
+
when :error_resilience
|
74
|
+
options << '--set-output-j2k-error-resilience' << value.to_s
|
75
|
+
when :lossless
|
76
|
+
if value
|
77
|
+
options << '--set-output-j2k-xform' << 'R53' << '5' << '--set-output-j2k-ratio' << '0'
|
78
|
+
else
|
79
|
+
options << '--set-output-j2k-xform' << 'I97' << '--set-output-j2k-psnr' << '46'
|
80
|
+
end
|
81
|
+
when :progression_order
|
82
|
+
options << '--set-output-j2k-progression-order' << value.to_s
|
83
|
+
when :tile_size
|
84
|
+
options << '--set-output-j2k-tile-size' << value[0].to_s << value[1].to_s
|
85
|
+
when :codeblock_size
|
86
|
+
options << '--set-output-j2k-codeblock-size' << value[0].to_s << value[1].to_s
|
78
87
|
else
|
79
|
-
|
80
|
-
end
|
81
|
-
when :progression_order
|
82
|
-
options << '--set-output-j2k-progression-order' << value.to_s
|
83
|
-
when :tile_size
|
84
|
-
options << '--set-output-j2k-tile-size' << value[0].to_s << value[1].to_s
|
85
|
-
when :codeblock_size
|
86
|
-
options << '--set-output-j2k-codeblock-size' << value[0].to_s << value[1].to_s
|
87
|
-
else # rubocop:disable Style/EmptyElse
|
88
|
-
# do nothing
|
88
|
+
#do nothing
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
92
|
+
|
93
|
+
Libis::Tools::Command.run(
|
94
|
+
Libis::Format::Config[:j2k_cmd],
|
95
|
+
'--input-file-name', source,
|
96
|
+
'--set-output-type', 'JP2',
|
97
|
+
*options,
|
98
|
+
'--output-file-name', target,
|
99
|
+
|
98
100
|
)
|
99
101
|
|
100
|
-
|
102
|
+
target
|
101
103
|
end
|
102
104
|
end
|
103
105
|
end
|
@@ -1,50 +1,56 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
3
|
require_relative 'base'
|
4
4
|
|
5
5
|
require 'libis/format/tool/office_to_pdf'
|
6
|
-
require 'libis/format/
|
6
|
+
require 'libis/format/library'
|
7
7
|
|
8
8
|
module Libis
|
9
9
|
module Format
|
10
10
|
module Converter
|
11
|
+
|
11
12
|
class OfficeConverter < Libis::Format::Converter::Base
|
13
|
+
|
12
14
|
def self.input_types
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
15
|
+
[
|
16
|
+
:TXT,
|
17
|
+
:RTF,
|
18
|
+
:HTML,
|
19
|
+
:MSDOC,
|
20
|
+
:MSDOT,
|
21
|
+
:MSXLS,
|
22
|
+
:MSPPT,
|
23
|
+
:MSDOCX,
|
24
|
+
:MSDOTX,
|
25
|
+
:MSXLSX,
|
26
|
+
:MSPPTX,
|
27
|
+
:WORDPERFECT,
|
28
|
+
:OO_WRITER,
|
29
|
+
:OO_IMPRESS,
|
30
|
+
:OO_CALC
|
29
31
|
]
|
30
32
|
end
|
31
33
|
|
32
34
|
def self.output_types(format = nil)
|
33
|
-
return [] unless input_types.include?(format)
|
34
|
-
|
35
|
+
return [] unless input_types.include?(format) if format
|
35
36
|
[:PDF]
|
36
37
|
end
|
37
38
|
|
38
39
|
def office_convert(_)
|
39
|
-
#
|
40
|
+
#force usage of this converter
|
40
41
|
end
|
41
42
|
|
42
43
|
def convert(source, target, format, opts = {})
|
43
44
|
super
|
44
45
|
|
45
|
-
Format::Tool::OfficeToPdf.run(source, target)
|
46
|
+
return nil unless Format::Tool::OfficeToPdf.run(source, target)
|
47
|
+
|
48
|
+
target
|
49
|
+
|
46
50
|
end
|
51
|
+
|
47
52
|
end
|
53
|
+
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
require 'libis/format/tool/pdf_merge'
|
6
|
+
|
7
|
+
module Libis
|
8
|
+
module Format
|
9
|
+
module Converter
|
10
|
+
|
11
|
+
# noinspection DuplicatedCode
|
12
|
+
class PdfAssembler < Libis::Format::Converter::Base
|
13
|
+
|
14
|
+
def self.input_types
|
15
|
+
[:PDF]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.output_types(format = nil)
|
19
|
+
return [] unless input_types.include?(format) if format
|
20
|
+
[:PDF]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.category
|
24
|
+
:assembler
|
25
|
+
end
|
26
|
+
|
27
|
+
def pdf_assemnble(_)
|
28
|
+
#force usage of this converter
|
29
|
+
end
|
30
|
+
|
31
|
+
def convert(source, target, format, opts = {})
|
32
|
+
super
|
33
|
+
|
34
|
+
result = if source.is_a? Array
|
35
|
+
assemble(source, target)
|
36
|
+
elsif File.directory?(source)
|
37
|
+
source_list = Dir[File.join(source, '**', '*')].reject {|p| File.directory? p}
|
38
|
+
assemble(source_list, target)
|
39
|
+
else
|
40
|
+
assemble([source], target)
|
41
|
+
end
|
42
|
+
return nil unless result
|
43
|
+
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def assemble(source, target)
|
50
|
+
|
51
|
+
result = Libis::Format::Tool::PdfMerge.run(source, target)
|
52
|
+
|
53
|
+
unless result[:err].empty?
|
54
|
+
error("PdfMerge encountered errors:\n%s", result[:err].join(join("\n")))
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
target
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|