Is there a lightweight way to include GDI rendered content when printing with WPF? - wpf

One of the projects I work on has some pre-existing reports that are printed via MFC's printing support and rendered more or less directly to a printer DC via GDI. We've started doing some new (unrelated) reports via WPF/XAML since we're transitioning new UI to WPF anyway and it's so much better to work with for layout.
The other shoe has finally dropped, and I've got the need to add some new functionality to an existing printed report, and the new functionality practically begs to be implemented with WPF. Our existing WPF reports are implemented via XAML pages sent to an XpsDocument (in-memory, not on disk) via XpsDocumentWriter. I would like to be able to continue to use this strategy, and take the approach of writing WPF/XAML reports that happen to have some pages rendered via GDI.
My first naive attempt was to embed an HwndHost in the UIElement that gets rendered in the XpsDocumentWriter, but that doesn't seem to work. No surprise but it was worth a try.
The next obvious solution, IMO, would be to render the GDI graphics to an appropriate sized and scaled bitmap, and render that bitmap to a page in the XpsDocument. That would work, but page-sized bitmaps (especially in-memory ones) seem like a recipe for high memory usage and poor performance on slower computers.
Ideally I'd like to render the GDI content to a metafile or some other vector format that could then be translated to XPS. But this has to be an automatic process that works every time since it's just a document printing feature. OTOH it's an application for in-house users so we can put up with some performance degredation
WPF development is not my main task, so I'd describe myself as a novice without much detailed knowledge of the underlying details. I just wanted to make sure I'm not missing something obvious before I revert to using a bitmap as the transfer medium, although I haven't turned up any other decent options in my search so far.
Anything I should be looking into?

One way of doing this would be to create a WriteableBitmap in WPF and blit the GDI drawn image directly to it so it can be rendered in your XPS document. An initial step could be to do a straight blit from your GDI DC (get a pointer to GDI DC, pointer to WriteableBitmap and use Platform Invoke to call memcpy). Later work could involve converting the MFC GDI drawing to vanilla WPF (using a library such as WriteableBitmapEx which has gdi like drawing methods).
Although the first approach above would involve two bitmaps, its the best way I can currently think of without a huge re-write. The second method may or may not be possible out of the box, since WriteableBitmaps's drawing support is not as extended as GDI. A final method I just thought of would be to use GDI via Platform Invoke and draw directly on the WriteableBitmap surface. This would allow a port without a massive re-write and would give you the performance you need, while keeping the code familiar.

Related

Exporting an image struct from native code to managed

I have a native codebase that creates an image every 50 ms. I want to use WPF to render this image into a WPF GUI view.
The image is an hbitmap constructed from a data structure of type boost::numeric::ublas::matrix. i.e. I start with a matrix of float values, then I create a HBITMAP, and then draw this HBITMAP using the device context of MFC. But now, I want to replace my MFC GUI with a WPF GUI, because it looks nicer. I plan to use C++/CLI to achieve the interop.
My question is as follows : How should I setup the transfer of my image across the interop boundary?
Should I transfer it over while it is still a structure of floats, or shall I transfer after I created the bitmap? I have heard marshaling is a big drain on efficiency, and so must be handled very carefully. Is there a type that is common to managed and native world, that can be used for this?
I am a complete newbie to interoping, any other related resources you share will be greatly appreciated.
Or, is there a way to completely avoid the transfer? - by drawing from native code into a WPF GUI view
My application is very performance sensitive, any alternative you suggest that achieves good performance will be greatly appreciated.
I've been through the same options and found that - at least for .NET 4.5 - the InteropBitmap is the best way to go, as long as your image stays the same size (e.g. for something like video streaming).
In brief, you create a memory mapped file (either in using C++/CLI or C# with p/invoke), and use that as the source of pixel data. The InteropBitmap is created over that same memory mapped file, and you can use it as an ImageSource in WPF.
In my application, a background thread updates the MMF and invalidates the InteropBitmap and the WPF front end just binds to the image source as normal.

When using a DirectX-based API with WPF (i.e. SlimDX, SharpDX, etc.) can you do sub-window-sized controls?

In our WPF application, we have a need to display about 64 real-time level meters for an audio application. The tests we've thrown at WPF, even when rendering basic primitives as efficiently as we can still show it to be nowhere near where our application needs to be, often times bogging down the main thread so much to the point that it's non-responsive to input.
As such, we have to go with something more optimized for graphics performance such as DirectX (via SlimDX or SharpDX) or OpenGL/ES (via Atlas which converts it to DirectX calls.)
My question is if it's possible to create multiple, small DirectX-based areas, each representing an individual meter, or for that matter, is that even the right approach? I was under the understanding that you have to run it as at a minimum, the entire window, not a portion thereof.
The issues I see with the latter are airspace issues wherein you can't have WPF content in front of DirectX content in the same window, and we really don't want to have to redo all of our controls in DirectX since for the other non-meter 95% of our UI WPF is great!
I have read that you can render DirectX to a brush, then use that inside WPF, or using the WriteableBitmap class which gives you direct access to the buffers WPF then uses in its Render thread, both of which don't seem to suffer from the Airspace issues, but that seems we'd be right back at the same place with WPF being the bottleneck since it still has to do the rendering.
We are of course going to dedicate a few weeks to sample applications testing all of the above, but I'm wondering if I'm even headed in the right direction, and/or if there are any caveats we can avoid by talking to people with experience doing something like this to avoid common pitfalls, etc. As such, any comments will be appreciated.
I'm hoping we can perhaps even start a wiki somewhere to discuss this topic as it seems to be a popular one, albeit spread all over the place making it hard for new entrants to get the information they seek.
With wpf / d3d interop, You should always try to create the smallest number of interop calls. So you should prefer rendering all 64 level meters in a single render target (also it allows you to batch your primitive rendering and draw everything in the smallest number of gpu calls).
you should try to use the D3DImage API that allows you to share your own D3D texture with the wpf renderer.
If WPF can't really handle these 64 moving bars, you could go with a single D3DImage and use Direct3D9 for rendering all bars at once directly to it. For your specific scenario, you shouldn't have any performance problem.

WPF-DirectX Interop Problem (D3DImage)

I'm writing a Video application utilizing D3DImage. Frames are from memory and rendered as textures in native code with DirectX9, finally exposed by D3DImage to the WPF GUI. I have some Overlays on top, created with WPF's painting framework (Text, shapes etc.). Up to this point, it works like a charm.
Now, I would like encode the composited image from my underlying native C++ code. Video is 640x480 BGR, 25 FPS and has to be rendered and encoded in parallel, also on older Hardware with Windows versions down to XP/SP3.
Problem is, I cannot find any documentation describing the composition process between WPF and D3DImage. They 'blend' in some sense, but what is the meaning of this? And is it possible to get a handle to the WPF's part of the drawing or even the composited image in my native C++ code?
p.s: I'm also open to managed solutions, but didn't found much performant up to now.
There is global static method called "CompositionTarget.Rendering". Add an event to that and every time WPF renders that method will be called before WPF presents(the FPS can vary though). So just updated your renderTarget accordingly.
There might be a better way, but i'm not aware of it.
NOTE:: Also for D3DImage on WindowsXP you use a D3D9 device with a lockable renderTarget while on Vista/7 you use a D3D9Ex device with a non-lockable renderTarget. Just a note.

WPF Architecture and Direct3D graphics acceleration

After reading the wikipedia article on WPF architecture, I am a bit confused with the benefits that WPF will offer me. (wikipedia is not a good research reference, but i found it useful). I have some questions
1) WPF uses d3d surfaces to render. However, the scenegraph is rendered into the d3d surface by the media integrated layer, which runs on the CPU. Is this true ?
2) I just found out by asking a question here that bitmaps dont use native resources. Does this mean that if i use alot of images, the MIL will copy each when rendering, rather than storing the bitmaps on the video card as a texture ?
3) The article mentions that WPF uses the painters algorithm which is back to front. Thats painfully slow. Is there any rational why WPF omits using Z-buffering and rendering front to back ? I am guessing its because the simplest way to handle transparency, but it seems weak.
The reason i ask is that i am thinking it wont be wise for me to put hundreds of buttons on a screen even though my colleagues are saying its directx accelerated. I dont quite believe that whole directx accelerated bit about WPF. I used to work on video games and my memory of writing d3d and opengl code tells me to be cautious.
For questions #1 and #3 you might want to check out this section of the SDK that discusses the Visual class and how it's rendering instructions are exchanged between the higher level framework and the media integration layer (MIL). It also discusses why the painters algorithm is used.
For #2, no that is most definitely not the case. The bitmap data will be moved to the hardware and cached there.
I tested that, I wrote two programs that show 1,000 buttons on screen, one in WinForms and one in WPF, both worked just fine.
I then pushed that up to 10,000 buttons, at that point the WPF app took a few seconds to start but run just fine, the WinForms app didn't start.
Win32 itself (and WinForms) isn't built for applications with hundreds of controls (believe me I wrote such an app), at some point it just stops working, WPF on the other hand, keeps working even if it slows down a bit at some point.
So, if you do need to put a lot of controls on screen WPF is your best bet (unless you want to roll your own UI framework - and you think you can do better than the entire MS perf team).
Also, WPF has many advantages other than graphics acceleration: richer graphics, drawing model that is easier to work with, animations, 3d and my personal favorite - amazing data-binding.
This will let you develop richer UIs faster - and I think that will make a much bigger difference than the painting algorithm used.
BTW, if you need to put hundreds of buttons on the screen this is likely to be a bad user experience and you may want to reconsider your UI design,

