I am having a bit of a hard time converting MemoryStream
into BitmapImage
. There are a lot of questions on SO
regarding similar situations, but after trying everything on them, I've been unable to fix this, so I turn to you. Note that I'm working with Magick.NET
(ImageMagick.NET) and Tessnet2
-- that is what some of that code is.
I use Bitmap
class to do most of the work in Magick.NET and Tessnet2. BitmapImage
is used for displaying purposes.
First, I load up the PDF and extract a cropped bitmap from its first page:
public Task PdfToBmp(string path)
{
return Task.Run(() =>
{
using (var image = new MagickImage())
{
MagickNET.SetGhostscriptDirectory("./");
var settings = new MagickReadSettings
{
Density = new MagickGeometry(300, 300),
FrameCount = 1
};
image.Read(path, settings);
image.Crop(new MagickGeometry(1850, 200, 600, 140));
// ImageStream is a MemoryStream property.
ImageStream = new MemoryStream();
image.Write(ImageStream, MagickFormat.Bmp);
ImageStream.Position = 0;
}
});
}
That is when I save the bitmap into the MemoryStream
. Once I have MemoryStream
loaded up, I move onto working with it. I instantiate a Bitmap
, so that I may use it for Tessnet2
related work and then try to instantiate a BitmapImage
.
public Task DoOcr()
{
if (ImageStream == null)
{
return null;
}
TargetImage = new Bitmap(ImageStream);
ImageStream.Position = 0;
// ----------------------- Problem Area ----------------------- //
DisplayImage = new BitmapImage();
DisplayImage.BeginInit();
DisplayImage.StreamSource = ImageStream;
DisplayImage.CacheOption = BitmapCacheOption.OnLoad;
DisplayImage.EndInit();
//ImageStream.Close();
// ------------------------------------------------------------ //
return Task.Run(() =>
{
var ocr = new Tesseract();
ocr.Init("tessdata", "eng", false);
var results = ocr.DoOCR(TargetImage, Rectangle.Empty);
Dispatcher.Invoke(() =>
{
Results = new ObservableCollection<Word>(results);
});
});
}
This is where I'm having a problem. Without that DisplayImage
block, the program runs fine and I just don't get the displayed image. I'm even able to save the Bitmap
(TargetImage
) to a file with no problems. However, with the DisplayImage
block, I get System.NullReferenceException
:
System.NullReferenceException occurred
_HResult=-2147467261
_message=Object reference not set to an instance of an object.
HResult=-2147467261
IsTransient=false
Message=Object reference not set to an instance of an object.
Source=System
StackTrace:
at System.Uri.CreateThisFromUri(Uri otherUri)
InnerException:
I'm unable to pinpoint where it occurs exactly, because the ImageStream
object looks "fine" upon inspection. It contains data and is at position 0. If I try to close it, or do anything with it, after assigning it as the StreamSource
to DisplayImage
, I get a null
exception on the line that attempts to perform such action. I even tried creating two different streams, to see if that's the problem; however, I was getting the exact same behavior. Debugging this is kind of a pain, considering it doesn't point to any one specific line. There's obviously an issue between this MemoryStream
and BitmapImage
. Could it be possible that there's some sort of format/conversion problem between the two, but not between MemoryStream
and Bitmap
in this particular situation?
I tried the file route, where I save MagickImage
to a file and load it up into BitmapImage
through Uri
and it worked flawlessly; however, I would like to be able to perform this in-memory. By the way, setting position to 0
on the MemoryStream did not seem to affect either Bitmap
(loads properly) or BitmapImage
(same exception).
The temporary fix I currently use is to make DisplayImage
a BitmapSource
, rather than BitmapImage
:
DisplayImage = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
TargetImage.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(TargetImage.Width, TargetImage.Height));
The Magick.NET's
Write()
method has some bugs, so we have to useToBitmap()
.