BitmapEncoder FlushAsync throws Argument Exception - c# - c#

When I'm using below code for image processing it throws exception at FlushAsync(). Strangely this issue happens for some video files only. Can you help why this happen ?
private async Task<String> PreProcessVideoToGetTextAsync(StorageFile file, int i)
{ /*--------To get frame from video----------*/
var thumbnail = await GetThumbnailAsync(file, i);
BitmapImage bitmapImage = new BitmapImage();
StringBuilder ocr = null;
InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
await RandomAccessStream.CopyAsync(thumbnail, randomAccessStream);
randomAccessStream.Seek(0);
SoftwareBitmap inputBitmap;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
// create a new stream and encoder for the new image
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
BitmapBounds bounds = new BitmapBounds();
bounds.Height = 270;//screnheight/4 =270
bounds.Width = 960;//screenwidth/2 =960
bounds.X = 960;//screenwidth/2 =960
bounds.Y = 810;
enc.BitmapTransform.Bounds = bounds;
// write out to the stream
try
{
await enc.FlushAsync();
}
catch (Exception ex)
{
string exx = ex.ToString();
var dialog = new MessageDialog(exx);
await dialog.ShowAsync();
}
//Remain portion of code
}

I've already used the following code snippet to save video thumbnails in my uwp app, hopefully you can apply a little bit of changes as you want to use it.
private async Task PreProcessVideoToGetTextAsync(string videopath)
{
try
{
SoftwareBitmap softwareBitmap = null;
StorageFile videofile = await StorageFile.GetFileFromPathAsync(videopath);
var thumbnail = await GetThumbnailAsync(videofile);
Windows.Storage.Streams.InMemoryRandomAccessStream randomAccessStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
await Windows.Storage.Streams.RandomAccessStream.CopyAsync(thumbnail, randomAccessStream);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
StorageFile outputFile = await ApplicationData.Current.LocalCacheFolder.CreateFileAsync(Path.GetFileNameWithoutExtension(videopath) + ".jpg");//save path for video thumbnail image in app cache folder
using (Windows.Storage.Streams.IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetSoftwareBitmap(softwareBitmap);
encoder.BitmapTransform.ScaledWidth = 128;//thumbnail width
encoder.BitmapTransform.ScaledHeight = 128;//thumbnail height
encoder.IsThumbnailGenerated = true;
try
{
await encoder.FlushAsync();
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
var source = new Windows.UI.Xaml.Media.Imaging.SoftwareBitmapSource();
await source.SetBitmapAsync(softwareBitmap);
return;
}
catch (Exception err)
{
switch (err.HResult)
{
case unchecked((int)0x88982F81): //WINCODEC_ERR_UNSUPPORTEDOPERATION
// If the encoder does not support writing a thumbnail, then try again
// but disable thumbnail generation.
encoder.IsThumbnailGenerated = false;
break;
default:
throw err;
}
}
if (encoder.IsThumbnailGenerated == false)
{
await encoder.FlushAsync();
}
}
return;
}
catch (Exception)
{
return;
}
finally
{
GC.Collect();
}
}
private async Task<Windows.Storage.Streams.IInputStream> GetThumbnailAsync(StorageFile file)
{
var mediaClip = await Windows.Media.Editing.MediaClip.CreateFromFileAsync(file);
var mediaComposition = new Windows.Media.Editing.MediaComposition();
mediaComposition.Clips.Add(mediaClip);
return await mediaComposition.GetThumbnailAsync(
TimeSpan.Zero, 0, 0, Windows.Media.Editing.VideoFramePrecision.NearestFrame);
}
}

Related

Error when convert byte array to BitmapImage in UWP

