How to convert Image.Source to byte array? - c#

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.

Related

How to bind byte array as image in windows 8 app

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

convert array of bytes to bitmapimage

I'm going to convert array of bytes to System.Windows.Media.Imaging.BitmapImage and show the BitmapImage in an image control.
When I'm using the first code, noting happens! no error and no image is displayed. But when I'm using the second one it works fine! can anyone say what is going on?
first code is here:
public BitmapImage ToImage(byte[] array)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(array))
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = ms;
image.EndInit();
return image;
}
}
second code is here:
public BitmapImage ToImage(byte[] array)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = new System.IO.MemoryStream(array);
image.EndInit();
return image;
}
In the first code example the stream is closed (by leaving the using block) before the image is actually loaded. You must also set BitmapCacheOptions.OnLoad to achieve that the image is loaded immediately, otherwise the stream needs to be kept open, as in your second example.
public BitmapImage ToImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad; // here
image.StreamSource = ms;
image.EndInit();
return image;
}
}
From the Remarks section in BitmapImage.StreamSource:
Set the CacheOption property to BitmapCacheOption.OnLoad if you wish
to close the stream after the BitmapImage is created.
Besides that, you can also use built-in type conversion to convert from type byte[] to type ImageSource (or the derived BitmapSource):
var bitmap = (BitmapSource)new ImageSourceConverter().ConvertFrom(array);
ImageSourceConverter is called implicitly when you bind a property of type ImageSource (e.g. the Image control's Source property) to a source property of type string, Uri or byte[].
In the first case, you defined your MemoryStream in a using block, which causes the object to be disposed when you go out of the block. So you return a BitmapImage with a disposes (and non-existing) stream.
MemoryStreams keep no unmanaged resources, so you can leave the memory and let the GC handle the freeing process (but that's not a good practice).

How to Copy Bitmap.Image in c#

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");
}
}
}

Convert System.Drawing.Image to System.Windows.Controls.Image?

Is there a way in C# to do this conversion and back?
I have a WPF app which has a Image control. I'm trying to save the image in that control to a SQL Database.
In my Entity Model, the datatype of the picture column in my database is a byte[]. So I found a method to convert a System.Drawing.Image to a byte[] and back. But I haven't found a method to convert from System.Windows.Controls.Image to a byte[].
So that's why I now need to do the above conversion.
If you have a byte array that represents a file that WPF can decode (bmp, jpg, gif, png, tif, ico), you can do the following:
BitmapSource LoadImage(Byte[] imageData)
{
using (MemoryStream ms = new MemoryStream(imageData))
{
var decoder = BitmapDecoder.Create(ms,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
return decoder.Frames[0];
}
}
Likewise, to convert it back, you can do the following:
byte[] SaveImage(BitmapSource bitmap)
{
using (MemoryStream ms = new MemoryStream())
{
var encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(ms);
return ms.GetBuffer();
}
}
Well, one is an image and one is a control that shows an image, so I don't think that there's a conversion between the two. But, you could set the Source of the ...Controls.Image to be your ...Drawing.Image.
Edit based on update
Does this do what you need - http://msdn.microsoft.com/en-us/library/ms233764%28VS.100%29.aspx

Best way to display image in WPF

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.

Categories

Resources