rustpdf 0.4.4-aarch64-linux → 0.4.6-aarch64-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/editable_doc.rb +70 -0
- data/lib/rustpdf/native.rb +12 -0
- data/lib/rustpdf.rb +72 -0
- data/vendor/aarch64-linux/libpdf_ffi.so +0 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70178a69ffe81e07690514a1c1fe8116707b848b381fbf1ae17952571c9c31ef
|
|
4
|
+
data.tar.gz: 753e07ad832d29f6d638397f10cb0888495fc2a4c56f39b2216d260edf2267b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10f7a53e4b0d0f3d76e51ef0aac75654b4a9efda0b355aa84415d2a81a0510079f686d116d9b7ec69ccf9637e4fe8a10349001a85a0a0aa38c238e64341eb5d0
|
|
7
|
+
data.tar.gz: 48d2852ad7d33e705c4e8dac80fb807109704799d270c93367838bc160465792535b8c2d94380e19e5f30dfb307f9624b7f52772db628bab62b56dfde62c5cb3
|
data/lib/rustpdf/editable_doc.rb
CHANGED
|
@@ -146,6 +146,76 @@ module RustPdf
|
|
|
146
146
|
self
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
# ---- positioned drawing primitives (issue #45 P1) -----------------------
|
|
150
|
+
|
|
151
|
+
# Paint a filled rectangle at (+x+, +y+) sized +width+ x +height+ on page
|
|
152
|
+
# +page_index+ (0-based), in RGB +color+ (each 0..1, default opaque white) at
|
|
153
|
+
# +opacity+ (0..1). Coordinates are in the page's VISIBLE space (origin
|
|
154
|
+
# lower-left, y up), regardless of the page's /Rotate. The common use is
|
|
155
|
+
# masking a placeholder with an opaque white box. Returns whether the page
|
|
156
|
+
# existed.
|
|
157
|
+
def fill_rect(page_index, x, y, width, height, color = [1.0, 1.0, 1.0], opacity = 1.0)
|
|
158
|
+
r, g, b = color
|
|
159
|
+
found = RustPdf.out_int do |buf|
|
|
160
|
+
Native.call("pdf_editable_fill_rect", ptr, page_index, x.to_f, y.to_f,
|
|
161
|
+
width.to_f, height.to_f, r.to_f, g.to_f, b.to_f, opacity.to_f, buf)
|
|
162
|
+
end
|
|
163
|
+
found != 0
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Draw a line of positioned +text+ with baseline at (+x+, +y+) on page
|
|
167
|
+
# +page_index+ (0-based), using standard Helvetica at +size+ points in RGB
|
|
168
|
+
# +color+ (each 0..1, default black). +rotation_deg+ rotates the text
|
|
169
|
+
# counter-clockwise about its anchor (match the page rotation to follow a
|
|
170
|
+
# rotated page). +align+ (RustPdf::Align, default LEFT) shifts the start
|
|
171
|
+
# point along the baseline direction by the text width for RIGHT/CENTER
|
|
172
|
+
# alignment. Coordinates are in the page's VISIBLE space (origin lower-left,
|
|
173
|
+
# y up), regardless of the page's /Rotate. Returns whether the page existed.
|
|
174
|
+
def place_text(page_index, x, y, text, size = 12.0, color = [0.0, 0.0, 0.0], rotation_deg = 0.0,
|
|
175
|
+
align: Align::LEFT)
|
|
176
|
+
r, g, b = color
|
|
177
|
+
found = RustPdf.out_int do |buf|
|
|
178
|
+
Native.call("pdf_editable_place_text_aligned", ptr, page_index, x.to_f, y.to_f, text,
|
|
179
|
+
size.to_f, r.to_f, g.to_f, b.to_f, rotation_deg.to_f, align, buf)
|
|
180
|
+
end
|
|
181
|
+
found != 0
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Mask a placeholder: fill an opaque background box +[x, y, x+width,
|
|
185
|
+
# y+height]+ in +bg_color+ (each 0..1, default white), then write +text+
|
|
186
|
+
# over it using standard Helvetica at +size+ points in +text_color+ (each
|
|
187
|
+
# 0..1, default black), horizontally aligned per +align+ (RustPdf::Align,
|
|
188
|
+
# default LEFT) and vertically centered within the box. Saves hand-computing
|
|
189
|
+
# the baseline when stamping a real value over a placeholder. Coordinates are
|
|
190
|
+
# in the page's VISIBLE space (origin lower-left, y up). Returns whether the
|
|
191
|
+
# page existed.
|
|
192
|
+
def masked_text(page_index, x, y, width, height, text, size = 12.0,
|
|
193
|
+
text_color = [0.0, 0.0, 0.0], bg_color = [1.0, 1.0, 1.0],
|
|
194
|
+
align: Align::LEFT)
|
|
195
|
+
tr, tg, tb = text_color
|
|
196
|
+
br, bg, bb = bg_color
|
|
197
|
+
found = RustPdf.out_int do |buf|
|
|
198
|
+
Native.call("pdf_editable_masked_text", ptr, page_index, x.to_f, y.to_f,
|
|
199
|
+
width.to_f, height.to_f, text, size.to_f,
|
|
200
|
+
tr.to_f, tg.to_f, tb.to_f, br.to_f, bg.to_f, bb.to_f, align, buf)
|
|
201
|
+
end
|
|
202
|
+
found != 0
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Stamp an +image+ (PNG or JPEG bytes; the core dispatches on the signature)
|
|
206
|
+
# onto page +page_index+ (0-based), with its lower-left corner at (+x+, +y+),
|
|
207
|
+
# scaled to +width+ x +height+ points and rotated +rotation_deg+ degrees
|
|
208
|
+
# counter-clockwise about that corner. Coordinates are in the page's VISIBLE
|
|
209
|
+
# space (origin lower-left, y up), regardless of the page's /Rotate. Returns
|
|
210
|
+
# whether the page existed.
|
|
211
|
+
def draw_image(page_index, image, x, y, width, height, rotation_deg = 0.0)
|
|
212
|
+
found = RustPdf.out_int do |buf|
|
|
213
|
+
Native.call("pdf_editable_draw_image", ptr, page_index, image, image.bytesize,
|
|
214
|
+
x.to_f, y.to_f, width.to_f, height.to_f, rotation_deg.to_f, buf)
|
|
215
|
+
end
|
|
216
|
+
found != 0
|
|
217
|
+
end
|
|
218
|
+
|
|
149
219
|
# ---- redaction + PDF/A conversion (Tier 2) ------------------------------
|
|
150
220
|
|
|
151
221
|
# Black out rectangles on a page. rects = [[x0,y0,x1,y1], ...].
|
data/lib/rustpdf/native.rb
CHANGED
|
@@ -78,6 +78,7 @@ 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_page_text" => [[VP, SZ, SZ, VP, VP], I],
|
|
81
82
|
"pdf_extract_images_to_dir" => [[VP, SZ, VP, VP], I],
|
|
82
83
|
"pdf_render_page_to_png" => [[VP, SZ, SZ, D, VP, VP], I],
|
|
83
84
|
"pdf_page_count" => [[VP, SZ, VP], I],
|
|
@@ -123,6 +124,17 @@ module RustPdf
|
|
|
123
124
|
"pdf_timestamp_begin" => [[VP, SZ, VP, VP, VP, VP], I],
|
|
124
125
|
"pdf_timestamp_request" => [[VP, SZ, VP, SZ, I, VP, VP], I],
|
|
125
126
|
"pdf_timestamp_token_from_response" => [[VP, SZ, VP, VP], I],
|
|
127
|
+
|
|
128
|
+
# Issue #45 P1: page geometry, document inspection, positioned drawing.
|
|
129
|
+
"pdf_measure_pages_json" => [[VP, SZ, VP, VP], I],
|
|
130
|
+
"pdf_inspect_json" => [[VP, SZ, VP, VP], I],
|
|
131
|
+
"pdf_editable_fill_rect" => [[VP, I, D, D, D, D, D, D, D, D, VP], I],
|
|
132
|
+
"pdf_editable_place_text" => [[VP, I, D, D, VP, D, D, D, D, D, VP], I],
|
|
133
|
+
"pdf_editable_place_text_aligned" => [[VP, I, D, D, VP, D, D, D, D, D, I, VP], I],
|
|
134
|
+
"pdf_editable_masked_text" => [[VP, I, D, D, D, D, VP, D, D, D, D, D, D, D, I, VP], I],
|
|
135
|
+
# Issue #50: stamp a PNG/JPEG image onto an existing page. The image bytes
|
|
136
|
+
# cross as the (uint8_t* data, uintptr_t len) pair, like pdf_editable_load.
|
|
137
|
+
"pdf_editable_draw_image" => [[VP, I, VP, SZ, D, D, D, D, D, VP], I],
|
|
126
138
|
}.freeze
|
|
127
139
|
|
|
128
140
|
def lib
|
data/lib/rustpdf.rb
CHANGED
|
@@ -157,6 +157,31 @@ module RustPdf
|
|
|
157
157
|
# origin lower-left; +x+/+y+ is the lower-left corner of the box.
|
|
158
158
|
TextHit = Struct.new(:page, :text, :x, :y, :width, :height)
|
|
159
159
|
|
|
160
|
+
# A rectangle in PDF user space (points, origin lower-left). Used for a page's
|
|
161
|
+
# MediaBox/CropBox. #width / #height are the (non-negative) extents.
|
|
162
|
+
PdfRect = Struct.new(:x0, :y0, :x1, :y1) do
|
|
163
|
+
def width
|
|
164
|
+
(x1 - x0).abs
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def height
|
|
168
|
+
(y1 - y0).abs
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Read-only geometry of one page (from #measure_page / #measure_pages). Sizes
|
|
173
|
+
# are in PDF points; +width+/+height+ ignore rotation while +rotated_width+/
|
|
174
|
+
# +rotated_height+ account for it (swapped for 90/270 pages). +media_box+ and
|
|
175
|
+
# +crop_box+ are PdfRect values.
|
|
176
|
+
PageGeometry = Struct.new(:page, :width, :height, :rotation,
|
|
177
|
+
:rotated_width, :rotated_height, :media_box, :crop_box)
|
|
178
|
+
|
|
179
|
+
# A non-mutating summary of a PDF (from #inspect_pdf). +pdfa_level+ is nil when
|
|
180
|
+
# the document is not PDF/A; +encryption+ is the cipher name ("None" when the
|
|
181
|
+
# document is not encrypted).
|
|
182
|
+
PdfOverview = Struct.new(:version, :pdfa_level, :encrypted, :encryption,
|
|
183
|
+
:requires_password, :page_count)
|
|
184
|
+
|
|
160
185
|
# An in-progress two-phase signature: #document holds the placeholder PDF and
|
|
161
186
|
# #bytes the exact bytes the signature covers. Hand #hash to a remote signer,
|
|
162
187
|
# build the CMS container, then call #complete.
|
|
@@ -203,6 +228,13 @@ module RustPdf
|
|
|
203
228
|
.force_encoding(Encoding::UTF_8)
|
|
204
229
|
end
|
|
205
230
|
|
|
231
|
+
# Extract the text of a single 0-based +page_index+ (Unicode via ToUnicode),
|
|
232
|
+
# without building an intermediate one-page document.
|
|
233
|
+
def extract_page_text(pdf, page_index)
|
|
234
|
+
take_bytes { |pp, pn| Native.call("pdf_extract_page_text", pdf, pdf.bytesize, page_index, pp, pn) }
|
|
235
|
+
.force_encoding(Encoding::UTF_8)
|
|
236
|
+
end
|
|
237
|
+
|
|
206
238
|
# Extract every raster image into +dir+ (JPEG verbatim as .jpg, others as
|
|
207
239
|
# .png; files named page{N}_{name}.{ext}). Returns the number written.
|
|
208
240
|
def extract_images_to_dir(pdf, dir)
|
|
@@ -240,6 +272,46 @@ module RustPdf
|
|
|
240
272
|
end
|
|
241
273
|
end
|
|
242
274
|
|
|
275
|
+
# Read the geometry (size, rotation, MediaBox, CropBox) of every page in +pdf+,
|
|
276
|
+
# in page order, without mutating it. Returns an Array of PageGeometry. Sizes
|
|
277
|
+
# are in PDF points; +rotated_width+/+rotated_height+ swap for 90/270 pages.
|
|
278
|
+
def measure_pages(pdf)
|
|
279
|
+
js = take_bytes { |pp, pn| Native.call("pdf_measure_pages_json", pdf, pdf.bytesize, pp, pn) }
|
|
280
|
+
.force_encoding(Encoding::UTF_8)
|
|
281
|
+
return [] if js.empty?
|
|
282
|
+
|
|
283
|
+
rect = lambda do |arr|
|
|
284
|
+
a = Array(arr)
|
|
285
|
+
a.size == 4 ? PdfRect.new(a[0], a[1], a[2], a[3]) : PdfRect.new(0, 0, 0, 0)
|
|
286
|
+
end
|
|
287
|
+
JSON.parse(js).map do |g|
|
|
288
|
+
PageGeometry.new(g["page"], g["width"], g["height"], g["rotation"],
|
|
289
|
+
g["rotatedWidth"], g["rotatedHeight"],
|
|
290
|
+
rect.call(g["mediaBox"]), rect.call(g["cropBox"]))
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Read the geometry of a single 0-based page of +pdf+. Raises IndexError if
|
|
295
|
+
# +index+ is out of range.
|
|
296
|
+
def measure_page(pdf, index)
|
|
297
|
+
pages = measure_pages(pdf)
|
|
298
|
+
raise IndexError, "page index #{index} out of range (#{pages.size} pages)" if index.negative? || index >= pages.size
|
|
299
|
+
|
|
300
|
+
pages[index]
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Inspect +pdf+ without mutating it: PDF version, PDF/A level (if any),
|
|
304
|
+
# encryption posture and page count. Works even on password-protected files
|
|
305
|
+
# (the encryption fields are still reported). Returns a PdfOverview. Named
|
|
306
|
+
# +inspect_pdf+ to avoid shadowing Object#inspect.
|
|
307
|
+
def inspect_pdf(pdf)
|
|
308
|
+
js = take_bytes { |pp, pn| Native.call("pdf_inspect_json", pdf, pdf.bytesize, pp, pn) }
|
|
309
|
+
.force_encoding(Encoding::UTF_8)
|
|
310
|
+
o = JSON.parse(js)
|
|
311
|
+
PdfOverview.new(o["version"], o["pdfaLevel"], o["encrypted"] ? true : false,
|
|
312
|
+
o["encryption"], o["requiresPassword"] ? true : false, o["pageCount"])
|
|
313
|
+
end
|
|
314
|
+
|
|
243
315
|
# Validate every signature in +pdf+. Returns one Hash per signature with keys
|
|
244
316
|
# "field_name", "sub_filter", "signer", "covers_whole_document",
|
|
245
317
|
# "digest_valid", "signature_valid", "is_valid" and "byte_range", plus the
|
|
Binary file
|