Add header and footer to XPS print output
Asked Answered
A

0

10

XpsDocument is loaded from disk

Create a FixedDocumentSequence via XpsDocument.GetFixedDocumentSequence Method ()

Display the via a DocumentViewer

Would like to add to add header and footer to print
I don't need to add the header and footer back to the XPS document - only to the print output

I tried implementing DocumentPaginator but cannot get the sizing or placement to work

NOT the same as this footer to FlowDocument
I use the solution there for FlowDocuments just fine
Convert XAML Flow Document to XPS with Style

On the FixedDocumentSequence the sizing comes from document (I guess)
For example could mix landscape and portrait
I cannot figure out how to hook into the sizing and make room for a header and footer
I can stamp a header on it but it is over the top of the page
And landscape pages are cut off

Cannot assign a PageSize when it comes from a FixedDocumentSequence
As stated in the link it is a suggested pages size
DocumentPage.Size is read only

Even if I create DocumentPage of the Size I want when the page is loaded using DocumentPaginator.GetPage then the Size is overwritten

Even worse the DocumentPaginator does not seem to be properly aware of the Size as it does not deal with mixed landscape and portrait properly. Landscape is printed portrait and just runs off the page.

some one asked me to post code
there also might be a just plain better approach
see footer to FlowDocument for how to use it
this is where it breaks
// this gets the page size from GetPage - ignores size above

public class DocumentPaginatorWrapperXPS : DocumentPaginator
{
    System.Windows.Size m_PageSize;
    System.Windows.Size m_Margin;
    DocumentPaginator m_Paginator;
    FixedDocumentSequence fixedDocumentSequence;
    Typeface m_Typeface;
    private string printHeader;
    private int? sID;
    private string docID;

