podoff 1.0.0 → 1.1.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.
- data/CHANGELOG.txt +7 -0
- data/lib/podoff.rb +123 -121
- data/spec/core_spec.rb +24 -1
- data/spec/document_spec.rb +101 -37
- data/spec/obj_spec.rb +15 -0
- data/todo.txt +12 -4
- metadata +2 -2
data/CHANGELOG.txt
CHANGED
data/lib/podoff.rb
CHANGED
@@ -23,10 +23,13 @@
|
|
23
23
|
# Made in Japan.
|
24
24
|
#++
|
25
25
|
|
26
|
+
require 'strscan'
|
27
|
+
require 'stringio'
|
28
|
+
|
26
29
|
|
27
30
|
module Podoff
|
28
31
|
|
29
|
-
VERSION = '1.
|
32
|
+
VERSION = '1.1.0'
|
30
33
|
|
31
34
|
def self.load(path, encoding='iso-8859-1')
|
32
35
|
|
@@ -38,13 +41,6 @@ module Podoff
|
|
38
41
|
Podoff::Document.new(s)
|
39
42
|
end
|
40
43
|
|
41
|
-
#OBJ_ATTRIBUTES =
|
42
|
-
# { type: 'Type', subtype: 'Subtype',
|
43
|
-
# parent: 'Parent', kids: 'Kids', contents: 'Contents', annots: 'Annots',
|
44
|
-
# pagenum: 'pdftk_PageNum' }
|
45
|
-
OBJ_ATTRIBUTES =
|
46
|
-
{ type: 'Type', contents: 'Contents', pagenum: 'pdftk_PageNum' }
|
47
|
-
|
48
44
|
class Document
|
49
45
|
|
50
46
|
def self.load(path, encoding='iso-8859-1')
|
@@ -58,6 +54,7 @@ module Podoff
|
|
58
54
|
end
|
59
55
|
|
60
56
|
attr_reader :source
|
57
|
+
attr_reader :version
|
61
58
|
attr_reader :xref
|
62
59
|
attr_reader :objs
|
63
60
|
attr_reader :obj_counters
|
@@ -68,9 +65,10 @@ module Podoff
|
|
68
65
|
def initialize(s)
|
69
66
|
|
70
67
|
fail ArgumentError.new('not a PDF file') \
|
71
|
-
unless s.match(/\A%PDF-\d+\.\d+\
|
68
|
+
unless s.match(/\A%PDF-\d+\.\d+\s/)
|
72
69
|
|
73
70
|
@source = s
|
71
|
+
@version = nil
|
74
72
|
@xref = nil
|
75
73
|
@objs = {}
|
76
74
|
@obj_counters = {}
|
@@ -78,47 +76,41 @@ module Podoff
|
|
78
76
|
|
79
77
|
@additions = {}
|
80
78
|
|
81
|
-
|
82
|
-
|
83
|
-
#
|
84
|
-
loop do
|
85
|
-
|
86
|
-
matches[:obj] ||= s.match(/^(\d+ \d+) obj\b/, index)
|
87
|
-
matches[:endobj] ||= s.match(/\bendobj\b/, index)
|
88
|
-
#
|
89
|
-
OBJ_ATTRIBUTES.each do |k, v|
|
90
|
-
matches[k] ||= s.match(/\/#{v} (\/?[^\/\n<>]+)/, index)
|
91
|
-
end
|
92
|
-
#
|
93
|
-
matches[:startxref] ||= s.match(/\bstartxref\s+(\d+)\s*%%EOF/, index)
|
94
|
-
|
95
|
-
objm = matches[:obj]
|
96
|
-
sxrm = matches[:startxref]
|
97
|
-
|
98
|
-
break unless sxrm || objm
|
79
|
+
sca = ::StringScanner.new(s)
|
80
|
+
@version = sca.scan(/%PDF-\d+\.\d+/)
|
99
81
|
|
100
|
-
|
82
|
+
loop do
|
101
83
|
|
102
|
-
|
103
|
-
|
84
|
+
i = sca.skip_until(
|
85
|
+
/(startxref\s+\d+|\d+\s+\d+\s+obj|\/Root\s+\d+\s+\d+\s+R)/)
|
104
86
|
|
105
|
-
|
106
|
-
|
87
|
+
m = sca.matched
|
88
|
+
break unless m
|
107
89
|
|
108
|
-
if
|
109
|
-
|
90
|
+
if m[0] == 's'
|
91
|
+
@xref = m.split(' ').last.to_i
|
92
|
+
elsif m[0] == '/'
|
93
|
+
@root = extract_ref(m)
|
94
|
+
else
|
95
|
+
obj = Podoff::Obj.extract(self, sca)
|
110
96
|
@objs[obj.ref] = obj
|
111
97
|
@obj_counters[obj.ref] = (@obj_counters[obj.ref] || 0) + 1
|
112
|
-
index = obj.end_index + 1
|
113
|
-
else
|
114
|
-
@xref = sxrm[1].to_i
|
115
|
-
index = sxrm.offset(0).last + 1
|
116
|
-
matches.delete(:startxref)
|
117
98
|
end
|
118
99
|
end
|
119
100
|
|
120
|
-
|
121
|
-
|
101
|
+
if @root == nil
|
102
|
+
sca.pos = 0
|
103
|
+
loop do
|
104
|
+
i = sca.skip_until(/\/Root\s+\d+\s+\d+\s+R/)
|
105
|
+
break unless sca.matched
|
106
|
+
@root = extract_ref(sca.matched)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def extract_ref(s)
|
112
|
+
|
113
|
+
s.gsub(/\s+/, ' ').gsub(/[^0-9 ]+/, '').strip
|
122
114
|
end
|
123
115
|
|
124
116
|
def updated?
|
@@ -232,7 +224,12 @@ module Podoff
|
|
232
224
|
|
233
225
|
def write(path)
|
234
226
|
|
235
|
-
f =
|
227
|
+
f =
|
228
|
+
case path
|
229
|
+
when :string, '-' then StringIO.new
|
230
|
+
when String then File.open(path, 'wb')
|
231
|
+
else path
|
232
|
+
end
|
236
233
|
|
237
234
|
f.write(@source)
|
238
235
|
|
@@ -274,9 +271,72 @@ module Podoff
|
|
274
271
|
f.write("%%EOF\n")
|
275
272
|
end
|
276
273
|
|
277
|
-
f.close
|
274
|
+
f.close if path.is_a?(String) || path.is_a?(Symbol)
|
278
275
|
|
279
|
-
|
276
|
+
f.is_a?(StringIO) ? f.string : nil
|
277
|
+
end
|
278
|
+
|
279
|
+
def rewrite(path=:string)
|
280
|
+
|
281
|
+
f =
|
282
|
+
case path
|
283
|
+
when :string, '-' then StringIO.new
|
284
|
+
when String then File.open(path, 'wb')
|
285
|
+
else path
|
286
|
+
end
|
287
|
+
|
288
|
+
v = source.match(/%PDF-\d+\.\d+/)[0]
|
289
|
+
f.write(v)
|
290
|
+
f.write("\n")
|
291
|
+
|
292
|
+
ptrs = {}
|
293
|
+
|
294
|
+
objs.keys.sort.each do |k|
|
295
|
+
ptrs[k] = f.pos + 1
|
296
|
+
f.write(objs[k].source)
|
297
|
+
f.write("\n")
|
298
|
+
end
|
299
|
+
|
300
|
+
xref = f.pos + 1
|
301
|
+
max = objs.keys.inject(-1) { |i, k| [ i, k.split(' ')[0].to_i ].max }
|
302
|
+
|
303
|
+
#f.write("xref\n0 #{max}\n0000000000 65535 f\n")
|
304
|
+
f.write("xref\n0 1\n0000000000 65535 f\n")
|
305
|
+
|
306
|
+
partitions = [ [] ]
|
307
|
+
#
|
308
|
+
(1..max).each do |i|
|
309
|
+
k = "#{i} 0"
|
310
|
+
last = partitions.last
|
311
|
+
if ptrs.has_key?(k)
|
312
|
+
last << i
|
313
|
+
else
|
314
|
+
partitions << [] unless last == []
|
315
|
+
end
|
316
|
+
end
|
317
|
+
#
|
318
|
+
partitions.each do |part|
|
319
|
+
|
320
|
+
f.write("#{part.first} #{part.size}\n")
|
321
|
+
|
322
|
+
part.each do |i|
|
323
|
+
k = "#{i} 0"
|
324
|
+
#f.write(sprintf("%010d 00000 n %% %s\n", ptrs[k], k))
|
325
|
+
f.write(sprintf("%010d 00000 n\n", ptrs[k]))
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
f.write("trailer\n")
|
330
|
+
f.write("<<\n")
|
331
|
+
f.write("/Size #{objs.size}\n")
|
332
|
+
f.write("/Root #{root} R\n")
|
333
|
+
f.write(">>\n")
|
334
|
+
f.write("startxref #{xref}\n")
|
335
|
+
f.write("%%EOF\n")
|
336
|
+
|
337
|
+
f.close if path.is_a?(String) || path.is_a?(Symbol)
|
338
|
+
|
339
|
+
f.is_a?(StringIO) ? f.string : nil
|
280
340
|
end
|
281
341
|
|
282
342
|
private
|
@@ -292,24 +352,26 @@ module Podoff
|
|
292
352
|
|
293
353
|
class Obj
|
294
354
|
|
295
|
-
|
355
|
+
ATTRIBUTES =
|
356
|
+
{ type: 'Type', contents: 'Contents', pagenum: 'pdftk_PageNum' }
|
296
357
|
|
297
|
-
|
298
|
-
st = matches[:obj].offset(0).first
|
299
|
-
en = matches[:endobj].offset(0).last - 1
|
358
|
+
def self.extract(doc, sca)
|
300
359
|
|
301
|
-
|
360
|
+
re = sca.matched[0..-4].strip
|
361
|
+
st = sca.pos - sca.matched.length
|
302
362
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
363
|
+
i = sca.skip_until(/endobj/); return nil unless i
|
364
|
+
en = sca.pos - 1
|
365
|
+
|
366
|
+
atts = {}
|
367
|
+
ATTRIBUTES.each do |k, v|
|
368
|
+
sca.pos = st
|
369
|
+
i = sca.skip_until(/\/#{v}\b/); next unless i
|
370
|
+
next if sca.pos > en
|
371
|
+
atts[k] = sca.scan(/ *\/?[^\n\r\/>]+/).strip
|
309
372
|
end
|
310
373
|
|
311
|
-
|
312
|
-
matches.delete(:endobj)
|
374
|
+
sca.pos = en
|
313
375
|
|
314
376
|
Podoff::Obj.new(doc, re, st, en, atts)
|
315
377
|
end
|
@@ -373,62 +435,6 @@ module Podoff
|
|
373
435
|
r ? r.to_i : nil
|
374
436
|
end
|
375
437
|
|
376
|
-
# def parent
|
377
|
-
#
|
378
|
-
# r = @attributes[:parent]
|
379
|
-
# r ? r[0..-2].strip : nil
|
380
|
-
# end
|
381
|
-
#
|
382
|
-
# def kids
|
383
|
-
#
|
384
|
-
# r = @attributes[:kids]
|
385
|
-
# (r || '').split(/[\[\]R]/).collect(&:strip).reject(&:empty?)
|
386
|
-
# end
|
387
|
-
#
|
388
|
-
# def contents
|
389
|
-
#
|
390
|
-
# r = @attributes[:contents]
|
391
|
-
# (r || '').split(/[\[\]R]/).collect(&:strip).reject(&:empty?)
|
392
|
-
# end
|
393
|
-
|
394
|
-
# def add_annotation(ref)
|
395
|
-
#
|
396
|
-
# if annots = @attributes[:annots]
|
397
|
-
# fail "implement me!"
|
398
|
-
# else
|
399
|
-
# i = @source.index('/Type ')
|
400
|
-
# @source.insert(i, "/Annots [#{ref} R]\n")
|
401
|
-
# end
|
402
|
-
# recompute_attributes
|
403
|
-
# end
|
404
|
-
|
405
|
-
# def add_free_text(x, y, text, font, size)
|
406
|
-
#
|
407
|
-
# fail ArgumentError.new('target is not a page') unless type == '/Page'
|
408
|
-
#
|
409
|
-
# nref = document.new_ref
|
410
|
-
#
|
411
|
-
# s = [
|
412
|
-
# "#{nref} obj <<",
|
413
|
-
# "/Type /Annot",
|
414
|
-
# "/Subtype /FreeText",
|
415
|
-
# "/Da (/F1 70 Tf 0 100 Td)",
|
416
|
-
# "/Rect [0 0 500 600]",
|
417
|
-
# "/Contents (#{text})",
|
418
|
-
# ">>",
|
419
|
-
# "endobj"
|
420
|
-
# ].join("\n")
|
421
|
-
# anno = Obj.create(document, nref, s)
|
422
|
-
#
|
423
|
-
# page = self.replicate
|
424
|
-
# page.add_annotation(nref)
|
425
|
-
#
|
426
|
-
# document.add(anno)
|
427
|
-
# document.add(page)
|
428
|
-
#
|
429
|
-
# anno
|
430
|
-
# end
|
431
|
-
|
432
438
|
def insert_font(nick, obj_or_ref)
|
433
439
|
|
434
440
|
fail ArgumentError.new("target '#{ref}' not a replica") \
|
@@ -462,9 +468,9 @@ module Podoff
|
|
462
468
|
def recompute_attributes
|
463
469
|
|
464
470
|
@attributes =
|
465
|
-
|
466
|
-
m = @source.match(/\/#{v}
|
467
|
-
h[k] = m[1] if m
|
471
|
+
ATTRIBUTES.inject({}) do |h, (k, v)|
|
472
|
+
m = @source.match(/\/#{v}\s+(\/?[^\/\n<>]+)/)
|
473
|
+
h[k] = m[1].strip if m
|
468
474
|
h
|
469
475
|
end
|
470
476
|
end
|
@@ -481,7 +487,7 @@ module Podoff
|
|
481
487
|
|
482
488
|
fail ArgumentError.new("obj not replicated") unless @source
|
483
489
|
|
484
|
-
pkey =
|
490
|
+
pkey = ATTRIBUTES[key]
|
485
491
|
|
486
492
|
if v = @attributes[key]
|
487
493
|
v = concat(v, ref)
|
@@ -504,10 +510,6 @@ module Podoff
|
|
504
510
|
@content = StringIO.new
|
505
511
|
end
|
506
512
|
|
507
|
-
#def document; obj.document; end
|
508
|
-
#def ref; obj.ref; end
|
509
|
-
#def source; self; end
|
510
|
-
|
511
513
|
def tf(font_name, font_size)
|
512
514
|
|
513
515
|
n = font_name[0] == '/' ? font_name[1..-1] : font_name
|
data/spec/core_spec.rb
CHANGED
@@ -17,8 +17,8 @@ describe Podoff do
|
|
17
17
|
d = Podoff.load('pdfs/t0.pdf')
|
18
18
|
|
19
19
|
expect(d.class).to eq(Podoff::Document)
|
20
|
-
expect(d.xref).to eq(414)
|
21
20
|
expect(d.objs.keys).to eq([ '1 0', '2 0', '3 0', '4 0', '5 0', '6 0' ])
|
21
|
+
expect(d.xref).to eq(414)
|
22
22
|
|
23
23
|
#pp d.objs.values.collect(&:to_a)
|
24
24
|
|
@@ -35,6 +35,8 @@ describe Podoff do
|
|
35
35
|
[ 1, 1, 1, 1, 1, 1 ])
|
36
36
|
|
37
37
|
expect(d.root).to eq('1 0')
|
38
|
+
|
39
|
+
expect(d.pages.size).to eq(1)
|
38
40
|
end
|
39
41
|
|
40
42
|
it 'loads a PDF document' do
|
@@ -48,6 +50,8 @@ describe Podoff do
|
|
48
50
|
expect(d.objs.keys).to include('273 0')
|
49
51
|
|
50
52
|
expect(d.root).to eq('65 0')
|
53
|
+
|
54
|
+
expect(d.pages.size).to eq(3)
|
51
55
|
end
|
52
56
|
|
53
57
|
it 'loads a PDF document with incremental updates' do
|
@@ -66,6 +70,25 @@ describe Podoff do
|
|
66
70
|
expect(d.root).to eq('1 0')
|
67
71
|
end
|
68
72
|
|
73
|
+
it 'loads a [re]compressed PDF documents' do
|
74
|
+
|
75
|
+
d = Podoff.load('pdfs/qdocument0.pdf')
|
76
|
+
|
77
|
+
expect(d.class).to eq(Podoff::Document)
|
78
|
+
expect(d.xref).to eq(1612815)
|
79
|
+
expect(d.objs.size).to eq(273)
|
80
|
+
|
81
|
+
expect(d.root).to eq('1 0')
|
82
|
+
|
83
|
+
#d.objs.each do |ref, o|
|
84
|
+
# p [ o.ref, o.attributes ]
|
85
|
+
#end
|
86
|
+
|
87
|
+
expect(d.pages.size).to eq(3)
|
88
|
+
expect(d.pages.first.attributes[:pagenum]).to eq('1')
|
89
|
+
expect(d.objs['46 0'].attributes[:type]).to eq('/Annot')
|
90
|
+
end
|
91
|
+
|
69
92
|
it 'rejects items that are not PDF documents' do
|
70
93
|
|
71
94
|
expect {
|
data/spec/document_spec.rb
CHANGED
@@ -77,43 +77,6 @@ describe Podoff::Document do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
describe '#write' do
|
81
|
-
|
82
|
-
it 'writes the document to a given path' do
|
83
|
-
|
84
|
-
@d.write('tmp/out.pdf')
|
85
|
-
|
86
|
-
s = File.open('tmp/out.pdf', 'r:iso8859-1') { |f| f.read }
|
87
|
-
lines = s.split("\n")
|
88
|
-
|
89
|
-
expect(lines.first).to match(/^%PDF-1.7$/)
|
90
|
-
expect(lines.last).to match(/^%%EOF$/)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'writes open streams as well' do
|
94
|
-
|
95
|
-
d = Podoff.load('pdfs/t0.pdf')
|
96
|
-
|
97
|
-
pa = d.re_add(d.page(1))
|
98
|
-
st = d.add_stream
|
99
|
-
st.bt(10, 20, 'hello open stream')
|
100
|
-
pa.insert_contents(st)
|
101
|
-
|
102
|
-
s = d.write(:string)
|
103
|
-
|
104
|
-
expect(
|
105
|
-
d.write(:string).index(%{
|
106
|
-
7 0 obj
|
107
|
-
<< /Length 37 >>
|
108
|
-
stream
|
109
|
-
BT 10 20 Td (hello open stream) Tj ET
|
110
|
-
endstream
|
111
|
-
endobj
|
112
|
-
}.strip)
|
113
|
-
).to eq(722)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
80
|
describe '#dup' do
|
118
81
|
|
119
82
|
it 'produces a shallow copy of the document' do
|
@@ -272,6 +235,107 @@ BT /Helvetica 35 Tf 40 50 Td (sixty there) Tj ET
|
|
272
235
|
expect(re.source).to eq(pa.source)
|
273
236
|
expect(re.source).not_to equal(pa.source)
|
274
237
|
end
|
238
|
+
|
239
|
+
it 'recomputes the attributes correctly' do
|
240
|
+
|
241
|
+
d = Podoff.load('pdfs/qdocument0.pdf')
|
242
|
+
|
243
|
+
pa = d.re_add(d.page(1))
|
244
|
+
|
245
|
+
expect(pa.attributes).to eq(
|
246
|
+
{ type: '/Page', contents: '151 0 R', pagenum: '1' })
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe '#write' do
|
252
|
+
|
253
|
+
it 'writes the document to a given path' do
|
254
|
+
|
255
|
+
@d.write('tmp/out.pdf')
|
256
|
+
|
257
|
+
s = File.open('tmp/out.pdf', 'r:iso8859-1') { |f| f.read }
|
258
|
+
lines = s.split("\n")
|
259
|
+
|
260
|
+
expect(lines.first).to match(/^%PDF-1.7$/)
|
261
|
+
expect(lines.last).to match(/^%%EOF$/)
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'writes open streams as well' do
|
265
|
+
|
266
|
+
d = Podoff.load('pdfs/t0.pdf')
|
267
|
+
|
268
|
+
pa = d.re_add(d.page(1))
|
269
|
+
st = d.add_stream
|
270
|
+
st.bt(10, 20, 'hello open stream')
|
271
|
+
pa.insert_contents(st)
|
272
|
+
|
273
|
+
s = d.write(:string)
|
274
|
+
|
275
|
+
expect(
|
276
|
+
d.write(:string).index(%{
|
277
|
+
7 0 obj
|
278
|
+
<< /Length 37 >>
|
279
|
+
stream
|
280
|
+
BT 10 20 Td (hello open stream) Tj ET
|
281
|
+
endstream
|
282
|
+
endobj
|
283
|
+
}.strip)
|
284
|
+
).to eq(722)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe '#rewrite' do
|
289
|
+
|
290
|
+
it 'rewrites a document in one go' do
|
291
|
+
|
292
|
+
d = Podoff.load('pdfs/t2.pdf')
|
293
|
+
|
294
|
+
s = d.rewrite(:string)
|
295
|
+
|
296
|
+
expect(s.strip).to eq(%{
|
297
|
+
%PDF-1.4
|
298
|
+
1 0 obj <</Type /Catalog /Pages 2 0 R>>
|
299
|
+
endobj
|
300
|
+
2 0 obj <</Type /Pages /Kids [3 0 R] /Count 1>>
|
301
|
+
endobj
|
302
|
+
3 0 obj <</Type /Page /Parent 2 0 R /Resources 4 0 R /MediaBox [0 0 500 800] /Contents [6 0 R 7 0 R]>>
|
303
|
+
endobj
|
304
|
+
4 0 obj <</Font <</F1 5 0 R>>>>
|
305
|
+
endobj
|
306
|
+
5 0 obj <</Type /Font /Subtype /Type1 /BaseFont /Helvetica>>
|
307
|
+
endobj
|
308
|
+
6 0 obj
|
309
|
+
<</Length 44>>
|
310
|
+
stream
|
311
|
+
BT /F1 24 Tf 175 720 Td (Hello Nadaa!)Tj ET
|
312
|
+
endstream
|
313
|
+
endobj
|
314
|
+
7 0 obj
|
315
|
+
<</Length 44>>
|
316
|
+
stream
|
317
|
+
BT /F1 24 Tf 175 520 Td (Smurf Megane)Tj ET
|
318
|
+
endstream
|
319
|
+
endobj
|
320
|
+
xref
|
321
|
+
0 1
|
322
|
+
0000000000 65535 f
|
323
|
+
1 7
|
324
|
+
0000000010 00000 n
|
325
|
+
0000000057 00000 n
|
326
|
+
0000000112 00000 n
|
327
|
+
0000000222 00000 n
|
328
|
+
0000000261 00000 n
|
329
|
+
0000000329 00000 n
|
330
|
+
0000000420 00000 n
|
331
|
+
trailer
|
332
|
+
<<
|
333
|
+
/Size 7
|
334
|
+
/Root 1 0 R
|
335
|
+
>>
|
336
|
+
startxref 511
|
337
|
+
%%EOF
|
338
|
+
}.strip)
|
275
339
|
end
|
276
340
|
end
|
277
341
|
end
|
data/spec/obj_spec.rb
CHANGED
@@ -232,6 +232,21 @@ endobj
|
|
232
232
|
expect(pa.source).to match(/\/Font\s+<<\s+\/MyHelv #{fo.ref} R\s+/)
|
233
233
|
end
|
234
234
|
end
|
235
|
+
|
236
|
+
describe '#add_to_attribute' do
|
237
|
+
|
238
|
+
it 'adds to a list of references' do
|
239
|
+
|
240
|
+
d = Podoff.load('pdfs/qdocument0.pdf')
|
241
|
+
|
242
|
+
o = d.re_add('56 0')
|
243
|
+
|
244
|
+
o.send(:add_to_attribute, :contents, '9999 0')
|
245
|
+
|
246
|
+
expect(o.attributes).to eq(
|
247
|
+
{ type: '/Page', contents: '[151 0 R 9999 0 R]', pagenum: '1' })
|
248
|
+
end
|
249
|
+
end
|
235
250
|
end
|
236
251
|
end
|
237
252
|
|
data/todo.txt
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
|
2
|
-
[
|
3
|
-
[
|
4
|
-
|
2
|
+
[o] implement Document#rewrite
|
3
|
+
[o] doc.add_stream { |st| st.bt ... }
|
5
4
|
[o] st = d.addstream
|
6
5
|
st.tf '/helv', 12
|
7
6
|
st.bt 5, 6, "hello"
|
8
7
|
d.write('out.pdf') # closes the stream...
|
9
8
|
[ ] fail if insert_content or insert_font on an unclosed stream obj
|
10
9
|
|
10
|
+
[o] Document.write('-') (stdout inspiration)
|
11
|
+
|
12
|
+
|
13
|
+
[ ] stop using the st-mark thing
|
11
14
|
[ ] recompress idea? uncompress with pdftk, recompress with podoff
|
12
|
-
smaller docs anyway...
|
15
|
+
smaller docs anyway... /Filter /FlatDecode
|
16
|
+
|
17
|
+
decompress:
|
18
|
+
qpdf --qdf --object-streams=disable in.pdf out.pdf
|
19
|
+
recompress:
|
20
|
+
qpdf in.pdf out.pdf
|
13
21
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: podoff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-10-
|
12
|
+
date: 2015-10-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|