Where to learn proper way to use Silverlight (or WPF)

Approaching Silverlight development is a rather daunting task as it seems to require a rather different mindset to work I have done in the past.
I have been working on it for several months and we have already released an application that presents form-based pages. So I have the basics of XAML for layout but what I need to do now is move into graphically representing data. For example transform a list of objects representing vehicle speed recordings into a line graph of speed. I am at a loss on what the best way is to approach this.
Can anyone point me to articles or tutorials that present this kind of thing?
Your first port of call for Silverlight learning should be the official site http://silverlight.net/Learn/
If you want to do any data visualization/charting then first try the Silverlight Toolkit on codeplex. It's fantastic if you want to get anything up and running quickly.
Also check out Delay's Blog on charting and the chartbuilder code
Bang your head against it for 3-6 months. That's how I did it and it's worked out pretty well so far.
But seriously, the learning curve sucks.
There's charting libraries for Silverlight out there, you could grab one of those but I wouldn't waste money on it. It's relatively easy to write this kind of code yourself.
All you really need is a DrawingVisual. Once you have that you can render what you need on to it's surface. The trick is to make sure that you have sufficient layout information when you render. Because this is vector graphics, you can use the ScaleTransform to match your content bounds instead of repainting on size changed. Other than that, you'll wanna host your DrawingVisual in a UIFrameworkElement and let the dimension of that object govern where and how you draw your data. This will give you all the layout goodness of WPF/Silverlight.
For drawing there are plenty of Geometry classes you can rely on but there's one thing that you'll wanna do and that's to adjust the level of detail in your data points with respect to your drawing. This is the number one trick to make sure you don't hog the CPU.
Avoid drawing more than one data point per pixel. If you have a lot of data points, and a small drawing surface you can use a rolling average to smooth the result.
If you approach this with the above things in mind you should be able to write a flexible graph UI element that you can visualize data with, in no time at all.
I did this in a WPF application, I'm pretty much assuming that you can do the exact same thing with Silverlight 2.0, you'll just yell at me if you cant?

Resources