A number of ideas, some are a bit convoluted...
Print to XPS then extract Bitmap
You could print the Visual
to an XPS Document.
If you're lucky then it will combine the 1bit images that you drew in in the DrawingContext
and produce a single bitmap in the XPS file.
For the Rectangles it might keep the Rectangles as vector based information in the XPS (the "Shape" based Rectangle
or DrawingContext
DrawRectangle
might both do this)....if that happens then create a bitmap into which your draw the rectangle part and draw that bitmap into the context.
Once you have the XPS files, you could then parse it and extract the "image" if you are lucky that's what it produced inside. (XPS is just a ZIP file that uses XAML to describe content and uses subdirectories to store bitmap image data files, fonts, etc).
(I think you can use the Package
class to access the raw parts of an XPS document, or XpsDocument
for a higher level interpretation).
Or just display the XPS in an XPS viewer if your intention is just to provide a way to allow your combined 1bit images to be viewed in a different context.
Use a Printer Driver that provides Print to Image functionality
This isn't ideal...not least because you have to install a Printer Driver on the machine.....but you might be able to use a "Print to Image" printer driver and then use that to produce your bitmap. Here are some suggestions:
Create a GDI+ HBITMAP and do the drawing using GDI+ calls...then wrap it for use by WPF...or save out to disk.
[1] First create a GDI+ Bitmap large enough to hold your composed rendering
(there are a few different ways to do this...one way is to use a WriteableBitmap to provide the backbuffer bits/store...that's if you wanted access to the bits in memory...in your case I don't think you do/need to).
var bmp = new System.Drawing.Bitmap( pixelwidth, pixelheight, System.Drawing.Imaging.Format1bppIndexed );
Or this way if you want WriteableBitmap access.
[2] Convert any WPF BitmapSources to GDI+ Bitmaps so you can draw them onto the GDI+ Graphics context using DrawImage.
You can use CopyPixels to do that on your BitmapSources.
For your rectangles you can just use the GDI+ DrawRectangle rendering command.
[3] Save the GDI+ Bitmap to disk
Use the .Save method on System.Image.Bitmap to save it as a Bitmap.
[4] Use the saved image as the Source to an Image element
(note this will probably use masses of memory when it loads your image even though it's 1bpp...because the WPF rendering path is all 32bpp).
[4] OR wrap the GDI+ Bitmap for use in WPF
You can use InteropBitmap to wrap the GDI+ based bitmap so you can use it as a BitmapSource in WPF. (note it may have to be a 32bpp one....if it has to...then you are back at square 1...but try anyway).
Create a Bitmap "Service"
Create another process which acts as a service (doesn't have to be an NT service...could just be a child process you start) to render your combined 1bpp images....there are various ways to communicate with it to give it the rendering commands.
When memory consumption gets too high/the LOH gets fragmented, then you could restart this service.
Other Ideas
You could render using OpenGL (e.g. use OpenTK or SharpGL), or render using DirectX...via the 3D path with D3DImage or Direct2D (whether this behaves the same as RenderTargetBitmap in terms of memory usage...that's to find out).
Try out NET 4.5 as there have been a number of improvements in the LOH Heap: