rustpdf 0.1.0-x86_64-linux → 0.2.0-x86_64-linux
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/lib/rustpdf/document.rb +38 -0
- data/lib/rustpdf/editable_doc.rb +63 -0
- data/lib/rustpdf/native.rb +21 -0
- data/lib/rustpdf.rb +55 -0
- data/vendor/x86_64-linux/libpdf_ffi.so +0 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95d16a8b08efac40f62d3b34401df96783fe696d1087b91cc28ee2024b36eb67
|
|
4
|
+
data.tar.gz: 3975ed0333b5a5ac46ece57182b763c815bb8dc4e5f13586461d7ec3bba0a04f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77a9b727af0be789c3bf95c82ba55f76c65cae9f8503e68eb528bc423404955cb61a79fbdb368191bc7448e5e24b4364e0835a27157c50851e45fd67d0a296be
|
|
7
|
+
data.tar.gz: bc65a31c85ff678f1a17012fdfa318932e566629570be38c668322802adadf1d2365d1b88518807270065fc7d35139d852caca4ce698aef2b9ef95cd7806bcdd
|
data/lib/rustpdf/document.rb
CHANGED
|
@@ -160,6 +160,44 @@ module RustPdf
|
|
|
160
160
|
self
|
|
161
161
|
end
|
|
162
162
|
|
|
163
|
+
# ---- hyperlinks + bookmarks (Tier 1) ------------------------------------
|
|
164
|
+
|
|
165
|
+
# rect = [x0, y0, x1, y1]; link to an external URI.
|
|
166
|
+
def link_uri(rect, uri)
|
|
167
|
+
RustPdf.check(Native.call("pdf_page_link_uri", ptr, rect[0], rect[1], rect[2], rect[3], uri))
|
|
168
|
+
self
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# rect = [x0, y0, x1, y1]; link to another page (optional +top+ y-offset).
|
|
172
|
+
def link_to_page(rect, page_index, top: nil)
|
|
173
|
+
RustPdf.check(Native.call("pdf_page_link_to_page", ptr, rect[0], rect[1], rect[2], rect[3],
|
|
174
|
+
page_index, top || 0.0, top.nil? ? 0 : 1))
|
|
175
|
+
self
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Append one outline tree (a RustPdf::Bookmark). Pre-order flattened into
|
|
179
|
+
# parallel arrays and emitted in a single native call.
|
|
180
|
+
def add_bookmark(bookmark)
|
|
181
|
+
entries = bookmark.flatten_into(0, [])
|
|
182
|
+
n = entries.size
|
|
183
|
+
levels = entries.map { |e| e[0] }.pack("i!*")
|
|
184
|
+
pages = entries.map { |e| e[2] }.pack("J*")
|
|
185
|
+
tops = entries.map { |e| e[3] || 0.0 }.pack("d*")
|
|
186
|
+
has = entries.map { |e| e[3].nil? ? 0 : 1 }.pack("i!*")
|
|
187
|
+
cstrs = entries.map { |e| Fiddle::Pointer[e[1].to_s] }
|
|
188
|
+
titles = cstrs.map(&:to_i).pack("J*")
|
|
189
|
+
RustPdf.check(Native.call("pdf_document_add_bookmarks", ptr, n, levels, titles, pages, tops, has))
|
|
190
|
+
cstrs.clear # released after the call returned
|
|
191
|
+
self
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# ---- ZUGFeRD / Factur-X (Tier 2) ----------------------------------------
|
|
195
|
+
|
|
196
|
+
def facturx(xml, profile: FacturxProfile::EN16931)
|
|
197
|
+
RustPdf.check(Native.call("pdf_document_facturx", ptr, xml, xml.bytesize, profile))
|
|
198
|
+
self
|
|
199
|
+
end
|
|
200
|
+
|
|
163
201
|
# ---- output -------------------------------------------------------------
|
|
164
202
|
|
|
165
203
|
def page_count
|
data/lib/rustpdf/editable_doc.rb
CHANGED
|
@@ -93,6 +93,69 @@ module RustPdf
|
|
|
93
93
|
found != 0
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
+
# ---- form fill + flatten + watermark (Tier 1) ---------------------------
|
|
97
|
+
|
|
98
|
+
# Set a checkbox by field name. Returns whether the field existed.
|
|
99
|
+
def set_checkbox(name, checked = true)
|
|
100
|
+
found = RustPdf.out_int { |buf| Native.call("pdf_editable_set_checkbox", ptr, name, checked ? 1 : 0, buf) }
|
|
101
|
+
found != 0
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Select a radio button by field name + export value. Returns whether found.
|
|
105
|
+
def set_radio(name, export_value)
|
|
106
|
+
found = RustPdf.out_int { |buf| Native.call("pdf_editable_set_radio", ptr, name, export_value, buf) }
|
|
107
|
+
found != 0
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Set a choice (dropdown/list) value by field name. Returns whether found.
|
|
111
|
+
def set_choice(name, value)
|
|
112
|
+
found = RustPdf.out_int { |buf| Native.call("pdf_editable_set_choice", ptr, name, value, buf) }
|
|
113
|
+
found != 0
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Flatten all AcroForm fields into page content (removes interactivity).
|
|
117
|
+
def flatten_forms
|
|
118
|
+
RustPdf.check(Native.call("pdf_editable_flatten_forms", ptr))
|
|
119
|
+
self
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Returns the list of AcroForm field names.
|
|
123
|
+
def field_names
|
|
124
|
+
p = ptr
|
|
125
|
+
text = RustPdf.take_bytes { |pp, pn| Native.call("pdf_editable_field_names", p, pp, pn) }
|
|
126
|
+
.force_encoding(Encoding::UTF_8)
|
|
127
|
+
text.split("\n").reject(&:empty?)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Stamp a diagonal text watermark across every page.
|
|
131
|
+
def watermark_text(text, size: 64.0, color: [0.5, 0.5, 0.5], opacity: 0.30, rotation_deg: 45.0)
|
|
132
|
+
r, g, b = color
|
|
133
|
+
RustPdf.check(Native.call("pdf_editable_watermark_text", ptr, text, size, r, g, b, opacity, rotation_deg))
|
|
134
|
+
self
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Stamp an image watermark (from a file) across every page.
|
|
138
|
+
def watermark_image_file(path, width, height, opacity: 0.30)
|
|
139
|
+
RustPdf.check(Native.call("pdf_editable_watermark_image_file", ptr, path, width, height, opacity))
|
|
140
|
+
self
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# ---- redaction + PDF/A conversion (Tier 2) ------------------------------
|
|
144
|
+
|
|
145
|
+
# Black out rectangles on a page. rects = [[x0,y0,x1,y1], ...].
|
|
146
|
+
# Returns whether the page existed.
|
|
147
|
+
def redact(page_index, rects)
|
|
148
|
+
flat = rects.flatten.pack("d*")
|
|
149
|
+
found = RustPdf.out_int { |buf| Native.call("pdf_editable_redact", ptr, page_index, flat, rects.size, buf) }
|
|
150
|
+
found != 0
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Convert the document to PDF/A (B-levels only: A1B=0, A2B=1, A3B=3).
|
|
154
|
+
def convert_to_pdfa(level = Pdfa::A2B)
|
|
155
|
+
RustPdf.check(Native.call("pdf_editable_convert_to_pdfa", ptr, level))
|
|
156
|
+
self
|
|
157
|
+
end
|
|
158
|
+
|
|
96
159
|
def optimize
|
|
97
160
|
RustPdf.check(Native.call("pdf_editable_optimize", ptr))
|
|
98
161
|
self
|
data/lib/rustpdf/native.rb
CHANGED
|
@@ -78,9 +78,30 @@ module RustPdf
|
|
|
78
78
|
"pdf_editable_save" => [[VP, VP], I],
|
|
79
79
|
|
|
80
80
|
"pdf_extract_text" => [[VP, SZ, VP, VP], I],
|
|
81
|
+
"pdf_extract_images_to_dir" => [[VP, SZ, VP, VP], I],
|
|
81
82
|
"pdf_sign" => [[VP, SZ, VP, SZ, VP, SZ, VP, VP, VP, I, VP, VP], I],
|
|
82
83
|
"pdf_timestamp" => [[VP, SZ, VP, SZ, VP, SZ, VP, VP, VP], I],
|
|
83
84
|
"pdf_add_dss" => [[VP, SZ, VP, VP, SZ, VP, VP, SZ, VP, VP], I],
|
|
85
|
+
|
|
86
|
+
# Tier 1: hyperlinks + bookmarks (Document)
|
|
87
|
+
"pdf_page_link_uri" => [[VP, D, D, D, D, VP], I],
|
|
88
|
+
"pdf_page_link_to_page" => [[VP, D, D, D, D, SZ, D, I], I],
|
|
89
|
+
"pdf_document_add_bookmarks" => [[VP, SZ, VP, VP, VP, VP, VP], I],
|
|
90
|
+
# Tier 2: ZUGFeRD / Factur-X (Document)
|
|
91
|
+
"pdf_document_facturx" => [[VP, VP, SZ, I], I],
|
|
92
|
+
# Tier 1: form fill + flatten + watermark (EditableDoc)
|
|
93
|
+
"pdf_editable_set_checkbox" => [[VP, VP, I, VP], I],
|
|
94
|
+
"pdf_editable_set_radio" => [[VP, VP, VP, VP], I],
|
|
95
|
+
"pdf_editable_set_choice" => [[VP, VP, VP, VP], I],
|
|
96
|
+
"pdf_editable_flatten_forms" => [[VP], I],
|
|
97
|
+
"pdf_editable_field_names" => [[VP, VP, VP], I],
|
|
98
|
+
"pdf_editable_watermark_text" => [[VP, VP, D, D, D, D, D, D], I],
|
|
99
|
+
"pdf_editable_watermark_image_file" => [[VP, VP, D, D, D], I],
|
|
100
|
+
# Tier 2: redaction + PDF/A conversion (EditableDoc)
|
|
101
|
+
"pdf_editable_redact" => [[VP, SZ, VP, SZ, VP], I],
|
|
102
|
+
"pdf_editable_convert_to_pdfa" => [[VP, I], I],
|
|
103
|
+
# Tier 2: signature validation (module-level)
|
|
104
|
+
"pdf_verify_signatures_json" => [[VP, SZ, VP, VP], I],
|
|
84
105
|
}.freeze
|
|
85
106
|
|
|
86
107
|
def lib
|
data/lib/rustpdf.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "fiddle"
|
|
2
|
+
require "json"
|
|
2
3
|
require_relative "rustpdf/native"
|
|
3
4
|
|
|
4
5
|
# Idiomatic Ruby binding for the rust-pdf core over its C ABI (libpdf_ffi),
|
|
@@ -50,6 +51,42 @@ module RustPdf
|
|
|
50
51
|
AES256 = 2
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
# ZUGFeRD / Factur-X conformance profiles.
|
|
55
|
+
module FacturxProfile
|
|
56
|
+
MINIMUM = 0
|
|
57
|
+
BASIC_WL = 1
|
|
58
|
+
BASIC = 2
|
|
59
|
+
EN16931 = 3
|
|
60
|
+
EXTENDED = 4
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# A document outline (bookmark) entry. Nest with #child to build a tree.
|
|
64
|
+
# Each #add_bookmark call on a Document appends one root tree (pre-order
|
|
65
|
+
# flattened into parallel arrays).
|
|
66
|
+
class Bookmark
|
|
67
|
+
attr_accessor :title, :page, :top, :children
|
|
68
|
+
|
|
69
|
+
def initialize(title, page, top: nil, children: nil)
|
|
70
|
+
@title = title
|
|
71
|
+
@page = page
|
|
72
|
+
@top = top
|
|
73
|
+
@children = children || []
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Append a child bookmark; returns self for chaining.
|
|
77
|
+
def child(bookmark)
|
|
78
|
+
@children << bookmark
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Pre-order flatten into +out+ as [level, title, page, top] tuples.
|
|
83
|
+
def flatten_into(level, out)
|
|
84
|
+
out << [level, title, page, top]
|
|
85
|
+
children.each { |c| c.flatten_into(level + 1, out) }
|
|
86
|
+
out
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
53
90
|
module_function
|
|
54
91
|
|
|
55
92
|
# Native library version string.
|
|
@@ -70,6 +107,24 @@ module RustPdf
|
|
|
70
107
|
.force_encoding(Encoding::UTF_8)
|
|
71
108
|
end
|
|
72
109
|
|
|
110
|
+
# Extract every raster image into +dir+ (JPEG verbatim as .jpg, others as
|
|
111
|
+
# .png; files named page{N}_{name}.{ext}). Returns the number written.
|
|
112
|
+
def extract_images_to_dir(pdf, dir)
|
|
113
|
+
count = Fiddle::Pointer.malloc(Native::SIZEOF_SZ, Fiddle::RUBY_FREE)
|
|
114
|
+
check(Native.call("pdf_extract_images_to_dir", pdf, pdf.bytesize, dir, count))
|
|
115
|
+
count[0, Native::SIZEOF_SZ].unpack1("J")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Validate every signature in +pdf+. Returns one Hash per signature with keys
|
|
119
|
+
# "field_name", "sub_filter", "signer", "covers_whole_document",
|
|
120
|
+
# "digest_valid", "signature_valid", "is_valid" and "byte_range". An empty
|
|
121
|
+
# array means the document is unsigned.
|
|
122
|
+
def verify_signatures(pdf)
|
|
123
|
+
js = take_bytes { |pp, pn| Native.call("pdf_verify_signatures_json", pdf, pdf.bytesize, pp, pn) }
|
|
124
|
+
.force_encoding(Encoding::UTF_8)
|
|
125
|
+
js.empty? ? [] : JSON.parse(js)
|
|
126
|
+
end
|
|
127
|
+
|
|
73
128
|
# Sign a PDF (PKCS#7 detached, incremental update). Requires a license.
|
|
74
129
|
def sign(pdf, key_der, cert_der, reason: nil, location: nil, name: nil, pades: false)
|
|
75
130
|
take_bytes do |pp, pn|
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rustpdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: x86_64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- rust-pdf
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Idiomatic Ruby binding over the rust-pdf C ABI (libpdf_ffi) using the
|
|
14
14
|
built-in Fiddle stdlib.
|