Class: Pdfrb::CLI
- Inherits:
-
Thor
show all
- Defined in:
- lib/pdfrb/cli.rb,
lib/pdfrb/cli/form.rb,
lib/pdfrb/cli/info.rb,
lib/pdfrb/cli/batch.rb,
lib/pdfrb/cli/files.rb,
lib/pdfrb/cli/fonts.rb,
lib/pdfrb/cli/merge.rb,
lib/pdfrb/cli/split.rb,
lib/pdfrb/cli/images.rb,
lib/pdfrb/cli/modify.rb,
lib/pdfrb/cli/inspect.rb,
lib/pdfrb/cli/optimize.rb,
lib/pdfrb/cli/image2pdf.rb,
lib/pdfrb/cli/watermark.rb,
lib/pdfrb/cli/debug_info.rb
Overview
pdfrb executable. Thor-based CLI mirroring pdftk/pdfinfo
ergonomics. Each subcommand wraps a Task::* module or reads
directly off the Document facade.
Defined Under Namespace
Modules: Files, Fonts, Images, Info, Split, Ubatch, UdebugUinfo, Uform, Uimage2pdf, Uinspect, Umerge, Umodify, Uoptimize, Uwatermark
Constant Summary
collapse
- PERMISSION_BITS =
{
"print" => 4,
"modify" => 8,
"copy" => 16,
"annotate" => 32,
"fill" => 256,
"extract" => 512,
"assemble" => 1024,
"print-hq" => 2048,
}.freeze
Instance Method Summary
collapse
-
#batch(input, output, *args) ⇒ Object
-
#decrypt(input, output) ⇒ Object
-
#diff(left, right) ⇒ Object
-
#encrypt(input, output) ⇒ Object
-
#extract_text(input, output = nil) ⇒ Object
-
#files(input) ⇒ Object
-
#files_add(input, output, file) ⇒ Object
-
#form(input) ⇒ Object
-
#images(input) ⇒ Object
-
#images_add(input, image, output) ⇒ Object
-
#info(input) ⇒ Object
-
#inspect(input) ⇒ Object
-
#merge(output, *inputs) ⇒ Object
-
#modify(input, output) ⇒ Object
-
#optimize(input, output) ⇒ Object
-
#split(input, output_pattern, from = nil, to = nil) ⇒ Object
-
#version ⇒ Object
-
#watermark(input, output) ⇒ Object
Instance Method Details
#batch(input, output, *args) ⇒ Object
268
269
270
271
272
273
274
275
276
277
|
# File 'lib/pdfrb/cli.rb', line 268
def batch(input, output, *args)
doc = open_doc(input)
commands = args.split("--").reject(&:empty?)
commands.each do |cmd_args|
cmd, *cmd_args = cmd_args
apply_batch_command(doc, cmd, cmd_args)
end
doc.write(output)
puts "Batch processed → #{output}"
end
|
#decrypt(input, output) ⇒ Object
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# File 'lib/pdfrb/cli.rb', line 123
def decrypt(input, output)
doc = open_doc(input)
trailer = doc.trailer
if trailer && trailer[:Encrypt]
trailer.value.delete(:Encrypt)
doc.config.delete("encryption.handler")
doc.config.delete("encryption.password")
puts "Stripped encryption"
end
doc.write(output)
puts "Decrypted → #{output}"
end
|
#diff(left, right) ⇒ Object
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/pdfrb/cli.rb', line 71
def diff(left, right)
report = Pdfrb::Compare.compare(
File.binread(left),
File.binread(right)
)
puts report.summary
unless report.equivalent?
puts
report.per_page_text_diffs.first(5).each do |d|
puts " Page #{d[:page] + 1}: #{(d[:similarity] * 100).round(1)}% similar"
end
unless report.font_diff[:added].empty? && report.font_diff[:removed].empty?
puts " Fonts added: #{report.font_diff[:added].join(', ')}" unless report.font_diff[:added].empty?
puts " Fonts removed: #{report.font_diff[:removed].join(', ')}" unless report.font_diff[:removed].empty?
end
puts " Page count delta: #{report.page_count_delta}" unless report.page_count_delta.zero?
exit 1
end
end
|
#encrypt(input, output) ⇒ Object
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
# File 'lib/pdfrb/cli.rb', line 97
def encrypt(input, output)
doc = open_doc(input)
bits = options[:bits]
password = options[:password]
owner_pw = options[:owner_password] || password
perms = parse_permissions(options[:permissions])
case bits
when 256
build_aes256_encrypt(doc, password, owner_pw, perms)
when 128
build_encrypt(doc, password, owner_pw, perms, v: 4, r: 4, length: 128)
when 40
build_encrypt(doc, password, owner_pw, perms, v: 2, r: 3, length: 40)
else
raise "unsupported key length: #{bits} (use 40, 128, or 256)"
end
doc.write(output)
puts "Encrypted #{output} (#{bits}-bit)"
end
|
42
43
44
45
46
47
48
49
50
51
|
# File 'lib/pdfrb/cli.rb', line 42
def (input, output = nil)
doc = open_doc(input)
texts = Pdfrb::Task::ExtractText.call(doc)
if output
File.write(output, texts.join("\n\n--- page break ---\n\n"))
puts "Wrote #{output}"
else
texts.each_with_index { |t, i| puts "--- page #{i + 1} ---"; puts t }
end
end
|
#files(input) ⇒ Object
244
245
246
247
248
249
250
251
252
253
254
|
# File 'lib/pdfrb/cli.rb', line 244
def files(input)
doc = open_doc(input)
if doc.files.empty?
puts "No embedded files."
return
end
doc.files.each do |name, spec|
size = spec[:EF] ? "embedded" : "external"
puts "#{name} (#{size})"
end
end
|
#files_add(input, output, file) ⇒ Object
258
259
260
261
262
263
264
|
# File 'lib/pdfrb/cli.rb', line 258
def files_add(input, output, file)
doc = open_doc(input)
doc.files.add(file, name: File.basename(file),
relationship: options[:relationship]&.to_sym)
doc.write(output)
puts "Embedded #{file} → #{output}"
end
|
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
# File 'lib/pdfrb/cli.rb', line 150
def form(input)
doc = open_doc(input)
acro = doc.catalog[:AcroForm]
if acro.nil?
puts "No AcroForm in this document."
return
end
fields = acro[:Fields]
return unless fields
fields.each do |ref|
field = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
next unless field
name = field[:T] || "(unnamed)"
type = field[:FT] || "?"
value = field[:V] || "-"
puts "/#{name} type=#{type} value=#{value}"
end
end
|
#images(input) ⇒ Object
54
55
56
57
58
59
60
|
# File 'lib/pdfrb/cli.rb', line 54
def images(input)
doc = open_doc(input)
Pdfrb::Task::ExtractImages.call(doc) do |info|
puts "page #{info.page_index + 1} /#{info.name} " \
"#{info.width}x#{info.height} filter=#{info.filter.inspect}"
end
end
|
#images_add(input, image, output) ⇒ Object
141
142
143
144
145
146
147
|
# File 'lib/pdfrb/cli.rb', line 141
def images_add(input, image, output)
doc = open_doc(input)
name = doc.images.add(image)
doc.pages.add doc.write(output)
puts "Added image as /#{name} and wrote #{output}"
end
|
#info(input) ⇒ Object
19
20
21
22
23
24
25
26
27
28
29
|
# File 'lib/pdfrb/cli.rb', line 19
def info(input)
doc = open_doc(input)
puts "File: #{input}"
puts "PDF version: #{doc.version}"
puts "Pages: #{doc.pages.count}"
puts "Title: #{doc.metadata.title || '-'}"
puts "Author: #{doc.metadata.author || '-'}"
puts "Subject: #{doc.metadata.subject || '-'}"
puts "Producer: #{doc.metadata.producer || '-'}"
puts "Encrypted: #{encrypted?(doc)}"
end
|
#inspect(input) ⇒ Object
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
# File 'lib/pdfrb/cli.rb', line 224
def inspect(input)
doc = open_doc(input)
if options[:object]
ref = Pdfrb::Model::Reference.new(options[:object], 0)
obj = doc.object(ref)
puts obj&.value
return
end
catalog = doc.catalog
puts "Catalog: /Type=#{catalog[:Type]}"
puts " Pages: #{doc.pages.count}"
puts " Title: #{doc.metadata.title || '-'}"
af = catalog[:AcroForm]
puts " AcroForm: #{af ? 'present' : 'absent'}"
outlines = catalog[:Outlines]
puts " Outlines: #{outlines ? 'present' : 'absent'}"
end
|
#merge(output, *inputs) ⇒ Object
32
33
34
35
36
37
38
39
|
# File 'lib/pdfrb/cli.rb', line 32
def merge(output, *inputs)
raise ArgumentError, "merge needs at least one INPUT" if inputs.empty?
target = Pdfrb::Document.new
inputs.each { |i| Pdfrb::Task::Merge.call(target, open_doc(i)) }
target.write(output)
puts "Wrote #{output} (#{target.pages.count} pages)"
end
|
#modify(input, output) ⇒ Object
214
215
216
217
218
219
220
|
# File 'lib/pdfrb/cli.rb', line 214
def modify(input, output)
doc = open_doc(input)
apply_delete(doc, options[:delete]) if options[:delete]
apply_rotate(doc, options[:rotate]) if options[:rotate]
doc.write(output)
puts "Modified → #{output}"
end
|
#optimize(input, output) ⇒ Object
63
64
65
66
67
68
|
# File 'lib/pdfrb/cli.rb', line 63
def optimize(input, output)
doc = open_doc(input)
Pdfrb::Task::Optimize.call(doc)
doc.write(output)
puts "Wrote #{output}"
end
|
#split(input, output_pattern, from = nil, to = nil) ⇒ Object
172
173
174
175
176
177
178
179
180
181
182
183
184
|
# File 'lib/pdfrb/cli.rb', line 172
def split(input, output_pattern, from = nil, to = nil)
doc = open_doc(input)
total = doc.pages.count
from_idx = from ? from.to_i : 1
to_idx = to ? to.to_i : total
(from_idx..to_idx).each do |i|
target = Pdfrb::Document.new
Pdfrb::Importer.new(target).import(doc.pages[i - 1].value, doc)
out_path = format(output_pattern, i)
target.write(out_path)
end
puts "Split #{input} into #{to_idx - from_idx + 1} files"
end
|
#version ⇒ Object
14
15
16
|
# File 'lib/pdfrb/cli.rb', line 14
def version
puts "pdfrb #{Pdfrb::VERSION}"
end
|
#watermark(input, output) ⇒ Object
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
# File 'lib/pdfrb/cli.rb', line 193
def watermark(input, output)
doc = open_doc(input)
color = options[:color].split(",").map(&:to_f)
doc.pages.each do |page|
canvas = page.canvas
doc.graphics_state.register_transparency(page, opacity: options[:opacity])
canvas.save_graphics_state
canvas.opacity = options[:opacity]
canvas.fill_color(color)
canvas.text(options[:text], at: [100, 400],
font: options[:font].to_sym,
size: options[:size])
canvas.restore_graphics_state
end
doc.write(output)
puts "Watermarked #{doc.pages.count} pages → #{output}"
end
|