xceedsoftware / wpftoolkit

All the controls missing in WPF. Over 1 million downloads.
Other
3.87k stars 871 forks source link

RichTextBox crashes with OutOfMemoryException when pasting in large image #1058

Open xceedsoftware opened 7 years ago

xceedsoftware commented 7 years ago

skybluecodeflier[CodePlex]
I tried pasting in a 4500x3250 image into the RichTextBox, and it crashes. The RichTextBox declared as follows:

lttoolkit:RichTextBox x:Name=quotrichTextBoxquot Grid.Row=quot1quot Grid.ColumnSpan=quot2quot Margin=quot10quot MaxHeight=quot345quot ScrollViewer.VerticalScrollBarVisibility=quotAutoquot Text=quot{Binding CurrentlySelectedNotePage.TextInRTF}quotgt lttoolkit:RichTextBoxFormatBarManager.FormatBargt lttoolkit:RichTextBoxFormatBar /gt lt/toolkit:RichTextBoxFormatBarManager.FormatBargt lt/toolkit:RichTextBoxgt If I try to paste the same image into a standard System.Windows.Controls.RichTextBox, the paste is successful.

And if it isn't possible to paste larger images into the WPF Toolkit RichTextBox, then maybe there should be a more elegant way of handling this?

xceedsoftware commented 7 years ago

BoucherS[CodePlex]
Hi,

The RichTextBox from the Toolkit formats the Text (RTF, XAML or PlainText) and in this case (RTF), the formatting causes the OutOfMemory exception. The problem is in file Xceed.Wpf.Toolkit/RichTextBox/Formatters/RtfFormatter.cs, in method GetText( FlowDocument document ). A MemoryStream is created and a TextRange tries to saves its data in this MemoryStream, in RtfFormat. There is enough memory : -when using a build in x64 -when using small images -when using XamlFormat and PlainTextFormat

But you fall in a specific case (x86, large image, RtfFormat) where there is not enough memory to proceed the action. This method can always return an empty string and it will work, but the Text property will not be formatted in RTF.

The standard RichTextBox doesn't format the Text.

You can always try another formatting, or try to reduce the image size before adding it to the Toolkit's RichTextBox.

xceedsoftware commented 7 years ago

skybluecodeflier[CodePlex]
It looks like you had more to say that you didn't finish?

In my case, there is no way for me to set the application to x64- we have to support x86 at this point. Surely there is some elegant way of handling this?

xceedsoftware commented 7 years ago

BoucherS[CodePlex]
Hi,

When pasting in the Toolkit's RichTextBox, the Toolkit's RtfFormatter will create a new MemoryStream to save the pasted data. In your case, you are using a pretty big image.

Make sure to set the platform's target of your application to x64, in Project properties, in tab Build.

For an image that big,

xceedsoftware commented 7 years ago

skybluecodeflier[CodePlex]
I still get a crash, whether or not I have the Text property set. And besides, what would be the point of removing the Text property? I need that binding. I have added the crash trace below- the crash occurs because of the WPF toolkit code, related to the Text property.

I am using v.2.9, .Net 4.0 version.

To clarify, the copied image must be in bitmap form. That is, if you add the following eventhandler to the rich text box:

DataObject.Pasting=RichTextBox1_Pasting

