Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to set an object transformation, without applying to the current one #117

Closed
benoitryder opened this issue Nov 1, 2023 · 7 comments
Assignees

Comments

@benoitryder
Copy link

Methods available to change the transformation of objects apply the provided transformation to the current matrix.
There is no method available to "reset" the transformation or force it to a given value (e.g. set translation to an absolute position, reset scale to 1).
A workaround exists: first apply the inverted matrix, then apply the desired transformation. But this may lead to inaccuracy errors, and is not very convenient.

PdfPageObjectPrivate::set_matrix() does that (it wraps FPDFPageObj_SetMatrix()), but it is not public and the name is already taken with a different meaning by the public set_matrix() methods.

I can think of several relatively easy solutions.
A flexible one would be to expose PdfPageObjectPrivate::set_matrix() with a different name (reset_matrix()?).
A method that resets the object's matrix to PdfMatrix::IDENTITY would work too.

@ajrcarey
Copy link
Owner

ajrcarey commented Nov 1, 2023

Hi @benoitryder , thank you for reporting the issue. It is possile to set the six matrix parameters to specific values using PdfMatrix::set_a() ... PdfMatrix::set_f(), but you're right - there is no way to reset an existing matrix to the identity value. Would a PdfMatrix::reset() or similar satisfy your use case?

@benoitryder
Copy link
Author

Hi!
My issue is not with PdfMatrix but with PdfPageObject (and its variants), so the method would need to be on PdfPageObject and its variants (I guess it should be added to create_transform_setters!() macro).

In my case, if I have a PdfPageTextObject I want to change its absolute position and scale on the page.
For instance, if I want to move it at position (20, 30) and its current position is (100, 100), I cannot use object.translate(PdfPoints::new(20), PdfPoints::new(30)) because it will add the offset to its current position and move it to (120, 130).
The same applies to other transformations (scale, rotation, flip). And as stated in the documentation, all methods internally use transform(), so there currently is no way to get around that.

@ajrcarey ajrcarey self-assigned this Nov 3, 2023
ajrcarey pushed a commit that referenced this issue Nov 3, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Nov 3, 2023

If I'm understanding you correctly, I think you could achieve a reset to the identity matrix by using PdfPageTextObject::set_matrix(PdfMatrix::IDENTITY), couldn't you? But I have no objection to adding a named function that does this - it's more expressive.

(I'm slightly confused, I think, because of the title of the issue - there really isn't a way to apply a transformation to an object independently of any previously-applied transformations. That is inherent to the design of transforms in PDF. The only real option is to reset all previously-applied transformations by applying the identity matrix to the object.)

I've pushed a small change that adds a new reset_to_identity() function to the create_transform_setters!() macro.

@benoitryder
Copy link
Author

I think you could achieve a reset to the identity matrix by using PdfPageTextObject::set_matrix(PdfMatrix::IDENTITY), couldn't you?

According to the documentation (and it seems to match the implementation), this will not reset the transformation but apply the identity transformation (thus not changing anything at all).

IMHO set_matrix(PdfMatrix::IDENTITY) should reset to the indentity matrix (because that's what the name implies). But that would break existing code. That's why I instead proposed adding a method with a different name.

there really isn't a way to apply a transformation to an object independently of any previously-applied transformations. That is inherent to the design of transforms in PDF.

pdfium provides FPDFPageObj_SetMatrix(); it sets the matrix as-is instead of applying it to the current transformation.

@ajrcarey
Copy link
Owner

ajrcarey commented Nov 3, 2023

Ok, I see what you're saying. For whatever reason, I had it in my mind that FPDFPageObj_SetMatrix() and FPDFPageObj_Transform() were equivalent functions that simply accepted different styles of specifying the matrix. Looking at the Pdfium source code, I can see that's definitely not the case, and _SetMatrix() definitely overwrites the current matrix rather than stacking on top of it.

I agree with you that set_matrix() is not a good name for this function in pdfium-render. apply_matrix() would be better.

Updated set_matrix() to actually overwrite the matrix using the appropriate Pdfium _SetMatrix() function. Added new apply_matrix() function to preserve the previous behaviour. Reworked create_transform_setters!() macro to allow for specifying the visibility of the set_matrix() function; we need to be able to make it private in the case of PdfPage, since there is no Pdfium function to directly set the matrix of an FPDF_PAGE. Updated examples/matrix.rs. Updated README.

The reset_to_identity() function should now have the desired effect.

@benoitryder
Copy link
Author

Thanks!

@ajrcarey ajrcarey reopened this Nov 4, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Nov 4, 2023

Renamed new set_matrix() to reset_matrix() to allow for clean deprecation of previous set_matrix() as part of #36. Renamed reset_to_identity() to reset_matrix_to_identity(). Added unit test coverage. Updated README. Ready for release as part of crate version 0.8.15.

@ajrcarey ajrcarey reopened this Nov 4, 2023
@ajrcarey ajrcarey closed this as completed Nov 4, 2023
ajrcarey pushed a commit that referenced this issue Nov 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants