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

Page.ByReference and Page.ByIndex change the behaviour of Flatten and Render #199

Open
jj10052 opened this issue Jan 7, 2025 · 5 comments

Comments

@jj10052
Copy link

jj10052 commented Jan 7, 2025

I have a pdf with annotations and form fields that I want to render to Images.

To render both, annotations and form fields, I need to flatten the page first and then render it (without flattening I only get annotations). Therefor I use FPDFPage_Flatten and RenderPageInDPI:

page, err := inst.FPDF_LoadPage(&requests.FPDF_LoadPage{
	Document: doc.Document,
	Index:    i,
})
if err != nil {
	return nil, err
}

defer inst.FPDF_ClosePage(&requests.FPDF_ClosePage{
	Page: page.Page,
})

flatten, err := inst.FPDFPage_Flatten(&requests.FPDFPage_Flatten{
	Page: requests.Page{
		ByReference: &page.Page,
	},
	Usage: requests.FPDFPage_FlattenUsageNormalDisplay,
})
if err != nil || flatten.Result == responses.FPDFPage_FlattenResultFail {
	return nil, err
}

pageRender, err := inst.RenderPageInDPI(&requests.RenderPageInDPI{
	DPI:         300,
	RenderFlags: enums.FPDF_RENDER_FLAG_ANNOT,
	Page: requests.Page{
		ByIndex: &requests.PageByIndex{
			Document: doc.Document,
			Index:    0,
		},
	},
})
if err != nil {
	return nil, err
}

imgs = append(imgs, pageRender.Result.Image)

If I change the Page to ByIndex instead of ByReference in FPDFPage_Flatten, neither annotations nor form fields are rendered:

flatten, err := inst.FPDFPage_Flatten(&requests.FPDFPage_Flatten{
	Page: requests.Page{
		// ByReference: &page.Page,
		ByIndex: &requests.PageByIndex{
			Document: doc.Document,
			Index:    0,
		},
	},
	Usage: requests.FPDFPage_FlattenUsageNormalDisplay,
})

If I change the Page to ByReference instead of ByIndex in RenderPageInDPI, also neither annotations nor form fields are rendered:

pageRender, err := inst.RenderPageInDPI(&requests.RenderPageInDPI{
	DPI:         300,
	RenderFlags: enums.FPDF_RENDER_FLAG_ANNOT,
	Page: requests.Page{
		// ByIndex: &requests.PageByIndex{
		// 	Document: doc.Document,
		// 	Index:    0,
		// },
		ByReference: &page.Page,
	},
})
@jerbob92
Copy link
Contributor

jerbob92 commented Jan 7, 2025

Hi, it's best to not mix the two different options in the same process, as they will both reference a different instance of the page object. I personally have never used FPDFPage_Flatten, so I don't know how it works exactly, did you try saving the PDF as a new file to check if the flattened file contains the form fields and annotations?

More things you might want to check:

  • You might need to load the form before flattening (FPDFDOC_InitFormFillEnvironment)
  • You might need to run FPDFPage_GenerateContent to make sure the page gets updated

I see that the unit tests for FPDFPage_Flatten are quite lacking, will improve that in the next version.

@jj10052
Copy link
Author

jj10052 commented Jan 8, 2025

Hi, thank you for your quick response!

I initially tried avoiding mixing the two different options, but I could only get the desired result by doing so.

I tried what you suggested and saved the PDF as a new file (FPDF_SaveAsCopy):

  1. No flattening -> the new PDF is unflattened and the rendered images miss the form fields
  2. Flattening
    1. ByIndex -> the new PDF is flattened and the rendered images miss the form fields
    2. ByReference -> the new PDF is flattened and the rendered images contain the form fields
  3. If I switch to ByReference in RenderPageInDPI in any case the form fields are not rendered into the images.
  4. Using FPDFPage_GenerateContent before rendering didn't change anything.
  5. I unfortunately didn't have time to implement the necessary functions for FPDFDOC_InitFormFillEnvironment to work, so I couldn't test this.

For now I found a solution that seems a little odd, but works.

@jerbob92
Copy link
Contributor

jerbob92 commented Jan 8, 2025

FPDF_SaveAsCopy returns a new PDF, so do you mean the new PDF when you say rendered images here? Or do you first do FPDF_SaveAsCopy, then load that again and then render that as image as a workaround?

So basically you're saying that flatting with ByReference and then do FPDF_SaveAsCopy gives you a PDF that's correct, right? Because that's what's expected. But if you flatten with ByReference and then directly render it, it won't work correctly, right?

@jj10052
Copy link
Author

jj10052 commented Jan 8, 2025

Sorry for the missunderstanding.

I did everything on the original document. I only used FPDF_SaveAsCopy to save a copy of the PDF to disk after flattening to be able to visually ensure that the PDF got flattened (with or without migrations). I only used FPDF_SaveAsCopy, because I didn't find another way to save a go-pdfium document to disk.

So I did everything as mentioned as in my original comment. For me it only works, if I flatten with ByReference and render with ByIndex.

@jerbob92
Copy link
Contributor

jerbob92 commented Jan 8, 2025

That's odd indeed, almost sounds like you need to re-open the page to make the flattening have effect. Will do some tests soon.

Note: all the tests inside pdfium itself only test flattening and then saving the document and comparing the result, it never does anything directly with the page after flattening. So you might want to do FPDF_ClosePage and FPDF_LoadPage after flattening.

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