Finally, I realized that there is an option that concerns my general requirement to embed a vector format in a print job, but it does not work with GDI-based printing.
The XPS file format created by the Microsoft XPS Writer print driver can be printed from WPF using the ReachFramework.dll file included with .NET. Using WPF for printing instead of GDI, you can embed an XPS document page in a larger print document. A.
The disadvantage is that working with WPF works quite a bit, so all the support code that directly uses the material in the Sytem.Drawing namespace needs to be rewritten.
Here are the basic ways to implement an XPS document:
Open the document:
XpsDocument xpsDoc = new XpsDocument(filename, System.IO.FileAccess.Read); var document = xpsDoc.GetFixedDocumentSequence().DocumentPaginator; // pass the document into a custom DocumentPaginator that will decide // what order to print the pages: var mypaginator = new myDocumentPaginator(new DocumentPaginator[] { document }); // pass the paginator into PrintDialog.PrintDocument() to do the actual printing: new PrintDialog().PrintDocument(mypaginator, "printjobname");
Then create a descendant of DocumentPaginator that will do your actual print. Override abstract methods, in particular GetPage should return DocumentPages in the correct order. Here's my proof of concept code demonstrating how to add custom content to your Xps docs list:
public override DocumentPage GetPage(int pageNumber) { for (int i = 0; i < children.Count; i++) { if (pageNumber >= pageCounts[i]) pageNumber -= pageCounts[i]; else return FixFixedPage(children[i].GetPage(pageNumber)); } if (pageNumber < PageCount) { DrawingVisual dv = new DrawingVisual(); var dc = dv.Drawing.Append(); dc = dv.RenderOpen(); DoRender(pageNumber, dc);
When you try to print in another XPS document, it gives the exception "FixedPage cannot contain another FixedPage", and the H. Alipurian message shows how to fix it: http://social.msdn.microsoft.com/Forums/da/wpf/thread/ 841e804b-9130-4476-8709-0d2854c11582
private DocumentPage FixFixedPage(DocumentPage page) { if (!(page.Visual is FixedPage)) return page; // Create a new ContainerVisual as a new parent for page children var cv = new ContainerVisual(); foreach (var child in ((FixedPage)page.Visual).Children) { // Make a shallow clone of the child using reflection var childClone = (UIElement)child.GetType().GetMethod( "MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic ).Invoke(child, null); // Setting the parent of the cloned child to the created ContainerVisual // by using Reflection. // WARNING: If we use Add and Remove methods on the FixedPage.Children, // for some reason it will throw an exception concerning event handlers // after the printing job has finished. var parentField = childClone.GetType().GetField( "_parent", BindingFlags.Instance | BindingFlags.NonPublic); if (parentField != null) { parentField.SetValue(childClone, null); cv.Children.Add(childClone); } } return new DocumentPage(cv, page.Size, page.BleedBox, page.ContentBox); }
Sorry this is not entirely compiling code, I just wanted to provide an overview of the code fragments needed to get it working, to give other people the opportunity to start all the disparate pieces that need to come together to make it work. Trying to create a more generalized solution will be much more complicated than the scope of this answer.