PDFsharp & MigraDoc Foundation
https://forum.pdfsharp.net/

Applying a template
https://forum.pdfsharp.net/viewtopic.php?f=2&t=3380
Page 1 of 1

Author:  WileECoyote [ Mon Jun 20, 2016 3:01 pm ]
Post subject:  Applying a template

Hi all,
I have a docx file which contains a stationery template (header and footer).
On the other side I have muti-page pdf documents which contain some information without headers and footers.

I would like to:

1) receive in input the multi-page pdf (Base64 encoded)
2) transform the docx file in a PDF (with another already purchased component)
3) apply the stationery template to all the pages of the input document (like printing over a phisical stationery)
4) send in output the document (Base64 encoded)

Language: C#

Any hints?

Thanks!

Author:  Thomas Hoevel [ Mon Jun 20, 2016 3:14 pm ]
Post subject:  Re: Applying a template

Hi!

With PDFsharp it is simple to add a PDF page as stationary below the existing contents of a PDF page.
If the page contains black text on nothing, then the stationary will be visible.
If it has black text on a white rectangle, then the stationary will not be visible.

So to some extent the result depends on the "input" PDF files you have.

The Watermark sample shows how to draw text over or under the existing contents of a page.
http://www.pdfsharp.net/wiki/Watermark-sample.ashx
Try variation 2, but with DrawImage instead of DrawPath and without transformation.

The Graphics sample shows DrawImage at work:
http://www.pdfsharp.net/wiki/Graphics-s ... #Images_35

You can download the ZIP with the sample here:
http://pdfsharp.codeplex.com/releases/view/618773

Author:  WileECoyote [ Mon Jun 20, 2016 4:15 pm ]
Post subject:  Re: Applying a template

HI Thomas,
thanks for the kind and superquick reply.
Please apologize me but I've never worked with PDFSharp.

So the code would be:

Code:
// Open the template file as image
XImage image = XImage.FromFile(pdfTemplatePath);

// Open an existing document for editing and loop through its pages.
var document = PdfReader.Open(filename);
// Set version to PDF 1.4 (Acrobat 5) because we use transparency.
            if (document.Version < 14)
                document.Version = 14;

            for (var idx = 0; idx < document.Pages.Count; idx++)
            {
                var page = document.Pages[idx];

                // Get an XGraphics object for drawing beneath the existing content.
                var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);
             

                gfx.DrawImage(image);

            }
            // Save the document...
            document.Save(filename);


Correct?
The image (template) will be placed under the "document"?

Thanks!

Author:  Thomas Hoevel [ Tue Jun 21, 2016 7:46 am ]
Post subject:  Re: Applying a template

The code looks good.

AFAIK you do not have to set the version to 14 - you need this for PNG and such with alpha blending, but not for templates.

You should specify position and size in the call to DrawImage.
gfx.DrawImage(image, 0, 0, page.Width, page.Height);

Author:  WileECoyote [ Tue Jun 21, 2016 8:37 pm ]
Post subject:  Re: Applying a template

Hi Thomas,
it seems to work correctly but, if I try to create an XImage from a Base64 coded documet, I get an "Invalid parameter" error.

Code:
byte[] bytes = System.Convert.FromBase64String(fileBase64);
MemoryStream ms = new MemoryStream(bytes);
XImage image= XImage.FromStream(ms);


Any hints?

Wile E

Author:  Thomas Hoevel [ Wed Jun 22, 2016 8:02 am ]
Post subject:  Re: Applying a template

A code snippet from MigraDoc ("XImage CreateXImage(string uri)"):
Code:
if (uri.StartsWith("base64:"))
{
    string base64 = uri.Substring("base64:".Length);
    byte[] bytes = Convert.FromBase64String(base64);
    {
        Stream stream = new MemoryStream(bytes);
        XImage image = XImage.FromStream(stream);
        return image;
    }
}
return XImage.FromFile(uri);
You can prepend "base64:" to your BASE64 string and let MigraDoc do the decoding - just pass the string as a filename.

Maybe the problem is with the encoding side?

Author:  WileECoyote [ Wed Jun 22, 2016 9:06 am ]
Post subject:  Re: Applying a template

Hi Thomas,
I start from a physical PDF file to simulate in test a base64 in:

