gettalong / hexapdf

Versatile PDF creation and manipulation for Ruby
https://hexapdf.gettalong.org
Other
1.21k stars 69 forks source link

How to create canvas with fill, border and font #299

Closed corny closed 4 months ago

corny commented 4 months ago

I'm currently trying to create a signature field and sign a document. The signature field might overlap content of the document. For that reason I would like to create a canvas with:

Example created with MacOS preview app:

grafik

I tried to adjust the signing example with visual appearance without succeeding. Is it possible to create a canvas like this with HexaPDF?

gettalong commented 4 months ago

From your linked example:

widget = sig_field.create_widget(doc.pages[0], Rect: [20, 20, 120, 120])
widget.create_appearance.canvas.
  stroke_color("red").rectangle(1, 1, 99, 99).stroke.
  font("Helvetica", size: 10).
  text("Certified by signer", at: [10, 10])

The line with stroke_color("red").rectangle(1, 1, 99, 99).stroke. already creates a red border for the widget annotation. What you want to do before that is something like this:

canvas.fill_color("white").opacity(fill_alpha: 0.5).rectangle(0, 0, 100, 100).fill

This would create a rectangle filling the widget with a white background and some opacity. Note that you need to adjust the values for the rectangle to fit the signature widget annotation size.

Here is the example with the new code:

require 'hexapdf'
require HexaPDF.data_dir + '/cert/demo_cert.rb'

doc = if ARGV[0]
        HexaPDF::Document.open(ARGV[0])
      else
        HexaPDF::Document.new.tap do |hpdoc|
          hpdoc.pages.add(:A6, orientation: :landscape).canvas.
            font('Helvetica', size: 18).
            text('Digital Signature Test - Visual Appearance', at: [10, 150]).
            text('This will be partially overlapped', at: [50, 50])
        end
      end

sig_field = doc.acro_form(create: true).create_signature_field('signature')
widget = sig_field.create_widget(doc.pages[0], Rect: [20, 20, 120, 120])
widget.create_appearance.canvas.
  save_graphics_state.
  fill_color("white").opacity(fill_alpha: 0.8).rectangle(0, 0, 100, 100).fill.
  restore_graphics_state.
  stroke_color("red").rectangle(1, 1, 99, 99).stroke.
  font("Helvetica", size: 10).
  text("Certified by signer", at: [10, 10])

doc.sign("signed.pdf", signature: sig_field,
                       reason: 'Some reason',
                       certificate: HexaPDF.demo_cert.cert,
                       key: HexaPDF.demo_cert.key,
                       certificate_chain: [HexaPDF.demo_cert.sub_ca,
                                           HexaPDF.demo_cert.root_ca])

And it will get you this output:

image

corny commented 4 months ago

Wow, amazing - thanks a lot! You saved my day 🚀 ❤️ I was missing the save_graphics_state and restore_graphics_state.