How to save BitmapImage / WriteableBitmap in png format (Silverlight/windows phone)? - silverlight

How can i save an image (BitmapImage / WriteableBitmap) in png format using Silverlight for windows phone?

Take a look at ImageTools on codeplex. That supports silverlight encoding PNG. I'm not sure whether this will work with or can be compiled for windows phone 7.

You could try the following code.
This code worked for me. Before you try, make sure that your writablebitmap has a transparent background (You can check by assigning to a image controller image source). If not, make the background transparent from the controller it was coming from.
var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await localFolder.CreateFileAsync("temp.png", CreationCollisionOption.ReplaceExisting);
using (var ras = await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
{
WriteableBitmap bitmap = imageSource;
var stream = bitmap.PixelBuffer.AsStream();
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, buffer.Length);
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, ras);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buffer);
await encoder.FlushAsync();
}

Related

image.jpg byte array to writeablebitmap through base64 WP8

I'm trying to convert a .jpg or .png file to a writeable bitmap. I obtain the image in another source and convert to a base64 encoding. After removing the packaging, I have a width, height, and base64 data. I then use:
var base64 = dataurl.Substring(dataurl.IndexOf("base64,") + 7);
binData = Convert.FromBase64String(base64);
This gives me the binary data of my image. The problem really comes in that I'm writing this for windows phone 8, so I'm limited in what libraries and methods I can use. The obvious choice is:
using (var stream = new MemoryStream(binData, 0, binDta.Length, true, true))
{
var wbp = new WriteableBitmap(1,1).LoadJpeg(stream);
}
but I'm getting a System.ArgumentException from the WriteableBitmap library. Any ideas that work on Windows Phone 8?
You should make sure the base64 decoded data is really a valid format like JPG and PNG.
Then I'd recommend you try the WriteableBitmapEx FromStream method:
var wbp = new WriteableBitmap(1, 1).FromStream(stream);

No image displayed when setting Image.Source to valid data

I'm receiving byte[] image-data (from a webcam source, transmitted over network) and want to display it in my WPF Image control.
If I set the resolution to 160x120, I see a nice tiny image being displayed.
For any other resolution though I see nada, nothing, zilch, squat.
If I write the raw bytes to disk I can see that the data is indeed a valid jpg-image.
Just to make sure it's not jpeg-incompatibility I've tested it with png- and bmp-encoding/decoding as well with the same results; still no image.
Anyone got a bright idea ?
private bool OnImage(byte[] inJpg)
{
this.Dispatch(() =>
{
//File.WriteAllBytes("h:\\tmp\\test" + sImageNum++ + ".jpg", inJpg);
using (MemoryStream ms = new MemoryStream(inJpg))
{
BitmapDecoder decoder = new JpegBitmapDecoder(ms, BitmapCreateOptions.None, BitmapCacheOption.Default);
ImageRemoteVideo.Source = decoder.Frames[0];
}
}
);
}
Assuming ImageRemoteVideo is an instance of a WPF Image control, you may be getting bit by some lazy resolve issues. The Image control has "BeginInit" and "EndInit" methods that you should probably be using. Put the BeginInit method before you set the stream, the other after you set it. Also, if I remember right, the Image class supports a StreamSource. You could try setting your MemoryStream (without disposing of it and without using the JpegBitmapDecoder) to that Property. If that works, then see if you can dispose it after the EndInit call.
I have just found a way to make it work, but I'd love it if someone can explain WHY it works :)
First off, I'm using the raw bytestream to create a BitmapImage.
BUT - if I use a "using" clause around the MemoryStream it doesn't work, if I don't it works.
So this doesn't work :
using (MemoryStream byteStream = new MemoryStream(inJpg))
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = byteStream;
image.EndInit();
ImageRemoteVideo.Source = image;
}
But this does :
MemoryStream byteStream = new MemoryStream(inJpg);
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = byteStream;
image.EndInit();
ImageRemoteVideo.Source = image;
Found it. It's like Brannon said a case of delayed loading.
Specifying "CacheOption = BitmapCacheOption.OnLoad;" fixes it !
Cheers !
Working version :
MemoryStream byteStream = new MemoryStream(inJpg);
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = byteStream;
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
ImageRemoteVideo.BeginInit();
ImageRemoteVideo.Source = image;
ImageRemoteVideo.EndInit();
}

How to load a very large sourceimage in WPF image?

I have a very large image (600mb) 30000x30000 and want to load it into a wpf image control.
I can watch this image with the Windows Photo Viewer!
I set my testapp to 64bit and used the following code.
var image = new BitmapImage();
image.BeginInit();
// load into memory and unlock file
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = uri;
image.EndInit();
imagecontrol.source = image;
The test app just shows a white screen with this large image.
Smaller ones like 100mb and 7000x7000 are working.
What am I doing wrong? Sry for my bad english and thanks in advance.
64-Bit Applications.
As with 32-bit Windows operating systems, there is a 2GB limit on the size of an object you can create while running a 64-bit managed application on a 64-bit Windows operating system.
Picture can be fetched directly from the hard drive to reduce a memory usage.
You can use BitmapCacheOption
Code bellow will read the image directly from the HDD and small thumbnail will be generated without the original image cache:
public BitmapImage memoryOptimizedBitmapRead(string url,FrameworkElement imageContainer)
{
if (string.IsNullOrEmpty(url) || imageContainer.ActualHeight<= 0)
{
return null;
}
var bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.None;
bi.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
bi.DecodePixelHeight = (int)imageContainer.ActualHeight;
bi.UriSource = new Uri(url, UriKind.Absolute);
// End initialization.
bi.EndInit();
bi.Freeze();
return bi;
}
Max thumbnail size is determined by the image container size.
Method usage example:
var image= new Image();
image.Source = memoryOptimizedBitmapRead(...);
I'd divide it into 10 (3000x3000) segments and put them into 10 files.
Also check what format you're using it. It may be filling up the threshold for file size or for that particular format. Try TIF format, then try JPG, then try BMP, etc.. Also see if you can compress it with the JPG format to 40-50% and see if that changes anything.
Let me know what you find out.

How to save a WPF BitmapSource image to a file?

In WPF, the System.Windows.Clipboard.getImage() function returns a BitmapSource object. As a newbie in WPF coming from a WinForms background, its not clear to me how to save this image to a file. What are the steps I must take?
You need to use an encoder (subclass of BitmapEncoder). For instance, to save it to the PNG format, you do something like that :
public static void SaveClipboardImageToFile(string filePath)
{
var image = Clipboard.GetImage();
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(fileStream);
}
}
By the way, note that there's a bug in Clipboard.GetImage. It shouldn't be a problem if you just save the image to a file, but it will be if you want to display it.
EDIT : the bug mentioned above seems to be fixed in 4.0
This clears up the BitmapFrame.Create issue that you have.
public static void SaveClipboardImageToFile(string filePath)
{
//var image = Clipboard.GetImage();
BitmapSource image = (BitmapSource)Clipboard.GetImage();
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
//encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Frames.Add(BitmapFrame.Create(image As BitmapSource));
encoder.Save(fileStream);
}
}

How to render an <image> in a background WPF process?

I'm taking Silverlight XAML and sending it to a web service that renders the XAML in a STA thread and generates a PNG image. All the XAML renders correctly except the <image> entries which 'appear' to load correctly when their Source property is set in WPF but the PNG does not show the referenced image - what am I doing wrong ?
The core of the code that I am using is as below. The value object is a DTO from Silverlight that contains the XAML in the string that ends up as the sXAML local property and the Image URI is in the value.ImageURL property.
var canvas = (FrameworkElement)XamlReader.Load(new XmlTextReader(new StringReader(sXAML)));
var obj = canvas.FindName("BGImage");
Image img = null;
if (obj != null)
{
img = obj as Image;
img.ImageFailed += img_ImageFailed;
img.Source = new BitmapImage(new Uri(value.ImageURL, UriKind.Absolute));
}
canvas.Arrange(new Rect(new Size(463d, 381d)));
canvas.UpdateLayout();
var mem = new MemoryStream();
var bmp = new RenderTargetBitmap(463, 381, 96d, 96d, PixelFormats.Pbgra32);
bmp.Render(canvas);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
encoder.Save(mem);
FileStream fs = new FileStream("D:\\out.png", FileMode.Create);
mem.WriteTo(fs);
fs.Close();
NB: The img_ImageFailed event handler is never invoked indicating that the img Source assignment was successful in some way.
Things I would try:
1) In your WPF app, if you 'render' your dynamically loaded Canvas to display in a Window, does it all work (images included)?
2) Have you tried attaching a Loaded handler to the img object to see when the image is actually loaded?
3) Assuming #1 works - where are the images located (are they on the internet/local web server)? If you put a breakpoint in the code on
bmp.Render(canvas);
and wait a while before stepping on - does the image then appear in the rendered output?
I suspect the image is being 'downloaded' asynchronously and you are rendering the Canvas too early, before the Image object has resolved its source.
[UPDATE 29-Jan-09]
possible solution
I copied you code down exactly and gave it a try. When I used a 'local' image location (eg. "c:\images\splash.jpg") the image was rendered fine in the output jpeg. When I used a URL (eg. "http://localhost/images/splash.jpg") it did NOT appear (as you describe).
So I modified your code as follows (to try and FORCE the image to be downloaded - will only work for http: image references) --
if (obj != null)
{
img = obj as Image;
// new stuff
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = getCachedURLStream(new Uri(ImageURL));
bi.EndInit();
img.BeginInit();
img.Source = bi;
img.EndInit();
//img.ImageFailed += img_ImageFailed;
//img.Loaded += new RoutedEventHandler(img_Loaded);
//img.Source = new BitmapImage(new Uri(ImageURL, UriKind.Absolute));
}
public static Stream getCachedURLStream(Uri url)
{
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
WebResponse response;
webrequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
response = webrequest.GetResponse();
Stream s = response.GetResponseStream();
BufferedStream bs = new BufferedStream(s, 8192);
return bs;
}
(the getCachedURLStream method is from synchronous image loading - it's kinda extraneous but I just wanted a quick chunk of code to test) and it seemed to then work (image visible in JPEG). Maybe that will work in your scenario?

Resources