pdfrb 0.7.21 → 0.7.23
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/docs/SEMVER.md +60 -0
- data/docs/USAGE.md +173 -0
- data/lib/pdfrb/model/type/action_go_to_e.rb +31 -0
- data/lib/pdfrb/model/type/action_rich_media_execute.rb +3 -2
- data/lib/pdfrb/model/type/action_thread.rb +1 -0
- data/lib/pdfrb/model/type/add_action_form_field.rb +42 -0
- data/lib/pdfrb/model/type/add_action_screen_annotation.rb +62 -0
- data/lib/pdfrb/model/type/add_action_widget_annotation.rb +72 -0
- data/lib/pdfrb/model/type/appearance_trap_net.rb +8 -18
- data/lib/pdfrb/model/type/movie_annotation.rb +25 -0
- data/lib/pdfrb/model/type/projection_annotation.rb +43 -0
- data/lib/pdfrb/model/type/three_d_annotation.rb +33 -0
- data/lib/pdfrb/model/type/trap_network_annotation.rb +28 -0
- data/lib/pdfrb/model/type.rb +13 -2
- data/lib/pdfrb/version.rb +1 -1
- metadata +12 -3
- data/pdfrb.gemspec +0 -45
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d9ae8c6a5750a4998d51924dc9d011b6b41565e2435e7dc87f25e913a5bf532
|
|
4
|
+
data.tar.gz: 7041b81cedd1d7387cc5ba54829da445add3278151d6579f30da6192d0244043
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35a3f9fe4ea0933fd2e33b2089799e32477e04824884ccc29f0c78377699d051a584e3facaef01c5a62666568db22f859557c394daff2c96c441574c2a054d75
|
|
7
|
+
data.tar.gz: 6baf785a854c19b549f6d66807bc9531fdd665164c6a02ab1570650a5faf9a8a5d5c412b7a7d01a9b467b4fb24301f53ac456bc6579d24615be837e786476a00
|
data/docs/SEMVER.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Pdfrb Semver Policy
|
|
2
|
+
|
|
3
|
+
## Version Scheme
|
|
4
|
+
|
|
5
|
+
Pdfrb follows [Semantic Versioning 2.0.0](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
- **MAJOR** (X.0.0): Breaking API changes. Existing code that depends
|
|
8
|
+
on pdfrb may need updates.
|
|
9
|
+
- **MINOR** (0.X.0): New features, backward-compatible. Existing code
|
|
10
|
+
continues to work.
|
|
11
|
+
- **PATCH** (0.0.X): Bug fixes, performance improvements, doc updates.
|
|
12
|
+
No new features, no breaking changes.
|
|
13
|
+
|
|
14
|
+
## Current Phase: 0.x (pre-1.0)
|
|
15
|
+
|
|
16
|
+
During 0.x development, the API is not yet frozen. Minor version bumps
|
|
17
|
+
MAY include breaking changes, but they will be documented in
|
|
18
|
+
CHANGELOG.md with migration notes.
|
|
19
|
+
|
|
20
|
+
The goal is to reach 1.0 once:
|
|
21
|
+
- The public API is stable (Document, Writer, Canvas, Conformance).
|
|
22
|
+
- Round-trip is proven against a broad fixture corpus.
|
|
23
|
+
- All P0 TODOs are complete.
|
|
24
|
+
- veraPDF cross-check passes on PDF/A output.
|
|
25
|
+
|
|
26
|
+
## Deprecation Policy
|
|
27
|
+
|
|
28
|
+
1. A deprecated API is marked with YARD `@deprecated` tags and emits a
|
|
29
|
+
`Warning.warn` on first use.
|
|
30
|
+
2. The deprecation period lasts at least one minor version.
|
|
31
|
+
3. Removal happens in the next major version bump.
|
|
32
|
+
|
|
33
|
+
## Release Checklist
|
|
34
|
+
|
|
35
|
+
- [ ] All specs pass: `bundle exec rake`
|
|
36
|
+
- [ ] Rubocop clean: `bundle exec rubocop`
|
|
37
|
+
- [ ] Coverage maintained or improved: `COVERAGE=1 bundle exec rspec`
|
|
38
|
+
- [ ] CHANGELOG.md updated with all changes
|
|
39
|
+
- [ ] Version bumped in `lib/pdfrb/version.rb`
|
|
40
|
+
- [ ] Git tag created: `vX.Y.Z`
|
|
41
|
+
- [ ] Gem pushed: `gem build && gem push`
|
|
42
|
+
|
|
43
|
+
## Public API Stability Contract
|
|
44
|
+
|
|
45
|
+
The following are considered **stable** (subject to semver guarantees):
|
|
46
|
+
|
|
47
|
+
- `Pdfrb::Document` — top-level facade (new, open, write, pages, fonts, etc.)
|
|
48
|
+
- `Pdfrb::Writer` — serialization
|
|
49
|
+
- `Pdfrb::Serializer` — COS-to-bytes
|
|
50
|
+
- `Pdfrb::Canvas` — content-stream drawing
|
|
51
|
+
- `Pdfrb::Compare` — semantic diff
|
|
52
|
+
- `Pdfrb::Conformance` — PDF/A and PDF/UA validators
|
|
53
|
+
- `Pdfrb::DigitalSignature` — signing and verification
|
|
54
|
+
- `Pdfrb::Error` hierarchy
|
|
55
|
+
|
|
56
|
+
The following are **internal** (may change without notice):
|
|
57
|
+
|
|
58
|
+
- `Pdfrb::Source::*` — tokenizer/parser internals
|
|
59
|
+
- `Pdfrb::Model::Cos::*` — COS implementation details
|
|
60
|
+
- `Pdfrb::Arlington::*` — predicate evaluation internals
|
data/docs/USAGE.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Pdfrb Usage Guide
|
|
2
|
+
|
|
3
|
+
A cookbook of common PDF tasks using pdfrb.
|
|
4
|
+
|
|
5
|
+
## Creating a PDF
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
require "pdfrb"
|
|
9
|
+
|
|
10
|
+
doc = Pdfrb::Document.new
|
|
11
|
+
font = doc.fonts.add("Helvetica")
|
|
12
|
+
page = doc.pages.add
|
|
13
|
+
page.canvas.text("Hello, World!", at: [72, 720], font: font, size: 24)
|
|
14
|
+
|
|
15
|
+
doc.write("hello.pdf")
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Reading a PDF
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
doc = Pdfrb.open("input.pdf")
|
|
22
|
+
puts "Pages: #{doc.pages.count}"
|
|
23
|
+
doc.pages.each do |page|
|
|
24
|
+
text = Pdfrb::Task::ExtractText.call_single_page(page)
|
|
25
|
+
puts text
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Drawing on a Canvas
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
doc = Pdfrb::Document.new
|
|
33
|
+
page = doc.pages.add
|
|
34
|
+
font = doc.fonts.add("Helvetica")
|
|
35
|
+
|
|
36
|
+
page.canvas.tap do |c|
|
|
37
|
+
c.text("Title", at: [72, 720], font: font, size: 18)
|
|
38
|
+
c.rectangle(point: [72, 700], width: 200, height: 50)
|
|
39
|
+
c.stroke
|
|
40
|
+
c.line(from: [72, 600], to: [300, 600])
|
|
41
|
+
c.stroke
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
doc.write("drawing.pdf")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Embedding an ICC Profile
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
icc_bytes = File.binread("sRGB.icc")
|
|
51
|
+
cs = doc.colors.embed_icc_profile(icc_bytes)
|
|
52
|
+
page = doc.pages.first
|
|
53
|
+
cs_name = doc.colors.register(page, cs)
|
|
54
|
+
# Use cs_name in content stream: "/CS1 cs 0.5 0.3 0.2 scn"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Tagged PDF (Accessibility)
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
doc.structure.enable!
|
|
61
|
+
doc.catalog.value[:Lang] = "en-US"
|
|
62
|
+
|
|
63
|
+
doc_elem = doc.structure.add_element(:Document)
|
|
64
|
+
doc.structure.add_child(doc_elem, :H1, title: "Introduction")
|
|
65
|
+
doc.structure.add_child(doc_elem, :P)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Optional Content Groups (Layers)
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
doc.layers.add("Background Art", default_on: false)
|
|
72
|
+
doc.layers.add("Annotations")
|
|
73
|
+
doc.layers.sync!
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Interactive Forms (AcroForm)
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
page = doc.pages.add
|
|
80
|
+
doc.form.add_text_field("username", page: page, rect: [50, 700, 250, 720])
|
|
81
|
+
doc.form.add_checkbox("agree", page: page, rect: [50, 650, 65, 665], checked: true)
|
|
82
|
+
doc.form.add_combo("country", page: page, rect: [50, 600, 200, 620],
|
|
83
|
+
options: ["US", "UK", "JP"], value: "US")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Digital Signatures
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
|
|
90
|
+
key = OpenSSL::PKey::RSA.new(File.read("key.pem"))
|
|
91
|
+
|
|
92
|
+
signed = Pdfrb::DigitalSignature::Signing.sign(doc, cert: cert, key: key,
|
|
93
|
+
reason: "Approval")
|
|
94
|
+
File.binwrite("signed.pdf", signed)
|
|
95
|
+
|
|
96
|
+
# Verify
|
|
97
|
+
results = Pdfrb::DigitalSignature::Verification.verify(signed, trusted_certs: [cert])
|
|
98
|
+
puts "Valid: #{results.first.valid?}"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Semantic Comparison (Diff)
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
left = File.binread("v1.pdf")
|
|
105
|
+
right = File.binread("v2.pdf")
|
|
106
|
+
report = Pdfrb::Compare.compare(left, right)
|
|
107
|
+
|
|
108
|
+
puts "Pages: #{report.page_count_delta}"
|
|
109
|
+
puts "Fonts added: #{report.font_diff[:added]}"
|
|
110
|
+
puts "Equivalent: #{report.equivalent?}"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Conformance Validation
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
doc = Pdfrb.open("archival.pdf")
|
|
117
|
+
|
|
118
|
+
# PDF/A
|
|
119
|
+
result = Pdfrb::Conformance::PdfA.validate(doc, level: :a2b)
|
|
120
|
+
puts "PDF/A-2b: #{result.passed? ? 'PASS' : 'FAIL'}"
|
|
121
|
+
result.errors.each { |e| puts " ERROR: #{e.message}" }
|
|
122
|
+
|
|
123
|
+
# PDF/UA
|
|
124
|
+
result = Pdfrb::Conformance::PdfUA.validate(doc)
|
|
125
|
+
puts "PDF/UA: #{result.passed? ? 'PASS' : 'FAIL'}"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Linearization (Fast Web View)
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
doc = Pdfrb.open("large.pdf")
|
|
132
|
+
io = StringIO.new
|
|
133
|
+
Pdfrb::Linearization::Writer.new(doc).write(io)
|
|
134
|
+
File.binwrite("linearized.pdf", io.string)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Encryption
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
doc = Pdfrb.open("input.pdf")
|
|
141
|
+
doc.write("encrypted.pdf")
|
|
142
|
+
# Encryption configuration via document.config
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Merging PDFs
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
target = Pdfrb.open("base.pdf")
|
|
149
|
+
source = Pdfrb.open("appendix.pdf")
|
|
150
|
+
Pdfrb::Task::Merge.call(target, source)
|
|
151
|
+
target.write("merged.pdf")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Extracting Images
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
doc = Pdfrb.open("input.pdf")
|
|
158
|
+
images = Pdfrb::Task::ExtractImages.call(doc)
|
|
159
|
+
images.each_with_index do |img, i|
|
|
160
|
+
File.binwrite("image_#{i}.#{img[:format]}", img[:data])
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## CLI
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
pdfrb info input.pdf
|
|
168
|
+
pdfrb extract-text input.pdf
|
|
169
|
+
pdfrb merge a.pdf b.pdf -o merged.pdf
|
|
170
|
+
pdfrb diff v1.pdf v2.pdf
|
|
171
|
+
pdfrb encrypt input.pdf -o encrypted.pdf
|
|
172
|
+
pdfrb optimize input.pdf -o optimized.pdf
|
|
173
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# GoToE action (s12.6.4.4, PDF 1.6). Navigate to a destination in
|
|
7
|
+
# an embedded PDF file.
|
|
8
|
+
class ActionGoToE < Action
|
|
9
|
+
arlington_object "ActionGoToE"
|
|
10
|
+
register_subtype :GoToE
|
|
11
|
+
|
|
12
|
+
def target_file; self[:F]; end
|
|
13
|
+
def destination; self[:D]; end
|
|
14
|
+
def new_window; self[:NewWindow]; end
|
|
15
|
+
def target; self[:T]; end
|
|
16
|
+
|
|
17
|
+
def new_window?
|
|
18
|
+
new_window == true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def targets_embedded_file?
|
|
22
|
+
!target_file.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def named_destination?
|
|
26
|
+
destination.is_a?(Symbol) || destination.is_a?(String)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -6,11 +6,12 @@ module Pdfrb
|
|
|
6
6
|
# RichMediaExecute action (s12.6.4.12, PDF 2.0). Execute a
|
|
7
7
|
# command on a RichMedia annotation.
|
|
8
8
|
class ActionRichMediaExecute < Action
|
|
9
|
+
arlington_object "ActionRichMediaExecute"
|
|
9
10
|
register_subtype :RichMediaExecute
|
|
10
11
|
|
|
11
12
|
def target; self[:TA]; end
|
|
12
|
-
def instance; self[:
|
|
13
|
-
def
|
|
13
|
+
def instance; self[:TI]; end
|
|
14
|
+
def command; self[:CMD]; end
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Additional Actions for interactive form fields (s12.6.3.17,
|
|
7
|
+
# Table 199). All four triggers carry JavaScript actions.
|
|
8
|
+
class AddActionFormField < Pdfrb::Model::Cos::Dictionary
|
|
9
|
+
arlington_object "AddActionFormField"
|
|
10
|
+
|
|
11
|
+
# /K — keystroke: format before committing a changed value.
|
|
12
|
+
def on_keystroke(document = nil)
|
|
13
|
+
resolve_action(:K, document)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# /F — format: reformat after a new value is committed.
|
|
17
|
+
def on_format(document = nil)
|
|
18
|
+
resolve_action(:F, document)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# /V — validate (recalculate) after the field value changes.
|
|
22
|
+
def on_validate(document = nil)
|
|
23
|
+
resolve_action(:V, document)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# /C — recalculate when another field changes.
|
|
27
|
+
def on_calculate(document = nil)
|
|
28
|
+
resolve_action(:C, document)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def resolve_action(key, document)
|
|
34
|
+
ref = value[key]
|
|
35
|
+
return nil unless ref && document
|
|
36
|
+
|
|
37
|
+
ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Additional Actions for screen annotations (s12.6.3.17, PDF 1.5).
|
|
7
|
+
# Media events on the screen's region.
|
|
8
|
+
class AddActionScreenAnnotation < Pdfrb::Model::Cos::Dictionary
|
|
9
|
+
arlington_object "AddActionScreenAnnotation"
|
|
10
|
+
|
|
11
|
+
# /E — cursor enters the screen region.
|
|
12
|
+
def on_cursor_enter(document = nil)
|
|
13
|
+
resolve_action(:E, document)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# /X — cursor exits the screen region.
|
|
17
|
+
def on_cursor_exit(document = nil)
|
|
18
|
+
resolve_action(:X, document)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# /D — mouse button pressed inside.
|
|
22
|
+
def on_mouse_down(document = nil)
|
|
23
|
+
resolve_action(:D, document)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# /U — mouse button released inside.
|
|
27
|
+
def on_mouse_up(document = nil)
|
|
28
|
+
resolve_action(:U, document)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# /PO — page containing the screen is opened.
|
|
32
|
+
def on_page_open(document = nil)
|
|
33
|
+
resolve_action(:PO, document)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# /PC — page containing the screen is closed.
|
|
37
|
+
def on_page_close(document = nil)
|
|
38
|
+
resolve_action(:PC, document)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# /PV — screen becomes visible.
|
|
42
|
+
def on_visible(document = nil)
|
|
43
|
+
resolve_action(:PV, document)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# /PI — screen becomes invisible.
|
|
47
|
+
def on_invisible(document = nil)
|
|
48
|
+
resolve_action(:PI, document)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def resolve_action(key, document)
|
|
54
|
+
ref = value[key]
|
|
55
|
+
return nil unless ref && document
|
|
56
|
+
|
|
57
|
+
ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Additional Actions for widget annotations (s12.6.3.17, PDF 1.2).
|
|
7
|
+
# Mouse, focus, and page events on the widget's region.
|
|
8
|
+
class AddActionWidgetAnnotation < Pdfrb::Model::Cos::Dictionary
|
|
9
|
+
arlington_object "AddActionWidgetAnnotation"
|
|
10
|
+
|
|
11
|
+
# /E — cursor enters the widget's region.
|
|
12
|
+
def on_cursor_enter(document = nil)
|
|
13
|
+
resolve_action(:E, document)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# /X — cursor exits the widget's region.
|
|
17
|
+
def on_cursor_exit(document = nil)
|
|
18
|
+
resolve_action(:X, document)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# /D — mouse button pressed inside.
|
|
22
|
+
def on_mouse_down(document = nil)
|
|
23
|
+
resolve_action(:D, document)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# /U — mouse button released inside.
|
|
27
|
+
def on_mouse_up(document = nil)
|
|
28
|
+
resolve_action(:U, document)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# /Fo — widget receives input focus.
|
|
32
|
+
def on_focus(document = nil)
|
|
33
|
+
resolve_action(:Fo, document)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# /Bl — widget loses input focus.
|
|
37
|
+
def on_blur(document = nil)
|
|
38
|
+
resolve_action(:Bl, document)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# /PO — page containing the widget is opened.
|
|
42
|
+
def on_page_open(document = nil)
|
|
43
|
+
resolve_action(:PO, document)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# /PC — page containing the widget is closed.
|
|
47
|
+
def on_page_close(document = nil)
|
|
48
|
+
resolve_action(:PC, document)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# /PV — widget becomes visible.
|
|
52
|
+
def on_visible(document = nil)
|
|
53
|
+
resolve_action(:PV, document)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# /PI — widget becomes invisible.
|
|
57
|
+
def on_invisible(document = nil)
|
|
58
|
+
resolve_action(:PI, document)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def resolve_action(key, document)
|
|
64
|
+
ref = value[key]
|
|
65
|
+
return nil unless ref && document
|
|
66
|
+
|
|
67
|
+
ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -6,7 +6,7 @@ module Pdfrb
|
|
|
6
6
|
# AppearanceTrapNet sub-dictionary (s7.7.3.3, Table 327). Per-
|
|
7
7
|
# appearance-stream trap-net (ink-flattening) parameters.
|
|
8
8
|
class AppearanceTrapNetSubDict < Pdfrb::Model::Cos::Dictionary
|
|
9
|
-
arlington_object "
|
|
9
|
+
arlington_object "AppearanceTrapNetSubDict"
|
|
10
10
|
def pos_h; self[:PosH]; end
|
|
11
11
|
def pos_l; self[:PosL]; end
|
|
12
12
|
def span_h_min; self[:SpanH]; end
|
|
@@ -19,8 +19,13 @@ module Pdfrb
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# AppearanceTrapNet (s7.7.3.3). The trap-net dictionary that wraps
|
|
22
|
-
# appearance sub-dicts.
|
|
22
|
+
# appearance sub-dicts (/N, /R, /D).
|
|
23
23
|
class AppearanceTrapNet < Pdfrb::Model::Cos::Dictionary
|
|
24
|
+
arlington_object "AppearanceTrapNet"
|
|
25
|
+
def normal; self[:N]; end
|
|
26
|
+
def rollover; self[:R]; end
|
|
27
|
+
def down; self[:D]; end
|
|
28
|
+
|
|
24
29
|
def type; self[:Type]; end
|
|
25
30
|
def version; self[:Version]; end
|
|
26
31
|
def font_state_appearance; self[:FontStateAppearance]; end
|
|
@@ -41,6 +46,7 @@ module Pdfrb
|
|
|
41
46
|
# AppearanceSubDict (s12.5.4). Sub-dictionary inside Appearance
|
|
42
47
|
# entries /N, /R, /D that maps each appearance state to a stream.
|
|
43
48
|
class AppearanceSubDict < Pdfrb::Model::Cos::Dictionary
|
|
49
|
+
arlington_object "AppearanceSubDict"
|
|
44
50
|
def each_state(&block)
|
|
45
51
|
return enum_for(:each_state) unless block
|
|
46
52
|
|
|
@@ -64,22 +70,6 @@ module Pdfrb
|
|
|
64
70
|
!!app_build
|
|
65
71
|
end
|
|
66
72
|
end
|
|
67
|
-
|
|
68
|
-
# Annotation Projection dict (s12.5.6.21). Projection annotation
|
|
69
|
-
# for spatial content.
|
|
70
|
-
class AnnotationProjectionDict < Pdfrb::Model::Cos::Dictionary
|
|
71
|
-
def ex_data; self[:ExData]; end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# ExData Projection dict (s12.5.6.21, Table 198). Holds the
|
|
75
|
-
# geospatial projection details used by Projection annotations.
|
|
76
|
-
class ExDataProjection < Pdfrb::Model::Cos::Dictionary
|
|
77
|
-
def type; self[:Type]; end
|
|
78
|
-
|
|
79
|
-
def project?
|
|
80
|
-
type == :ProjectedPDL
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
73
|
end
|
|
84
74
|
end
|
|
85
75
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Movie annotation (s12.5.6.14). /Subtype /Movie. Plays a Movie
|
|
7
|
+
# when activated.
|
|
8
|
+
class MovieAnnotation < Annotation
|
|
9
|
+
arlington_object "AnnotMovie"
|
|
10
|
+
|
|
11
|
+
def movie; self[:Movie]; end
|
|
12
|
+
def action; self[:A]; end
|
|
13
|
+
def title; self[:T]; end
|
|
14
|
+
|
|
15
|
+
def has_movie?
|
|
16
|
+
!movie.nil?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def uses_action?
|
|
20
|
+
!action.nil?
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Projection annotation (s12.5.6.19, PDF 1.7+AdobeExt). Projects
|
|
7
|
+
# a duplicate of a region of a page with a modified appearance.
|
|
8
|
+
class ProjectionAnnotation < MarkupAnnotation
|
|
9
|
+
arlington_object "AnnotProjection"
|
|
10
|
+
|
|
11
|
+
def title; self[:T]; end
|
|
12
|
+
def popup; self[:Popup]; end
|
|
13
|
+
def rich_contents; self[:RC]; end
|
|
14
|
+
def creation_date; self[:CreationDate]; end
|
|
15
|
+
def in_reply_to; self[:IRT]; end
|
|
16
|
+
def subject; self[:Subj]; end
|
|
17
|
+
def reply_type; self[:RT]; end
|
|
18
|
+
def intent; self[:IT]; end
|
|
19
|
+
def ex_data; self[:ExData]; end
|
|
20
|
+
|
|
21
|
+
def has_projection_data?
|
|
22
|
+
!ex_data.nil?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Annotation Projection dict (s12.5.6.21). Projection annotation
|
|
27
|
+
# for spatial content.
|
|
28
|
+
class AnnotationProjectionDict < Pdfrb::Model::Cos::Dictionary
|
|
29
|
+
def ex_data; self[:ExData]; end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ExData Projection dict (s12.5.6.21, Table 198). Holds the
|
|
33
|
+
# geospatial projection details used by Projection annotations.
|
|
34
|
+
class ExDataProjection < Pdfrb::Model::Cos::Dictionary
|
|
35
|
+
def type; self[:Type]; end
|
|
36
|
+
|
|
37
|
+
def project?
|
|
38
|
+
type == :ProjectedPDL
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# 3D annotation (s13.6.2, PDF 1.6+). /Subtype /3D. Hosts a 3D
|
|
7
|
+
# artwork stream, activation behaviour, and viewing state.
|
|
8
|
+
class ThreeDAnnotation < Annotation
|
|
9
|
+
arlington_object "Annot3D"
|
|
10
|
+
|
|
11
|
+
def artwork; self[:"3DD"]; end
|
|
12
|
+
def default_view; self[:"3DV"]; end
|
|
13
|
+
def activation; self[:"3DA"]; end
|
|
14
|
+
def interactive; self[:"3DI"]; end
|
|
15
|
+
def view_box; self[:"3DB"]; end
|
|
16
|
+
def units; self[:"3DU"]; end
|
|
17
|
+
def geometry; self[:GEO]; end
|
|
18
|
+
|
|
19
|
+
def interactive?
|
|
20
|
+
interactive == true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def has_measure?
|
|
24
|
+
!geometry.nil?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def default_view_name?
|
|
28
|
+
default_view.is_a?(Symbol) || default_view.is_a?(String)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Trap network annotation (s14.11.5). Marks the extent of the
|
|
7
|
+
# trap network applied by a prepress system. Its appearance
|
|
8
|
+
# stream carries per-colorant trap parameters.
|
|
9
|
+
class TrapNetworkAnnotation < MarkupAnnotation
|
|
10
|
+
arlington_object "AnnotTrapNetwork"
|
|
11
|
+
|
|
12
|
+
def last_modified; self[:LastModified]; end
|
|
13
|
+
def version; self[:Version]; end
|
|
14
|
+
def annot_states; self[:AnnotStates]; end
|
|
15
|
+
def font_fauxing; self[:FontFauxing]; end
|
|
16
|
+
|
|
17
|
+
def annot_states?
|
|
18
|
+
!annot_states.nil?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def fauxed_font_names
|
|
22
|
+
fonts = font_fauxing
|
|
23
|
+
fonts.is_a?(Pdfrb::Model::PdfArray) ? fonts.to_a : fonts
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/pdfrb/model/type.rb
CHANGED
|
@@ -201,6 +201,10 @@ module Pdfrb
|
|
|
201
201
|
autoload :PrinterMarkSubDict, "pdfrb/model/type/transition"
|
|
202
202
|
autoload :ScreenAnnotation, "pdfrb/model/type/screen_annotation"
|
|
203
203
|
autoload :SoundAnnotation, "pdfrb/model/type/sound_annotation"
|
|
204
|
+
autoload :ThreeDAnnotation, "pdfrb/model/type/three_d_annotation"
|
|
205
|
+
autoload :MovieAnnotation, "pdfrb/model/type/movie_annotation"
|
|
206
|
+
autoload :ProjectionAnnotation, "pdfrb/model/type/projection_annotation"
|
|
207
|
+
autoload :TrapNetworkAnnotation, "pdfrb/model/type/trap_network_annotation"
|
|
204
208
|
|
|
205
209
|
# Rich Media annotation family (s13.6).
|
|
206
210
|
autoload :RichMediaAnnotation, "pdfrb/model/type/rich_media_annotation"
|
|
@@ -270,6 +274,7 @@ module Pdfrb
|
|
|
270
274
|
autoload :ActionGoTo3DView, "pdfrb/model/type/action_go_to_3d_view"
|
|
271
275
|
autoload :ActionGoToDp, "pdfrb/model/type/action_go_to_dp"
|
|
272
276
|
autoload :ActionRichMediaExecute, "pdfrb/model/type/action_rich_media_execute"
|
|
277
|
+
autoload :ActionGoToE, "pdfrb/model/type/action_go_to_e"
|
|
273
278
|
autoload :ActionNOP, "pdfrb/model/type/action_nop"
|
|
274
279
|
|
|
275
280
|
# Signature family (s12.8).
|
|
@@ -286,8 +291,8 @@ module Pdfrb
|
|
|
286
291
|
autoload :AppearanceSubDict, "pdfrb/model/type/appearance_trap_net"
|
|
287
292
|
autoload :MediaClip, "pdfrb/model/type/media_clip"
|
|
288
293
|
autoload :Rendition, "pdfrb/model/type/rendition"
|
|
289
|
-
autoload :ExDataProjection, "pdfrb/model/type/
|
|
290
|
-
autoload :AnnotationProjectionDict, "pdfrb/model/type/
|
|
294
|
+
autoload :ExDataProjection, "pdfrb/model/type/projection_annotation"
|
|
295
|
+
autoload :AnnotationProjectionDict, "pdfrb/model/type/projection_annotation"
|
|
291
296
|
|
|
292
297
|
# Media offset / player / screen types.
|
|
293
298
|
autoload :MediaOffsetTime, "pdfrb/model/type/media_offset"
|
|
@@ -405,6 +410,12 @@ module Pdfrb
|
|
|
405
410
|
# Additional actions on page objects (s12.6.3.16).
|
|
406
411
|
autoload :AddActionPageObject, "pdfrb/model/type/add_action_page_object"
|
|
407
412
|
|
|
413
|
+
# Additional actions on form fields / screen + widget annotations
|
|
414
|
+
# (s12.6.3.17).
|
|
415
|
+
autoload :AddActionFormField, "pdfrb/model/type/add_action_form_field"
|
|
416
|
+
autoload :AddActionScreenAnnotation, "pdfrb/model/type/add_action_screen_annotation"
|
|
417
|
+
autoload :AddActionWidgetAnnotation, "pdfrb/model/type/add_action_widget_annotation"
|
|
418
|
+
|
|
408
419
|
# Border style (s12.5.4). BorderEffect lives in its own file.
|
|
409
420
|
autoload :BorderStyle, "pdfrb/model/type/border_style"
|
|
410
421
|
autoload :BorderEffect, "pdfrb/model/type/border_effect"
|
data/lib/pdfrb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pdfrb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.23
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|
|
@@ -701,6 +701,8 @@ files:
|
|
|
701
701
|
- data/pdfrb/glyphlist.txt
|
|
702
702
|
- data/pdfrb/layout/hyphenation_en.txt
|
|
703
703
|
- data/pdfrb/zapfdingbats.txt
|
|
704
|
+
- docs/SEMVER.md
|
|
705
|
+
- docs/USAGE.md
|
|
704
706
|
- exe/pdfrb
|
|
705
707
|
- lib/pdfrb.rb
|
|
706
708
|
- lib/pdfrb/action.rb
|
|
@@ -954,6 +956,7 @@ files:
|
|
|
954
956
|
- lib/pdfrb/model/type/action.rb
|
|
955
957
|
- lib/pdfrb/model/type/action_go_to_3d_view.rb
|
|
956
958
|
- lib/pdfrb/model/type/action_go_to_dp.rb
|
|
959
|
+
- lib/pdfrb/model/type/action_go_to_e.rb
|
|
957
960
|
- lib/pdfrb/model/type/action_go_to_r.rb
|
|
958
961
|
- lib/pdfrb/model/type/action_goto.rb
|
|
959
962
|
- lib/pdfrb/model/type/action_hide.rb
|
|
@@ -975,7 +978,10 @@ files:
|
|
|
975
978
|
- lib/pdfrb/model/type/action_trans.rb
|
|
976
979
|
- lib/pdfrb/model/type/action_uri.rb
|
|
977
980
|
- lib/pdfrb/model/type/add_action_catalog.rb
|
|
981
|
+
- lib/pdfrb/model/type/add_action_form_field.rb
|
|
978
982
|
- lib/pdfrb/model/type/add_action_page_object.rb
|
|
983
|
+
- lib/pdfrb/model/type/add_action_screen_annotation.rb
|
|
984
|
+
- lib/pdfrb/model/type/add_action_widget_annotation.rb
|
|
979
985
|
- lib/pdfrb/model/type/af_embedded_file.rb
|
|
980
986
|
- lib/pdfrb/model/type/af_file_specification.rb
|
|
981
987
|
- lib/pdfrb/model/type/alternate_image.rb
|
|
@@ -1077,6 +1083,7 @@ files:
|
|
|
1077
1083
|
- lib/pdfrb/model/type/metadata.rb
|
|
1078
1084
|
- lib/pdfrb/model/type/misc_helpers.rb
|
|
1079
1085
|
- lib/pdfrb/model/type/movie.rb
|
|
1086
|
+
- lib/pdfrb/model/type/movie_annotation.rb
|
|
1080
1087
|
- lib/pdfrb/model/type/names.rb
|
|
1081
1088
|
- lib/pdfrb/model/type/namespace.rb
|
|
1082
1089
|
- lib/pdfrb/model/type/object_reference.rb
|
|
@@ -1103,6 +1110,7 @@ files:
|
|
|
1103
1110
|
- lib/pdfrb/model/type/polyline_annotation.rb
|
|
1104
1111
|
- lib/pdfrb/model/type/popup_annotation.rb
|
|
1105
1112
|
- lib/pdfrb/model/type/printer_mark_annotation.rb
|
|
1113
|
+
- lib/pdfrb/model/type/projection_annotation.rb
|
|
1106
1114
|
- lib/pdfrb/model/type/redact_annotation.rb
|
|
1107
1115
|
- lib/pdfrb/model/type/rendition.rb
|
|
1108
1116
|
- lib/pdfrb/model/type/resources.rb
|
|
@@ -1144,6 +1152,7 @@ files:
|
|
|
1144
1152
|
- lib/pdfrb/model/type/thread.rb
|
|
1145
1153
|
- lib/pdfrb/model/type/three_d_activation.rb
|
|
1146
1154
|
- lib/pdfrb/model/type/three_d_animation_style.rb
|
|
1155
|
+
- lib/pdfrb/model/type/three_d_annotation.rb
|
|
1147
1156
|
- lib/pdfrb/model/type/three_d_background.rb
|
|
1148
1157
|
- lib/pdfrb/model/type/three_d_cross_section.rb
|
|
1149
1158
|
- lib/pdfrb/model/type/three_d_lighting_scheme.rb
|
|
@@ -1163,6 +1172,7 @@ files:
|
|
|
1163
1172
|
- lib/pdfrb/model/type/timespan.rb
|
|
1164
1173
|
- lib/pdfrb/model/type/to_unicode_cmap_stream.rb
|
|
1165
1174
|
- lib/pdfrb/model/type/transition.rb
|
|
1175
|
+
- lib/pdfrb/model/type/trap_network_annotation.rb
|
|
1166
1176
|
- lib/pdfrb/model/type/trap_region.rb
|
|
1167
1177
|
- lib/pdfrb/model/type/underline_annotation.rb
|
|
1168
1178
|
- lib/pdfrb/model/type/ur_transform_parameters.rb
|
|
@@ -1218,7 +1228,6 @@ files:
|
|
|
1218
1228
|
- lib/pdfrb/xmp/packet.rb
|
|
1219
1229
|
- lib/pdfrb/xmp/schemas.rb
|
|
1220
1230
|
- lib/pdfrb/xref_section.rb
|
|
1221
|
-
- pdfrb.gemspec
|
|
1222
1231
|
- script/apply_fixes.sh
|
|
1223
1232
|
- script/make_jpeg_fixture.rb
|
|
1224
1233
|
- script/make_png_fixture.rb
|
data/pdfrb.gemspec
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/pdfrb/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "pdfrb"
|
|
7
|
-
spec.version = Pdfrb::VERSION
|
|
8
|
-
spec.authors = ["Ribose Inc."]
|
|
9
|
-
spec.email = ["open.source@ribose.com"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Pure-Ruby PDF parser, Arlington-model-driven domain model, and serializer"
|
|
12
|
-
spec.description = <<~HEREDOC
|
|
13
|
-
Pdfrb is a pure-Ruby PDF library: a byte-level reader, an
|
|
14
|
-
Arlington-model-driven typed domain model, and a serializer. The
|
|
15
|
-
PDF object model is sourced directly from the vendored Arlington
|
|
16
|
-
PDF Model TSVs (machine-readable ISO 32000-2:2020), so field
|
|
17
|
-
metadata, version predicates, and validators stay aligned with
|
|
18
|
-
the spec by data, not by hand-coded mimicry.
|
|
19
|
-
|
|
20
|
-
Two-direction contract: "PDF file <=> Model" and "API Builder
|
|
21
|
-
Input => Model". Mirrors the layered design of the sibling
|
|
22
|
-
postscript gem.
|
|
23
|
-
HEREDOC
|
|
24
|
-
|
|
25
|
-
spec.homepage = "https://github.com/claricle/pdfrb"
|
|
26
|
-
spec.license = "BSD-2-Clause"
|
|
27
|
-
spec.required_ruby_version = ">= 3.2.0"
|
|
28
|
-
|
|
29
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
30
|
-
spec.metadata["source_code_uri"] = "https://github.com/claricle/pdfrb"
|
|
31
|
-
spec.metadata["changelog_uri"] = "https://github.com/claricle/pdfrb/blob/main/CHANGELOG.md"
|
|
32
|
-
spec.metadata["bug_tracker_uri"] = "https://github.com/claricle/pdfrb/issues"
|
|
33
|
-
spec.metadata["rubygems_mfa_required"] = "true"
|
|
34
|
-
|
|
35
|
-
spec.files = Dir.chdir(__dir__) do
|
|
36
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
37
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
spec.bindir = "exe"
|
|
41
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
42
|
-
spec.require_paths = ["lib"]
|
|
43
|
-
|
|
44
|
-
spec.add_dependency "thor"
|
|
45
|
-
end
|