And have the following handler (which is somewhat : private void RichTextBox1_Pasting(object sender, DataObjectPastingEventArgs e) { MessageBox.Show(e.FormatToApply); } Then it will display Bitmap in the message box when you try to paste into the rich text box.

What I did to create such an image (other than via some proprietary code in my application), is to download this image from online at full resolution:

http://www.wallpaperup.com/201488/galaxy_stars_ht.html

Then I opened the image in Gimp. Then I chose Select All, and then Edit Copy. This properly copied the file in bitmap format. Then I pasted it into the RichTextBox. It takes a while, then crashes with the following trace:

Exception of type 'System.OutOfMemoryException' was thrown.: at System.IO.MemoryStream.set_Capacity(Int32 value) at System.IO.MemoryStream.EnsureCapacity(Int32 value) at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) at MS.Internal.IO.Packaging.PackagingUtilities.CopyStream(Stream sourceStream, Stream targetStream, Int64 bytesToCopy, Int32 bufferSize) at MS.Internal.IO.Packaging.SparseMemoryStream.WriteToStream(Stream stream) at MS.Internal.IO.Zip.ZipIOFileItemStream.Save() at MS.Internal.IO.Zip.ZipIOLocalFileBlock.Save() at MS.Internal.IO.Zip.ZipIOBlockManager.SaveContainer(Boolean closingFlag) at MS.Internal.IO.Zip.ZipIOBlockManager.SaveStream(ZipIOLocalFileBlock blockRequestingFlush, Boolean closingFlag) at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Dispose(Boolean disposing) at System.IO.Stream.Close() at System.IO.Packaging.PackagePart.Close() at System.IO.Packaging.Package.DoClose(PackagePart p) at System.IO.Packaging.Package.DoOperationOnEachPart(PartOperation operation) at System.IO.Packaging.Package.System.IDisposable.Dispose() at System.Windows.Documents.WpfPayload.SaveRange(ITextRange range, Stream stream, Boolean useFlowDocumentAsRoot, Boolean preserveTextElements) at System.Windows.Documents.TextRangeBase.Save(ITextRange thisRange, Stream stream, String dataFormat, Boolean preserveTextElements) at System.Windows.Documents.TextRange.System.Windows.Documents.ITextRange.Save(Stream stream, String dataFormat) at System.Windows.Documents.TextRange.Save(Stream stream, String dataFormat) at Xceed.Wpf.Toolkit.RtfFormatter.GetText(FlowDocument document) at Xceed.Wpf.Toolkit.RichTextBox.UpdateTextFromDocument() at Xceed.Wpf.Toolkit.RichTextBox.OnTextChanged(TextChangedEventArgs e) at System.Windows.Controls.Primitives.TextBoxBase.OnTextContainerChanged(Object sender, TextContainerChangedEventArgs e) at System.Windows.Documents.TextContainerChangedEventHandler.Invoke(Object sender, TextContainerChangedEventArgs e) at System.Windows.Documents.TextContainer.EndChange(Boolean skipEvents) at System.Windows.Documents.TextContainer.System.Windows.Documents.ITextContainer.EndChange(Boolean skipEvents) at System.Windows.Documents.TextRangeBase.EndChange(ITextRange thisRange, Boolean disableScroll, Boolean skipEvents) at System.Windows.Documents.TextRange.System.Windows.Documents.ITextRange.EndChange(Boolean disableScroll, Boolean skipEvents) at System.Windows.Documents.TextRange.ChangeBlock.System.IDisposable.Dispose() at System.Windows.Documents.TextEditorCopyPaste.Paste(TextEditor This) at System.Windows.Documents.TextEditorCopyPaste.OnPaste(Object target, ExecutedRoutedEventArgs args) at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e) at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding) at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute) at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e) at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e) at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated) at System.Windows.Input.RoutedCommand.ExecuteCore(Object parameter, IInputElement target, Boolean userInitiated) at System.Windows.Input.CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs) at System.Windows.UIElement.OnKeyDownThunk(Object sender, KeyEventArgs e) at System.Windows.Input.KeyEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) at System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawKeyboardActions actions, Int32 scanCode, Boolean isExtendedKey, Boolean isSystemKey, Int32 virtualKey) at System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(MSG msg, Boolean handled)

xceedsoftware commented 7 years ago

BoucherS[CodePlex]
Hi,

I removed the Text Property binding from your snipet and pasted a 4500x3250 image in this RichTextBox without any exceptions in Toolkit v2.9, v3.0 and v3.1. It took some time to paste, but worked good. What version of the Toolkit are you using, What version of Windows are you using ? Do you have the Toolkit for .NET 4.0 ?

The Toolkit's RichTextBox derives from System.Windows.Controls.RichTextBox, so there shouldn't be a big difference.