I want to save a section of an image taken with a webcam (using Windows.Media.Capture).
Here is what I got so far:
[...]
MediaCapture mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
await mediaCapture.StartPreviewAsync();
public async void takePhoto(){
var lowLagCapture = await mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));
var capturedPhoto = await lowLagCapture.CaptureAsync();
await lowLagCapture.FinishAsync();
await CapturePhotoWithOrientationAsync();
}
private async Task CapturePhotoWithOrientationAsync() {
var captureStream = new InMemoryRandomAccessStream();
try {
await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);
} catch (Exception ex) {
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
return;
}
var decoder = await BitmapDecoder.CreateAsync(captureStream);
var file = await storageFolder.CreateFileAsync("test.jpeg", CreationCollisionOption.ReplaceExisting);
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) {
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(Windows.Devices.Sensors.SimpleOrientation.Rotated270DegreesCounterclockwise);
var properties = new BitmapPropertySet {
{ "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
await encoder.BitmapProperties.SetPropertiesAsync(properties);
await encoder.FlushAsync();
}
}
[...]
This way I can save the whole image. But how can I only save a section of the image?
But how can I only save a section of the image?
With a start point and size you could define a crop bound, and then create a BitmapTransform, with this transform you can get the cropped image pixies by GetPixelDataAsync() method. BitmapEncoder can SetPixelData. Details for how to do please reference How to crop bitmap in a Windows Store app (C#) sample and this tutorial.
For example, based on your code snippet:
//Inside CapturePhotoWithOrientationAsync method
...
Point startPoint = new Point(0, 0);
Size corpSize = new Size(250, 250);
// Convert start point and size to integer.
uint startPointX = (uint)Math.Floor(startPoint.X);
uint startPointY = (uint)Math.Floor(startPoint.Y);
uint height = (uint)Math.Floor(corpSize.Height);
uint width = (uint)Math.Floor(corpSize.Width);
// Refine the start point and the size.
if (startPointX + width > decoder.PixelWidth)
{
startPointX = decoder.PixelWidth - width;
}
if (startPointY + height > decoder.PixelHeight)
{
startPointY = decoder.PixelHeight - height;
}
// Create cropping BitmapTransform to define the bounds.
BitmapTransform transform = new BitmapTransform();
BitmapBounds bounds = new BitmapBounds();
bounds.X = startPointX;
bounds.Y = startPointY;
bounds.Height = height;
bounds.Width = width;
transform.Bounds = bounds;
// Get the cropped pixels within the the bounds of transform.
PixelDataProvider pix = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.ColorManageToSRgb);
byte[] pixels = pix.DetachPixelData();
StorageFolder storageFolder = KnownFolders.PicturesLibrary;
var file = await storageFolder.CreateFileAsync("test.jpeg", CreationCollisionOption.ReplaceExisting);
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
// Set the pixel data to the cropped image.
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
width,
height,
decoder.DpiX,
decoder.DpiY,
pixels);
// Flush the data to file.
await encoder.FlushAsync();
}
Related
I am trying to generate a pdf in my project where I converted Image into Pdf and Image generated from Layout. Generated image size is very large and also There are not received good quality.
Please Help me to solve this.
I am using this code in program.
RenderTargetBitmap renderTargetBitmapimg = new RenderTargetBitmap();
var mainlayoutHeight = pageStackPanel.ActualHeight;
var mainlayoutWidth = pageStackPanel.ActualWidth;
int mlHeight = Convert.ToInt32(mainlayoutHeight);
int mlWidth = Convert.ToInt32(mainlayoutWidth);
await renderTargetBitmapimg.RenderAsync(pageStackPanel, mlWidth, mlHeight);
///SAVE IMAGE IN FOLDER
var pixelBufferimg = await renderTargetBitmapimg.GetPixelsAsync();
var pixels = pixelBufferimg.ToArray();
var displayInformation = DisplayInformation.GetForCurrentView();
var storageFolder = await KnownFolders.GetFolderForUserAsync(null, KnownFolderId.PicturesLibrary);
StorageFolder projectFolder = await storageFolder.CreateFolderAsync("TestImage", CreationCollisionOption.OpenIfExists);
var file = await projectFolder.CreateFileAsync(jpgFilename, CreationCollisionOption.GenerateUniqueName);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)renderTargetBitmapimg.PixelWidth,
(uint)renderTargetBitmapimg.PixelHeight,
200, 200,
pixels);
await encoder.FlushAsync();
StorageFile prescriptionJpgFile = await projectFolder.GetFileAsync(jpgFilename);
await stream.FlushAsync();
stream.Seek(0);
stream.Dispose();
renderTargetBitmapimg = null;
The answer is no, you can't set the size of the generated image file. But you could try to resize it to reduce its physical size by giving a specific width and height. You could use BitmapEncoder class to encode the original image, change the BitmapInterpolationMode of the image. The code looks like this:
//open file as stream
using (IRandomAccessStream fileStream = await imagefile.OpenAsync(FileAccessMode.ReadWrite))
{
var decoder = await BitmapDecoder.CreateAsync(fileStream);
var resizedStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder);
double widthRatio = (double)reqWidth / decoder.PixelWidth;
double heightRatio = (double)reqHeight / decoder.PixelHeight;
double scaleRatio = Math.Min(widthRatio, heightRatio);
if (reqWidth == 0)
scaleRatio = heightRatio;
if (reqHeight == 0)
scaleRatio = widthRatio;
uint aspectHeight = (uint)Math.Floor(decoder.PixelHeight * scaleRatio);
uint aspectWidth = (uint)Math.Floor(decoder.PixelWidth * scaleRatio);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
encoder.BitmapTransform.ScaledHeight = aspectHeight;
encoder.BitmapTransform.ScaledWidth = aspectWidth;
await encoder.FlushAsync();
resizedStream.Seek(0);
var outBuffer = new byte[resizedStream.Size];
await resizedStream.ReadAsync(outBuffer.AsBuffer(), (uint)resizedStream.Size, InputStreamOptions.None);
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
Debug.WriteLine(storageFolder.Path);
StorageFile sampleFile = await storageFolder.CreateFileAsync("testfile.pdf", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBytesAsync(sampleFile, outBuffer);
}
For more information, you could check this document:How to Compress image and change its Size.
Another suggestion is that you could just use the UWP print API to generate the PDF file. You could take a look at the Print Helper of Windows Community Toolkit. You could choose not to print but save it as a PDF file.
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
}
I'm working with UWP app. I'm generating set of WriteableBitmap's and after that, i want to add it to MediaComposition and play in video player. I found one way how to do this, but it's really slow. Here is my code:
var clip = await MediaClip.CreateFromImageFileAsync(await
WriteableBitmapToStorageFile(wb), new TimeSpan(0, 0, 0, 0, 1));
(...)
private static async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap WB)
{
string FileName = "MyFile.";
Guid BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
FileName += "tiff";
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;
}
Function "WriteableBitmapToStorageFile" takes almost 400ms to proceed WriteableBitmap. Is there any option to do it faster? I know, that MediaClip can be created from IDirect3DSurface but i don't know how to convert to it from WriteableBitmap.
Ok as #Johnny Westlake mentioned i used CanvasBitmap to draw my images. But now, after drawing many images only last image is displayed. Code:
public static CanvasDevice device = new CanvasDevice();
public static CanvasRenderTarget renderer = new CanvasRenderTarget(device, 2048, 1080, 96);
public static CanvasBitmap cb = CanvasBitmap.CreateFromBytes(device, new byte[64*64*4], 64, 64, Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalizedSrgb);
public static Rect dest = new Rect
{
Width = 2048,
Height = 1080
};
public static Rect src = new Rect
{
Width = 64,
Height = 64
};
private static CanvasBitmap GenerateHeatmap(byte[] renderedHeatmap )
{
cb.SetPixelBytes(renderedHeatmap);
using (var ds = renderer.CreateDrawingSession())
{
ds.DrawImage(cb, dest, src, 1, CanvasImageInterpolation.Cubic, CanvasComposite.Copy);
}
return renderer;
}
(...)
Later in the code:
cb = GenerateHeatmap(renderedHeatmap);
MediaOverlay mediaOverlay = new MediaOverlay(MediaClip.CreateFromSurface(cb, new TimeSpan(0, 0, 0, 0, 1)));
mediaOverlay.Position = overlayPosition;
mediaOverlay.Opacity = heatmapOpacity;
return mediaOverlay;
After i did it many times at the end there was only one image in MediaOverlays
To create a video file by WriteableBitmap and MediaClip which created from IDirect3DSurface, you can try the following code using CanvasBitmap.
private async void CreateVideoFromWritableBitmapAsync(List<WriteableBitmap> WBs)
{
var mediaComposition = new MediaComposition();
foreach (WriteableBitmap WB in WBs)
{
var pixels = WB.PixelBuffer.ToArray();
CanvasBitmap bitmap = CanvasBitmap.CreateFromBytes(CanvasDevice.GetSharedDevice(), pixels,
64, 64, DirectXPixelFormat.B8G8R8A8UIntNormalized);
MediaClip mediaClip = MediaClip.CreateFromSurface(bitmap, TimeSpan.FromSeconds(1));
mediaComposition.Clips.Add(mediaClip);
}
//Save the video
var file =await ApplicationData.Current.LocalFolder.CreateFileAsync("WBVideo.mp4");
await mediaComposition.SaveAsync(file);
mediaComposition=await MediaComposition.LoadAsync(file);
await mediaComposition.RenderToFileAsync(file);
}
I have a problem to place an image with down-scale. Image is rasterized and I don't know find way to place it correctly.
Is it possible to place picture without losing quality ?
Code:
public async Task<BitmapImage> BitmapTransform(string filePath, uint width)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return null;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
double ration =
enc.BitmapTransform.ScaledWidth = width;
enc.BitmapTransform.ScaledHeight = (uint)(((double)decoder.PixelHeight / (double)decoder.PixelWidth) * (double)width);
// write out to the stream
try
{
await enc.FlushAsync();
}
catch (Exception ex)
{
string s = ex.ToString();
}
// render the stream to the screen
BitmapImage bImg = new BitmapImage();
bImg.SetSource(ras);
return bImg;
}
You can choose the way of resizing - Nearest Neighbor, Linear, Cubic, Fant - by BitmapTransform.InterporationMode property.
Have you tried it?
https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmaptransform.interpolationmode
double ration =
enc.BitmapTransform.ScaledWidth = width;
enc.BitmapTransform.ScaledHeight = (uint)(((double)decoder.PixelHeight / (double)decoder.PixelWidth) * (double)width);
enc.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Cubic; // <----- Set the Interporation mode here
But the quality of result is vary. It's depend on the original image.
I've got simple question, but so far I've found no answer: how to resize jpeg image in C# WinRT/WinMD project and save it as new jpeg?
I'm developing Windows 8 Metro application for downloading daily image form certain site and displaying it on a Live Tile. The problem is the image must be smaller than 1024x1024 and smaller than 200kB, otherwise it won't show on the tile:
http://msdn.microsoft.com/en-us/library/windows/apps/hh465403.aspx
If I got larger image, how to resize it to be fit for the Live Tile? I'm thinking just about simple resize like width/2 and height/2 with keeping the aspect ration.
The specific requirement here is that the code must run as Windows Runtime Component, so WriteableBitmapEx library won't work here - it's only available for regular WinRT projects. There is even a branch for WriteableBitmapEx as winmd project, but it's far from ready.
Example of how to scale and crop taken from here:
async private void BitmapTransformTest()
{
// hard coded image location
string filePath = "C:\\Users\\Public\\Pictures\\Sample Pictures\\fantasy-dragons-wallpaper.jpg";
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
// convert the entire bitmap to a 100px by 100px bitmap
enc.BitmapTransform.ScaledHeight = 100;
enc.BitmapTransform.ScaledWidth = 100;
BitmapBounds bounds = new BitmapBounds();
bounds.Height = 50;
bounds.Width = 50;
bounds.X = 50;
bounds.Y = 50;
enc.BitmapTransform.Bounds = bounds;
// write out to the stream
try
{
await enc.FlushAsync();
}
catch (Exception ex)
{
string s = ex.ToString();
}
// render the stream to the screen
BitmapImage bImg = new BitmapImage();
bImg.SetSource(ras);
img.Source = bImg; // image element in xaml
}
More simpler code to re-size the image, not crop. The below code re-size the image as 80x80
using (var sourceStream = await sourceFile.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceStream);
BitmapTransform transform = new BitmapTransform() { ScaledHeight = 80, ScaledWidth = 80 };
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
using (var destinationStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, 80, 80, 96, 96, pixelData.DetachPixelData());
await encoder.FlushAsync();
}
}
Source
So here is my solution I came with after lot of googling and trial/error coding:
The goal here was to find out, how to manipulate images in WinRT, specifically in Background Tasks. Background Tasks are even more limited than just regular WinRT projects, because they must be of type Windows Runtime Component. 99% of available libraries on NuGet targeting WinRT are targeting only the default WinRT projects, therefore they cannot be used in Windows Runtime Component projects.
At first I tried to use the well-known WriteableBitmapEx library - porting the necessary code to my winmd project. There is even branch of the WBE project targeting winmd, but it is unfinished. I made it compile after adding [ReadOnlyArray], [WriteOnlyArray] attributes to method parameters of type array and also after changing the project namespace to something not starting with "Windows" - winmd project limitation.
Even though I was able to use this library in my Background Task project it wasn't working, because, as I discovered, WriteableBitmap must be instantiated in UI thread and this is not possible as far as I know in Background Task.
In the meantime I have also found this MSDN article about Image manipulation in WinRT. Most of samples there are only in the JavaScript section, so I had to convert it to C# first. I've also found this helpful article on StackOverflow about image manipulation in WinRT.
internal static async Task LoadTileImageInternalAsync(string imagePath)
{
string tileName = imagePath.GetHashedTileName();
StorageFile origFile = await ApplicationData.Current.LocalFolder.GetFileAsync(imagePath);
// open file for the new tile image file
StorageFile tileFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(tileName, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream tileStream = await tileFile.OpenAsync(FileAccessMode.ReadWrite))
{
// get width and height from the original image
IRandomAccessStreamWithContentType stream = await origFile.OpenReadAsync();
ImageProperties properties = await origFile.Properties.GetImagePropertiesAsync();
uint width = properties.Width;
uint height = properties.Height;
// get proper decoder for the input file - jpg/png/gif
BitmapDecoder decoder = await GetProperDecoder(stream, imagePath);
if (decoder == null) return; // should not happen
// get byte array of actual decoded image
PixelDataProvider data = await decoder.GetPixelDataAsync();
byte[] bytes = data.DetachPixelData();
// create encoder for saving the tile image
BitmapPropertySet propertySet = new BitmapPropertySet();
// create class representing target jpeg quality - a bit obscure, but it works
BitmapTypedValue qualityValue = new BitmapTypedValue(TargetJpegQuality, PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
// create the target jpeg decoder
BitmapEncoder be = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, tileStream, propertySet);
be.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96.0, 96.0, bytes);
// crop the image, if it's too big
if (width > MaxImageWidth || height > MaxImageHeight)
{
BitmapBounds bounds = new BitmapBounds();
if (width > MaxImageWidth)
{
bounds.Width = MaxImageWidth;
bounds.X = (width - MaxImageWidth) / 2;
}
else bounds.Width = width;
if (height > MaxImageHeight)
{
bounds.Height = MaxImageHeight;
bounds.Y = (height - MaxImageHeight) / 2;
}
else bounds.Height = height;
be.BitmapTransform.Bounds = bounds;
}
// save the target jpg to the file
await be.FlushAsync();
}
}
private static async Task<BitmapDecoder> GetProperDecoder(IRandomAccessStreamWithContentType stream, string imagePath)
{
string ext = Path.GetExtension(imagePath);
switch (ext)
{
case ".jpg":
case ".jpeg":
return await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, stream);
case ".png":
return await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, stream);
case ".gif":
return await BitmapDecoder.CreateAsync(BitmapDecoder.GifDecoderId, stream);
}
return null;
}
In this sample we open one file, decode it into byte array, and encode it back into new file with different size/format/quality.
The result is fully working image manipulation even in Windows Runtime Component Class and without WriteableBitmapEx library.
Here is even shorter version, without overhead of accessing pixel data.
using (var sourceFileStream = await sourceFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
using (var destFileStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceFileStream);
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(destFileStream, decoder);
enc.BitmapTransform.ScaledWidth = newWidth;
enc.BitmapTransform.ScaledHeight = newHeight;
await enc.FlushAsync();
await destFileStream.FlushAsync();
}
I just spent the last hour and half trying to figure this one out, I have a byte array that is a JPG and tried the answer given... I could not get it to work so I am putting up a new answer... Hopefully this will help someone else out... I am converting the JPG to 250/250 pixels
private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
{
BitmapImage image = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes((byte[])byteArray);
writer.StoreAsync().GetResults();
}
image.SetSource(stream);
}
image.DecodePixelHeight = 250;
image.DecodePixelWidth = 250;
return image;
}
if you want quality image then add
InterpolationMode = BitmapInterpolationMode.Fant in BitmapTransform ,
here is example
`
public static async Task ResizeImage(Windows.Storage.StorageFile imgeTOBytes, int maxWidth, int maxHeight)
{
using (var sourceStream = await imgeTOBytes.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceStream);
double widthRatio = (double)maxWidth / decoder.OrientedPixelWidth;
double heightRatio = (double)maxHeight / decoder.OrientedPixelHeight;
double scaleRatio = Math.Min(widthRatio, heightRatio);
uint aspectHeight = (uint)Math.Floor((double)decoder.OrientedPixelHeight * scaleRatio);
uint aspectWidth = (uint)Math.Floor((double)decoder.OrientedPixelWidth * scaleRatio);
BitmapTransform transform = new BitmapTransform() { InterpolationMode = BitmapInterpolationMode.Fant, ScaledHeight = aspectHeight, ScaledWidth = aspectWidth };
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Premultiplied,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
using (var destinationStream = await imgeTOBytes.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, aspectWidth, aspectHeight, 96, 96, pixelData.DetachPixelData());
await encoder.FlushAsync();
}
}`