Closed WSPDV closed 10 months ago
Please have a look at https://hexapdf.gettalong.org/documentation/api/HexaPDF/Type/AcroForm/Field/index.html#method-i-create_widget - the :rotation
key is not a valid dictionary entry for a widget annotation.
If you want to rotate the image, you should use the rotated image size in the Rect
value and use the canvas.rotate
command before placing the image.
widget = field.create_widget(@page, defaults: false, Rect: [0, 0, 146, 364])
image = widget.create_appearance
.canvas.rotate(90)
.xobject(@image_path, at: [0, 0], width: 146, height: 364)
image[:Resources] = {}
field
rotate like this @gettalong ?
the Rect
is correct but the image is still not appear
Can you please provide a complete sample script that shows the problem?
FYI: The rect you specify is in the lower-left corner of the page, is that correct?
this is a picture of signature
and this is a full code
class Trial4
require 'hexapdf'
require HexaPDF.data_dir + '/cert/demo_cert.rb'
def initialize(pdf_path)
@signed_pdf_path = "tmp/img_signed_#{Time.now.to_i}.pdf"
@pdf_path = pdf_path
@doc = HexaPDF::Document.open(pdf_path)
@image_path = 'spec/fixtures/files/signature.png'
end
def call
@doc.sign(@signed_pdf_path, reason: 'Some reason',
location: 'Hatimu',
contact_info: 'wspdv@tampan.coeg',
signature: field_signature,
certificate: HexaPDF.demo_cert.cert,
key: HexaPDF.demo_cert.key,
certificate_chain: [HexaPDF.demo_cert.sub_ca,
HexaPDF.demo_cert.root_ca])
end
def image
@image ||= Magick::Image.read(@image_path).first
end
def field_signature
field = @doc.acro_form(create: true)
.create_signature_field('AQ')
widget = field.create_widget(@doc.pages[0], defaults: false,
Rect: [0, 0, image.columns, image.rows])
img_sig = widget.create_appearance
.canvas
.xobject(@image_path, at: [0, 0], width: image.columns, height: image.rows)
img_sig[:Resources] = {}
field
end
end
and the result like below (this coordinate is expected because I set the coordinate in 0, 0 in the document that has 180 rotate). see the picture of the signature (the picture is rotated, different from the original picture).
i want to set the rotation image (the position image kept like an original picture). then i wrote code like this (override the method field_signature
)
def field_signature
field = @doc.acro_form(create: true)
.create_signature_field('AQ')
widget = field.create_widget(@doc.pages[0], defaults: false,
Rect: [0, 0, image.columns, image.rows])
img_sig = widget.create_appearance
.canvas.rotate(180)
.xobject(@image_path, at: [0, 0], width: image.columns, height: image.rows)
img_sig[:Resources] = {}
field
end
then the result is image does not appear
So the problem here is that once the canvas is rotated, everything is upside down, including the coordinate system. So the positive x direction will now go to the left and the positive y direction will now go down. And note that the origin did not change its location, it is still at the bottom-left corner of the rectangle. To remedy that you need to move the origin to the upper-right corner.
Here is an example:
require 'hexapdf'
doc = HexaPDF::Document.new
canvas = doc.pages.add([0, 0, 200, 200]).canvas
canvas.save_graphics_state do
canvas.stroke_color("grey").line_width(0.5).
line(100, 0, -100, 0).line(0, -100, 0, 100).stroke
end
canvas.rotate(180) do
canvas.rectangle(0, 0, 80, 40).stroke
end
canvas.rotate(180) do
canvas.translate(-200, -200) # move origin to the upper-right corner
canvas.stroke_color("hp-blue").
rectangle(0, 0, 80, 40).stroke
end
doc.write('rotation.pdf')
Here is the result:
You can only see the second rectangle, the blue one, in the image because the other one, the first one, is out of view below the bottom-left corner.
In your case you would need to use .rotate(180).translate(image.columns, image.rows)
.
if using canvas means can break the PDF content, I already have a code using canvas, and it works. so I need it for the signature field only.
i already added the code that you suggested, but the image still not showing
def field_signature
field = @doc.acro_form(create: true)
.create_signature_field('AQ')
widget = field.create_widget(@doc.pages[0], defaults: false,
Rect: [0, 0, image.rows, image.columns])
img_sig = widget.create_appearance
.canvas
.rotate(270).translate(image.rows, image.columns)
.xobject(@image_path, at: [0, 0], width: image.rows, height: image.columns)
img_sig[:Resources] = {}
field
end
if without .rotate(270).translate(image.rows, image.columns)
image showing, but the rotation for the image is not true.
I need the image still like the original
like this
If you rotate by 270 degrees, you have to adjust the translation arguments as well as the width/height arguments for the #xobject
call.
You might also need to use the :no_rotate flag, i.e. widget.flag(:no_rotate)
to avoid the viewer rotating the annotation if the page has the /Rotate
key set.
translation argument height and width are correct when I click on the signature panel, it will show the box where the signature is placed (only the dots in frame) like the picture below (in the bottom right). I assumed this is already correct.
for this is code -> widget.flag(:no_rotate)
where is the right placed ?
I already added widget.flag(:no_rotate)
after create_widget:
field = @doc.acro_form(create: true)
.create_signature_field('AQ')
widget = field.create_widget(@doc.pages[0], defaults: false, Rect: [0, 0, 512, 908], flag: :no_rotate)
widget.flag(:no_rotate)
image = widget.create_appearance
.canvas
.xobject(image_signature, at: [0, 0])
widget.flag(:no_rotate)
field
but the image is still now shown. I also tried to larger the width and height of the signature field (to be full of pages), and try rearrange this section -> .xobject(image_signature, at: [100, 100])
but still not appear
Here is a self-contained example based on your code:
require 'hexapdf'
require HexaPDF.data_dir + '/cert/demo_cert.rb'
doc = HexaPDF::Document.new
doc.pages.add.canvas.
font("Helvetica", size: 10).
text("Top-left", at: [20, 800])
doc.pages[0].rotate(180)
image = doc.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 200, 100]})
image.canvas.font("Helvetica", size: 10).text('Signature', at: [20, 20])
field = doc.acro_form(create: true).create_signature_field('AQ')
widget = field.create_widget(doc.pages[0], defaults: false,
Rect: [0, 0, image.width, image.height])
img_sig = widget.create_appearance.
canvas.
save_graphics_state.fill_color("ffddff").rectangle(0, 0, image.width, image.height).fill.restore_graphic_state.
xobject(image, at: [0, 0], width: image.width, height: image.height)
img_sig[:Resources] = {}
doc.sign('signed.pdf', reason: 'Some reason',
location: 'Hatimu',
contact_info: 'wspdv@tampan.coeg',
signature: field,
certificate: HexaPDF.demo_cert.cert,
key: HexaPDF.demo_cert.key,
certificate_chain: [HexaPDF.demo_cert.sub_ca,
HexaPDF.demo_cert.root_ca])
resulting in this:
In this case the :no_rotate
flag is not needed. If you still use it, the signature widget annotation will still be at the top-right of the page (i.e. where (0,0) is located) but extends to the left and top, out of the bounds of the page.
You can use image.width
and image.height
to get the width and height of the image, so no need to use Magick::Image
.
If you want to have the signature widget correctly rotated, you need to insert rotate(180).translate(-image.width, -image.height).
after the canvas.
call. This will then result in this:
If the page has another rotation, you will need to appropriately size the widget and rotate and translate the canvas before placing the image. You could also just call page.rotate(0, flatten: true)
before doing anything to remove the /Rotate
key from the page and embed the rotation into the content stream. This could make it easier for you to place the signature field.
Thanks, mas @gettalong
the simple choice is using page.rotate(0, flatten: true)
but if the document already has a certificate, it will break the certificate before, because it will modify the content/page.
i already tried that and I also tried use rotate(180).translate(-image.width, -image.height)
. the second is work (not breaking the certificate before if the document has a certificate).
Could you let me know the rules/formula for the value from .translate()
.?
The rules are just basic geometry. You can visualize it:
require 'hexapdf'
doc = HexaPDF::Document.new
canvas = doc.pages.add.canvas
canvas.font('Helvetica', size: 8)
iw, ih = 100, 60
[0, 90, 180, 270].each_with_index do |rotation, index|
canvas.save_graphics_state do
# Simulate page rotation
canvas.translate(220, 700 - index * 150)
canvas.rotate(rotation)
canvas.rectangle(0, 0, iw, ih).stroke
canvas.text("Text", at: [5, 5])
canvas.fill_color("hp-blue").circle(0, 0, 2).fill
case rotation
when 0 then #nothing
when 90 then canvas.rotate(-90).translate(-ih, 0)
when 180 then canvas.rotate(-180).translate(-iw, -ih)
when 270 then canvas.rotate(-270).translate(0, -iw)
end
canvas.fill_color("hp-orange").circle(0, 0, 2).fill
canvas.stroke_color("hp-teal").rectangle(0, 0, iw, ih).stroke
canvas.text("Text", at: [5, 5])
end
end
doc.write('visualize.pdf')
The result is this: visualize.pdf
Your answer is very helpful. I will try in my local. Hopefully, it can work. I'll close this discussion. Thank you mas @gettalong 🙏🏿
hi, mas @gettalong I am stuck on the rotation image using the signature field. There is no error, but the signature image does not appear in the result.