libis-format 1.2.9 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/bin/{pdf_copy → pdf_tool} +3 -2
- data/data/types.yml +1 -1
- data/lib/libis/format/command_line.rb +2 -3
- data/lib/libis/format/config.rb +17 -20
- data/lib/libis/format/converter/base.rb +9 -16
- data/lib/libis/format/converter/chain.rb +36 -28
- data/lib/libis/format/converter/email_converter.rb +5 -8
- data/lib/libis/format/converter/fop_pdf_converter.rb +4 -6
- data/lib/libis/format/converter/image_converter.rb +51 -58
- data/lib/libis/format/converter/jp2_converter.rb +33 -35
- data/lib/libis/format/converter/office_converter.rb +19 -23
- data/lib/libis/format/converter/pdf_converter.rb +133 -52
- data/lib/libis/format/converter/repository.rb +7 -13
- data/lib/libis/format/converter/spreadsheet_converter.rb +7 -11
- data/lib/libis/format/converter/video_converter.rb +41 -55
- data/lib/libis/format/converter/xslt_converter.rb +14 -13
- data/lib/libis/format/converter.rb +1 -1
- data/lib/libis/format/identifier.rb +41 -43
- data/lib/libis/format/tool/droid.rb +29 -30
- data/lib/libis/format/tool/ff_mpeg.rb +11 -13
- data/lib/libis/format/tool/fido.rb +1 -1
- data/lib/libis/format/tool/pdf_optimizer.rb +21 -27
- data/lib/libis/format/tool/pdf_to_pdfa.rb +2 -6
- data/lib/libis/format/tool/pdf_tool.rb +52 -0
- data/lib/libis/format/tool/pdfa_validator.rb +2 -3
- data/lib/libis/format/tool/spreadsheet_to_ods.rb +23 -20
- data/lib/libis/format/tool.rb +2 -2
- data/lib/libis/format/type_database.rb +51 -28
- data/lib/libis/format/type_database_impl.rb +57 -24
- data/lib/libis/format/version.rb +1 -1
- data/lib/libis/format.rb +3 -2
- data/lib/libis-format.rb +2 -0
- data/tools/PdfTool.jar +0 -0
- data/tools/pdfbox/pdfbox-app-3.0.3.jar +0 -0
- data/tools/pdfbox/{preflight-app-2.0.13.jar → preflight-app-3.0.3.jar} +0 -0
- metadata +8 -10
- data/lib/libis/format/tool/pdf_copy.rb +0 -57
- data/lib/libis/format/tool/pdf_merge.rb +0 -58
- data/lib/libis/format/tool/pdf_split.rb +0 -56
- data/tools/pdfbox/pdfbox-app-2.0.13.jar +0 -0
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
2
4
|
|
3
5
|
module Libis
|
4
6
|
module Format
|
@@ -9,10 +11,9 @@ module Libis
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def self.output_types(format = nil)
|
12
|
-
if format
|
13
|
-
|
14
|
-
|
15
|
-
[:XML, :HTML, :TXT]
|
14
|
+
return [] if format && !input_types.include?(format)
|
15
|
+
|
16
|
+
%i[XML HTML TXT]
|
16
17
|
end
|
17
18
|
|
18
19
|
def xsl_file(file_path)
|
@@ -28,20 +29,20 @@ module Libis
|
|
28
29
|
end
|
29
30
|
|
30
31
|
unless @options[:xsl_file]
|
31
|
-
error
|
32
|
+
error 'No xsl_file supplied'
|
32
33
|
return nil
|
33
34
|
end
|
34
35
|
|
35
36
|
FileUtils.mkpath(File.dirname(target))
|
36
37
|
|
37
|
-
if RUBY_PLATFORM ==
|
38
|
-
require
|
38
|
+
if RUBY_PLATFORM == 'java'
|
39
|
+
require 'saxon-xslt'
|
39
40
|
xsl = Saxon.XSLT(File.open(@options[:xsl_file]))
|
40
41
|
xml = Saxon.XML(File.open(source))
|
41
42
|
result = xsl.transform(xml)
|
42
43
|
File.write(target, result.to_s)
|
43
44
|
else
|
44
|
-
require
|
45
|
+
require 'nokogiri'
|
45
46
|
|
46
47
|
doc = nil
|
47
48
|
begin
|
@@ -65,7 +66,7 @@ module Libis
|
|
65
66
|
xsl = nil
|
66
67
|
|
67
68
|
begin
|
68
|
-
fp = File.open(file,
|
69
|
+
fp = File.open(file, 'r')
|
69
70
|
xsl = Nokogiri::XSLT(fp) do |config|
|
70
71
|
config.options = Nokogiri::XML::ParseOptions::STRICT | Nokogiri::XML::ParseOptions::NOBLANKS
|
71
72
|
end
|
@@ -80,17 +81,17 @@ module Libis
|
|
80
81
|
|
81
82
|
begin
|
82
83
|
target_xml = xsl.transform(doc)
|
83
|
-
fp = File.open(target,
|
84
|
+
fp = File.open(target, 'w')
|
84
85
|
fp.write(target_xml)
|
85
86
|
rescue Exception => e
|
86
87
|
error "Error transforming '#{source}' with '#{file}': #{e.message} @ #{e.backtrace[0]}"
|
87
88
|
return nil
|
88
89
|
ensure
|
89
|
-
fp.close unless fp.nil?
|
90
|
+
fp.close unless fp.nil? || fp.closed?
|
90
91
|
end
|
91
92
|
|
92
93
|
{
|
93
|
-
command: {status: 0},
|
94
|
+
command: { status: 0 },
|
94
95
|
files: [target]
|
95
96
|
}
|
96
97
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'singleton'
|
4
4
|
require 'pathname'
|
@@ -7,7 +7,6 @@ require 'libis-tools'
|
|
7
7
|
require 'libis/tools/extend/hash'
|
8
8
|
require 'libis/tools/extend/string'
|
9
9
|
require 'libis/tools/extend/empty'
|
10
|
-
require 'nori/core_ext/object'
|
11
10
|
|
12
11
|
require 'libis/format/type_database'
|
13
12
|
|
@@ -19,13 +18,10 @@ require_relative 'tool/extension_identification'
|
|
19
18
|
|
20
19
|
module Libis
|
21
20
|
module Format
|
22
|
-
|
23
21
|
class Identifier
|
24
22
|
include ::Libis::Tools::Logger
|
25
23
|
include Singleton
|
26
24
|
|
27
|
-
public
|
28
|
-
|
29
25
|
def self.add_xml_validation(mimetype, xsd_file)
|
30
26
|
instance.xml_validations[mimetype] = xsd_file
|
31
27
|
end
|
@@ -41,29 +37,28 @@ module Libis
|
|
41
37
|
attr_reader :xml_validations
|
42
38
|
|
43
39
|
def get(file, options = {})
|
44
|
-
|
45
|
-
options[:
|
46
|
-
options[:
|
47
|
-
options[:file] = true unless options.keys.include?(:file) or (options[:tool] and options[:tool] != :file)
|
40
|
+
options[:droid] = true unless options.keys.include?(:droid) || (options[:tool] && (options[:tool] != :droid))
|
41
|
+
options[:fido] = true unless options.keys.include?(:fido) || (options[:tool] && (options[:tool] != :fido))
|
42
|
+
options[:file] = true unless options.keys.include?(:file) || (options[:tool] && (options[:tool] != :file))
|
48
43
|
options[:xml_validation] = true if options[:xml_validation].nil?
|
49
44
|
|
50
|
-
result = {messages: [], output: {}, formats: {}}
|
45
|
+
result = { messages: [], output: {}, formats: {} }
|
51
46
|
|
52
47
|
begin
|
53
48
|
get_droid_identification(file, result, options) if options[:droid]
|
54
|
-
rescue => e
|
49
|
+
rescue StandardError => e
|
55
50
|
log_msg(result, :error, "Error running Droid: #{e.message} @ #{e.backtrace.first}")
|
56
51
|
end
|
57
52
|
|
58
53
|
begin
|
59
54
|
get_fido_identification(file, result, options) if options[:fido]
|
60
|
-
rescue => e
|
55
|
+
rescue StandardError => e
|
61
56
|
log_msg(result, :error, "Error running Fido: #{e.message} @ #{e.backtrace.first}")
|
62
57
|
end
|
63
58
|
|
64
59
|
begin
|
65
60
|
get_file_identification(file, result, options) if options[:file]
|
66
|
-
rescue => e
|
61
|
+
rescue StandardError => e
|
67
62
|
log_msg(result, :error, "Error running File: #{e.message} @ #{e.backtrace.first}")
|
68
63
|
end
|
69
64
|
|
@@ -74,14 +69,13 @@ module Libis
|
|
74
69
|
# Libis::Tools::Format::Identifier.add_xml_validation('my_type', '/path/to/my_type.xsd')
|
75
70
|
begin
|
76
71
|
validate_against_xml_schema(result, options[:base_dir]) if options[:xml_validation]
|
77
|
-
rescue => e
|
72
|
+
rescue StandardError => e
|
78
73
|
log_msg(result, :error, "Error validating XML files: #{e.message} @ #{e.backtrace.first}")
|
79
74
|
end
|
80
75
|
|
81
76
|
process_results(result, !options[:keep_output])
|
82
77
|
|
83
78
|
result
|
84
|
-
|
85
79
|
end
|
86
80
|
|
87
81
|
protected
|
@@ -123,18 +117,21 @@ module Libis
|
|
123
117
|
end
|
124
118
|
|
125
119
|
def xml_validate(file, file_result, result, base_dir)
|
126
|
-
return unless file_result[:mimetype] =~
|
120
|
+
return unless file_result[:mimetype] =~ %r{^(text|application)/xml$}
|
121
|
+
|
127
122
|
filepath = base_dir ? File.join(base_dir, file) : file
|
128
123
|
doc = ::Libis::Tools::XmlDocument.open filepath
|
129
124
|
xml_validations.each do |mime, xsd_file|
|
130
125
|
next unless xsd_file
|
126
|
+
|
131
127
|
begin
|
132
128
|
if doc.validates_against?(xsd_file)
|
133
129
|
log_msg result, :debug, "XML file validated against XML Schema: #{xsd_file}"
|
134
|
-
info = {mimetype: mime, tool_raw: file_result[:tool], tool: :xsd_validation, match_type: 'xsd_validation',
|
130
|
+
info = { mimetype: mime, tool_raw: file_result[:tool], tool: :xsd_validation, match_type: 'xsd_validation',
|
131
|
+
format_version: '' }
|
135
132
|
file_result.merge! Libis::Format::TypeDatabase.enrich(info, PUID: :puid, MIME: :mimetype, NAME: :format_name)
|
136
133
|
end
|
137
|
-
rescue => e
|
134
|
+
rescue StandardError => e
|
138
135
|
# Do nothing - probably Nokogiri chrashed during validation. Could have many causes
|
139
136
|
# (remote schema (firewall, network, link rot, ...), schema syntax error, corrupt XML,...)
|
140
137
|
# so we log and continue.
|
@@ -142,7 +139,7 @@ module Libis
|
|
142
139
|
"Error during XML validation of file #{file} against #{File.basename(xsd_file)}: #{e.message}")
|
143
140
|
end
|
144
141
|
end
|
145
|
-
rescue => e
|
142
|
+
rescue StandardError => e
|
146
143
|
# Not much we can do. probably Nokogiri chrashed opening the XML file. What caused this?
|
147
144
|
# (XML not parsable, false XML identification, ???)
|
148
145
|
# so we log and continue.
|
@@ -150,30 +147,30 @@ module Libis
|
|
150
147
|
end
|
151
148
|
|
152
149
|
def process_results(result, delete_output = true)
|
153
|
-
result[:output].
|
150
|
+
result[:output].each_key do |file|
|
154
151
|
output = result[:output][file]
|
155
152
|
file_result = result[:formats][file] = {}
|
156
153
|
if output.empty?
|
157
154
|
log_msg(result, :warn, "Could not identify format of '#{file}'.")
|
158
|
-
file_result
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
155
|
+
file_result.merge!(
|
156
|
+
mimetype: 'application/octet-stream',
|
157
|
+
puid: 'fmt/unknown',
|
158
|
+
score: 0,
|
159
|
+
tool: nil
|
160
|
+
)
|
164
161
|
else
|
165
|
-
format_matches = output.group_by {|x| [x[:mimetype], x[:puid]]}
|
162
|
+
format_matches = output.group_by { |x| [x[:mimetype], x[:puid]] }
|
166
163
|
format_matches.each do |match, group|
|
167
|
-
format_matches[match] = group.group_by {|x| x[:score]}.sort.reverse.to_h
|
164
|
+
format_matches[match] = group.group_by { |x| x[:score] }.sort.reverse.to_h
|
168
165
|
end
|
169
166
|
case format_matches.count
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
167
|
+
when 0
|
168
|
+
# No this really cannot happen. If there are no hits, there will be at least a format [nil,nil]
|
169
|
+
when 1
|
170
|
+
# only one match, that's easy. The first of the highest score will be used
|
171
|
+
file_result.merge!(get_best_result(output))
|
172
|
+
else
|
173
|
+
process_multiple_formats(file_result, format_matches, output)
|
177
174
|
end
|
178
175
|
end
|
179
176
|
end
|
@@ -184,12 +181,13 @@ module Libis
|
|
184
181
|
# multiple matches. Let's select the highest score matches
|
185
182
|
file_result.merge!(get_best_result(output))
|
186
183
|
file_result[:alternatives] = []
|
187
|
-
format_matches.
|
184
|
+
format_matches.each_key do |mime, puid|
|
188
185
|
next if file_result[:mimetype] == mime && puid.nil?
|
189
|
-
|
186
|
+
|
187
|
+
selection = output.select { |x| x[:mimetype] == mime && x[:puid] == puid }
|
190
188
|
file_result[:alternatives] << get_best_result(selection)
|
191
189
|
end
|
192
|
-
file_result[:alternatives] = file_result[:alternatives].sort_by {|x| x[:score]}.reverse
|
190
|
+
file_result[:alternatives] = file_result[:alternatives].sort_by { |x| x[:score] }.reverse
|
193
191
|
file_result.delete(:alternatives) if file_result[:alternatives].size <= 1
|
194
192
|
end
|
195
193
|
|
@@ -208,15 +206,15 @@ module Libis
|
|
208
206
|
end
|
209
207
|
|
210
208
|
def get_mimetype(puid)
|
211
|
-
::Libis::Format::TypeDatabase.puid_typeinfo(puid)[:MIME].first
|
209
|
+
::Libis::Format::TypeDatabase.puid_typeinfo(puid)[:MIME].first
|
210
|
+
rescue StandardError
|
211
|
+
nil
|
212
212
|
end
|
213
213
|
|
214
214
|
def get_best_result(results)
|
215
|
-
score = results.map {|x| x[:score]}.max
|
216
|
-
results.select {|x| x[:score] == score}.reduce(:apply_defaults)
|
215
|
+
score = results.map { |x| x[:score] }.max
|
216
|
+
results.select { |x| x[:score] == score }.reduce(:apply_defaults)
|
217
217
|
end
|
218
|
-
|
219
218
|
end
|
220
|
-
|
221
219
|
end
|
222
220
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'singleton'
|
2
4
|
|
3
5
|
require 'tempfile'
|
@@ -5,10 +7,10 @@ require 'csv'
|
|
5
7
|
|
6
8
|
require 'libis/format/config'
|
7
9
|
|
8
|
-
unless CSV::HeaderConverters.
|
9
|
-
CSV::HeaderConverters[:droid_headers] = lambda {|h|
|
10
|
-
h.encode(ConverterEncoding).downcase.strip
|
11
|
-
|
10
|
+
unless CSV::HeaderConverters.key?(:droid_headers)
|
11
|
+
CSV::HeaderConverters[:droid_headers] = lambda { |h|
|
12
|
+
h.encode(ConverterEncoding).downcase.strip
|
13
|
+
.gsub(/\W+/, '').to_sym
|
12
14
|
}
|
13
15
|
end
|
14
16
|
|
@@ -17,9 +19,7 @@ require_relative 'identification_tool'
|
|
17
19
|
module Libis
|
18
20
|
module Format
|
19
21
|
module Tool
|
20
|
-
|
21
22
|
class Droid < Libis::Format::Tool::IdentificationTool
|
22
|
-
|
23
23
|
def run_list(filelist, _options = {})
|
24
24
|
runner(filelist)
|
25
25
|
end
|
@@ -43,12 +43,13 @@ module Libis
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def parse_report(report)
|
46
|
-
keys = [
|
47
|
-
|
48
|
-
|
46
|
+
keys = %i[
|
47
|
+
id parent_id uri filepath filename matchtype status filesize type extension
|
48
|
+
mod_time ext_mismatch hash format_count puid mimetype format_name format_version
|
49
|
+
]
|
49
50
|
result = CSV.parse(File.readlines(report).join)
|
50
|
-
|
51
|
-
|
51
|
+
.map { |a| Hash[keys.zip(a)] }
|
52
|
+
.select { |a| a[:type] == 'File' }
|
52
53
|
# File.delete report
|
53
54
|
result.each do |r|
|
54
55
|
r.delete(:id)
|
@@ -70,39 +71,39 @@ module Libis
|
|
70
71
|
|
71
72
|
def create_report(profile, report)
|
72
73
|
args = [
|
73
|
-
|
74
|
-
|
75
|
-
|
74
|
+
'-e', report,
|
75
|
+
'-p', profile,
|
76
|
+
'-q'
|
76
77
|
]
|
77
78
|
timeout = Libis::Format::Config[:timeouts][:droid]
|
78
79
|
result = Libis::Tools::Command.run(
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
Libis::Format::Config[:droid_cmd], *args,
|
81
|
+
timeout:,
|
82
|
+
kill_after: timeout * 2
|
82
83
|
)
|
83
|
-
result[:err].select! {|x| x =~ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} ERROR /}
|
84
|
-
raise
|
85
|
-
raise
|
84
|
+
result[:err].select! { |x| x =~ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} ERROR / }
|
85
|
+
raise "#{self.class} report took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
86
|
+
raise "#{self.class} report errors: #{result[:err].join("\n")}" unless result[:err].empty?
|
86
87
|
|
87
88
|
File.delete profile
|
88
89
|
end
|
89
90
|
|
90
91
|
def create_profile(file_or_list, profile, recursive = false)
|
91
92
|
args = []
|
92
|
-
files =
|
93
|
-
files.each {|file| args << '-a' << file}
|
93
|
+
files = file_or_list.is_a?(Array) ? file_or_list.map(&:escape_for_string) : [file_or_list.escape_for_string]
|
94
|
+
files.each { |file| args << '-a' << file }
|
94
95
|
args << '-q'
|
95
96
|
args << '-p' << profile
|
96
97
|
args << '-R' if recursive
|
97
98
|
timeout = Libis::Format::Config[:timeouts][:droid]
|
98
99
|
result = Libis::Tools::Command.run(
|
99
|
-
|
100
|
-
|
101
|
-
|
100
|
+
Libis::Format::Config[:droid_cmd], *args,
|
101
|
+
timeout:,
|
102
|
+
kill_after: timeout * 2
|
102
103
|
)
|
103
|
-
result[:err].select! {|x| x =~ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} ERROR /}
|
104
|
-
raise
|
105
|
-
raise
|
104
|
+
result[:err].select! { |x| x =~ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} ERROR / }
|
105
|
+
raise "#{self.class} profile took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
106
|
+
raise "#{self.class} profile errors: #{result[:err].join("\n")}" unless result[:err].empty?
|
106
107
|
end
|
107
108
|
|
108
109
|
def profile_file_name
|
@@ -112,9 +113,7 @@ module Libis
|
|
112
113
|
def result_file_name
|
113
114
|
Tools::TempFile.name('droid', '.csv')
|
114
115
|
end
|
115
|
-
|
116
116
|
end
|
117
|
-
|
118
117
|
end
|
119
118
|
end
|
120
119
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'libis/tools/extend/string'
|
2
4
|
require 'libis/tools/extend/empty'
|
3
5
|
require 'libis/tools/command'
|
@@ -8,18 +10,17 @@ require 'libis/format/config'
|
|
8
10
|
module Libis
|
9
11
|
module Format
|
10
12
|
module Tool
|
11
|
-
|
12
13
|
class FFMpeg
|
13
14
|
include Singleton
|
14
15
|
include ::Libis::Tools::Logger
|
15
16
|
|
16
17
|
def self.installed?
|
17
|
-
result = Libis::Tools::Command.run(Libis::Format::Config[:ffmpeg_cmd],
|
18
|
-
result[:status]
|
18
|
+
result = Libis::Tools::Command.run(Libis::Format::Config[:ffmpeg_cmd], '-h')
|
19
|
+
(result[:status]).zero?
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.run(source, target, options = {})
|
22
|
-
|
23
|
+
instance.run source, target, options
|
23
24
|
end
|
24
25
|
|
25
26
|
def run(source, target, options = {})
|
@@ -33,25 +34,22 @@ module Libis
|
|
33
34
|
|
34
35
|
timeout = Libis::Format::Config[:timeouts][:ffmpeg]
|
35
36
|
result = Libis::Tools::Command.run(
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
Libis::Format::Config[:ffmpeg_cmd], *opts,
|
38
|
+
timeout:,
|
39
|
+
kill_after: timeout * 2
|
39
40
|
)
|
40
41
|
|
41
|
-
raise
|
42
|
-
raise
|
42
|
+
raise "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
43
|
+
raise "#{self.class} errors: #{result[:err].join("\n")}" unless (result[:status]).zero?
|
43
44
|
|
44
45
|
warn "FFMpeg warnings: #{(result[:err] + result[:out]).join("\n")}" unless result[:err].empty?
|
45
46
|
|
46
47
|
{
|
47
48
|
command: result,
|
48
|
-
files: [
|
49
|
+
files: [target]
|
49
50
|
}
|
50
|
-
|
51
51
|
end
|
52
|
-
|
53
52
|
end
|
54
|
-
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
@@ -80,7 +80,7 @@ module Libis
|
|
80
80
|
|
81
81
|
# Log warning if needed
|
82
82
|
raise "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
83
|
-
raise "#{self.class} errors: #{result[:err].join("\n")}" unless (result[:status])
|
83
|
+
raise "#{self.class} errors: #{result[:err].join("\n")}" unless (result[:status])&.zero? && result[:err].empty?
|
84
84
|
|
85
85
|
# Parse output (CSV) text into array and return result
|
86
86
|
keys = %i[status time puid format_name format_version filesize filepath mimetype matchtype]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'os'
|
2
4
|
|
3
5
|
require 'libis/tools/extend/string'
|
@@ -9,46 +11,38 @@ require 'libis/format/config'
|
|
9
11
|
module Libis
|
10
12
|
module Format
|
11
13
|
module Tool
|
12
|
-
|
13
14
|
class PdfOptimizer
|
14
15
|
include ::Libis::Tools::Logger
|
15
16
|
|
16
17
|
def self.installed?
|
17
|
-
result = Libis::Tools::Command.run(Libis::Format::Config[:ghostscript_cmd],
|
18
|
-
result[:status]
|
18
|
+
result = Libis::Tools::Command.run(Libis::Format::Config[:ghostscript_cmd], '--version')
|
19
|
+
(result[:status]).zero?
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.run(source, target, quality)
|
22
|
-
|
23
|
+
new.run source, target, quality
|
23
24
|
end
|
24
25
|
|
25
26
|
def run(source, target, quality)
|
26
|
-
|
27
27
|
timeout = Libis::Format::Config[:timeouts][:pdf_optimizer]
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
{
|
45
|
-
command: result,
|
46
|
-
files: [ target ]
|
47
|
-
}
|
48
|
-
|
28
|
+
args = [
|
29
|
+
Libis::Format::Config[:ghostscript_cmd],
|
30
|
+
'-sDEVICE=pdfwrite',
|
31
|
+
'-dCompatibilityLevel=1.4',
|
32
|
+
"-dPDFSETTINGS=/#{quality}",
|
33
|
+
'-dNOPAUSE',
|
34
|
+
'-dBATCH',
|
35
|
+
"-sOutputFile=#{target}",
|
36
|
+
source.to_s
|
37
|
+
]
|
38
|
+
|
39
|
+
result = Libis::Tools::Command.run(*args, timeout:, kill_after: timeout * 2)
|
40
|
+
|
41
|
+
result[:err] << "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
42
|
+
|
43
|
+
result
|
49
44
|
end
|
50
45
|
end
|
51
|
-
|
52
46
|
end
|
53
47
|
end
|
54
48
|
end
|
@@ -64,15 +64,11 @@ module Libis
|
|
64
64
|
kill_after: timeout * 2
|
65
65
|
)
|
66
66
|
|
67
|
-
|
68
|
-
raise "#{self.class} failed with error #{result[:status]}: \n#{(result[:out] + result[:err]).join("\n")}" if result[:status] != 0
|
67
|
+
result[:err] << "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
69
68
|
|
70
69
|
FileUtils.rm [icc_file, def_filename].compact, force: true
|
71
70
|
|
72
|
-
|
73
|
-
command: result,
|
74
|
-
files: [target]
|
75
|
-
}
|
71
|
+
result
|
76
72
|
end
|
77
73
|
|
78
74
|
private
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'os'
|
4
|
+
|
5
|
+
require 'libis/tools/extend/string'
|
6
|
+
require 'libis/tools/logger'
|
7
|
+
require 'libis/tools/command'
|
8
|
+
|
9
|
+
require 'libis/format/config'
|
10
|
+
|
11
|
+
module Libis
|
12
|
+
module Format
|
13
|
+
module Tool
|
14
|
+
class PdfTool
|
15
|
+
include ::Libis::Tools::Logger
|
16
|
+
|
17
|
+
def self.installed?
|
18
|
+
result = Libis::Tools::Command.run(Libis::Format::Config[:java_cmd], '-version')
|
19
|
+
return false unless (result[:status]).zero?
|
20
|
+
|
21
|
+
File.exist?(Libis::Format::Config[:pdf_tool])
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.run(command, source, target, *options)
|
25
|
+
new.run command, source, target, *options
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(command, source, target, *options)
|
29
|
+
if OS.java?
|
30
|
+
# TODO: import library and execute in current VM. For now do exactly as in MRI.
|
31
|
+
end
|
32
|
+
|
33
|
+
timeout = Libis::Format::Config[:timeouts][:pdf_tool]
|
34
|
+
args = [
|
35
|
+
Libis::Format::Config[:java_cmd],
|
36
|
+
'-jar', Libis::Format::Config[:pdf_tool],
|
37
|
+
[command],
|
38
|
+
'-i', source,
|
39
|
+
'-o', target,
|
40
|
+
options,
|
41
|
+
].flatten
|
42
|
+
|
43
|
+
result = Libis::Tools::Command.run(*args, timeout: , kill_after: timeout * 2)
|
44
|
+
|
45
|
+
result[:err] << "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
46
|
+
|
47
|
+
result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -38,8 +38,7 @@ module Libis
|
|
38
38
|
kill_after: timeout * 2
|
39
39
|
)
|
40
40
|
|
41
|
-
|
42
|
-
raise "#{self.class} errors: #{result[:err].join("\n")}" unless (result[:status]).zero? && result[:err].empty?
|
41
|
+
result[:err] << "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
43
42
|
|
44
43
|
Dir.chdir(previous_wd)
|
45
44
|
|
@@ -57,7 +56,7 @@ module Libis
|
|
57
56
|
kill_after: timeout * 2
|
58
57
|
)
|
59
58
|
|
60
|
-
|
59
|
+
result[:err] << "#{self.class} took too long (> #{timeout} seconds) to complete" if result[:timeout]
|
61
60
|
|
62
61
|
end
|
63
62
|
result
|