VisualBrush Resources not included in Visual in XP

2019-08-04 09:25发布

UPDATE: We replaced the Image generation with an alternative that solves the issue (PDF to image) but I am going to leave this question open as I would like to understand if this is possible.

On our website at http://www.cloudformatter.com, we were attempting to implement some code for processing our generated XPS files to image. Most all works well except for SVGs in the page which are included into the XPS document through VisualBrush resources.

We took inspriation from the code here and some others around the web XPS to image

Below is code for our converter which is building a package of page images for a REST response through that website. The XPS is fine and most all pages work as expected for image, so the code works currently for everything except SVG in pages. I should note that the same code the generates the XPS for download generates the stream fed into the code below so it is not broken going in. Even examining the Visual in debug shows the existence of the VisualBrush objects.

This page is perfect (no SVG images) [click "embed PNG" and "download XPS" options and they are correct.

http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage

But this page has SVG:

http://www.cloudformatter.com/CSS2Pdf.SVGCharts.HighCharts

The download XPS is perfect. But getting the PNG with the below code results in the SVGs being lost. Note again: The system implemented on the backend currently does not use the code below as we found a working solution for PDF to image. However, we would like to solve the XPS to image issue we are having. The XPS has this:

<Path>
            <Path.Fill>
                <VisualBrush Visual="{StaticResource svg0}" Viewbox="0,0,432.0,222.0"
                    Viewport="0,0,432.0,222.0" ViewportUnits="Absolute" ViewboxUnits="Absolute"
                />
            </Path.Fill>
            <Path.Data>
                <PathGeometry>
                    <PathFigure IsClosed="true" StartPoint="0,0">
                        <PolyLineSegment Points="0,0 432.0,0 432.0,222.0 0,222.0"/>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>

And the resource has this:

 ResourceDictionary xmlns="http://schemas.microsoft.com/xps/2005/06"
xmlns:x="http://schemas.microsoft.com/xps/2005/06/resourcedictionary-key">
<Canvas RenderTransform="1,0,0,1,0,0" x:Key="svg0">
    <Canvas RenderTransform="1.0,0.0,0.0,-1.0,0.0,222.0">
        <Canvas.Clip>
            <PathGeometry Figures="M 0.0,0.0 L 0.0,222.0 L 432.0,222.0 L 432.0,0.0 L 0.0,0.0 z "
            />
        </Canvas.Clip>
        <Path Fill="#ffffff" Data="M 0.0,0.0 L 0.0,222.0 L 432.0,222.0 L 432.0,0.0 L 0.0,0.0 z "/> 
 <!--snipped-->

The code is below. Is it just not possible to get the Visual of the Page this way?

private static List<byte[]> XPStoIMG(Stream xpsStream)
    {
        xpsStream.Seek(0, SeekOrigin.Begin);

        List<byte[]> pages = new List<byte[]>();

        MemoryStream imgStream = new MemoryStream();
        var mt = new MultiThreader("single_thread", true);
        mt.Run(delegate()
        {
            using (Package package = Package.Open(xpsStream))
            {
                string inMemoryPackageName = "memorystream://myXps.xps";
                Uri packageUri = new Uri(inMemoryPackageName);
                PackageStore.AddPackage(packageUri, package);
                XpsDocument xpsDoc = new XpsDocument(package, CompressionOption.Maximum, inMemoryPackageName);

                FixedDocumentSequence seq = xpsDoc.GetFixedDocumentSequence();
                DocumentPaginator paginator = seq.DocumentPaginator;
                for (int page = 0; page < paginator.PageCount; page++)
                {
                    DocumentPage docPage = paginator.GetPage(page);
                    RenderTargetBitmap bmp = new RenderTargetBitmap((int)docPage.Size.Width * 120 / 96, (int)docPage.Size.Height * 120 / 96, 120d, 120d, PixelFormats.Default);
                    bmp.Render(docPage.Visual);
                    PngBitmapEncoder png = new PngBitmapEncoder();
                    png.Frames.Add(BitmapFrame.Create(bmp));
                    MemoryStream pstream = new MemoryStream();
                    png.Save(pstream);
                    pstream.Flush();
                    pstream.Seek(0, SeekOrigin.Begin);
                    byte[] parr = new byte[pstream.Length];
                    pstream.Read(parr, 0, Convert.ToInt32(pstream.Length));
                    pages.Add(parr);
                }
                PackageStore.RemovePackage(packageUri);
                xpsDoc.Close();
            }
        }, System.Threading.ApartmentState.STA);
        mt.Start();
        mt.CurrentThread.Join();
        return pages;
    }

1条回答
贼婆χ
2楼-- · 2019-08-04 10:19

Partly. When you got your FixedDocumentSequence, you can go on like this:

foreach (PageContent content in xps.GetFixedDocumentSequence().References.First().GetDocument(true).Pages) {
  FixedPage page = content.GetPageRoot(true);
  foreach (UIElement element in page.Children) {
    //... do what you want
  }
}

The what you want part might be, for instance, to create a DrawingVisual for the page, RenderOpen() it to get a DrawingContext and rendering the individual elements to that context. When finished, you can render the whole collected visual to a RenderTargetBitmap all right.

查看更多
登录 后发表回答