4

My requirement is to create xps document which has 10 pages (say). I am using the following code to create a xps document. Please take a look.

// Create the new document
        XpsDocument xd = new XpsDocument("D:\\9780545325653.xps", FileAccess.ReadWrite);

        IXpsFixedDocumentSequenceWriter xdSW = xd.AddFixedDocumentSequence();

        IXpsFixedDocumentWriter xdW = xdSW.AddFixedDocument();

        IXpsFixedPageWriter xpW = xdW.AddFixedPage();

            fontURI = AddFontResourceToFixedPage(xpW, @"D:\arial.ttf");

            image = AddJpegImageResourceToFixedPage(xpW, @"D:\Single content\20_1.jpg");

            StringBuilder pageContents = new StringBuilder();

            pageContents.Append(ReadFile(@"D:\Single content\20.fpage\20.fpage", i));

            xmlWriter = xpW.XmlWriter;
            xmlWriter.WriteRaw(pageContents.ToString());               
        }
        xmlWriter.Close();
        xpW.Commit();

        // Commit the fixed document
        xdW.Commit();
        // Commite the fixed document sequence writer
        xdSW.Commit();
        // Commit the XPS document itself
        xd.Close();

    }

    private static string AddFontResourceToFixedPage(IXpsFixedPageWriter pageWriter, String fontFileName)
    {
        string fontUri = "";
        using (XpsFont font = pageWriter.AddFont(false))
        {
            using (Stream dstFontStream = font.GetStream())
            using (Stream srcFontStream = File.OpenRead(fontFileName))
            {
                CopyStream(srcFontStream, dstFontStream);

                // commit font resource to the package file
                font.Commit();
            }
            fontUri = font.Uri.ToString();
        }
        return fontUri;
    }

    private static Int32 CopyStream(Stream srcStream, Stream dstStream)
    {
        const int size = 64 * 1024; // copy using 64K buffers
        byte[] localBuffer = new byte[size];
        int bytesRead;
        Int32 bytesMoved = 0;

        // reset stream pointers
        srcStream.Seek(0, SeekOrigin.Begin);
        dstStream.Seek(0, SeekOrigin.Begin);

        // stream position is advanced automatically by stream object
        while ((bytesRead = srcStream.Read(localBuffer, 0, size)) > 0)
        {
            dstStream.Write(localBuffer, 0, bytesRead);
            bytesMoved += bytesRead;
        }
        return bytesMoved;
    }

    private static string ReadFile(string filePath,int i)
    {

        FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);

        StringBuilder sb = new StringBuilder();
        using (StreamReader sr = new StreamReader(fs))
        {
            String line;
            // Read and display lines from the file until the end of 
            // the file is reached.
            while ((line = sr.ReadLine()) != null)
            {
                sb.AppendLine(line);
            }
        }
        string allines = sb.ToString();

        //allines = allines.Replace("FontUri=\"/Resources/f7728e4c-2606-4fcb-b963-d2d3f52b013b.odttf\"", "FontUri=\"" + fontURI + "\" ");

        //XmlReader xmlReader = XmlReader.Create(fs, new XmlReaderSettings() { IgnoreComments = true });

        XMLSerializer serializer = new XMLSerializer();

        FixedPage fp = (FixedPage)serializer.DeSerialize(allines, typeof(FixedPage));

        foreach (Glyphs glyph in fp.lstGlyphs)
        {
            glyph.FontUri = fontURI;
        }

        fp.Path.PathFill.ImageBrush.ImageSource = image;

        fs.Close();

        string fpageString = serializer.Serialize(fp);



        return fpageString;
    }

    private static string AddJpegImageResourceToFixedPage(IXpsFixedPageWriter pageWriter, String imgFileName)
    {
        XpsImage image = pageWriter.AddImage("image/jpeg");
        using (Stream dstImageStream = image.GetStream())
        using (Stream srcImageStream = File.OpenRead(imgFileName))
        {
            CopyStream(srcImageStream, dstImageStream); // commit image resource to the package file 
            //image.Commit();
        }

        return image.Uri.ToString();

    }

If you see it, i would have passed single image and single fpage to create a xps document. I want to pass multiple fpages list and image list to create a xps document which has multiple pages..?

Shafiq Abbas
  • 484
  • 1
  • 5
  • 18

1 Answers1

3

You are doing this in the most excruciatingly difficult manner possible. I'd suggest taking the lazy man's route.

Realize that an XpsDocument is just a wrapper on a FixedDocumentSequence, which contains zero or more FixedDocuments, which contains zero or more FixedPages. All these types can be created, manipulated and combined without writing XML.

All you really need to do is create a FixedPage with whatever content on it you need. Here's an example:

static FixedPage CreateFixedPage(Uri imageSource)
{
    FixedPage fp = new FixedPage();
    fp.Width = 320;
    fp.Height = 240;
    Grid g = new Grid();
    g.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
    g.VerticalAlignment = System.Windows.VerticalAlignment.Center;
    fp.Children.Add(g);
    Image img = new Image
    {
        UriSource = imageSource,
    };
    g.Children.Add(image);
    return fp;
}

This is all WPF. I'm creating a FixedPage that has as its root a Grid, which contains an Image that is loaded from the given Uri. The image will be stretched to fill the available space of the Grid. Or, you could do whatever you want. Create a template as a UserControl, send it text to place within itself, whatever.

Next, you just need to add a bunch of fixed pages to an XpsDocument. It's incredibly hard, so read carefully:

public void WriteAllPages(XpsDocument document, IEnumerable<FixedPage> pages)
{

    var writer = XpsDocument.CreateXpsDocumentWriter(document);
    foreach(var page in pages)
        writer.Write(page);
}

And that's all you need to do. Create your pages, add them to your document. Done.

  • +1 for saving my time by denying excruciatingly difficult things :) – WiiMaxx Jul 05 '13 at 07:57
  • 2
    writer.Write(page) leads to "Document Writer is done writing and cannot process any more write requests." – wischi Oct 24 '13 at 15:17
  • @wischi: Nope. Create a minimum repro in a prototype and see if it happens again. If it does, ask a quesiton using the code from the repro. If not, you're doing something wrong with the writer, such as flushing or closing or disposing. –  Oct 24 '13 at 15:42
  • 4
    @Will, you can only call XpsDocumentWriter.Write() once. wischi isn't doing anything wrong. – Cory Nelson Feb 16 '15 at 16:10