How to save a WriteableBitmap as a file? - c#

I have a WriteableBitmap that I need to save in a file. I have a feeling I need the AsStream() extension method on WriteableBitmap.PixelBuffer. However, I don't see that extension method on my WriteableBitmap.
Should AsStream() be on all WriteableBitmaps?
Once I get AsStream(), what do I do next?

Here you go !!!
using System.Runtime.InteropServices.WindowsRuntime;
private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap WB, FileFormat fileFormat)
{
string FileName = "MyFile.";
Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
switch (fileFormat)
{
case FileFormat.Jpeg:
FileName += "jpeg";
BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
break;
case FileFormat.Png:
FileName += "png";
BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
break;
case FileFormat.Bmp:
FileName += "bmp";
BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
break;
case FileFormat.Tiff:
FileName += "tiff";
BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
break;
case FileFormat.Gif:
FileName += "gif";
BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
break;
}
var file = await Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFileAsync(FileName, CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
Stream pixelStream = WB.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
(uint)WB.PixelWidth,
(uint)WB.PixelHeight,
96.0,
96.0,
pixels);
await encoder.FlushAsync();
}
return file;
}
private enum FileFormat
{
Jpeg,
Png,
Bmp,
Tiff,
Gif
}

Related

Cannot read a Bitmap image that I just saved in Base64

I try to load a picture (PNG), save-it in Base64 in a text file and reload it, but I only see gliberish pictures (black and white, very ugly, far from original!) after I load the picture from the text file.
Where's my problem?
BTW all examples (load the picture from image file, save to base64, load from base64) are all taken from SO questions.
First it's how a load the pictures from the PNG file:
try
{
var openFileDialog = new OpenFileDialog
{
CheckFileExists = true,
Multiselect = false,
DefaultExt = "png",
InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
};
if (openFileDialog.ShowDialog() == true)
{
Bitmap img;
using (var stream = File.Open(openFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
img = new Bitmap(stream);
}
Logo.Source = BitmapToImageSource(img);
}
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString(), "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
Save it to base64:
try
{
Bitmap img = BitmapSourceToBitmap2((BitmapSource) Logo.Source);
string base64String;
using (var stream = new MemoryStream())
{
img.Save(stream, ImageFormat.Png);
byte[] imageBytes = stream.ToArray();
base64String = Convert.ToBase64String(imageBytes);
}
string fileName = string.Format(CultureInfo.InvariantCulture, "image{0:yyyyMMddHHmmss}.txt",
DateTime.Now);
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
using (var stream = File.Open(path, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (var writer = new StreamWriter(stream, System.Text.Encoding.UTF8))
{
writer.Write(base64String);
writer.Flush();
}
}
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString(), "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
BitmapSourceToBitmap2:
int width = srs.PixelWidth;
int height = srs.PixelHeight;
int stride = width*((srs.Format.BitsPerPixel + 7)/8);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(height*stride);
srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height*stride, stride);
using (var btm = new Bitmap(width, height, stride, PixelFormat.Format1bppIndexed, ptr))
{
// Clone the bitmap so that we can dispose it and
// release the unmanaged memory at ptr
return new Bitmap(btm);
}
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
And load it back from the file:
try
{
var openFileDialog = new OpenFileDialog
{
CheckFileExists = true,
Multiselect = false,
DefaultExt = "txt",
InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
};
if (openFileDialog.ShowDialog() == true)
{
string base64String;
using (FileStream stream = File.Open(openFileDialog.FileName, FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
base64String = reader.ReadToEnd();
}
}
byte[] binaryData = Convert.FromBase64String(base64String);
var bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = new MemoryStream(binaryData);
bi.EndInit();
Logo.Source = bi;
}
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString(), "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
Here is a short code sequence that reads a JPG file into a byte array, creates a BitmapSource from it, then encodes it into a base64 string and writes that to file.
In a second step, the base64 string is read back from the file, decoded and a second BitmapSource is created.
The sample assumes that there is some XAML with two Image elements named image1 and image2.
Step 1:
var imageFile = #"C:\Users\Clemens\Pictures\DSC06449.JPG";
var buffer = File.ReadAllBytes(imageFile);
using (var stream = new MemoryStream(buffer))
{
image1.Source = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
var base64File = #"C:\Users\Clemens\Pictures\DSC06449.b64";
var base64String = System.Convert.ToBase64String(buffer);
File.WriteAllText(base64File, base64String);
Step 2:
base64String = File.ReadAllText(base64File);
buffer = System.Convert.FromBase64String(base64String);
using (var stream = new MemoryStream(buffer))
{
image2.Source = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
In case you need to encode an already existing BitmapSource into a byte array, use code like this:
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
buffer = stream.ToArray();
}

Setting thumbnail of SystemMediaTransportControlsDisplayUpdater

I am Setting thumbnail of SMTC control from stream via SystemMediaTransportControlsDisplayUpdater, but it is not working
var response = await new HttpClient().GetAsync(imgUrl);
systemMediaTransportControlsDisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromStream((await response.Content.ReadAsStreamAsync()).AsRandomAccessStream());
Same is working if i use Url to create random stream.
systemMediaTransportControlsDisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(new Uri(imgUrl));
I am merging two images and i want to assign that image as thumbnai to SMTC. To merge images below code i am using.
var response = await httpClient.GetAsync(imgUrl);
var writeableBmp = new WriteableBitmap(1, 1);
var image1 = await writeableBmp.FromStream(await response.Content.ReadAsStreamAsync());
var image2 = await writeableBmp.FromContent(imgUrl1);
image1.Blit(new Rect(0, 0, image1.PixelWidth, image1.PixelHeight), image2, new Rect(0, 0, image2.PixelWidth, image2.PixelHeight));
var randomAccessStream = image1.PixelBuffer.AsStream().AsRandomAccessStream();
systemMediaTransportControlsDisplayUpdater.Thumbnail =
= RandomAccessStreamReference.CreateFromStream(randomAccessStream );
What exactly wrong with merging or setting thumbnail to SMTC?
Thanks
stream via SystemMediaTransportControlsDisplayUpdater, but it is not working
I could reproduce your issue, I will report this, currently there is a workaround that converter WriteableBitmap to StorageFile then pass file argument to RandomAccessStreamReference.CreateFromFile method. You could refer the following code,
private async void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
var imgUrl = new Uri("https://image.diyidan.net/post/2015/10/27/LILeAOb3BF8qR8Uz.png");
var imgUrl1 = new Uri("ms-appx:///Assets/test.png");
var httpclient = new HttpClient();
var response = await httpclient.GetAsync(imgUrl);
var writeableBmp = new WriteableBitmap(1, 1);
var image1 = await writeableBmp.FromStream(await response.Content.ReadAsStreamAsync());
var image2 = await writeableBmp.FromContent(imgUrl1);
image1.Blit(new Rect(0, 0, image1.PixelWidth, image1.PixelHeight), image2, new Rect(0, 0, image2.PixelWidth, image2.PixelHeight));
var file = await WriteableBitmapToStorageFile(image1, FileFormat.Png);
SystemMediaTransportControlsDisplayUpdater updater = sender.SystemMediaTransportControls.DisplayUpdater;
updater.Thumbnail = RandomAccessStreamReference.CreateFromFile(file);
updater.Update();
});
}
private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap WB, FileFormat fileFormat)
{
string FileName = "YourFile.";
Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
switch (fileFormat)
{
case FileFormat.Jpeg:
FileName += "jpeg";
BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
break;
case FileFormat.Png:
FileName += "png";
BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
break;
case FileFormat.Bmp:
FileName += "bmp";
BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
break;
case FileFormat.Tiff:
FileName += "tiff";
BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
break;
case FileFormat.Gif:
FileName += "gif";
BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
break;
}
var file = await Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFileAsync(FileName, CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
Stream pixelStream = WB.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)WB.PixelWidth, (uint)WB.PixelHeight,
96.0,
96.0,
pixels);
await encoder.FlushAsync();
}
return file;
}
private enum FileFormat
{
Jpeg,
Png,
Bmp,
Tiff,
Gif
}