Code:
// simulate a base64 string in
Byte[] bytes = File.ReadAllBytes(path);

//byte[] bytes = System.Convert.FromBase64String(fileBase64);
MemoryStream ms = new MemoryStream(bytes);
XImage image= XImage.FromStream(ms);


If I analyze the code snippet you proposed, it looked really similar to the one used by me which causes an "Invalid parameter" error generated.

XImage CreateXImage(string uri) Code:
Code:
byte[] bytes = Convert.FromBase64String(base64);
using (Stream stream = new MemoryStream(bytes))
{
      XImage image = XImage.FromStream(stream);
      return image;
}


I'm missing something?
Please note that I use PDFsharp and not MigraDoc.

Regards

Author:  Thomas Hoevel [ Wed Jun 22, 2016 9:50 am ]
Post subject:  Re: Applying a template

Sorry, PDFsharp does not support the "base64:" prefix.

If you think there is something wrong with PDFsharp, then please provide a solution that allows us to replicate the problem.

It could help us if you'd show a complete stack trace for the "Invalid parameter" error.

BTW: Do not dispose the stream too early, I think PDFsharp stores a reference to the stream.

Author:  WileECoyote [ Wed Jun 22, 2016 10:33 am ]
Post subject:  Re: Applying a template

Hi Thomas,
I confirm I'm not using the "base64:" string.

The code that triggers the error (tested with a number of pdf files from different sources) is:

PDFSharp 1.50.4000-beta3b

Code:
protected void Page_Load(object sender, EventArgs e)
        {
                // simulate an imput a real PDF file
                Byte[] bytes = File.ReadAllBytes(@"D:\file5mb.pdf");
                MemoryStream stream = new MemoryStream(bytes);
                XImage image = XImage.FromStream(stream);     
        }


The Stack Trace is:

Code:
[ArgumentException: Invalid parameter.]
   System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData) +1402079
   PdfSharp.Drawing.XImage..ctor(Stream stream) +139
   PdfSharp.Drawing.XImage.FromStream(Stream stream) +43
   System.Web.UI.Control.OnLoad(EventArgs e) +109
   System.Web.UI.Control.LoadRecursive() +68
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4498


Thanks!

Author:  Thomas Hoevel [ Wed Jun 22, 2016 11:34 am ]
Post subject:  Re: Applying a template

You have to call XPdfForm.FromStream if the stream contains a PDF file.

XImage.FromFile checks the extension and forwards ".pdf" to XPdfForm. XImage.FromStream does not handle PDF files automatically (yet).

Author:  WileECoyote [ Wed Jun 22, 2016 2:56 pm ]
Post subject:  Re: Applying a template

Hi Thomas,
please apologize me for this misunderstanding.

I'll try to explain better which is the aim of my request.

I'd like to develop a class that receives in imput a single page pdf file Template and a multi page pdf file Document.

we can consider the two PDF as a MemoryStream even if they could have different origin (base64, other APIs memory stream, pdf file, ..).

I came accross this post: viewtopic.php?f=2&t=149 vhich stated:

Quote:
you simply create a New PdfDocument and add a page to it. Then you declare XPdfForm.FromFile(InFile) and XPdfForm.FromFile(OverlayFile). Finally you declare an XGraphics.FromPdfPage(page) and use XGraphics.DrawImage to "paint" the XPdfForms, i.e. the contents of the desired pages from both InFile and OverlayFile onto the new page.


So, I suppose I will have to start with:
Code:
XPdfForm xpfTemplatePdf = XPdfForm.FromStream(xpfTemplateStream);

XPdfForm xpfMultiPagePdf = XPdfForm.FromStream(xpfMultiPageStream);


Can you please help me on the code to apply the xpfTemplatePdf "under" all the pages of xpfMultiPagePdf ?

Thankyou

Author:  Thomas Hoevel [ Wed Jun 22, 2016 3:12 pm ]
Post subject:  Re: Applying a template

XPdfForm is a derived class of XImage.
You can use XPdfForm objects in calls to DrawImage as outlined in your code snippet above.

Use "Prepend" for the background so it will be drawn before the original contents of the page. Thus text on the original page will be drawn on the background image.

Author:  WileECoyote [ Wed Jun 22, 2016 4:08 pm ]
Post subject:  Re: Applying a template

Hi Thomas,
you rule.

