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 support for creating annotations. #89

Open
Christopher-S-25 opened this issue May 30, 2023 · 14 comments
Open

Add support for creating annotations. #89

Christopher-S-25 opened this issue May 30, 2023 · 14 comments
Assignees

Comments

@Christopher-S-25
Copy link

Looking at google's Pdfium library, I figured that it's possible to add Annotations using FPDFPage_CreateAnnot(). An example can be found in the AddAndSaveLinkAnnotation test in pdfium/fpdfsdk/fpdf_annot_embeddertest.cpp.
I'm not entirely sure what needs to be done to implement it, whether it's easy or hard or whether the existing types for Annotations are adequate for creating an Annotation or need to be changed. I'm not good at C++, let alone C++ interop, and it's pretty confusing to me overall.
I mainly need this for creating Link Annotations.

@ajrcarey
Copy link
Owner

ajrcarey commented May 30, 2023

Hi @Christopher-S-25 , thank you for reporting the issue.

There are several additional features required to support your use case:

  • The PdfPageAnnotations collection needs to support mutation.
  • The PdfPageLinkAnnotation needs to support setting a URI (this is supported by Pdfium using the FPDFAnnot_SetLink() function).
  • Annotations need to support setting their appearance points (this sets their location and size) and their attachment points (this sets the location the annotation connects to).
  • Annotations need to support setting their colors and borders.

So, there are several steps to get a complete implementation. However, none of them are especially difficult. I will focus on adding the features in the order above.

@ajrcarey ajrcarey self-assigned this May 31, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Jun 6, 2023

Added annotations_mut() accessor to PdfPage. Added annotation creation and deletion functions to PdfPageAnnotations collection. Added support for setting and retrieving a URI to PdfPageLinkAnnotation, and setting and retrieving comment text to PdfPageTextAnnotation. Added in-progress example examples/create_annotation.rs.

The next step is to allow setting the position and appearance of the annotation.

ajrcarey pushed a commit that referenced this issue Jun 6, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Jun 7, 2023

Moved setting of comment text out of PdfPageTextAnnotation into PdfPageAnnotationCommon trait, since it can apply to all annotation types (annotation types which do not directly display text use the given text as an alt-text instead). Added set_creation_date(), set_modification_date(), set_bounds(), set_position(), set_width(), and set_height() functions to PdfPageAnnotationCommon trait. Added utils::date::date_time_to_pdf_string() date conversion helper function. Added positioning of text (sticky note) and free text annotations to examples/create_annotation.rs. The annotations are positioned correctly, albeit with the default styling.

Currently, the annotations are not explicitly attached to anything in particular. The next step is to deliberately attach them to specific page objects.

ajrcarey pushed a commit that referenced this issue Jun 7, 2023
@ajrcarey ajrcarey changed the title Add support for creating Annotations Add support for creating annotations. Jun 12, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Jun 12, 2023

Added new PdfPageAnnotationAttachmentPoints collection. Added support for creating and updating attachment points to supported annotation types. Updated examples/create_annotation.rs to demonstrate the new functionality, including creating a clickable link annotation. Updated documentation. Updated README. Bumped crate version to 0.8.6.

More work is needed to add customising the annotation's appearance. The relationship between the position of the annotation and the attachment points that associate it with a page object is also not yet entirely clear.

ajrcarey pushed a commit that referenced this issue Jun 12, 2023
@ajrcarey
Copy link
Owner

ajrcarey commented Jun 24, 2023

Corrected two bugs in handling of attachment points. Added setting and retrieving of stroke and fill colors for markup annotations. Added PdfAnnotations::create_squiggly_annotation_under_object(), PdfAnnotations::create_underline_annotation_under_object(), PdfAnnotations::create_strikeout_annotation_through_object(), and PdfAnnotations::create_highlight_annotation_over_object() convenience functions for creating common markup annotations and positioning them correctly relative to a target page object in a single function call.

