gettalong / hexapdf

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

using `.rotate(0, flatten: true)` on a filled form looses text in form fields #215

Closed andi-dev closed 1 year ago

andi-dev commented 1 year ago

Hi again :)

While trying to reproduce a different bug, I ran into this issue:

  1. I take the example pdf from http://foersom.com/net/HowTo/data/OoPdfFormExample.pdf, fill in some fields, save it!
  2. I run doc.pages.first.rotate(90, flatten: true)
  3. doc.write("rotated.pdf")
  4. The rotated.pdf apparently lost all texts in the form, also all checked checkboxes etc.

Apparently rotate with flatten: true is flattening the form, which is fine for us. However, if I first call acro_form.flatten and then doc.pages.first.rotate(90, flatten: true) the field values do not get lost, so I assume there is something different between what rotate with flatten: true does with the form, compared to acro_form.flatten.

Tested with master and devel branches.

Let me know If I can provide any more information.

gettalong commented 1 year ago

When you invoke Page#rotate, the flatten argument means that the rotation is done by incorporating it into the content stream instead of using the /Rotate key. This involves the manipulation of the page boxes and additions to the content stream. When you rotate the page by 90 degree, the following happens (where 0 marks the origin of the coordinate system):

            d-----c
            |     | 
            |     |
            |     |
            0-----b

--->

c-----------b
|           |
|           |
d-----------0

The annotations of a page, however, are currently not rotated which means that they stay where the are, in the upper right quadrant whereas the page now lives in the upper left quadrant. And form fields are represented by widget annotations.

Also see https://github.com/gettalong/hexapdf/issues/188

The best way currently to avoid problems is to flatten all annotations before rotating the page, i.e. first doc.acro_form.flatten to flatten form fields (and possibly generate the appearances in the first place) followed by page.flatten_annotations and then the rotation.

andi-dev commented 1 year ago

Ok, thank you for pointing this out, I would have missed to call page.flatten_annotations before flattening the rotation.

gettalong commented 1 year ago

@andi-dev Due to my recent work in this area I also have a draft solution for this problem. I will finish this before the next release.

gettalong commented 1 year ago

@andi-dev I have implemented annotation rotation, so your stated use case now works correctly. Due to another change involving the rotation of form fields, the filling out the rotated PDF still works correctly, i.e. the changed form field entries appear rotated.