How to take Screen shot in windows store apps

I want to take the screenshot in my application and want to save it in local folder of app with unique name.
so please help me.
You can capture you screen using RenderTargetBitmap. Try this code:
//create and capture Window
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Window.Current.Content);
//create unique file in LocalFolder
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("screenshotCapture.jpg", CreationCollisionOption.GenerateUniqueName);
//create JPEG image
using (var stream = await file.OpenStreamForWriteAsync())
{
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream.AsRandomAccessStream());
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight, logicalDpi, logicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
Or
public static async Task<StorageFile> AsUIScreenShotFileAsync(this UIElement elememtName, string ReplaceLocalFileNameWithExtension)
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(ReplaceLocalFileNameWithExtension, CreationCollisionOption.ReplaceExisting);
try
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
// Render to an image at the current system scale and retrieve pixel contents
await renderTargetBitmap.RenderAsync(elememtName);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
// Encode image to an in-memory stream
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi, pixelBuffer.ToArray());
await encoder.FlushAsync();
//CreatingFolder
// var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
RandomAccessStreamReference rasr = RandomAccessStreamReference.CreateFromStream(stream);
var streamWithContent = await rasr.OpenReadAsync();
byte[] buffer = new byte[streamWithContent.Size];
await streamWithContent.ReadAsync(buffer.AsBuffer(), (uint)streamWithContent.Size, InputStreamOptions.None);
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(buffer);
await dataWriter.StoreAsync(); //
dataWriter.DetachStream();
}
// write data on the empty file:
await outputStream.FlushAsync();
}
await fileStream.FlushAsync();
}
// await file.CopyAsync(folder, "tempFile.jpg", NameCollisionOption.ReplaceExisting);
}
catch (Exception ex)
{
Reporting.DisplayMessageDebugExemption(ex.Message);
}
return file;
}

how to convert an image to base64string in c#

The helper methods i use are....
private async Task<string> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
{
var encoded = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
await encoder.FlushAsync();
encoded.Seek(0);
var bytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes);
}
private byte[] ImageToByteArray(WriteableBitmap wbm)
{
using (Stream stream = wbm.PixelBuffer.AsStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
The code that picks an image and converts to writable bitmap is
WriteableBitmap image;
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var bitmp = new BitmapImage();
// Application now has read/write access to the picked file
var filePath = await file.OpenReadAsync();
bitmp.SetSource(filePath);
proPic.Source = bitmp;
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
image = new WriteableBitmap(1, 1);
image.SetSource(stream);
}
imageT = await ToBase64(ImageToByteArray(image), 100, 100, 96, 96);
pic = 1;
}
else
{
//OutputTextBlock.Text = "Operation cancelled.";
}
When i compare the base64string i get from the helper methods with http://www.dailycoding.com/utils/converter/imagetobase64.aspx
The both are not the same.
changing the file into в base64
public async Task<string> GetBase64(string name)
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.GetFileAsync(name);
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(file.Path));
byte[] fileBytes = null;
using (var stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
return Convert.ToBase64String(fileBytes);
}

Cropping Image with Xamlcropcontrol for UI and WriteableBitmapEx

For the past week I've been researching as much as i can on how to add the ability to crop a profile image in my windows store app. So far I have looked at the Microsoft solution to this but have decided to go a different route. I downloaded a control from NuGet called XamlCropControl. It works pretty well for the UI and even give me information like Original Height/Width The position of the cropped top/bottom/left/right/width/height all within the xaml control. my question is as how to take that information and crop the the image using WriteableBitmapEx. So far this is my code and i'm having a problem.
private async void ProfilePhotoImageClick(object sender, TappedRoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
using (Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(fileStream);
BackgroundLogo.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
PhotoUploadCropper.Opacity = 1;
PhotoUploadCropper.ImageSource = bitmapImage;
ProfileSetupStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
imagetoResize = bitmapImage;
}
}
}
BitmapImage imagetoResize;
private void AcceptPhotoImageCropClick(object sender, RoutedEventArgs e)
{
WriteableBitmap bmp = new WriteableBitmap(0,0).FromContent(imagetoResize);
var croppedBmp = bmp.Crop(0, 0, bmp.PixelWidth / 2, bmp.PixelHeight / 2);
croppedBmp.SaveToMediaLibrary("ProfilePhoto.jpg");
}
PhotoUploadCropper is the xamlcropcontrol.
This is the information from xamlcropcontrol
This is the problem im having
It tells me there is no deffinition for FromContent if i have the (imagetoResize) there but if i remove it i get no error. After all the cropping is done it will be uploading to azure blob storage which i have already setup.
Edit: Works like this.
private async void ProfilePhotoImageClick(object sender, TappedRoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
fileclone = file;
BackgroundLogo.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
PhotoUploadCropper.IsEnabled = true;
PhotoUploadCropper.Opacity = 1;
PhotoUploadCropper.ImageSource = bitmapImage;
ProfileSetupStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
}
StorageFile fileclone;
async Task<WriteableBitmap> LoadBitmap(StorageFile file)
{
int cropx = PhotoUploadCropper.CropTop;
int cropy = PhotoUploadCropper.CropLeft;
int cropW = PhotoUploadCropper.CropWidth;
int cropH = PhotoUploadCropper.CropHeight;
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
var bmp = await BitmapFactory.New(1, 1).FromStream(fileStream);
var croppedBmp = bmp.Crop(cropy, cropx, cropW, cropH);
var resizedcroppedBmp = croppedBmp.Resize(200, 200, WriteableBitmapExtensions.Interpolation.Bilinear);
return resizedcroppedBmp;
}
}
private async void AcceptPhotoImageCropClick(object sender, RoutedEventArgs e)
{
var CroppedBMP = await CropBitmap(fileclone);
using (IRandomAccessStream fileStream = new InMemoryRandomAccessStream())
{
string filename = Path.GetRandomFileName() + ".JPG";
var file = await Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFileAsync(filename, CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
Stream pixelStream = CroppedBMP.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)CroppedBMP.PixelWidth, (uint)CroppedBMP.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();
}
ProfilePhotoButtonsGrid.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
BackgroundLogo.Visibility = Windows.UI.Xaml.Visibility.Visible;
PhotoUploadCropper.IsEnabled = false;
PhotoUploadCropper.Opacity = 0;
ProfileSetupStackPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
if (fileStream != null)
{
UploadFile(file);
}
}
}
You will have to use the WBX WinRT APIs for this. Looks like you are trying the WP / Silverlight methods.
Try this:
async Task<WriteableBitmap> LoadBitmap(string path)
{
Uri imageUri = new Uri(BaseUri, path);
var bmp = await BitmapFactory.New(1, 1).FromContent(imageUri);
return bmp;
}
Note it takes an URI. In your case you can rather use the IRandomAccessStream directly:
var bmp = await BitmapFactory.New(1, 1).FromStream(fileStream);

Categories