How to save SoftwareBitmap object to bmp file C#, UWP - c#

I converted jpg image to SoftwareBitmap object, I hope it will work. The code is below.
SoftwareBitmap softwareBitmap;
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
{
// Create the decoder from the stream
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
// Get the SoftwareBitmap representation of the file
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
}
So I do not know now how to make .bmp file using this softwareBitmap.. Thanks in advance.

Use Bitmap instead:
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
{
Bitmap bmp = new Bitmap(stream);
bmp.Save(filePath, System.Drawing.Imaging.ImageFormat.Bmp);
}

Related

Converting from PixelBuffer to Image in UWP C# (Using only Windows.UI.Xaml)

Hi all I want to convert pixel buffer to image and print it. This is information that I have in my program:
PixelBuffer: int width, int height, IntPtr buffer, stride. This is how I cannot do it because of some assembly errors:
Windows.UI.Xaml.Controls.Image image = new Windows.UI.Xaml.Controls.Image();
System.Windows.Media.Imaging.BitmapFrame frame = System.Windows.Media.Imaging.BitmapFrame.Create(System.Windows.Media.Imaging.BitmapSource.Create(
(int)pr.pixelBuffer.width,
(int)pr.pixelBuffer.height,
96,
96,
System.Windows.Media.PixelFormats.Rgb24,
null,
pr.pixelBuffer.buffer,
(int)(pr.pixelBuffer.stride * pr.pixelBuffer.height),
(int)pr.pixelBuffer.stride));
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage(frame.BaseUri);
image.Source = bitmapImage;//frame;
stackPanel.Children.Add(image)
Is there any way to do this without System.Windowxs.Media.Imaging? Using only Windows.UI.Xaml ?
Thanks!
I want to convert pixel buffer to image and print it.
I'm not sure what your pixel buffer come from since your code only shows getting from pr obejct. In uwp app
if you got it from Writeable​Bitmap instance, you may not need to get pixel buffer firstly, just set the WriteableBitmap as the source of image. Both Bitmap​Image and WriteableBitmap can be the image source, not only BitmapImage.
StorageFile imagefile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/caffe1.jpg"));
WriteableBitmap writeableimage;
using (IRandomAccessStream stream = await imagefile.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
writeableimage = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
writeableimage.SetSource(stream);
}
Windows.UI.Xaml.Controls.Image image = new Windows.UI.Xaml.Controls.Image();
image.Source = writeableimage;
stackPanel.Children.Add(image);
If it doesn't from WriteableBitmap, you may need to create a WriteableBitmap with the known width, height, and write pixel data to it.
StorageFile imagefile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/caffe2.jpg"));
int width;
int height;
byte[] Inptrbuffer;
using (IRandomAccessStream stream = await imagefile.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
width = softwareBitmap.PixelWidth;
height = softwareBitmap.PixelHeight;
Windows.Graphics.Imaging.PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
Inptrbuffer = pixelData.DetachPixelData();
}
WriteableBitmap newfrompixel=new WriteableBitmap(width,height);
using (Stream stream = newfrompixel.PixelBuffer.AsStream())
{
await stream.WriteAsync(Inptrbuffer, 0, Inptrbuffer.Length);
}
Windows.UI.Xaml.Controls.Image image = new Windows.UI.Xaml.Controls.Image();
image.Source = newfrompixel;
stackPanel.Children.Add(image);
If you need to edit the image before present it, please reference Create, edit, and save bitmap images.

Saving list of Bitmap Images

I have a list of Bitmap images. I need to save them to local folder.
This doesn't work on windows 10 Universal application.
var serializer = new DataContractSerializer(typeof(List<BitmapImage>));
using (var stream = await ApplicationData.Current.LocalCacheFolder.OpenStreamForWriteAsync(fileName, CreationCollisionOption.ReplaceExisting)) {
serializer.WriteObject(stream, collection);
}
WriteObject method throws the following error
Exception thrown: 'System.Runtime.Serialization.InvalidDataContractException' in System.Private.DataContractSerialization.dll
BitmapImage is not serializable. Convert that to a byte array and write that to disk instead:
public static byte[] ConvertToBytes(BitmapImage bitmapImage)
{
using (var ms = new MemoryStream())
{
var btmMap = new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
btmMap.SaveJpeg(ms, bitmapImage.PixelWidth, bitmapImage.PixelHeight, 0, 100);
return ms.ToArray();
}
}
var serializer = new DataContractSerializer(typeof(byte[]));
using (var stream = await ApplicationData.Current.LocalCacheFolder.OpenStreamForWriteAsync(fileName, CreationCollisionOption.ReplaceExisting)) {
serializer.WriteObject(stream, ConvertToBytes(collection));
}
You cannot extract the bitmap from a BitmapImage. There is no way to save a BitmapImage to file directly. The only way is to remember the original source and save that out. For more details about save BitmapImage to file please reference this thread.
If you know the original source, for example, you read the BitmapImage from the file picked by a FileOpenPicker, then you can read the image file to a WriteableBitmap then you can extract the PixelBuffer, encode it with a BitmapEncoder, and then save the resulting stream to a StorageFile as Rob said. Sample code as follows:
private async void btncreate_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker openpicker = new FileOpenPicker();
openpicker.FileTypeFilter.Add(".jpg");
openpicker.FileTypeFilter.Add(".png");
StorageFile originalimage = await openpicker.PickSingleFileAsync();
WriteableBitmap writeableimage1;
using (IRandomAccessStream stream = await originalimage.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
writeableimage1 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
writeableimage1.SetSource(stream);
}
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile newimage = await folder.CreateFileAsync(originalimage.Name, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream ras = await newimage.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras);
var stream = writeableimage1.PixelBuffer.AsStream();
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, buffer.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage1.PixelWidth, (uint)writeableimage1.PixelHeight, 96.0, 96.0, buffer);
await encoder.FlushAsync();
}
}
For list of images, you may need save them one by one.

Create Tiff File from multiple BitmapImage

Background:
I'm developing Win 10 Universal App, have list of BitmapImage:
List<BitmapImage> ImagesList = new List<BitmapImage>();
Each list item is created by converting byte[] to BitmapImage by this code:
public async Task<BitmapImage> GetBitmapImage(byte[] array)
{
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes(array);
await writer.StoreAsync();
}
BitmapImage image = new BitmapImage();
List<BitmapImage> ImagesList = new List<BitmapImage>();
await image.SetSourceAsync(stream);
return image;
}
}
Question:
How to convert this list to single multi-page Tiff file?
Notes:
I've found many related answers like this but all are based on System.Drawing library which is not supported in Windows 10 Universal Apps, so as you can see in my code, I'm using Windows.Ui.Xaml.Media.Imaging.BitmapImage object instead of System.Drawing.Bitmap to get the image.
How to convert this list to single multi-page Tiff file
In UWP app, we can use BitmapEncoder to encode a Tiff image file to contain several frames. BitmapEncoder.SetPixelData method can be used for setting pixel data on one frame and then BitmapEncoder.GoToNextFrameAsync can asynchronously commits the current frame data and appends a new empty frame to be edited. So the Tiff image can be created by multiply images.
Suppose I want to create a Tiff image file from three images that are located on my local folder, I decode and read pixel data from them and set to the Tiff image. Sample code as follows:
private async void btnConvert_Click(object sender, RoutedEventArgs e)
{
StorageFolder localfolder = ApplicationData.Current.LocalFolder;
StorageFile image1 = await localfolder.GetFileAsync("caffe1.jpg");
StorageFile image2 = await localfolder.GetFileAsync("caffe2.jpg");
StorageFile image3 = await localfolder.GetFileAsync("caffe3.jpg");
StorageFile targettiff = await localfolder.CreateFileAsync("temp.tiff", CreationCollisionOption.ReplaceExisting);
WriteableBitmap writeableimage1;
WriteableBitmap writeableimage2;
WriteableBitmap writeableimage3;
using (IRandomAccessStream stream = await image1.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
writeableimage1 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
writeableimage1.SetSource(stream);
}
using (IRandomAccessStream stream = await image2.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
writeableimage2 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
writeableimage2.SetSource(stream);
}
using (IRandomAccessStream stream = await image3.OpenAsync(FileAccessMode.Read))
{
SoftwareBitmap softwareBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
writeableimage3 = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);
writeableimage3.SetSource(stream);
}
using (IRandomAccessStream ras = await targettiff.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.TiffEncoderId, ras);
var stream = writeableimage1.PixelBuffer.AsStream();
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, buffer.Length);
var stream2 = writeableimage2.PixelBuffer.AsStream();
byte[] buffer2 = new byte[stream2.Length];
await stream2.ReadAsync(buffer2, 0, buffer2.Length);
var stream3 = writeableimage3.PixelBuffer.AsStream();
byte[] buffer3 = new byte[stream3.Length];
await stream3.ReadAsync(buffer3, 0, buffer3.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage1.PixelWidth, (uint)writeableimage1.PixelHeight, 96.0, 96.0, buffer);
await encoder.GoToNextFrameAsync();
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage2.PixelWidth, (uint)writeableimage2.PixelHeight, 96.0, 96.0, buffer2);
await encoder.GoToNextFrameAsync();
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableimage3.PixelWidth, (uint)writeableimage3.PixelHeight, 96.0, 96.0, buffer3);
await encoder.FlushAsync();
}
}
The temp.tiff will be created successfully. I'm not sure how you got the image byte array, but BitmapImage cannot be directly written to or updated, you need to got WriteableBitmap object from your byte array. If you don't know how to get the WriteableBitmap please try to reference the following code or save the BitmapImage to local folder and using the code I provided above.
public async Task<WriteableBitmap> SaveToImageSource(byte[] imageBuffer)
{
using (MemoryStream stream = new MemoryStream(imageBuffer))
{
var ras = stream.AsRandomAccessStream();
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, ras);
var provider = await decoder.GetPixelDataAsync();
byte[] buffer = provider.DetachPixelData();
WriteableBitmap ablebitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
await ablebitmap.PixelBuffer.AsStream().WriteAsync(buffer, 0, buffer.Length);
return ablebitmap;
}
}
More details please reference the official sample.