I want to get a BitmapImage when capture view's screenshot. So I start to get byte array data first, then convert to BitmapImage.
RenderTargetBitmap renderTarget = new RenderTargetBitmap();
await renderTarget.RenderAsync(swapChainPanel);
IBuffer pixelBuffer = await renderTarget.GetPixelsAsync();
await GetBitmapAsync(pixelBuffer.ToArray());
...
public static async Task<BitmapImage> GetBitmapAsync(byte[] data)
{
var bitmapImage = new BitmapImage();
try
{
using (var stream = new InMemoryRandomAccessStream())
{
using (var writer = new DataWriter(stream))
{
writer.WriteBytes(data);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
}
stream.Seek(0);
await bitmapImage.SetSourceAsync(stream); // throw Exception
}
return bitmapImage;
}
catch (Exception e)
{
return null;
}
}
But it give error :
The component cannot be found. (Exception from HRESULT: 0x88982F50)
Please help me to find the problem.
Error when convert byte array to BitmapImage in UWP
The problem is you have not specific BitmapEncoder for BitmapImage when convertering. In general, we often use the following code to get BitmapImage from bytes.
_backAction = new Action<byte[]>(async (bytes) =>
{
InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
BitmapImage img = new BitmapImage();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)48,
(uint)32,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
bytes);
await encoder.FlushAsync();
await img.SetSourceAsync(stream);
});

Resize image and save as file

My objective is to resize an image that I create and after resizing it with the same ratio and finally save it on my drive.
so just below the code is working I'm 100% sure that the code work
The problem is on the ResizeImage method.
Everything work well until the decoder, I don't know why but it always return me the code:
System.Exception: 'The component was not found. (Exception from HRESULT: 0x88982F50)'
private async Task<StorageFile> SaveSquaresPhotos(WriteableBitmap WB, FileFormat fileFormat, string username) {
string FileName = username + "-Carre.";
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;
}
if (config.getFolder() == null)
{
try
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
var folder = await StorageFolder.GetFolderFromPathAsync(resourceLoader.GetString("Folder"));
var file = await folder.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 ResizeImage(pixels, 75, 75, pixelStream);
await encoder.FlushAsync();
}
return file;
}
catch {
var file = await _captureFolder.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 ResizeImage(pixels, 75, 75, pixelStream);
await encoder.FlushAsync();
}
return file;
}
}
else
{
var file = await config.getFolder().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 ResizeImage(pixels, 75, 75, pixelStream);
await encoder.FlushAsync();
}
return file;
}
}
public async Task<byte[]> ResizeImage(byte[] imageData, int reqWidth, int reqHeight, Stream stream)
{
var memStream = new MemoryStream();
stream.Position = 0;
await stream.CopyToAsync(memStream);
IRandomAccessStream imageStream = memStream.AsRandomAccessStream();
imageStream.Seek(0);
//The problem start just below
var decoder = await BitmapDecoder.CreateAsync(imageStream);
if (decoder.PixelHeight > reqHeight || decoder.PixelWidth > reqWidth)
{
using (imageStream)
{
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];
uint x = await resizedStream.WriteAsync(outBuffer.AsBuffer());
return outBuffer;
}
}
return imageData;
}
if someone can tell me where the problem is from, I'll be very grateful.
Edit:
I found the solution.
First my call for the second method was not on the correct line.
Finally I found an other method for resizing my file, that was more close to what I had.
private async Task<StorageFile> SaveThumbsPhotos(WriteableBitmap WB, FileFormat fileFormat, string username)
{
string FileName = username + "-Thumbs.";
Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
switch (fileFormat)
{
case FileFormat.Jpg:
FileName += "jpg";
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;
}
if (config.getFolder() == null)
{
try
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
var folder = await StorageFolder.GetFolderFromPathAsync(resourceLoader.GetString("Folder"));
var file = await folder.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();
}
await RescaleImage(file, 75, 75, username);
return file;
}
catch
{
var file = await _captureFolder.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();
}
await RescaleImage(file, 75, 75, username);
return file;
}
}
else
{
var file = await config.getFolder().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();
}
await RescaleImage(file, 75, 75, username);
return file;
}
}
private async Task<StorageFile> RescaleImage(StorageFile source, uint width, uint height, string username)
{
var imageStream = await source.OpenReadAsync();
var decoder = await BitmapDecoder.CreateAsync(imageStream);
using (var resizedStream = await source.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
encoder.BitmapTransform.ScaledWidth = width;
encoder.BitmapTransform.ScaledHeight = height;
await encoder.FlushAsync();
}
return source;
}

Get a new Image by cropping

