Pagination of XPS files into Graphics format files in A3 or A4 Pages


Introduction

This is a continuation of the previous post (Craig’s Eclectic Blog » Convert an XPS to JPEG, PNG, TIFF or BMP in A4 Pages ) in which I presented a solution to producing A3 of A4 pages from a large XPS file. There were a number of things in that solution which I was not entirely happy with, which this post addresses.

Things which were “not to my satisfaction”

There were a couple of problems I had with the solution presented. These included:

  • The Paper size occurred twice in the functions arguments. It was there once as a size, and once as a string for encoding into the file name. This looked like a classic case of a class which should have existed which was overlooked.
  • There were a number of places where the string for the encoding was passed into API class, or used as part of the file name generation. Again, this looked like a case of an enumeration which should have existed in the solution which was missing. One could also argue that the .Net Framework API’s should be using a similar enumeration.
  • There was a better way to handle the encoding of page parts. This solution is a “bit” more efficient.

Also there were a couple of things which should have been included in the previous post which I forgot to put in. These included:

  • The main needs to be [STAThreadAttribute]. The attribute (see the following on MSDN for an explanation of attributes in C#: Attributes (C# and Visual Basic) ) on the main STAThread is vital (the program will throw an exception without it). The main also give a clue as to why I cleaned up some of the memory management in the source code which this started from. I had over 500 XPS files to tile into workable, and all user consumable, files.
  • There was an optimisation of the tiling process which I should have included. This optimisation is to align the longest edge of the paper with the longest edge of the bitmap to be tiled. This, should and I’ve only my empirical “feel” for the subject which suggests it should be so, should minimise the number of tiles produces.

The Classes in the Final Solution

The  following diagram is the class call structure, generated by Visual Studio

XPS_to_Graphic_Structure

The following the class diagram for the final solution (final being loosely used term – in that it is final only until I thinks of another improvement, or a new requirement, for the solution).

ClassDiagram1

The Main Program

There are a couple of key point to note here:

  • The STAThread attribute is necessary. The underlying API’s used by the program require the STA (Single Threaded Apartment)Threading model.
  • The redesign of the interface into the pagination process has yielded a far more flexible API. The ability too specify multiple:
    • Encodings
    • Paper sizes
    • Output file types (one big one, multiple pages in one file and multiple encoded by paper size files)
    • The “skip done” provides a rudimentary restart facility.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace XpsConverter
{
    /// <summary>
    /// Program for the conversion of XPS files to graphics files in:
    ///     Multiple output formats
    ///     Multiple tilings of the image (A3 or A4 currently)
    /// </summary>
    class Program
    {
        /// <summary>
        /// Where the XPS files are found
        /// </summary>
        private static string XPS_Path =
            @"H:\Visual Studio 2010\Projects\ProduceDGML_from_XML\DGML_From_LINQ\XPS";
        /// <summary>
        /// Where the graphics files are written
        /// </summary>
        private static string JPG_Path =
            @"H:\Visual Studio 2010\Projects\Convert_XPS_to_BPM\JPG_Files\";

        /// <summary>
        /// Main for the execution of the program.
        /// 
        /// args">
        [STAThread]
        static void Main(string[] args)
        {
            List<PaperSize> papers = new List<PaperSize>()
            {
                new PaperSize(PaperSizes.A3),
                new PaperSize(PaperSizes.A4)
            };

            List<EncoderTypes> singleFileOuptut = new List<EncoderTypes>
            {
                EncoderTypes.gif, EncoderTypes.png, EncoderTypes.jpg,
                EncoderTypes.bmp, EncoderTypes.tiff, EncoderTypes.wdp
                //EncoderTypes.gif
            };
            var filesList = Directory.GetFiles(XPS_Path, "*.xps");
            foreach (string fileName in filesList)
            {
                //XPS_Outputs_Producer producer = new XPS_Outputs_Producer();
                XPS_Outputs_Producer.XPS_To_Pages(fileName, JPG_Path, false, true,
                    papers, singleFileOuptut, true,
                    EncoderTypes.tiff, papers);
            }
        }
    }
}

The Encoder Encapsulation

This is simply a very thin wrapper class around the Framework’s Encoder classes. Simply it allows the creation of a specific encoder on the basis of the Encoder Types enumeration. My API design philosophy would have the Framework working in this manner, through a factory class. One day, I may convert this into an extension method, but for now it does the job.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;

namespace XpsConverter
{
    /// <summary>
    /// A very thing wrapper class over the native framework bit map
    /// encoding classes.
    /// </summary>
    public class EncoderEncapsulation
    {
        private EncoderTypes _encoderType;
        private BitmapEncoder _encoder;
        public EncoderEncapsulation(EncoderTypes requiredType)
        {
            this._encoderType = requiredType;
            this._encoder = null;
        }
        public BitmapEncoder Encoder
        {
            get
            {
                if (this._encoder != null)
                    return this._encoder;
                switch (this._encoderType)
                {
                    case EncoderTypes.png:
                        this._encoder = new PngBitmapEncoder();
                        return this._encoder;
                    case EncoderTypes.jpg:
                        this._encoder = new JpegBitmapEncoder();
                        return this._encoder;
                    case EncoderTypes.tiff:
                        this._encoder = new TiffBitmapEncoder();
                        return this._encoder;
                    case EncoderTypes.gif:
                        this._encoder = new GifBitmapEncoder();
                        return this._encoder;
                    case EncoderTypes.bmp:
                        this._encoder = new BmpBitmapEncoder();
                        return this._encoder;
                    case EncoderTypes.wdp:
                        this._encoder = new WmpBitmapEncoder();
                        return this._encoder;
                    default:
                        this._encoder = new BmpBitmapEncoder();
                        return this._encoder;
                }
            }
        }
        public EncoderTypes EncoderType
        {
            get
            {
                return this._encoderType;
            }
        }
    }
}

The File Namer Class

This is simply a file name generator class. It works with the pages in the XPS file and the tiles being generated.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XpsConverter
{
    /// <summary>
    /// This class is just a file name generating object.
    /// There is a degree of structure in the input names,
    /// and the generated names embellish on that with extra metadata.
    /// </summary>
    public class FileNamer
    {
        private string _filename;

        private FileNamer()
        {
            this._filename = null;
        }

        public FileNamer(string FilePath, string fileNamePart,
            int pageNo, int iTotalPages, EncoderTypes FileType):this()
        {
            StringBuilder res = new StringBuilder(FilePath);
            if(FilePath[FilePath.Length -1] != '\\')
                res.Append('\\');
            int iPage = pageNo + 1;
            int iPageTotal = iTotalPages;
            res.AppendFormat("{0}_Page_{1}_of_{3}.{2}",
                fileNamePart, iPage,
                Enum.GetName(typeof(EncoderTypes), FileType), iPageTotal);
            this._filename = res.ToString();
        }

        public FileNamer(string RootOutputPath, string fileNamePart,
            int pageNum, int iTotalPages,
            int iHrozTiles, int iVertTiles, int i, int j,
            PaperSize paperSize, EncoderTypes encoderType) : this()
        {
            int iPart = ((i * (iVertTiles)) + j) + 1;
            int iTotal = (iHrozTiles) * (iVertTiles);
            int iPage = pageNum + 1;

            StringBuilder result = new StringBuilder(RootOutputPath);
            if (RootOutputPath[RootOutputPath.Length - 1] != '\\')
                result.Append('\\');
            result.AppendFormat("{0}_Page_{1}_of_{6}_Part_{2}_of_{3}_{5}.{4}",
                fileNamePart, iPage, iPart, iTotal,
                Enum.GetName(typeof(EncoderTypes), encoderType),
                Enum.GetName(typeof(PaperSizes), paperSize.PaperSizeEnum),
                iTotalPages);
            this._filename = result.ToString();
        }

        public    FileNamer(string rootOutputPath,
            string fileNamePart,EncoderTypes MultiPageEncoder,PaperSize paper)
        {
            StringBuilder result = new StringBuilder(rootOutputPath);
            if (rootOutputPath[rootOutputPath.Length - 1] != '\\')
                result.Append('\\');
            result.AppendFormat("{0}_{2}.{1}", fileNamePart,
                Enum.GetName(typeof(EncoderTypes), MultiPageEncoder),
                Enum.GetName(typeof(PaperSizes), paper.PaperSizeEnum));
            this._filename = result.ToString();
        }

        public string FileName
        {
            get
            {
                return this._filename;
            }
        }
    }
}

Bitmap Metadata Generation

The following is major function in my bitmap metadata generation method. There was a bit of “trial and exception” to determine which metadata elements are valid for each of the encoding types.

public BitmapMetadata MakeMetadata(EncoderTypes encoderType)
{
    string encoder = System.Enum.GetName(typeof(EncoderTypes), encoderType);
    if (encoderType == EncoderTypes.wdp || encoderType == EncoderTypes.gif || encoderType == EncoderTypes.bmp)
        return null;
    BitmapMetadata metadata = new BitmapMetadata(encoder);
    switch (encoderType)
    {
        case EncoderTypes.png:
            metadata.DateTaken = this.Taken;
            break;
        case EncoderTypes.jpg:
            metadata.ApplicationName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
            metadata.Author = this.Author;
            metadata.Comment = this.Comment;
            metadata.Copyright = this.Copyright;
            metadata.DateTaken = this.Taken;
            metadata.Keywords = this.Keywords;
            metadata.Subject = this.Subject;
            metadata.Title = this.Title;
            break;
        case EncoderTypes.tiff:
            metadata.ApplicationName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
            metadata.Author = this.Author;
            metadata.Comment = this.Comment;
            metadata.Copyright = this.Copyright;
            metadata.DateTaken = this.Taken;
            metadata.Keywords = this.Keywords;
            metadata.Subject = this.Subject;
            metadata.Title = this.Title;
            break;
        case EncoderTypes.gif:
            Debug.WriteLine("GIF files do not appear to support metadata. Should not get here");
            break;
        case EncoderTypes.bmp:
            Debug.WriteLine("BMP files do not appear to support metadata. Should not get here!");
            break;
        case EncoderTypes.wdp:
            Debug.WriteLine("WDP files do not appear to support metadata. Should not get here!");
            break;
        default:
            Debug.WriteLine("Should not get here");
            break;
    }
    return metadata;
}

Paper Size Encapsulation

The class, and enumeration, wrap the details of paper size into a usable class. Also, the class includes overrides of Equals and GetHashCode.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace XpsConverter
{
    /// <summary>
    /// Enumeration which contains the paper types for which size information is kept
    /// </summary>
    public enum PaperSizes { A4, A3 }

    /// <summary>
    /// Encapsulation of the Paper size information.
    /// </summary>
    public class PaperSize
    {
        private Size _paperSize;
        private PaperSizes _paperSizeEnum;
        private PaperSize()
        {

        }

        public PaperSize(PaperSizes paperSize)
        {
            this._paperSizeEnum = paperSize;
            switch (paperSize)
            {
                case PaperSizes.A4:
                    this._paperSize = new Size(780, 1100);
                    break;
                case PaperSizes.A3:
                    this._paperSize = new Size(1560, 2200);
                    break;
                default:
                    this._paperSize = new Size(780, 1100);
                    break;
            }
        }
        public PaperSizes PaperSizeEnum
        {
            get
            {
                return this._paperSizeEnum;
            }
        }
        public Size CurrentSize
        {
            get
            {
                return this._paperSize;
            }
        }
        public int Height
        {
            get
            {
                return (int)this._paperSize.Height;
            }
        }
        public int Width
        {
            get
            {
                return (int) this._paperSize.Width;
            }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            PaperSize temp = obj as PaperSize;
            if (temp == null)
                return false;
            if (temp._paperSizeEnum == this._paperSizeEnum)
                return true;
            return false;
        }

        public override int GetHashCode()
        {
            return this._paperSizeEnum.GetHashCode();
        }
    }
}

The Pagination Process

This is where most of the work happens.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Xps.Packaging;
using System.Windows.Documents;
using System.Windows.Media.Imaging;
using System.Diagnostics;
using System.Windows;

namespace XpsConverter
{
    public static class XPS_Outputs_Producer
    {
        /// <summary>
        /// This is the main entry point in to the process of converting an
        /// XPS file into graphics files
        /// </summary>
        /// <param name="fileName">The name of the file to be processed.
        /// It should include all of the path information to find the file
        /// RootOutputPath">The path to the output root
        /// SkipDone">Skip files which have already been created
        /// OneBigOne">Generate a graphics file which is not tiled into parts</param>
        /// <param name="papers">The list of paper sizes to tile the XPS file into
        /// singleFileOuptut">The list of encodings which the XPS file
        /// is to be converted into
        /// multiplePageOutput">The flag used to indicate that one file
        /// with multiple pages (frames in graphics file terms) is to be created
        /// MultiPageEncoder">The list of encodings which are to be used
        /// for the multiple page output
        /// multiplePapers">The list of papers which the XPS is to be tiled into.</param>
        internal static void XPS_To_Pages(string fileName, string RootOutputPath,
            bool SkipDone ,
            bool OneBigOne,
            List<PaperSize> papers,
            List<EncoderTypes> singleFileOuptut,
            bool multiplePageOutput ,
            EncoderTypes MultiPageEncoder,
            List<PaperSize> multiplePapers)
        {
            string fileNamePart = Path.GetFileNameWithoutExtension(fileName);
            FileNameDecoder decoder = new FileNameDecoder(fileNamePart);
            string DirectoryPart = decoder.MakeDirectoryPartsFromName(RootOutputPath);
            RootOutputPath = DirectoryPart;
            FileNameDecoder.copyXPSFile(fileName, RootOutputPath, fileNamePart);
            if (SkipDone &&
                AlreadyDone(new FileNamer(RootOutputPath, fileNamePart, 0, 0, singleFileOuptut[0])))
                return;

            MultiplePageFilePaperAndEncoder multiPageOutput = null;
            if(multiplePageOutput)
            {
                multiPageOutput = new MultiplePageFilePaperAndEncoder();
                foreach(PaperSize paper in multiplePapers)
                {
                    multiPageOutput.Add(new EncoderEncapsulation(MultiPageEncoder),  paper,
                        new FileNamer(RootOutputPath, fileNamePart, MultiPageEncoder, paper));
                }
            }
            XpsDocument xpsDoc = null;
            try
            {
                xpsDoc = ProcessXPSDocument(fileName, RootOutputPath, OneBigOne, papers,
                    singleFileOuptut, multiplePageOutput, fileNamePart, decoder,
                    multiPageOutput, xpsDoc);
                xpsDoc = null;
            }
            finally
            {
                if (xpsDoc != null)
                    xpsDoc.Close();
            }
        }

        /// <summary>
        /// This method processes the XPS document and extracts the pages of that document.
        /// 
        /// 
        /// RootOutputPath">
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static XpsDocument ProcessXPSDocument(string fileName, string RootOutputPath,
            bool OneBigOne, List<PaperSize> papers, List<EncoderTypes> singleFileOuptut,
            bool multiplePageOutput, string fileNamePart, FileNameDecoder decoder,
            MultiplePageFilePaperAndEncoder multiPageOutput, XpsDocument xpsDoc)
        {
            using (xpsDoc = new XpsDocument(fileName, System.IO.FileAccess.Read))
            {
                FixedDocumentSequence docSeq = xpsDoc.GetFixedDocumentSequence();
                int iTotalPages = docSeq.DocumentPaginator.PageCount;
                for (int pageNum = 0; pageNum < iTotalPages; ++pageNum)
                {
                    DocumentPage docPage = null;
                    try
                    {
                        docPage = ProcessBitMapImage(RootOutputPath, OneBigOne,
                            papers, singleFileOuptut, fileNamePart, decoder,
                            multiPageOutput, docSeq, iTotalPages, pageNum, docPage);
                        docPage = null;
                    }
                    finally
                    {
                        if (docPage != null)
                            docPage.Dispose();
                    }
                }
                if (multiplePageOutput)
                {
                    GenerateMultpliePageOutputs(multiPageOutput);
                }
            }
            return xpsDoc;
        }

        /// <summary>
        /// This method renders the page into a BitMap and then calls the required
        /// pagination routines.
        /// 
        /// RootOutputPath">
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static DocumentPage ProcessBitMapImage(string RootOutputPath, bool OneBigOne,
            List<PaperSize> papers, List<EncoderTypes> singleFileOuptut, string fileNamePart,
            FileNameDecoder decoder, MultiplePageFilePaperAndEncoder multiPageOutput,
            FixedDocumentSequence docSeq, int iTotalPages, int pageNum, DocumentPage docPage)
        {
            using (docPage = docSeq.DocumentPaginator.GetPage(pageNum))
            {
                RenderTargetBitmap renderTarget =
                    new RenderTargetBitmap((int)docPage.Size.Width,
                                            (int)docPage.Size.Height,
                                            96, // WPF (Avalon) units are 96dpi based
                                            96,
                                            System.Windows.Media.PixelFormats.Default);
                renderTarget.Render(docPage.Visual);
                if (OneBigOne)
                {
                    MakeOutputFile(RootOutputPath, fileNamePart, pageNum, iTotalPages, singleFileOuptut, renderTarget, decoder);
                }
                MakeOutputFiles(RootOutputPath, fileNamePart, pageNum, iTotalPages, singleFileOuptut, papers, renderTarget, decoder, multiPageOutput);
            }
            return docPage;
        }

        /// <summary>
        /// Produces the output files for each of the multiple page outputs
        /// 
        /// MultiplePageEncoders">
        private static void GenerateMultpliePageOutputs(
            MultiplePageFilePaperAndEncoder MultiplePageEncoders)
        {
            foreach(Tuple<EncoderEncapsulation, FileNamer> output in MultiplePageEncoders.GetOutputDetails())
            {
                ProcudeOutputFile(output);
            }
        }

        /// <summary>
        /// Does the writing of the encoded bitmap to output file.
        /// </summary>
        /// <param name="output"></param>
        private static void ProcudeOutputFile(Tuple<EncoderEncapsulation, FileNamer> output)
        {
            FileStream pageOutStream = null;
            using (pageOutStream = new FileStream(output.Item2.FileName, FileMode.Create, FileAccess.Write))
            {
                try
                {
                    output.Item1.Encoder.Save(pageOutStream);
                    pageOutStream.Close();
                    pageOutStream = null;
                }
                catch (AccessViolationException ex)
                {
                    Debug.WriteLine(ex);
                    Debug.WriteLine(
                        "{0} File {1} is broken trying next", DateTime.Now.ToLongTimeString(), output.Item2.FileName);
                    pageOutStream.Close();
                    File.Delete(output.Item2.FileName);
                }
                finally
                {
                    if (pageOutStream != null)
                    {
                        pageOutStream.Dispose();
                    }
                }
            }
        }

        /// <summary>
        /// Crops the Image to each of the Paper sized tiles, and then produces the output file.
        /// 
        /// 
        /// fileNamePart">
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void MakeOutputFiles(string RootOutputPath,
            string fileNamePart,
            int pageNum, int iTotalPages,
            List<EncoderTypes> singleFileOuptut,
            List<PaperSize> papers,
            RenderTargetBitmap renderTarget,
            FileNameDecoder decoder,
            MultiplePageFilePaperAndEncoder MultiEncoders)
        {
            foreach (PaperSize PaperSize in papers)
            {
                int iHorzTiles;
                int iVertTiles;
                Size Paper = CalculateTiles(renderTarget, PaperSize.CurrentSize, out iHorzTiles, out iVertTiles);
                for (int i = 0; i < iHorzTiles; i++)
                {
                    for (int j = 0; j < iVertTiles; j++)
                    {
                        Int32Rect crop = CalculateCropRectangle(renderTarget, Paper, i, j);
                        if (crop.X == renderTarget.Width || crop.Y == renderTarget.Height)
                            continue;
                        CroppedBitmap croppedBitmap = new CroppedBitmap(renderTarget, crop);
                        AddToMultiPageEncoders(MultiEncoders, croppedBitmap, decoder, iHorzTiles, iVertTiles, i, j, PaperSize, pageNum, iTotalPages);
                        foreach (EncoderTypes encoderType in singleFileOuptut)
                        {
                            FileNamer namer = new FileNamer(
                                RootOutputPath, fileNamePart, pageNum, iTotalPages,
                                iHorzTiles, iVertTiles, i, j,
                                PaperSize, encoderType);
                            EncoderEncapsulation encoder = new EncoderEncapsulation(encoderType);
                            BitmapEncoder enc = encoder.Encoder;
                            enc.Frames.Add(BitmapFrame.Create(croppedBitmap, null,
                                decoder.MakeMetadata(encoderType, pageNum,  iTotalPages, i,j, iHorzTiles, iVertTiles), null));
                            ProduceOutputFile(namer, enc);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Adds the copped bitmap to the correct paper sizes multiple page output encoder
        /// 
        /// 
        /// croppedBitmap">
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static void AddToMultiPageEncoders(
            MultiplePageFilePaperAndEncoder MultiplePageEncoders,
            CroppedBitmap croppedBitmap,
            FileNameDecoder Decoder,
            int iHorzTiles, int iVertTiles,
            int i, int j, PaperSize paper,
            int iPage, int iPages)
        {
            if (MultiplePageEncoders == null)
                return;
            BitmapEncoder encoder = MultiplePageEncoders.getEncoder(paper);
            encoder.Frames.Add(BitmapFrame.Create(croppedBitmap, null,
                Decoder.MakeMetadata(MultiplePageEncoders.getEncoderType(paper), iPage, iPages, i, j, iHorzTiles, iVertTiles),
                null));
        }

        private static Int32Rect CalculateCropRectangle(RenderTargetBitmap renderTarget, Size Paper, int i, int j)
        {
            Int32Rect crop = new Int32Rect((int)Math.Min(i * Paper.Width, renderTarget.Width),
                  (int)Math.Min(j * Paper.Height, renderTarget.Height),
                  (int)Math.Min(Paper.Width, renderTarget.Width - ((i) * Paper.Width)),
                  (int)Math.Min(Paper.Height, renderTarget.Height - (j * Paper.Height)));
            return crop;
        }

        /// <summary>
        /// This routine tries and optimises the way the tiles are carved off the base image.
        /// It is more efficient (in terms of number of tiles required) to carve the image
        /// up with the tile longest edge, matching the image longest edge.
        /// (An unproven assertions - the math is probably quite long winded to prove).
        /// </summary>
        /// <param name="renderTarget">The bitmap which will have tiles produced</param>
        /// <param name="Paper">The size of the tile to create
        /// iHrozTiles">The number of horizontal tiles
        /// iVertTiles">The number of vertical tiles</param>
        /// <returns></returns>
        private static Size CalculateTiles(RenderTargetBitmap renderTarget, Size Paper, out int iHrozTiles, out int iVertTiles)
        {
            if (renderTarget.Height > renderTarget.Width)
            {
                iHrozTiles = ((int)(renderTarget.Width / Paper.Width)) + 1;
                iVertTiles = ((int)(renderTarget.Height / Paper.Height)) + 1;
            }
            else
            {
                Size switched = new Size(Paper.Height, Paper.Width);
                iHrozTiles = ((int)(renderTarget.Width / Paper.Width)) + 1;
                iVertTiles = ((int)(renderTarget.Height / Paper.Height)) + 1;
            }
            return Paper;
        }

        /// <summary>
        /// Encodes the full size (same as the original) bit map to required encoding.
        /// </summary>
        /// <param name="RootOutputPath"></param>
        /// <param name="fileNamePart"></param>
        /// <param name="pageNum"></param>
        /// <param name="iTotalPages"></param>
        /// <param name="singleFileOuptut"></param>
        /// <param name="renderTarget"></param>
        /// <param name="decoder"></param>
        private static void MakeOutputFile(string RootOutputPath, string fileNamePart, int pageNum, int iTotalPages,
            List<EncoderTypes> singleFileOuptut,
            RenderTargetBitmap renderTarget,
            FileNameDecoder decoder)
        {
            foreach (EncoderTypes encoding in singleFileOuptut)
            {
                FileNamer namer = new FileNamer(RootOutputPath, fileNamePart, pageNum, iTotalPages, encoding);
                try
                {
                    EncoderEncapsulation encoderType = new EncoderEncapsulation(encoding);
                    BitmapEncoder encoder = encoderType.Encoder;
                    //BitmapFrame framed = BitmapFrame.Create(renderTarget);
                    encoder.Frames.Add(BitmapFrame.Create(renderTarget, null,
                        decoder.MakeMetadata(encoding), null));
                    ProduceOutputFile(namer, encoder);

                }
                catch (AccessViolationException ex)
                {
                    Debug.WriteLine(ex);
                }
            }
        }

        /// <summary>
        /// Does the writing of the encoded bitmap to the output file.
        /// 
        /// namer">
        /// 
        private static void ProduceOutputFile(FileNamer namer, BitmapEncoder encoder)
        {
            FileStream pageOutStream = null;
            try
            {
                using (pageOutStream = new FileStream(namer.FileName, FileMode.Create, FileAccess.Write))
                {
                    encoder.Save(pageOutStream);
                    pageOutStream.Close();
                    pageOutStream = null;
                }
            }
            finally
            {
                if (pageOutStream != null)
                    pageOutStream.Dispose();
            }
        }

        /// <summary>
        /// Checks to see if the file exists
        /// </summary>
        /// <param name="namer"></param>
        /// <returns></returns>
        private static bool AlreadyDone(FileNamer namer)
        {
            return File.Exists(namer.FileName);
        }

    }
}
Advertisements

, , , , , , , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: