In my Windows store application, i am displaying a picture using Image control in XAML. Source of the Image control is set, code wise using WriteableBitmap. I am trying to send this image as attachment in email. Is there any easy way for that? I am trying to save that image locally( within application ) and attach that saved image to email. But not able to save locally. Any help is appreciated.
Here is the code.
bitmap = await WriteableBitmapRenderExtensions.Render(dataCanvas);
image.Source = bitmap;
dataCanvas is a Canvas control consists of two images, one place above another. Actually i have to place a sunglass top of users face and display it as another image in xaml. Also email that image.
Check out the WriteableBitmapSaveExtensions class in WinRT XAML Toolkit for all the SaveToFile() extension methods you can use to save your WriteableBitmap.
The core one is this:
public static async Task SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFile outputFile,
Guid encoderId)
{
Stream stream = writeableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writeableBitmap.PixelWidth,
(uint)writeableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
}
You can get the encoder ID using an overload of the method:
public static async Task<StorageFile> SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFolder storageFolder,
string fileName,
CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
{
StorageFile outputFile =
await storageFolder.CreateFileAsync(
fileName,
options);
Guid encoderId;
var ext = Path.GetExtension(fileName);
if (new[] { ".bmp", ".dib" }.Contains(ext))
{
encoderId = BitmapEncoder.BmpEncoderId;
}
else if (new[] { ".tiff", ".tif" }.Contains(ext))
{
encoderId = BitmapEncoder.TiffEncoderId;
}
else if (new[] { ".gif" }.Contains(ext))
{
encoderId = BitmapEncoder.GifEncoderId;
}
else if (new[] { ".jpg", ".jpeg", ".jpe", ".jfif", ".jif" }.Contains(ext))
{
encoderId = BitmapEncoder.JpegEncoderId;
}
else if (new[] { ".hdp", ".jxr", ".wdp" }.Contains(ext))
{
encoderId = BitmapEncoder.JpegXREncoderId;
}
else //if (new [] {".png"}.Contains(ext))
{
encoderId = BitmapEncoder.PngEncoderId;
}
await writeableBitmap.SaveToFile(outputFile, encoderId);
return outputFile;
}
Any subclass of BitmapSource (including WritableBitmap) can be passed to a BitmapEncoder. A BitmapEncoder takes a Stream to which the encoded JPEG, PNG or other image is written.
You can then use a mailer library to reference the stream used by the encoder, or use the Share contract, and pass the stream directly.
Example:
var bitmap = new WritableBitmap();
// ... draw your bitmap
var tempPath = // path to where you want to save (probably in your appx temp);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(bitmap);
using (var fs = new FileStream(tempPath))
{
encoder.Save(fs);
}
// use the image saved to tempPath
// http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871370.aspx
Related
I am making a Note application where I can draw with Windows ink and also paste images. I want to save the images and ink in a single file. Therefore I am converting the image to a string in base64 format so that I can easily serialize it. My problem is when I try to recreate the image from the string.
My code to decode the image data into a base64 string:
var decoder = await BitmapDecoder.CreateAsync(imageStream);
var pixels = await decoder.GetPixelDataAsync();
var bytes = pixels.DetachPixelData();
base64String = Convert.ToBase64String(bytes);
My code to encode the base64 string into an image again (This code does NOT work! The image is not added to the redCanvas):
var bytes = Convert.FromBase64String(base64String);
BitmapImage bitmapImage = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(bytes.AsBuffer());
stream.Seek(0);
bitmapImage.SetSource(stream);
}
Image image = new Image();
image.Source = bitmapImage;
// Add the image to a second canvas
redCanvas.Children.Add(image);
Full code for pasting the image and creating the base64 string:
private async Task myButton_ClickAsync(object sender, RoutedEventArgs e)
{
var dataPackageView = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
if (dataPackageView.Contains(StandardDataFormats.Bitmap))
{
IRandomAccessStreamReference imageReceived = null;
imageReceived = await dataPackageView.GetBitmapAsync();
if (imageReceived != null)
{
using (var imageStream = await imageReceived.OpenReadAsync())
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
var decoder = await BitmapDecoder.CreateAsync(imageStream);
var pixels = await decoder.GetPixelDataAsync();
var bytes = pixels.DetachPixelData();
base64String = Convert.ToBase64String(bytes);
TextBox_Image_Base64.Text = base64;
Image image = new Image();
// Add the image to a list of Images
ListImages.Add(image);
blueCanvas.Children.Add(image);
image.Source = bitmapImage;
TextBlock_Status.Text = "Status : Image is retrieved from the
clipboard and pasted successfully.";
}
}
}
else
{
TextBlock_Status.Text = "Status : Bitmap format is not available in clipboard";
}
}
Anyone have any suggestions as to how I can recreate the image from the string?
Screenshot from my app showing that I am able to paste an image and decode it into a string
How to create Image from string in Base64 (UWP)
We suggest you convet stream buffer to Base64 from imageStream diteactly, but not from PixelData. you could use CryptographicBuffer class to approach.
using (var imageStream = await imageReceived.OpenReadAsync())
{
var buffer = new Windows.Storage.Streams.Buffer((uint)imageStream.Size);
await imageStream.ReadAsync(buffer, (uint)imageStream.Size, InputStreamOptions.None);
String strBase64New = CryptographicBuffer.EncodeToBase64String(buffer);
}
Retrive from base64 string
public static async Task<BitmapImage> LoadBase64(string base64)
{
byte[] bytes = Convert.FromBase64String(base64);
var bitmap = new BitmapImage();
using (MemoryStream ms = new MemoryStream(bytes))
{
await bitmap.SetSourceAsync(ms.AsRandomAccessStream());
}
return bitmap;
}
I don't know how to convert Bitmap to BitmapImage on UWP. Not WPF.
-C#-
Icon appIcon = System.Drawing.Icon.ExtractAssociatedIcon(path);
Bitmap bitmap = appIcon.ToBitmap();
BitmapImage bitmapImage = bitmap.toBitmapImage(); // It doesn't works.
DesktopIcon.Source = bitmapImage;
-XAML-
<Image Width="32" Height="32" x:Name="DesktopIcon"></Image>
Do you know any other way to get file's Icon
In UWP platform, we could use GetThumbnailAsync to get file's Thumbnail, for image file we could get an empty file's thumbnail to avoid getting the image preview. You could use the following method directly.
public static class FileExtension
{
public async static Task<StorageItemThumbnail> GetFileIcon(this StorageFile file, uint size = 32)
{
StorageItemThumbnail iconTmb;
var imgType = new[] { "bmp", "gif", "jpeg", "jpg", "png" }.FirstOrDefault(ext => file.Path.ToLower().EndsWith(ext));
if (imgType != null)
{
var dummy = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("dummy." + imgType , CreationCollisionOption.ReplaceExisting); //may overwrite existing
iconTmb = await dummy.GetThumbnailAsync(ThumbnailMode.SingleItem, size);
}
else
{
iconTmb = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, size);
}
return iconTmb;
}
}
Usage
var icon = await file.GetFileIcon();
var imgSource = new BitmapImage();
imgSource.SetSource(icon);
Myimage.Source = imgSource;
I'm using this code to write a Byte Array inside a file BMP:
private async void ScriviBMP()
{
using (Stream stream = immagineBitmap.PixelBuffer.AsStream())
{
await stream.WriteAsync(arrayImmagine, 0, arrayImmagine.Length);
}
StorageFolder folder = KnownFolders.PicturesLibrary;
if (folder != null)
{
StorageFile file = await folder.CreateFileAsync("area2_128x128" + ".bmp", CreationCollisionOption.ReplaceExisting);
using (var storageStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, storageStream);
var pixelStream = immagineBitmap.PixelBuffer.AsStream();
var pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)immagineBitmap.PixelWidth, (uint)immagineBitmap.PixelHeight, 48, 48, pixels);
await encoder.FlushAsync();
}
}
}
Then i'm using this code to display the BMP image in a Image object
private async void VisBMP()
{
var file = await KnownFolders.PicturesLibrary.GetFileAsync("area2_128x128.bmp");
using (var fileStream = (await file.OpenAsync(Windows.Storage.FileAccessMode.Read)))
{
var bitImg = new BitmapImage();
//bitImg.UriSource = new Uri(file.Path);
bitImg.SetSource(fileStream);
image.Source = bitImg;
}
}
these functions take about 400 milliseconds to complete the process, that's a lot of time.
Is there a way to avoid the usage of a BMP file and use only a stream to display the image on the image object?
It can be that debugging the program can slow the processes? I'm using Visual Studio 2015.
You can transfer the data buffer(arrayImmagine) to image in InMemoryRandomAccessStream.These codes take about 200ms.I tested with following pieces of code. In addition, you can reference this article to get more information.
BitmapImage biSource = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(bytes.AsBuffer());
stream.Seek(0);
await biSource.SetSourceAsync(stream);
}
image.Source = biSource;
I'm working on windows phone 8.1 application. I have different pictures locally in app and displaying those pictures in list view. Now select one picture id and pass it to detail screen, where I have to save that file .
My detail.Xaml screen contain image control named as Imaged.
I got image on detail page and press image save button. I'm using this Sample app https://code.msdn.microsoft.com/windowsapps/Save-Edited-Picture-16d910c4/sourcecode?fileId=119937&pathId=946309183 "Sample"
My detail page Code is here.
string tempimg;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var imagePath = e.Parameter as string;
imaged.Source = new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute));
tempimg = imagePath;
}
My SaveImage button code is here.
if (tempimg == null)
return;
// WriteableBitmap abc = new WriteableBitmap(400, 400);
string filename = "Image-" + DateTime.Now.ToFileTime() + ".jpeg";
// await SaveWriteableBitmapAsJpeg(img, filename);
Blockquote
await SaveWriteableBitmapAsJpeg(tempimg, filename);
private static async Task SaveWriteableBitmapAsJpeg(WriteableBitmap bmp, string fileName)
{
// Create file in Pictures library and write jpeg to it
var outputFile = await KnownFolders.CameraRoll.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
await EncodeWriteableBitmap(bmp, writeStream, BitmapEncoder.JpegEncoderId);
}
}
private static async Task EncodeWriteableBitmap(WriteableBitmap bmp, IRandomAccessStream writeStream, Guid encoderId)
{
// Copy buffer to pixels
byte[] pixels;
using (var stream = bmp.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
// Encode pixels into stream
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied,
(uint)bmp.PixelWidth, (uint)bmp.PixelHeight,
96, 96, pixels);
await encoder.FlushAsync();
}
My this function "await SaveWriteableBitmapAsJpeg(tempimg, filename);" creates a problem. I just have the image source while that require the writeablebitmap. I just want to save image and not able to proceed from here. let me know the exact solution or problem.
I'm trying to upload an image from my Windows Store App (Windows Phone 8.1) to hosting (using PHP) but always when I "uploaded" the image, and I check its result the "image" it's a corrupted file. I think it's related to the byte array conversion but I haven't found another way to do it. This is my code:
C# Code:
byte[] ConvertBitmapToByteArray()
{
WriteableBitmap bmp = bitmap;
using (Stream stream = bmp.PixelBuffer.AsStream())
{
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
public async Task<string> Upload()
{
try
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent())
{
byte[] data = ConvertBitmapToByteArray();
content.Add(new StreamContent(new MemoryStream(data)), "userfile", fileNewImage);
using (
var message =
await client.PostAsync("http://xplace.com/uploadtest.php", content))
{
var input = await message.Content.ReadAsStringAsync();
return input;
}
}
}
}
catch (Exception ex)
{
return null;
}
}
PHP code:
<?php
header('Content-Type: application/json');
$uploaddir = getcwd();
$uploadfile = $uploaddir . "/" . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo '{"result": "sucessfull"}';
} else {
echo '{"result": "-1"}';
}
?>
I wish someone could give me an idea about what I my mistake and how to fix it. Thanks in advance for your worthy knowledge.
You need to pass your byte[] data through a BitmapEncoder to convert it into a common image format (e.g. BMP, PNG, JPEG) before uploading. At the moment you are just sending the raw ARGB pixel data with no information about how it should be interpreted.
For example, to encode as a BMP:
...
byte[] data = bitmap.PixelBuffer.ToArray();
using (var stream = new InMemoryRandomAccessStream())
{
// encoder *outputs* to stream
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
// encoder's input is the bitmap's pixel data
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
(uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96, 96, data);
await encoder.FlushAsync();
content.Add(new StreamContent(stream.AsStream()), "userfile", fileNewImage);
...
}