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

Partial Appearance Left Behind After Field Removal #1001

Closed
4 tasks done
Trapfether opened this issue Sep 22, 2021 · 3 comments · Fixed by #1002
Closed
4 tasks done

Partial Appearance Left Behind After Field Removal #1001

Trapfether opened this issue Sep 22, 2021 · 3 comments · Fixed by #1002

Comments

@Trapfether
Copy link
Contributor

Trapfether commented Sep 22, 2021

What were you trying to do?

I was attempting to remove a field I had added previously using pdf-lib from a pdf and display that pdf with pdf.js in the browser.

I am using pdf-lib for the pdf alterations, and I am using pdf.js for displaying the pdf in-browser.

Why were you trying to do this?

I am building a web tool that allows individuals to place / remove / adjust fields within a pdf. This is part of an automation system in a larger project.

How did you attempt to do it?

I had previously added a field using pdf-lib to the pdf and saved it.

I then removed the field (can be textbox, checkbox, doesn't matter) and displayed the resulting pdf with pdf.js.

What actually happened?

the default rectangle and border are still shown on the pdf. When I open the same pdf in Chrome pdf viewer or Acrobat, those appearances are not there. This leads me to suspect that something is being left behind when removing a field and that Chrome and Acrobat are intelligently ignoring whatever was still there. Pdf.js seems to still see this remnant and display it though.

What did you expect to happen?

When the field is deleted and the pdf is reloaded into pdf.js, I would expect any visual trace of the field to be removed.

How can we reproduce the issue?

I have attached a zip file with a single simple HTML document that creates a pdf document, adds some text and fields to said document, then removes a single field from that document before finally rendering that document to a canvas using pdf.js

You can see that the border & background for the field that should have been removed is still showing. Although the actual text and interactive items have been removed as expected.

test.zip

Version

1.16.0

What environment are you running pdf-lib in?

Browser

Required Reading

Additional Notes

No response

@Hopding
Copy link
Owner

Hopding commented Sep 22, 2021

Thanks for submitting this and providing a nice SSCCE @Trapfether! I'll dig into this further when I get a chance 👍

@Trapfether
Copy link
Contributor Author

Trapfether commented Sep 22, 2021

Digging into the library line by line, I think I might have found the source of the issue.

In the 1.16.0 version of pdf-lib (non-minimized) there is this function beginning on line 35783

`

PDFForm.prototype.removeField = function (field) {
    var widgets = field.acroField.getWidgets();  
    var pages = new Set();  
    for (var i = 0, len = widgets.length; i < len; i++) {  
        var widget = widgets[i];  
        var widgetRef = this.findWidgetAppearanceRef(field, widget);  
        var page = this.findWidgetPage(widget);  
        pages.add(page);  
        page.node.removeAnnot(widgetRef);  
    }  
    pages.forEach(function (page) { return page.node.removeAnnot(field.ref); });  
    this.acroForm.removeField(field.acroField);  
    this.doc.context.delete(field.ref);  
};

`

You can see that we attempt to remove the field annotation from the page using page.node.removeAnnot.
Stepping into this function, I was able to see that the widgetRef wasn't being found in the page annotations.
I was able to correct the behavior by removing the widgetRef from the document context by adding the following line; however, this breaks the 18th integration test, I'm still digging, but you might already know what I am missing

`

PDFForm.prototype.removeField = function (field) {
    var widgets = field.acroField.getWidgets();  
    var pages = new Set();  
    for (var i = 0, len = widgets.length; i < len; i++) {  
        var widget = widgets[i];  
        var widgetRef = this.findWidgetAppearanceRef(field, widget);  
        var page = this.findWidgetPage(widget);  
        pages.add(page);  
        page.node.removeAnnot(widgetRef);  
        //////add this line//////
        this.doc.context.delete(widgetRef);  
    }  
    pages.forEach(function (page) { return page.node.removeAnnot(field.ref); });  
    this.acroForm.removeField(field.acroField);  
    this.doc.context.delete(field.ref);  
};

`

@nayanprasad
Copy link

I'm facing the same issue, I'm deleting the field like this

deletedAcroFields.forEach((acroField) => {
      const field = form
        .getFields()
        .find((f) => f.getName() === acroField.name);
      if (field) {
        while (field.acroField.getWidgets().length) {
          field.acroField.removeWidget(0);
          field.doc.context.delete(field.ref);
        }
        pdfDoc.context.delete(field.ref);
        form.removeField(field);
      }
    });

This method deletes the field but leaves the border and the values of the field. I want to remove that too. how would I do that ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants