Bind image and save for cache folder - c#

I have a ListBox with Image :
<Image Margin="0" Source="{Binding Path=ImgUrl}" HorizontalAlignment="Stretch" Width="80" Height="80"
Tag="{Binding idStr}" OpacityMask="{x:Null}" Stretch="Fill"/>
And i want that when i bind it it will save the image to my disk for cache issues,and the next time it will check if the image exist and take it from the disk. It is possible to do something like this?
Download image-> Save to disk -> make image as image source

You could use a specialized binding converter that saves each image to file.
The sample code below shows the basic structure of such a converter. You will have to add some error handling and of course you need to define a mapping from image URIs to local file paths. You may also support System.Uri as alternative source type.
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = value;
var imageUrl = value as string;
if (imageUrl != null)
{
var buffer = (new WebClient().DownloadData(imageUrl));
if (buffer != null)
{
// create an appropriate file path here
File.WriteAllBytes("CachedImage.jpg", buffer);
var image = new BitmapImage();
result = image;
using (var stream = new MemoryStream(buffer))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
}
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
You would use that converter in your binding like this:
<Image Source="{Binding Path=ImgUrl,
Converter={StaticResource ImageConverter}}" ... />

Related

Display data URL in WPF

I am trying to create WPF application that gets data from service. The data is image URLs. Sometimes the service returns Data URLs.
If I tries to bind that URL to Image control like:
<Image Source="{Binding URL}" />
It's working for regular URL, but Data URLs are not displayed.
Is there any way to display Data URL in WPF control?
Create a value converter, which converts base64 data to a BitmapImage:
public class DataUrlConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var data = (string) value;
var base64Data = Regex.Match(data, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = System.Convert.FromBase64String(base64Data);
var image = new BitmapImage();
using (var mem = new MemoryStream(binData))
{
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then create a converter resource:
<Window.Resources>
<local:DataUrlConverter x:Key="DataUrlConverter"></local:DataUrlConverter>
</Window.Resources>
and use it like this:
<Image Source="{Binding URL, Converter={StaticResource DataUrlConverter}}" />

BitmapImage throws an initialization exception when file does not exist

I have XAMl like this
<Image x:Name="MyImage">
<Image.Source>
<BitmapImage UriSource="{Binding FullPhotoPath}" CacheOption="OnLoad" />
</Image.Source>
</Image>
This works fine so long as FullPhotoPath exists. if it does not then it throws an exception of
Initialization of 'System.Windows.Media.Imaging.BitmapImage' threw an exception.
I realize I can use just the Image tag
To show an image and if it doesn't exist then nothing is displayed (and no exception is thrown), but as far as I can tell this syntax does not allow me to use a CacheOption.
How can I show nothing if the image path does not exist?
You could use a converter to create your BitmapImage with whatever settings you need which can also just return null if you see that the file doesn't exist and then just bind the Image.Source through the converter.
public class PathToBitmapImagelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string path = value as string;
if (path == null || !File.Exists(path))
return null;
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
bmp.EndInit();
return bmp;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Make the converter accessible somewhere
<local:PathToBitmapImagelConverter x:Key="PathToBitmapImagelConverter"/>
Then use in your XAML like
<Image x:Name="MyImage" Source="{Binding FullPhotoPath, Converter={StaticResource PathToBitmapImagelConverter}}"/>

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

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

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