I'm trying to convert my cropped image (and/or Grid) to new Normal Image , but it returns as it cropped , in same position, how to fix it, there is how works my program after cropping
private async void Save(object sender, RoutedEventArgs e)
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(GGrid, 4096 , 2448);
// IBuffer pixels = await renderTargetBitmap.GetPixelsAsync();
IBuffer pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
FileSavePicker fileSavePicker = new FileSavePicker();
fileSavePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
fileSavePicker.FileTypeChoices.Add("JPEG files", new List<string>() { ".png"});
fileSavePicker.SuggestedFileName = "image";
var outputFile = await fileSavePicker.PickSaveFileAsync();
if (outputFile == null)
{
// The user cancelled the picking operation
return;
}
using (IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
try
{
await encoder.FlushAsync();
}
catch (Exception err)
{
switch (err.HResult)
{
case unchecked((int)0x88982F81): //WINCODEC_ERR_UNSUPPORTEDOPERATION
// If the encoder does not support writing a thumbnail, then try again
// but disable thumbnail generation.
encoder.IsThumbnailGenerated = false;
break;
default:
throw err;
}
}
//if (encoder.IsThumbnailGenerated == false)
//{
// await encoder.FlushAsync();
//}
}
}
You need to translate and crop the bitmap.
double x,y,w,h;
GGrid.RenderTransform = new TranslateTransform
{
X = -x, // translate back to origin (0,0)
Y = -y
};
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(GGrid, w, h); // use crop size

How to save <Image /> content to file

I have to save a content from Image tag to a file. I used a lot of Uncle Google but he doesn't know :(
private void QRbutton_Click(object sender, RoutedEventArgs e)
{
IBarcodeWriter writer = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new ZXing.Common.EncodingOptions
{
Height = 1200,
Width = 1200
}
};
String message = "";
if (String.IsNullOrEmpty(QRtxt.Text))
{
message = "You send empty message. ";
}
else
{
//Saving Input to string
message = QRtxt.Text;
StckPnlProfile_Layout.Visibility = Visibility.Collapsed;
QRsendbtn.Visibility = Visibility.Visible;
}
var result = writer.Write(message);
var wb = result.ToBitmap() as WriteableBitmap;
System.Diagnostics.Debug.WriteLine("BEFORE[Saving image to file]");
QRimage.Source = wb;
}
And there is XAML code of Image:
<Image x:Name="QRimage" Height="300"/>
I think your only option can be using RenderTargetBitmap class , it captures an image from any UIElement inherited class type like Image.
https://msdn.microsoft.com/library/windows/apps/xaml/windows.ui.xaml.media.imaging.rendertargetbitmap.aspx
HesamM, thank you for your response. Actually I did it in this way:
private async void saveImage(object sender, RoutedEventArgs e)
{
Debug.WriteLine("********** Function STARTED: Save QR code as image to jpg **********");
try
{
System.Diagnostics.Debug.WriteLine("Searching for assets folder.");
var package = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder localFolder = await package.GetFolderAsync("Assets");
StorageFile file = await localFolder.CreateFileAsync("savedimage.jpg", CreationCollisionOption.ReplaceExisting);
var renderTargetBitmap = new RenderTargetBitmap();
System.Diagnostics.Debug.WriteLine("Rendering an image.");
await renderTargetBitmap.RenderAsync(QRimage);
var pixels = await renderTargetBitmap.GetPixelsAsync();
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
System.Diagnostics.Debug.WriteLine("Save QR code to jpg.");
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
bytes);
await encoder.FlushAsync();
}
MessageDialog SuccessMsg = new MessageDialog("Code QR saved.");
await SuccessMsg.ShowAsync();
}
catch (Exception ex)
{
//MessageDialog ErrMsg = new MessageDialog("Error Ocuured!");
System.Diagnostics.Debug.WriteLine("ERROR ZAPISU PLIKU: " + ex);
}
Debug.WriteLine("********** Function STOPPED: Save QR code as image to jpg **********");
}

BitmapEncoder flush throws Argument Exception

