rustpdf 0.4.4-universal-darwin → 0.4.5-universal-darwin

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26be79c246143805efc4c3a4551e4afc5a189bc808f4554285b13dd533b90b6f
4
- data.tar.gz: 3bd71a7b39e767292d447821de06952d60f0b79c2222aa77f7f775390b0c09dc
3
+ metadata.gz: bf26136e96e0bb69576cf294f81bbe62b5b9974c4a0646fac69ed40e72ffa82d
4
+ data.tar.gz: f60566e9fc77e467e8b29328769a86fd3ec013d5a93a00bc7453ba8a12e7cef7
5
5
  SHA512:
6
- metadata.gz: b196d1f22eff0fe24fb7ca9b4d61bf30670a1f7e847e7c5bd847790b5dc6913ad87c1adffa123f9b41c51548a3be421747da752c342a5d06beeec8f2368b8a27
7
- data.tar.gz: f5a0d5b8ee82a2ab459a632058ada47f4c36a54474fe2e62fe33504cb6b5c4991b8cc0bd0cb9b9614d298006c338c88491da32a898c169c164e4b961fb90c6b7
6
+ metadata.gz: c7330892e700726c8f1f8d4b3e8bd4876afc20b3d24909d8e3a3bc154f5a3130a9fe456aadbae0b1f31c8a3dd33046c17945cc6cf32bb0f3f1a55d16be67dd40
7
+ data.tar.gz: ddaaf60885bdccea7dd06eb990d9af4b2e021b313f51a8f5e9dd035de833c1d15a8ba6981b6b8a0359dde450c8669bf977b221a3a18a45f7e6bcc8e8b8a06294
@@ -146,6 +146,39 @@ 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). Coordinates are in the page's VISIBLE space (origin
171
+ # lower-left, y up), regardless of the page's /Rotate. Returns whether the
172
+ # page existed.
173
+ def place_text(page_index, x, y, text, size = 12.0, color = [0.0, 0.0, 0.0], rotation_deg = 0.0)
174
+ r, g, b = color
175
+ found = RustPdf.out_int do |buf|
176
+ Native.call("pdf_editable_place_text", ptr, page_index, x.to_f, y.to_f, text,
177
+ size.to_f, r.to_f, g.to_f, b.to_f, rotation_deg.to_f, buf)
178
+ end
179
+ found != 0
180
+ end
181
+
149
182
  # ---- redaction + PDF/A conversion (Tier 2) ------------------------------
150
183
 
151
184
  # Black out rectangles on a page. rects = [[x0,y0,x1,y1], ...].
@@ -123,6 +123,12 @@ module RustPdf
123
123
  "pdf_timestamp_begin" => [[VP, SZ, VP, VP, VP, VP], I],
124
124
  "pdf_timestamp_request" => [[VP, SZ, VP, SZ, I, VP, VP], I],
125
125
  "pdf_timestamp_token_from_response" => [[VP, SZ, VP, VP], I],
126
+
127
+ # Issue #45 P1: page geometry, document inspection, positioned drawing.
128
+ "pdf_measure_pages_json" => [[VP, SZ, VP, VP], I],
129
+ "pdf_inspect_json" => [[VP, SZ, VP, VP], I],
130
+ "pdf_editable_fill_rect" => [[VP, I, D, D, D, D, D, D, D, D, VP], I],
131
+ "pdf_editable_place_text" => [[VP, I, D, D, VP, D, D, D, D, D, VP], I],
126
132
  }.freeze
127
133
 
128
134
  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.
@@ -240,6 +265,46 @@ module RustPdf
240
265
  end
241
266
  end
242
267
 
268
+ # Read the geometry (size, rotation, MediaBox, CropBox) of every page in +pdf+,
269
+ # in page order, without mutating it. Returns an Array of PageGeometry. Sizes
270
+ # are in PDF points; +rotated_width+/+rotated_height+ swap for 90/270 pages.
271
+ def measure_pages(pdf)
272
+ js = take_bytes { |pp, pn| Native.call("pdf_measure_pages_json", pdf, pdf.bytesize, pp, pn) }
273
+ .force_encoding(Encoding::UTF_8)
274
+ return [] if js.empty?
275
+
276
+ rect = lambda do |arr|
277
+ a = Array(arr)
278
+ a.size == 4 ? PdfRect.new(a[0], a[1], a[2], a[3]) : PdfRect.new(0, 0, 0, 0)
279
+ end
280
+ JSON.parse(js).map do |g|
281
+ PageGeometry.new(g["page"], g["width"], g["height"], g["rotation"],
282
+ g["rotatedWidth"], g["rotatedHeight"],
283
+ rect.call(g["mediaBox"]), rect.call(g["cropBox"]))
284
+ end
285
+ end
286
+
287
+ # Read the geometry of a single 0-based page of +pdf+. Raises IndexError if
288
+ # +index+ is out of range.
289
+ def measure_page(pdf, index)
290
+ pages = measure_pages(pdf)
291
+ raise IndexError, "page index #{index} out of range (#{pages.size} pages)" if index.negative? || index >= pages.size
292
+
293
+ pages[index]
294
+ end
295
+
296
+ # Inspect +pdf+ without mutating it: PDF version, PDF/A level (if any),
297
+ # encryption posture and page count. Works even on password-protected files
298
+ # (the encryption fields are still reported). Returns a PdfOverview. Named
299
+ # +inspect_pdf+ to avoid shadowing Object#inspect.
300
+ def inspect_pdf(pdf)
301
+ js = take_bytes { |pp, pn| Native.call("pdf_inspect_json", pdf, pdf.bytesize, pp, pn) }
302
+ .force_encoding(Encoding::UTF_8)
303
+ o = JSON.parse(js)
304
+ PdfOverview.new(o["version"], o["pdfaLevel"], o["encrypted"] ? true : false,
305
+ o["encryption"], o["requiresPassword"] ? true : false, o["pageCount"])
306
+ end
307
+
243
308
  # Validate every signature in +pdf+. Returns one Hash per signature with keys
244
309
  # "field_name", "sub_filter", "signer", "covers_whole_document",
245
310
  # "digest_valid", "signature_valid", "is_valid" and "byte_range", plus the
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rustpdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: universal-darwin
6
6
  authors:
7
7
  - rust-pdf