Merge scaled down annotated PDFs files

1 Answer 236 Views
PdfProcessing
Eric Moreau
Top achievements
Rank 2
Iron
Iron
Veteran
Eric Moreau asked on 15 Jan 2023, 04:43 PM

Hi

I have been able to merge PDFs files all together into a single document by using File.OpenRead to read into a PdfFIleSource and then use the PdfStreamWriter WritePage method to concatenate them all.

But now I want to scale down the pages to be able to add page numbering.

I haven't been able to use scale down (reduce) using the previous method.

I have found another mechanism (https://www.telerik.com/forums/scaling-pdf-document) that is reading the input pages into a RadFixedDocument before adding them with WritePage to the PdfStreamWriter. This works (page are reduced as I want) but when input PDFs are annoted (textboxes or images), the annotations are not added to the scaled down output.

Do you have a sample that is doing that (merge scale down input files while keeping annotations)?

1 Answer, 1 is accepted

Sort by
0
Yoan
Telerik team
answered on 18 Jan 2023, 03:52 PM

Hello Eric,

This unexpected behavior might occur because the annotations of the used documents might not be among the Supported Features of PdfProcessing and therefore are skipped when importing/exporting a new document. In the example, you have found, even if the annotations are supported, they are lost when creating a new merged document, because they are not added to it in the process.

A merging of documents without loss of supported annotations can be achieved through the PdfStreamWriter and PdfFileSource. The approach takes a collection of paths, creates a new document, and appends the documents from those paths to the newly created one and returns a RadFixedDocument.

In this example, I have created a MergeDocuments() method that executes said functionality and allows modification of each document in the iteration. 

public static RadFixedDocument MergeDocuments(string[] pathsCollection)
        {
            RadFixedDocument result = new RadFixedDocument();

            PdfFormatProvider provider = new PdfFormatProvider();

            using (MemoryStream stream = new MemoryStream())
            {
                using (PdfStreamWriter fileWriter = new PdfStreamWriter(stream, true))
                {
                    foreach (var path in pathsCollection)
                    {
                        using (PdfFileSource fileSource = new PdfFileSource(new MemoryStream(File.ReadAllBytes(path))))
                        {
                            PdfPageStreamWriter resultPage = null;
                            for (int i = 0; i < fileSource.Pages.Length; i++)
                            {
                                // set page size
                                resultPage = fileWriter.BeginPage(new Size(
                                    fileSource.Pages.First().Size.Width,
                                    fileSource.Pages.First().Size.Height),
                                    Rotation.Rotate0);
                                // set content scale
                                resultPage.ContentPosition.Scale(1, 1);
                                PdfPageSource sourcePage = fileSource.Pages[i];
                                resultPage.WriteContent(sourcePage);
                                resultPage.Dispose();
                            }
                        }
                    }                    
                }
                File.WriteAllBytes("result.pdf", stream.ToArray());
            }

            return result;
        }

Hope this helps.

Regards, Yoan Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Eric Moreau
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 19 Jan 2023, 03:37 PM

Hi

 

Many thanks for that sample. I played with it a lot and discovered that I can now generate scaled down pages and merge them all togheter and at this point, my output PDF still have annotations.

I am now to the point where I need to add page number in the footer of the pages. This is now where I am loosing the annotations.

How can your MergeDocuments be modified to add a footer to the scaled down page?

This is my current method that adds the page footer but also removes all annotations (surely because on of the cast!):

        private static void DrawHeaderAndFooterToPage(RadFixedPage pPage, int pPageNumber, int pNumberOfPages, string pFileName)
        {
            FixedContentEditor pageEditor = new FixedContentEditor(pPage);

            Block footer = new Block();
            footer.InsertText($"{pFileName} - Page {pPageNumber} of {pNumberOfPages}");
            footer.Measure();

            double footerOffsetX = (pPage.Size.Width / 2) - (footer.DesiredSize.Width / 2);
            double footerOffsetY = pPage.Size.Height - 20 - footer.DesiredSize.Height;
            pageEditor.Position.Translate(footerOffsetX, footerOffsetY);
            pageEditor.DrawBlock(footer);
        }

And this is how I call it:

            //add page numbers
            using (Stream stream = File.OpenRead(strPathScaledContent))
            {
                string strFileName = Path.GetFileName(strPathFinal);
                Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.PdfFormatProvider formatProvider = new Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.PdfFormatProvider();
                RadFixedDocument document = formatProvider.Import(stream);
                int intNbPageTOC = 1;
                int numberOfPages = document.Pages.Count;
                for (int pageIndex = 0; pageIndex < numberOfPages; pageIndex++)
                {
                    RadFixedPage currentPage = document.Pages[pageIndex];
                    DrawHeaderAndFooterToPage(currentPage, pageIndex + intNbPageTOC + 1, numberOfPages+intNbPageTOC, strFileName);
                }

                using (Stream output = File.OpenWrite(strPathScaledContentNumbered))
                {
                    formatProvider.Export(document, output);
                }
            }

 

Dimitar
Telerik team
commented on 24 Jan 2023, 10:34 AM

Hello Eric,

I tested the provided code and it seems to be working as expected on my end. Maybe I am missing something, but the loss of annotations you are experiencing might come from the type of annotations the document contains. While working with the PdfFormatProvider, in case the annotations are unsupported, they will be stripped from the document. The list of supported features can be found here: Features supported by PdfFormatProvider.

If you happen to need further and more specific information, sharing an example document with us for examination would be of great help.

Should you need anything else, feel free to ask.

Eric Moreau
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 24 Jan 2023, 11:23 AM | edited

Hi Dimitar

I used "annotations" but maybe it is not the right term in the PDF files world. Let me reword the question.

I have a bunch of PDFs file to which:

  • I need to add some images (screenshot) and textboxes (notes for the accountant).
  • I need to "package" these PDFs in a single file for the accountant.
  • I need to reduce the height of the PDFs to give a place to insert a footer.
  • In that footer, I want to add a page number.
  • In front of the package, I want to insert a table of content.

I have everything so far working except page numbers. When I call the DrawHeaderAndFooterToPage method to add the page number, the sample I found need to convert pages into RadFixedPage and this is where I seem to loose the images and textboxes from my document.

 

Yoan
Telerik team
commented on 27 Jan 2023, 07:37 AM

Hi Eric,

As for the images, I tested the code snippet on a document with images and didn't manage to reproduce the mentioned behavior. For me to better understand the situation, it would be a great help if you could attach an example document that fits your case, so I can take a look at it and get back to you with specifics.

When it comes to the first step you mention, the PdfFormatProvider does not support annotations of type FreeText and if the textboxes, the document contains, are of such type, then they are indeed being skipped in the DrawHeaderAndFooterToPage() method when utilizing the provider. We already have a feature request in our Feedback Portal about this topic (PdfProcessing: Add support for FreeText annotation type). If you'd like, you can vote for it to increase its priority or subscribe to get notified of any changes.

А possible workaround for that would be first to do the scaling, merging, and page numbering and then add the unsupported items (textboxes). Another way would be to just use plain text or a TextBoxField instead of  Free Text Annotations so that the content is preserved.

I am looking forward to your reply.

Best Regards,

Yoan

Eric Moreau
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 27 Jan 2023, 01:24 PM

Hi Yoan

Thanks for the reply.

Changing the sequence of actions (adding images and textboxes to PDF after the merge) is not possible. Single PDFs are modified through the month as they are processed and merge at the beginning of the following month.

I have found another workaround. I used a sample that was adding a watermark (sorry lost the exact URL) and modified it to "draw" the page number at the bottom of the page (maybe that mechanism can inspire your team for the feature request!). I now have almost everything tied up.

Dimitar
Telerik team
commented on 30 Jan 2023, 11:09 AM

Hi Eric,

I am glad that you have a solution now. 

Do not hesitate to contact us if you have other questions.

 

Tags
PdfProcessing
Asked by
Eric Moreau
Top achievements
Rank 2
Iron
Iron
Veteran
Answers by
Yoan
Telerik team
Share this question
or