1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8/*
9Compile with:
10
11    "...../csc" \
12        /lib:"....." \
13        /reference:"ReachFramework.dll" \
14        /reference:"WindowsBase.dll" \
15        /reference:"PresentationCore.dll" \
16        /reference:"PresentationFramework.dll" \
17        xps_to_png.cs
18
19*/
20// logic inspired by this example: https://goo.gl/nCxrjQ
21class Program {
22    static int ceil(double x) { return (int)System.Math.Ceiling(x); }
23    static void convert(double dpi, string path, string out_path) {
24        double scale = dpi / 96.0;
25        System.Windows.Xps.Packaging.XpsDocument xpsDoc =
26                new System.Windows.Xps.Packaging.XpsDocument(
27                        path, System.IO.FileAccess.Read);
28        if (xpsDoc == null) {
29            throw new System.Exception("XpsDocumentfailed");
30        }
31        System.Windows.Documents.FixedDocumentSequence docSeq =
32                xpsDoc.GetFixedDocumentSequence();
33        if (docSeq == null) {
34            throw new System.Exception("GetFixedDocumentSequence failed");
35        }
36        System.Windows.Documents.DocumentReferenceCollection drc = docSeq.References;
37        int index = 0;
38        foreach (System.Windows.Documents.DocumentReference dr in drc) {
39            System.Windows.Documents.FixedDocument dp = dr.GetDocument(false);
40            foreach (System.Windows.Documents.PageContent pc in dp.Pages) {
41                System.Windows.Documents.FixedPage fixedPage = pc.GetPageRoot(false);
42                double width = fixedPage.Width;
43                double height = fixedPage.Height;
44                System.Windows.Size sz = new System.Windows.Size(width, height);
45                fixedPage.Measure(sz);
46                fixedPage.Arrange(
47                        new System.Windows.Rect(new System.Windows.Point(), sz));
48                fixedPage.UpdateLayout();
49                System.Windows.Media.Imaging.BitmapImage bitmap =
50                        new System.Windows.Media.Imaging.BitmapImage();
51                System.Windows.Media.Imaging.RenderTargetBitmap renderTarget =
52                        new System.Windows.Media.Imaging.RenderTargetBitmap(
53                            ceil(scale * width), ceil(scale * height), dpi, dpi,
54                            System.Windows.Media.PixelFormats.Default);
55                renderTarget.Render(fixedPage);
56                System.Windows.Media.Imaging.BitmapEncoder encoder =
57                    new System.Windows.Media.Imaging.PngBitmapEncoder();
58                encoder.Frames.Add(
59                        System.Windows.Media.Imaging.BitmapFrame.Create(renderTarget));
60                string filename = string.Format("{0}_{1}.png", out_path, index);
61                System.IO.FileStream pageOutStream = new System.IO.FileStream(
62                    filename, System.IO.FileMode.Create, System.IO.FileAccess.Write);
63                encoder.Save(pageOutStream);
64                pageOutStream.Close();
65                System.Console.WriteLine(filename);
66                ++index;
67            }
68        }
69    }
70    // Executes convert, catching thrown exceptions, and printing them
71    // to stdout, and exiting immediately.
72    static void try_convert(double dpi, string path, string out_path) {
73        try {
74            convert(dpi, path, out_path);
75        } catch (System.Exception e) {
76            System.Console.WriteLine(e);
77            System.Environment.Exit(1);
78        }
79    }
80    // For each command line argument, convert xps to sequence of pngs.
81    static void Main(string[] args) {
82        double dpi = 72.0;
83        if (args.Length == 0) {
84            System.Console.WriteLine("usage:\n\txps_to_png [-dDPI] [XPS_FILES]\n\n");
85            System.Environment.Exit(1);
86        }
87        System.Collections.Generic.List<string> xpsFiles =
88                new System.Collections.Generic.List<string>();
89        foreach (string arg in args) {
90            string flag = "-d";
91            if (arg.StartsWith(flag)) {
92                dpi = System.Convert.ToDouble(arg.Remove(0, flag.Length));
93            } else if (System.IO.File.Exists(arg)) {
94                xpsFiles.Add(arg);
95            } else {
96                System.Console.WriteLine("file missing: '" + arg + "'\n\n");
97                System.Environment.Exit(1);
98            }
99        }
100        foreach (string file in xpsFiles) {
101            System.Threading.Thread t = new System.Threading.Thread(
102                    () => try_convert(dpi, file, file));
103            t.SetApartmentState(System.Threading.ApartmentState.STA);
104            t.Start();
105        }
106    }
107}
108