PDF versions after 1.3 support appearance streams, allowing for multiple representations of annotations and their popups depending on an appearance mode parameter set by the PDF viewer. There are a few little details to tidy up, but the main missing item in the implementation is support for these appearance streams. Ideally this would be transparent, so the caller doesn't have to worry about whether they are using a PDF file before or after version 1.3.

ajrcarey pushed a commit that referenced this issue Jun 24, 2023
ajrcarey pushed a commit that referenced this issue Jul 1, 2023
ajrcarey pushed a commit that referenced this issue Nov 10, 2023
@ajrcarey
Copy link
Owner

Added mutable unwrapper functions for all annotation types to PdfPageAnnotation.

@Christopher-S-25
Copy link
Author

Christopher-S-25 commented Nov 26, 2023

I'm sorry for being super late, I can create annotations easily now, thank you very much for your excellent code!
Feel free to close the issue when appropriate.

@ajrcarey
Copy link
Owner

No problem. I'd like to improve the appearance streams support, but other than that I think the work is basically done.

@Jay00
Copy link

Jay00 commented Jan 9, 2024

Could you add an example of how to add a Stamp? I have not been able to successfully create anything but an empty blank stamp. How do I change the stamp contents and appearance?

@ajrcarey
Copy link
Owner

ajrcarey commented Jan 12, 2024

Hi @Jay00 , yes, I will extend the examples/create_annotations.rs example to include a stamp annotation example. I am away at the moment, so there will be a delay in doing this. The basic idea is that you use the objects_mut() accessor in the stamp annotation to add the page objects - text, image, or path - that make up your stamp to the annotation.

If you prefer to use raw FPDF_* functions, you can see an example of how to do this at https://pdfium.googlesource.com/pdfium/+/refs/heads/main/fpdfsdk/fpdf_annot_embeddertest.cpp#1261.

It may also be necessary to update the annotation's appearance stream. A discussion related to that is currently underway in #132.

@Jay00
Copy link

Jay00 commented Jan 14, 2024

@ajrcarey thanks! I appreciate the direction. I am trying to implement a custom stamp. I found this C# example, but I have not been able to recreate it with bindings in Rust.

using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    if (page.Annots == null)
        page.CreateAnnotations();

    //Load bitmap from a file and create image object.
    var bmp = PdfBitmap.FromFile(@"e:\0\stamp.png");
    var img = PdfImageObject.Create(page.Document, bmp, 300, 650);

    var stamp = new PdfStampAnnotation(page, "", 0, 0, FS_COLOR.SteelBlue);
    //create an empty normal appearance of the annotation.
    stamp.NormalAppearance.Clear();
    //add the image to the NormalAppearance.
    stamp.NormalAppearance.Add(img);
    //Generate the NormalAppearance
    stamp.GenerateAppearance(AppearanceStreamModes.Normal);

    page.Annots.Add(stamp);

    //Save a copy of PDF document
    doc.Save("sample_withAnnot.pdf", SaveFlags.NoIncremental);
}

I was able to add a stamp object to the page, but it was not my custom image, it was just blank. And very strangely, after manipulating the stamp's rotation value in Adobe Acrobat, the blank stamp turned into a generic DRAFT stamp. It is probably something to do with the appearance stream issues you mentioned, but I have not been able to figure it out yet.

@ajrcarey
Copy link
Owner

ajrcarey commented Jan 14, 2024

Yes, it's very likely because the appearance stream for your custom object is not being generated. In the short term you may be able to set a null appearance stream directly as discussed at #132; this would force viewer applications to generate the appearance stream themselves, which would at least display something. In the longer term I will think of a cleaner (ideally, an automatic) way of having pdfium-render do this, so you don't have to.

ajrcarey pushed a commit that referenced this issue Mar 16, 2024
@ajrcarey
Copy link
Owner

Bumped crate version to 0.8.20 to formally release work so far. With PR now submitted for #132, next steps are to move ahead with appearance stream regeneration and creation of an example of creating a custom stamp annotation.

@ajrcarey
Copy link
Owner

Appearance stream regeneration should ultimately be handled upstream in Pdfium itself as part of work done in #145.

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

3 participants