UWP encode image to PNG

I get an image by URI (web or file system) and want to encode it into PNG and save to a temporary file:
var bin = new MemoryStream(raw).AsRandomAccessStream(); //raw is byte[]
var dec = await BitmapDecoder.CreateAsync(bin);
var pix = (await dec.GetPixelDataAsync()).DetachPixelData();
var res = new FileStream(Path.Combine(ApplicationData.Current.LocalFolder.Path, "tmp.png"), FileMode.Create);
var enc = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, res.AsRandomAccessStream());
enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, dec.PixelWidth, dec.PixelHeight, 96, 96, pix);
await enc.FlushAsync(); //hangs here
res.Dispose();
Problem is, this code hangs on the await enc.FlushAsync() line.
Please help! Thanks.
I don't know for sure why your code hangs -- but you're using several IDisposable thingies, which may be related. At any rate, here's some code that does pretty much what you're trying to do, and it does work:
StorageFile file = await ApplicationData.Current.TemporaryFolder
.CreateFileAsync("image", CreationCollisionOption.GenerateUniqueName);
using (IRandomAccessStream outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (MemoryStream imageStream = new MemoryStream())
{
using (Stream pixelBufferStream = image.PixelBuffer.AsStream())
{
pixelBufferStream.CopyTo(imageStream);
}
BitmapEncoder encoder = await BitmapEncoder
.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)image.PixelWidth,
(uint)image.PixelHeight,
dpiX: 96,
dpiY: 96,
pixels: imageStream.ToArray());
await encoder.FlushAsync();
}
}
(My image is a WriteableBitmap; not sure what your raw is?)

BitmapImage or ImageStream to image file - Windows 10

I have Windows.Graphics.Imaging ImageStream. It is easy to get it as source of XAML Image:
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
XAMLImage.Source = bitmapImage;
But I did not figured out how to save it to image file (png,jpg,...) in Windows 10 app.
Thnx for help.
You can not save a BitmapImage as png or jepg file, you should use WriteableBitmap to instead.
CODE(How to save a WriteableBitmap as JPEG):
var image = new WriteableBitmap(50, 50);
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/StoreLogo.png"));
var content = await file.OpenReadAsync();
image.SetSource(content);
var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("saveas.jpg");
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId,
await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite));
Stream pixelStream = image.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)image.PixelWidth, (uint)image.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();

Categories

Resources