0

I've got a problem whereby I've using this code to apply a watermark to each page in an Xps document.

    private static XpsDocument AddWatermark(string watermark, Package container, XpsDocument xpsOld)
    {
        // Open original XPS document    
        FixedDocumentSequence seqOld = xpsOld.GetFixedDocumentSequence();

        // Create new XPS document
        Uri u = new Uri("pack://TemporaryPackageUri.xps");

        try
        {                
            PackageStore.RemovePackage(u);
        }
        catch { }

        PackageStore.AddPackage(u, container);
        var newdoc = new XpsDocument(container, CompressionOption.Maximum, u.AbsoluteUri);

        XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(newdoc);

        // Needed for writing multiple pages

        SerializerWriterCollator vxpsd = writer.CreateVisualsCollator();

        int pageno = 1;

        foreach (DocumentReference r in seqOld.References)
        {
            FixedDocument d = r.GetDocument(false);

            // Walk through each page

            foreach (PageContent pc in d.Pages)
            {
                FixedPage fixedPage = pc.GetPageRoot(false);

                double width = fixedPage.Width;
                double height = fixedPage.Height;
                Size sz = new Size(width, height);

                // Convert to WPF Visual

                fixedPage.Measure(sz);
                fixedPage.Arrange(new Rect(new Point(), sz));
                fixedPage.UpdateLayout();

                ContainerVisual newpage = new ContainerVisual();
                newpage.Children.Add(fixedPage);

                if (!string.IsNullOrEmpty(watermark))
                {
                    newpage.Children.Add(CreateWatermark(width, height, watermark + " (" + pageno + ")"));
                }

                pageno++;

                // Write out modified page
                vxpsd.Write(newpage);

            }
        }

        vxpsd.EndBatchWrite();

        container.Flush();

        // this part serializes the doc to a stream so we can get the bytes
        var ms = new MemoryStream();
        var writerx = new XpsSerializerFactory().CreateSerializerWriter(ms);
        writerx.Write(newdoc.GetFixedDocumentSequence());            

        xpsOld.Close();

        return newdoc;
    }

It basically takes an Xps document as an argument and iterates through each page, creating a visual and adding diagonal watermark across it.

The problem I have is that it loses an image embedded in the original Xps.

Is there something I'm missing? like a series of embedded resources I need to copy?

Any help appreciated, I'm not that familiar with Xps docs.

EDIT 1: This is actually the method thats causing the problem

 public static void PrintFlowDocument(PrintQueue printQueue, DocumentPaginator document, string watermark)
    {
        MemoryStream lMemoryStream = new MemoryStream();
        Package package = Package.Open(lMemoryStream, FileMode.Create);
        Uri u = new Uri("pack://TempTemporaryPackageUri.xps");
        PackageStore.AddPackage(u, package);
        XpsDocument doc = new XpsDocument(package, CompressionOption.NotCompressed, "pack://TempTemporaryPackageUri.xps");

        XpsDocumentWriter xpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);
        xpsDocumentWriter.Write(doc.GetFixedDocumentSequence());          

        PackageStore.RemovePackage(u);
    }

This is the function that calls (although I've omitted to avoid confusion) the addwatermark function. All I'm doing is creating a new xps and adding the Document sequence to it (following the addition and scaling of watermark).

After this, the embedded XpsImage is a 1x1 black pixel... presumably as I need to copy resources (thanks Jon) to it.

Any suggestions on how I complete this?

Thanks

sambomartin
  • 6,663
  • 7
  • 40
  • 64

2 Answers2

0

You should add a fixedPage.UpdateLayout() after adding the watermark.

0

It looks like you skipped copying all the resources and print tickets over. In general though, you should try to modify the existing document, rather than create a new one that is a copy.

Jon
  • 3,065
  • 1
  • 19
  • 29
  • this is the problem. the new Xps has a reference to a png image (XpsImage) but it's a 1px x 1px black image. I've narrowed it down, it's not obviously happening in the AddWatermark method i originally posted, but rather simple by reserialising the xps. Can you give me any advice on how you'd 'copy' the resources across (i've updated question). thanks. – sambomartin Apr 17 '12 at 15:05
  • @sambomartin Is there some reason that you're trying to copy the document rather than modify the existing one? Presumably, you could simply add the watermark content to the FixedPage's Children collection. On the other hand, if your watermark is nothing but a string, why not use the PageWatermark feature of the printticket? – Jon Apr 17 '12 at 16:23
  • PageWatermark property sounds good. I'll look into it. tbh I've only dabbled in printing from WPF using Xps so any advice welcome. thanks – sambomartin Apr 17 '12 at 20:18
  • can you give me any examples of the PageWatermark feature? can't find much about it. it is a .net property of the print job? – sambomartin Apr 23 '12 at 09:01
  • It does not appear that PageWatermark is exposed directly in .net. You'd have to open up the PrintTicket's xml and modify it directly. The PageWatermark feature is defined in the [PrintSchema spec](http://msdn.microsoft.com/en-us/windows/hardware/gg463385.aspx) – Jon Apr 23 '12 at 15:05