I past the final code so that could be useful for any other user.

Code:
// Create the Template XPdf from a MemoryStream
XPdfForm xpfTemplatePdf = XPdfForm.FromStream(templateMS);

// Create a Document from a MemoryStream
var document = PdfReader.Open(docMS);

for (var idx = 0; idx < document.Pages.Count; idx++)
{
    var page = document.Pages[idx];

    // Get an XGraphics object for drawing beneath the existing content.
    var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);

    gfx.DrawImage(xpfTemplatePdf, 0, 0, page.Width, page.Height);

}
// Save the document...
document.Save(@"D:\fattura.pdf");



Regards

Author:  Gahmah [ Fri Nov 11, 2016 5:53 pm ]
Post subject:  Re: Applying a template

Hi I'm trying to apply headers and footers to documents, they're almost perfect, but they're clipping a little bit along the bottom for some reason, I've included my code and the document. I've tried modifying the media box, adjusting the draw image of the form, changing the rect for the headergraphics onto the form, I'm not sure what else to try, they're both the same file going in, but when I use XPdfForm to add to the form it removes all the whitespace, which I was going for, but crops a little to closely

Code:
public PDFConcatenate(PackageToJoin pdfPackage)
        {
            MemoryStream outStream = new MemoryStream();

            CreateBaseDocument(pdfPackage).Save(outStream, false);
            ReturnFile = outStream.ToArray();
            DocName = pdfPackage.Name + ".pdf";
        }

        private PdfDocument CreateBaseDocument(PackageToJoin package)
        {
            OutputDocument = new PdfDocument();
            CreateHeaderAndFooter(package);
            foreach (var chunk in package.Chunks)
            {
                InputDocument = PdfReader.Open(new MemoryStream(chunk.Data), PdfDocumentOpenMode.Import);
               
                int count = InputDocument.PageCount;

                for (int idx = 0; idx < count; idx++)
                {
                    PdfPage page = InputDocument.Pages[idx];               
                    OutputDocument.AddPage(page);
                    AddHeaderFooter(OutputDocument.Pages[OutputDocument.PageCount-1], chunk.UseHeaderFooter);                 
                }
            }
            return OutputDocument;
        }

        private void AddHeaderFooter(PdfPage page, HeaderAndFooter headersAndFooters)
        {
            XGraphics gfx = XGraphics.FromPdfPage(page);

            if (headersAndFooters.ApplyHeader)
            {
                XRect adjustedHeaderRect = new XRect(5, 5, HeaderRect.Width,
                    HeaderRect.Height);
                gfx.DrawImage(Header, adjustedHeaderRect);
            }

            if (headersAndFooters.ApplyFooter)
            {
                XRect adjustedFooterRect = new XRect(5, page.Height - FooterRect.Height - 5, FooterRect.Width,
                    FooterRect.Height);
                gfx.DrawImage(Footer, adjustedFooterRect);
            }
            gfx.Dispose();
        }

        private void CreateHeaderAndFooter(PackageToJoin package)
        {
            //assign header form
            var rawHeader = PdfReader.Open(new MemoryStream(package.HeaderData), PdfDocumentOpenMode.Import);
            PdfPage page = rawHeader.Pages[0];
            HeaderRect = new XRect(0,0, page.Width, page.Height);
            Header = new XForm(OutputDocument, page.Width, page.Height);
            XGraphics headGraphics = XGraphics.FromForm(Header);
            headGraphics.DrawImage(XPdfForm.FromStream(new MemoryStream(package.HeaderData)), HeaderRect);
            headGraphics.Dispose();
           
            //assign footer form
            var rawFooter = PdfReader.Open(new MemoryStream(package.FooterData), PdfDocumentOpenMode.Import);
            page = rawFooter.Pages[0];
            FooterRect = new XRect(0,0, page.Width, page.Height);
            Footer = new XForm(OutputDocument, page.Width, page.Height);
            XGraphics footGraphics = XGraphics.FromForm(Footer);
            footGraphics.DrawImage(XPdfForm.FromStream(new MemoryStream(package.FooterData)), FooterRect);
            footGraphics.Dispose();
        }


Attachments:
HeaderOnDoc.PNG
HeaderOnDoc.PNG [ 38.77 KiB | Viewed 13620 times ]

Page 1 of 1 All times are UTC
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/