Сброс BitmapEncoder генерирует исключение аргумента
Я пытаюсь изменить размеры изображений в моем приложении UWP. Большую часть времени прилагаемый код работает, но иногда await encoder.FlushAsync();
бросает ArgumentException
,
Я направился в MSDN ( https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.bitmaptransform.aspx), и мне сказали (в "Замечаниях"):
Если вы попытаетесь масштабировать изображение, хранящееся в индексированном пиксельном формате, используя член BitmapTransform, FlushAsync завершится ошибкой с HRESULT WINCODEC_ERR_INVALIDPARAMETER . Вместо этого вы должны использовать GetPixelDataAsync, чтобы получить масштабированные данные пикселей, а затем использовать SetPixelData, чтобы установить их в кодировщике.
Я пытался сделать это, увидеть две закомментированные строки (которые выглядят как-то неправильно из-за повторения). На второй линии (где я пытаюсь SetPixelData
) Кодировщик награждает меня buffer allocated not sufficient
Исключение.
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
}
Пример изображения, которое вызывает эту проблему: http://www.spiegel.de/images/image-1028227-hppano-lqbn.jpg. Модульное тестирование здесь: https://github.com/famoser/OfflineMedia/blob/master/Famoser.OfflineMedia.UnitTests/Presentation/ImageResizeTest.cs
Как я могу избежать ArgumentException
? Как я могу узнать, что изображение в "индексированном пиксельном формате", и как мне изменить его размер?
1 ответ
Во второй строке (где я пытаюсь установить SetPixelData) кодировщик награждает меня буфером, выделенным не достаточным исключением.
Это потому что когда ты SetPixelData
данные пикселей не совпадают с GetPixelDataAsync
, Вы можете, например, код, как это:
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;
}
}
Как я могу узнать, что изображение в "индексированном пиксельном формате", и как мне изменить его размер?
Я не мог найти какой-либо эффективный способ обнаружения изображения в формате индексированного пикселя, но так как он сказал
Если вы попытаетесь масштабировать изображение, хранящееся в индексированном пиксельном формате, используя член BitmapTransform, FlushAsync завершится ошибкой с HRESULT WINCODEC_ERR_INVALIDPARAMETER . Вместо этого вы должны использовать GetPixelDataAsync, чтобы получить масштабированные данные пикселей, а затем использовать SetPixelData, чтобы установить их в кодировщике.
Это метод для использования поймать исключение и использовать SetPixelData
еще раз, например:
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;
}
}