    public DocumentPaginatorWrapperXPS(FixedDocumentSequence FixedDocumentSequence, System.Windows.Size margin, string PrintHeader, int? SID, string DOCID)
    {
        //m_PageSize = pageSize;
        //m_PageSize = new Size(800, 600);

        fixedDocumentSequence = FixedDocumentSequence;

        m_Margin = margin;
        m_Paginator = fixedDocumentSequence.DocumentPaginator;
        //m_Paginator.PageSize = new System.Windows.Size(m_PageSize.Width - margin.Width * 2,
        //                                               //m_PageSize.Height - margin.Width * 2);
        printHeader = PrintHeader;
        sID = SID;
        docID = DOCID;
    }
    Rect Move(Rect rect)
    {
        if (rect.IsEmpty)
        {
            return rect;
        }
        else
        {
            return new Rect(rect.Left + m_Margin.Width, rect.Top + m_Margin.Height,
                            rect.Width, rect.Height);
        }
    }
    private Size sizeXPS;
    public override DocumentPage GetPage(int pageNumber)
    {
        System.Windows.Documents.DocumentPage page = m_Paginator.GetPage(pageNumber);
        Debug.WriteLine(page.Size.Width + " " + page.Size.Height);


        m_Paginator.PageSize = new System.Windows.Size(page.Size.Width/2 - m_Margin.Width * 2, page.Size.Height/2 - m_Margin.Height * 2);

        page = m_Paginator.GetPage(pageNumber);  // this get the page size from GetPage - ignores size above
        Debug.WriteLine(page.Size.Width + " " + page.Size.Height);

        DynamicDocumentPaginator paginatorPage = fixedDocumentSequence.DocumentPaginator as DynamicDocumentPaginator;
        paginatorPage.PageSize = new System.Windows.Size(page.Size.Width / 2 - m_Margin.Width * 2, page.Size.Height / 2 - m_Margin.Height * 2);
        sizeXPS = new System.Windows.Size(page.Size.Width / 2 - m_Margin.Width * 2, page.Size.Height / 2 - m_Margin.Height * 2);
        page = paginatorPage.GetPage(pageNumber);  // still does not change the page size
        Debug.WriteLine(page.Size.Width + " " + page.Size.Height);

        //page.PageSize = new System.Windows.Size(m_PageSize.Width - margin.Width * 2,
        //m_PageSize.Height - margin.Width * 2);
        //page.Size = new System.Windows.Size(page.Size.Width - m_Margin.Width * 2, page.Size.Height - m_Margin.Height * 2);
        //page.Size.Width = page.Size.Width - m_Margin.Width * 2;
        // Create a wrapper visual for transformation and add extras

        ContainerVisual newpage = new ContainerVisual();
        DrawingVisual title = new DrawingVisual();
        using (DrawingContext ctx = title.RenderOpen())
        {
            if (m_Typeface == null)
            {
                m_Typeface = new Typeface("Segoe UI Symbol");  //Ariel
            }
            //FormattedText text = new FormattedText("Attorney eyes only  \uE18B  \u1F440                Page " + (pageNumber + 1), 
            //                                        System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, 
            //                                        m_Typeface, 14, System.Windows.Media.Brushes.Black);

            string pageS = "m_PageSize.Width " + m_PageSize.Width + "  m_Margin.Width " + m_Margin.Width + "  m_PageSize.Height " + m_PageSize.Height + "  m_Margin.Height " + m_Margin.Height + Environment.NewLine +
                            "page.Size.Width " + page.Size.Width + "  page.Size.Height " + page.Size.Height;
            FormattedText header = new FormattedText("\u1F440 " + printHeader + Environment.NewLine + pageS,
                                                    System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                                    m_Typeface, 14, System.Windows.Media.Brushes.Black);
            ctx.DrawText(header, new System.Windows.Point(96 / 2, -96 / 4)); // 1/4 inch above page content
            //text = new FormattedText(pageS, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
            //                         m_Typeface, 14, System.Windows.Media.Brushes.Black);

            string goGabe = string.Empty;
            if (sID != null)
            {
                goGabe += Environment.NewLine + "Gabriel Docs™ sysDocID: " + sID;
                if (!string.IsNullOrEmpty(docID))
                    goGabe += "  docID: " + docID;
            }
            goGabe += Environment.NewLine + "Page: " + (pageNumber + 1) + "   Date: " + DateTime.Now.ToString() + "  User: " + App.StaticGabeLib.CurUserP.UserID;
            FormattedText footer = new FormattedText(goGabe
                                                    , System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                                        m_Typeface, 14, System.Windows.Media.Brushes.Black);
            ctx.DrawText(footer, new System.Windows.Point(96 / 2, page.Size.Height - m_Margin.Height));
            //ctx.DrawText(footer, new System.Windows.Point(96 / 2, m_Paginator.PageSize.Height - m_Margin.Height));
        }
        DrawingVisual background = new DrawingVisual();
        using (DrawingContext ctx = background.RenderOpen())
        {
            ctx.DrawRectangle(new SolidColorBrush(System.Windows.Media.Color.FromRgb(240, 240, 240)), null, page.ContentBox);
        }
        newpage.Children.Add(background); // Scale down page and center
        ContainerVisual smallerPage = new ContainerVisual();
        smallerPage.Children.Add(page.Visual);
        smallerPage.Transform = new MatrixTransform(0.8, 0, 0, 0.8, 0.1 * page.ContentBox.Width, 0.1 * page.ContentBox.Height);
        newpage.Children.Add(smallerPage);
        newpage.Children.Add(title);
        newpage.Transform = new TranslateTransform(m_Margin.Width, m_Margin.Height);
        return new DocumentPage(newpage, m_PageSize, Move(page.BleedBox), Move(page.ContentBox));
    }
    public override bool IsPageCountValid
    {
        get
        {
            return m_Paginator.IsPageCountValid;
        }
    }
    public override int PageCount
    {
        get
        {
            return m_Paginator.PageCount;
        }
    }
    public override System.Windows.Size PageSize
    {
        get
        {
            Debug.WriteLine("PageSize " + sizeXPS.Width + " " + sizeXPS.Height);
            return sizeXPS;  // this is not called

            //m_Paginator.PageSize;
        }
        set
        {
            sizeXPS = value;
            // m_Paginator.PageSize = value;
        }
    }
    public override IDocumentPaginatorSource Source
    {
        get
        {
            return m_Paginator.Source;
        }
    }
}
Altruist answered 24/5, 2016 at 19:7 Comment(13)
Thinking about going from having controls/visuals and printing an XpsDocument, you essentially pass/provide a collection of Visuals for the paginator and it builds the document. So my thought is, maybe get each page of the document, then call GetVisual, then with the visual you can get the dimensions, and based on the dimensions you can put your header & footer in relative/absolute positions, then you would feed(print) your visuals to a new XpsDocument printer, creating a new XpsDocument. What I do know is the solution to this question will take a good amount of time.Kersten
@Kevin I was not clear - I don't need to add to the XPS documentAltruist
I +1'd to counter the downvote. If you had a simple solution/project put together that demonstrates your issues that I can download, I'd be willing to try accomplishing your goal, but until then, I think it'll be a daunting task trying to explain how to do things.Kersten
@Kevin What I have is a bit hacked up but I posted itAltruist
Can you confirm that PageSize getter does not get called? It should get called when the document is printed...Kersten
@Kevin Strangely it is not getting called. I ran in debug. But I will test again to confirm.Altruist
@Kevin Yes I confirmed again it is not calledAltruist
Have you tried the approach sketchen in Jo0815's answer at this msdn forum?Fissionable
@StefanSchmiedl That is a FixedPage not a DocumentPage and that link is not resizing. But still I check into it. Thanks.Altruist
@Paparazzi: I came across some posts that indicated that you might run into rendering problems with nested scaling, which would result in an ugly, low-resulotion rasterized image. When I had to do something similar a few years back, I plugged a ruby script into CUPS (common printing system on linux boxes) and patched the overlay into the postscript code submitted by the client driver, then converted the result to PDF. I hope you don't have to write a printer driver on Windows for your problem :-)Fissionable
@StefanSchmiedl I won't write a print drive and I will stay away from PDF. I can do an overlay with no re-sizing but they really want a header and footer. There is commercial product but it is not cheap - I think they go into the API. And yes when I tried this with Annotations on a FlowDocument I got some bad rendering and some hard crashes.Altruist
@Paparazzi would the code work if you were using a FlowDocument?Supernational
@Supernational As stated in my question yes it works fine for a FlowDocument. There the size comes from the paginator.Altruist

© 2022 - 2024 — McMap. All rights reserved.