I've created a FixedDocument report to be printed monthly. It will average about 350 pages in length with about half the pages being ~200kb jpeg images. The report displays nicely in the DocumentViewer, but I hit problems when attempting to print it.
When using
DocumentViewer1.Print()
If I just try and print the first third of the months data eg. 120 pages, it works fine. But if I try the whole month, at about the 160th Page I get the following error
System.OutOfMemoryException: Insufficient memory to continue the execution
of the program.
at System.Windows.Media.Imaging.BitmapSource.CriticalCopyPixels(Int32Rect
sourceRect, IntPtr buffer, Int32 bufferSize, Int32 stride)
at System.Windows.Media.Imaging.BitmapSource.CriticalCopyPixels(Int32Rect
sourceRect, Array pixels, Int32 stride, Int32 offset)
at Microsoft.Internal.GDIExporter.CGDIBitmap.Load(BitmapSource pBitmap,
Byte[] buffer, PixelFormat LoadFormat)
at
Microsoft.Internal.GDIExporter.CGDIRenderTarget.DrawBitmap(BitmapSource
pImage, Byte[] buffer, Rect rectDest)
at Microsoft.Internal.GDIExporter.CGDIRenderTarget.DrawImage(BitmapSource
source, Byte[] buffer, Rect rect)
at
Microsoft.Internal.AlphaFlattener.BrushProxyDecomposer.Microsoft.Internal.Al
phaFlattener.IProxyDrawingContext.DrawImage(ImageProxy image, Rect dest,
Geometry clip, Matrix trans)
at
Microsoft.Internal.AlphaFlattener.PrimitiveRenderer.RenderImage(ImageProxy
image, Rect dest, Geometry bounds, Boolean clipToBounds, Int32 start, Matrix
trans, String desp)
at
Microsoft.Internal.AlphaFlattener.PrimitiveRenderer.RenderImage(ImageProxy
image, Rect dest, Geometry clip, Matrix trans, String desp)
at Microsoft.Internal.AlphaFlattener.Flattener.AlphaRender(Primitive
primitive, List`1 overlapping, Int32 overlapHasTransparency, Boolean
disjoint, String desp)
at
Microsoft.Internal.AlphaFlattener.Flattener.AlphaFlatten(IProxyDrawingContex
t dc, Boolean disjoint)
at Microsoft.Internal.AlphaFlattener.Flattener.Convert(Primitive tree,
ILegacyDevice dc, Double width, Double height, Double dpix, Double dpiy,
Nullable`1 quality)
at Microsoft.Internal.AlphaFlattener.MetroDevice0.FlushPage(ILegacyDevice
sink, Double width, Double height, Nullable`1 outputQuality)
at Microsoft.Internal.AlphaFlattener.MetroToGdiConverter.FlushPage()
at
System.Windows.Xps.Serialization.NgcSerializationManagerAsync.EndPage()
at
System.Windows.Xps.Serialization.NgcFixedPageSerializerAsync.EndPersistObjec
tData(Boolean isManualStartDoc)
at
System.Windows.Xps.Serialization.NgcFixedPageSerializerAsync.AsyncOperation(
NGCSerializerContext context)
at
System.Windows.Xps.Serialization.NgcSerializationManagerAsync.InvokeSaveAsXa
mlWorkItem(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object
source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at
System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object
state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedClea
nup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32
msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam,
IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object
source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority
priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr
wParam, IntPtr lParam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.Unsaf
eNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,
Int32 reason, Int32 pvLoopData)
at
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun(
)
at
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoAppl
icationModel()
I then thought I'd outsmart it by just printing 30 pages at a time by splitting the document into small 30 page documents using:
Dim dlg = New PrintDialog()
If dlg.ShowDialog() = True Then
Dim PageCounter As Int32 = 0
Dim ListOfDocs As New List(Of FixedDocument)
Dim CurrentFixedDoc As New FixedDocument
For Each FixedSizePag As FixedPage In PrintListOfPages
Dim FixedSizedPageConten As PageContent = New PageContent
CType(FixedSizedPageConten, IAddChild).AddChild(FixedSizePag)
CurrentFixedDoc.Pages.Add(FixedSizedPageConten)
PageCounter = PageCounter + 1
If PageCounter >= 30 Then
ListOfDocs.Add(CurrentFixedDoc)
PageCounter = 0
CurrentFixedDoc = New FixedDocument
End If
Next
If CurrentFixedDoc.Pages.Count > 0 Then
ListOfDocs.Add(CurrentFixedDoc)
End If
For Each docum In ListOfDocs
dlg.PrintDocument(docum.DocumentPaginator, "Testing - Part " & (ListOfDocs.IndexOf(docum) + 1) & " of " & ListOfDocs.Count)
Next
End If
But that just caused exactly the same error. I've tried printing a hundred pages from the midpoint and towards the end of month and that works, so it must be the volume of pages rather than a particular image(images are just jpegs all from one source, max size 400kb).
Watching the amount of memory being used while printing 30 pages at a time I see
Start = 96Mb
30 pages = 367Mb
60 pages = 588Mb
90 pages = 825Mb
120 pages = 1003Mb
150 pages = 1238Mb
then crashes on the next batch at 1281Mb
I've tested on a real printer and the XPS windows printer. When I noted down those memory values, I waited until each section had completely spooled and printed.
I can't understand why its just building up like this when I'm splitting them into separate individual documents. I must have to dispose something but I'm not sure what?
You should generate 10 pages per file (a FixedDocument per file), then you merge these files into one (you will have a FixedDocumentSequence). Next you print on this FixedDocumentSequence. I am sure that this solution consumes no much memory.
System.Windows.Xps.XpsDocumentWriter.Write(System.Windows.Documents.FixedDocumentSequence fixedDocumentSequence)