WPF Печать большого отчета вызывает исключение OutOfMemoryException - PullRequest
1 голос
/ 30 января 2012

Я создал отчет FixedDocument, который будет печататься ежемесячно. Это будет в среднем около 350 страниц в длину, причем около половины страниц составляют ~ 200 КБ изображений в формате JPEG. Отчет красиво отображается в DocumentViewer, но при попытке его печати возникают проблемы.

При использовании

DocumentViewer1.Print()

Если я просто попытаюсь распечатать данные за первую треть месяцев, например. 120 страниц, работает нормально. Но если я пробую весь месяц, примерно на 160-й странице я получаю следующую ошибку

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()

Тогда я решил перехитрить его, просто печатая 30 страниц за раз, разбивая документ на небольшие 30-страничные документы, используя:

    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

Но это вызвало точно такую ​​же ошибку. Я попытался напечатать сто страниц с середины и ближе к концу месяца, и это работает, поэтому это должен быть объем страниц, а не отдельное изображение (изображения представляют собой просто JPEG-файлы из одного источника, максимальный размер 400 КБ).

Просмотр количества используемой памяти при печати 30 страниц за раз.

    Start = 96Mb
    30 pages = 367Mb
    60 pages = 588Mb
    90 pages = 825Mb
    120 pages = 1003Mb
    150 pages = 1238Mb

затем вылетает при следующей партии на 1281Mb

Я тестировал на реальном принтере и принтере XPS для Windows. Когда я записал эти значения в память, я подождал, пока каждый раздел не будет полностью помещен в буфер и напечатан.

Я не могу понять, почему это так складывается, когда я делю их на отдельные отдельные документы. Я должен что-то распоряжаться, но я не уверен, что?

1 Ответ

0 голосов
/ 07 августа 2013

Вы должны сгенерировать 10 страниц на файл (FixedDocument на файл), затем объединить эти файлы в один (у вас будет FixedDocumentSequence). Далее вы печатаете на этом FixedDocumentSequence. Я уверен, что это решение не потребляет много памяти.

System.Windows.Xps.XpsDocumentWriter.Write (System.Windows.Documents.FixedDocumentSequence fixedDocumentSequence)

...