I have some troubles with saving a image from memorystream.
Here is my code:
MemoryStream ms = new MemoryStream(onimg);
if (ms.Length > 0)
{
Bitmap bm = new Bitmap(ms);
returnImage = (Image)bm.Clone();
}
ms.Close();
returnImage.Save(#"C:\img.jpeg");
And on returnImage.Save i have the following exception:
A generic error occurred in GDI+.
If I do not close the MemoryStream all is OK but that requires lot of memory after some time.
How can I do this?
EDIT:That Save is only demonstration.. I really need returnImage for place it in ObservableCollection and display in window when i Need it convert to System.Windows.Media.Imaging.BitmapImage();
[ValueConversion(typeof(System.Drawing.Image), typeof(System.Windows.Media.ImageSource))]
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
// empty images are empty...
if (value == null) { return null; }
var image = (System.Drawing.Image)value;
// Winforms Image we want to get the WPF Image from...
var bitmap = new System.Windows.Media.Imaging.BitmapImage();
bitmap.BeginInit();
MemoryStream memoryStream = new MemoryStream();
// Save to a memory stream...
image.Save(memoryStream, ImageFormat.Bmp);
// Rewind the stream...
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
return bitmap;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
And XAML when i do this
<DataTemplate>
<Image Width="32" Height="32" Source="{ Binding Thumb, Converter={StaticResource imageConverter} }" />
</DataTemplate>
According to documentation:
You must keep the stream open for the lifetime of the Bitmap.
Bitmap needs to store its data samewhere, and I deduce (although have no proof for this) that Bitmap does not copy the data, instead using the stream, keeping a lock on it.
Also, there is no evidence that Clone will create new bitmap with the copy of byte representation. And your testcase suggests it is not a case.
Therefore, I am afraid you need to keep your stream open for the lifetime of your image. It requires memory, true, but otherwise if Bitmap copied the data, you will still need that memory for the bitmap representation. Therefore, no more memory is consumed with open stream (if my previous deduction was true).
If you really want to overcome the bitmap's dependency on the original memory stream, you will need to draw the orginal bitmap on the new one instead of cloning like here.
But this will impact the performance, I would better re-analyze if it is not a good idea to keep the original stream, just making sure it is closed when bitmap is disposed.
Isn't a save to disk basically a clone?
using (MemoryStream ms = new MemoryStream(onimg))
{
if (ms.Length > 0)
{
using (Bitmap bm = new Bitmap(ms))
{
bm.Save(#"C:\img.jpeg");
}
}
}
Related
I have something like:
public Bitmap GetBitmap()
{
Byte[] byteArray= bring it from somewhere
using (Stream stream = new MemoryStream(byteArray))
{
return new Bitmap(stream);
}
}
When I use this method outside the Bitmap is crushed. but if I stepped into the "using" scope the bitmap will be exists and works fine. it seems that disposing the stream cause disposing the bitmap..
the question is:
Do I need some deep copy? how should I perform it?
When you dispose the Bitmap will be lost, so indeed you need so perform a deep copy.
Eventually your code should be:
public static Bitmap GetBitmap()
{
byte[] byteArray = bring it from somewhere
using (Stream stream = new MemoryStream(byteArray))
{
var tempBitmap = new Bitmap(stream);
return new Bitmap(tempBitmap); // This will deep-copy the Bitmap
}
}
By the way, usually primitive types, like byte are written in small case.
Im very new to this site. Its my first question! hope somone knows the answer.
Here is the deal, I have a database with entities that hold a byte array as a picture (one of the entity properties).
here is the code that convets the pic to byte[] before saving it to the DB:
public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
{
IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
return pixelData.DetachPixelData();
}
when I pull the entity from the database I see that it comes with the correct data of the picture as byte[].
Im working on a windows 8.1 app and with mvvmCross. in my viewModel I have a full prop named selectedGuest. this property holds the current Guest. all the info about the guest is succsessfuly transformed to the UI accept the image! here is the xaml of the image:
<Image Grid.Column="2" Source="{Binding SelectedGuest.Image, Converter={StaticResource ByteArrayToImageConverter}}"/>
and here is the converter:
public class ByteArrayToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null || !(value is byte[]))
return null;
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes((byte[])value);
writer.StoreAsync().GetResults();
}
BitmapImage image = new BitmapImage();
image.DecodePixelHeight = 200;
image.DecodePixelWidth = 150;
image.SetSource(stream);
return image;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
when debuging the thread ENTERS the converter and the 'value' is correct! but somhow I cant see the image. nothing apears, the image just wont display.
thanks for the viewers!
You should store the original encoded image buffer (i.e. the binary image file content) in your database, not the raw pixel data:
public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
{
var buffer = await FileIO.ReadBufferAsync(file);
return buffer.ToArray();
}
I have a function that returns an array of bytes containing the data of a bmp img live from a camera (including header).
I write that array in to a MemoryStream object.
That object, I pass to a Image object constructor, which will be passed to a PictureBox.
tl;dr:
byte[] AoB = GetImage();
MemoryStream ms = new MemoryStream();
ms.Write(AoB, 0, AoB.Length);
pictureBoxImage.Image = Image.FromStream(ms);
ms.Dispose();
All of this is done in a timer with a delay of 200 ms (5fps).
It works fine for about a minute or 2 until OutOfMemory exception.
For some reason, even though I dispose of the memory used, it keeps generating new one.
I've also tried to declare ms as global and flush it every time, still no go.
How can I stream the images while using the same memory space?
Try disposing the Image objects when you're done with them as well:
byte[] AoB = GetImage();
using (MemoryStream ms = new MemoryStream()) {
ms.Write(AoB, 0, AoB.Length);
Image old = pictureBoxImage.Image;
pictureBoxImage.Image = Image.FromStream(ms);
if (old != null) {
old.Dispose();
}
}
You definitely should dispose the old images when you are done with them (as adv12 mentioned), however you are also creating two byte[]s in memory. The first one is the one you get from GetImage() the second one is the one stored inside the MemoryStream and that one could be larger than your source array due to its growing algorithms.
Instead use this overload of the MemoryStream constructor to allow you to pass the byte[] directly in and the MemoryStream will reuse that single array for its internal store, reducing the memory requirement.
byte[] AoB = GetImage();
using (MemoryStream ms = new MemoryStream(AoB)) {
Image old = pictureBoxImage.Image;
pictureBoxImage.Image = Image.FromStream(ms);
old.Dispose();
}
Try setting your timer's AutoReset=false and manually starting it over at the end of the last call.
myTimer.AutoReset = false;
Start after image assignment.
byte[] AoB = GetImage();
MemoryStream ms = new MemoryStream();
ms.Write(AoB, 0, AoB.Length);
pictureBoxImage.Image = Image.FromStream(ms);
ms.Dispose();
myTimer.Start().
The timer has the potential to get ahead of the retrieval of the images.
My WP7 app has an Image control whose Source is set in XAML to an image with its Build Action set to Content:
<Image x:Name="MyImage" Source="/Images/myimage.png"/>
I need to store this image in my SqlCe database as a byte array. This is my current code to convert to byte[]:
public byte[] ImageToArray() {
BitmapImage image = new BitmapImage();
image.CreateOptions = BitmapCreateOptions.None;
image.UriSource = new Uri( "/Images/myimage.png", UriKind.Relative );
WriteableBitmap wbmp = new WriteableBitmap( image );
return wbmp.ToArray();
}
The byte array saves to the database, but when I retrieve and my converter tries to convert it back (on a different page), I get "unspecified error." This is my converter:
public class BytesToImageConverter : IValueConverter {
public object Convert( object Value, Type TargetType, object Parameter, CultureInfo Culture ) {
if( Value != null && Value is byte[] ) {
byte[] bytes = Value as byte[];
using( MemoryStream stream = new MemoryStream( bytes ) ) {
stream.Seek( 0, SeekOrigin.Begin );
BitmapImage image = new BitmapImage();
image.SetSource( stream ); // Unspecified error here
return image;
}
}
return null;
}
public object ConvertBack( object Value, Type TargetType, object Parameter, CultureInfo Culture ) {
throw new NotImplementedException( "This converter only works for one way binding." );
}
}
I've done quite a bit of searching. As far as the converter, my code is pretty standard. I've seen mention that stream.Position = 0; is necessary, but my understanding is stream.Seek is doing the same thing; I've tried both.
As my converter is the same I've used in about a dozen projects now, I'm fairly convinced the problem lies in converting the Image control's Source to a byte array and thus my image data is corrupted. In the code above I'm hard coding the Uri, but I've also tried
BitmapImage image = MyImage.Source as BitmapImage;
without luck. I've been at this for hours and at my wit's end. What am I missing?
I think the problem is in your ImageToArray() method. You are converting your WriteableBitmap object to array, but not the image itself. Try by replacing your method with the following:
public byte[] ImageToArray()
{
BitmapImage image = new BitmapImage();
image.CreateOptions = BitmapCreateOptions.None;
image.UriSource = new Uri("/Images/myimage.png", UriKind.Relative);
WriteableBitmap wbmp = new WriteableBitmap(image);
MemoryStream ms = new MemoryStream();
wbmp.SaveJpeg(ms, wbmp.PixelWidth, wbmp.PixelHeight, 0, 100);
return ms.ToArray();
}
This methd writes the image to a stream as jpg, and returns it bytes. I haven't tried the code, but you shouldn't have problem to convert it back to a BitmapImage using your converter.
The byte[] from image.UriSource may be base64 radix.You can browse byte[] or data in the SQL tale.
If radix is wrong,can not reverse to stream from byte[].So if radix is 64,must convert to 16 radix.
Currently I'm working on a Ultrasound scanning project, which displays the continues images aquired from a probe, to do that I'm writing following code.
XAML:
<Image Name="imgScan" DataContext="{Binding}" Source="{Binding Path=prescanImage,Converter={StaticResource imgConverter}}" />
C# Assignment:
Bitmap myImage = GetMeImage();
imageMem = new MemoryStream();
myImage .Save(imageMem, ImageFormat.Png);
imgScan.DataContext = new { prescanImage = imageMem.ToArray() };
Converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is byte[])
{
byte[] ByteArray = value as byte[];
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(ByteArray);
bmp.EndInit();
return bmp;
}
return null;
}
This method is costing me lot of (performance),
is there any better way to do it??
Since you're already setting the DataContext in code (not xaml), why not just skip a few steps?
Bitmap myImage = GetMeImage();
imageMem = new MemoryStream();
myImage.Save(imageMem, ImageFormat.Png);
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(imageMem.ToArray());
bmp.EndInit();
imgScan.Source = bmp;
If you have access to GetMeImage(), you may want to consider altering it to better fit into your application - Does it really need to return a Bitmap?
Also, how often is your first piece of code being executed? You may want to consider altering that, or allowing it to vary when it needs to.