I'm trying to resize images in my UWP application. Most of the time the appended code works, but sometimes await encoder.FlushAsync(); throws an ArgumentException.
I've headed over to MSDN (https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.bitmaptransform.aspx) and they tell me (at "Remarks"):
If you try scale an image stored in an indexed pixel format using the BitmapTransform member, FlushAsync fails with HRESULT WINCODEC_ERR_INVALIDPARAMETER . Instead, you must use GetPixelDataAsync to obtain the scaled pixel data and then use SetPixelData to set it on the encoder.
I've tried to do that, see the two commented lines (which look somehow wrong to me due to the repetition). On the second line (where I try to SetPixelData) the Encoder rewards me with an buffer allocated not sufficient Exception.
var decoder = await BitmapDecoder.CreateAsync(streamToReadFrom.AsStream().AsRandomAccessStream());
if (decoder.OrientedPixelHeight > height ||
decoder.OrientedPixelWidth > width)
{
var resizedStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.BitmapTransform.ScaledHeight = newHeight;
encoder.BitmapTransform.ScaledWidth = newWidth;
//"buffer allocated not sufficient"
// var pd = await decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba16, BitmapAlphaMode.Ignore,
// encoder.BitmapTransform, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
// encoder.SetPixelData(BitmapPixelFormat.Rgba16, BitmapAlphaMode.Ignore,
// decoder.OrientedPixelWidth, decoder.OrientedPixelHeight, decoder.DpiX, decoder.DpiY, pd.DetachPixelData());
// write out to the stream
// might fail cause https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.bitmaptransform.aspx
await encoder.FlushAsync();
// Read out resizedStream and return
}
Example image which causes this issue: http://www.spiegel.de/images/image-1028227-hppano-lqbn.jpg. Unit Test here: https://github.com/famoser/OfflineMedia/blob/master/Famoser.OfflineMedia.UnitTests/Presentation/ImageResizeTest.cs
How can I avoid the ArgumentException? How do I know an image is in an "indexed pixel format", and how can I resize this format too?
On the second line (where I try to SetPixelData) the Encoder rewards me with an buffer allocated not sufficient Exception.
This is because when you SetPixelData, the pixel data doesn't match it from GetPixelDataAsync. You can for example code like this:
if (file != null)
{
BitmapImage bmp = new BitmapImage();
using(var imageStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream);
InMemoryRandomAccessStream pixelras = new InMemoryRandomAccessStream();
BitmapEncoder pixelencoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, pixelras);
BitmapTransform transform = new BitmapTransform();
transform.InterpolationMode = BitmapInterpolationMode.Fant;
transform.ScaledHeight = 400;
transform.ScaledWidth = 400;
var provider = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
var pixels = provider.DetachPixelData();
pixelencoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, 400,
400, decoder.DpiX, decoder.DpiY, pixels);
try
{
await pixelencoder.FlushAsync();
}
catch(Exception ex)
{
}
bmp.SetSource(pixelras);
img.Source = bmp;
}
}
How do I know an image is in an "indexed pixel format", and how can I resize this format too?
I couldn't find any effective way to detect an indexed pixel format image, but since it is said
If you try scale an image stored in an indexed pixel format using the BitmapTransform member, FlushAsync fails with HRESULT WINCODEC_ERR_INVALIDPARAMETER . Instead, you must use GetPixelDataAsync to obtain the scaled pixel data and then use SetPixelData to set it on the encoder.
It is a method to use catch the exception and use SetPixelData again, for example:
if (file != null)
{
BitmapImage bmp = new BitmapImage();
using(var imageStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream);
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.BitmapTransform.ScaledHeight = 400;
encoder.BitmapTransform.ScaledWidth = 400;
try
{
await encoder.FlushAsync();
bmp.SetSource(ras);
}
catch (Exception ex)
{
if (ex.HResult.ToString() == "WINCODEC_ERR_INVALIDPARAMETER")
{
InMemoryRandomAccessStream pixelras = new InMemoryRandomAccessStream();
BitmapEncoder pixelencoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, pixelras)
BitmapTransform transform = new BitmapTransform();
transform.InterpolationMode = BitmapInterpolationMode.Fant;
transform.ScaledHeight = 400;
transform.ScaledWidth = 400;
var provider = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
var pixels = provider.DetachPixelData();
pixelencoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, 400,
400, decoder.DpiX, decoder.DpiY, pixels);
try
{
await pixelencoder.FlushAsync();
bmp.SetSource(pixelras);
}
catch
{
}
}
}
img.Source = bmp;
}
}

Categories

Resources