【问题标题】:BitmapEncoder flush throws Argument ExceptionBitmapEncoder 刷新抛出参数异常
【发布时间】:2016-07-27 15:48:03
【问题描述】:

我正在尝试调整我的 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?我如何知道图像是“索引像素格式”,以及如何调整这种格式的大小?

【问题讨论】:

    标签: c# uwp bitmapencoder


    【解决方案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 在编码器上进行设置。

    是一种使用catch异常并再次使用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;                  
        }
    }
    

    【讨论】:

    • 非常感谢!一旦我可以测试它,我会试一试并接受你的答案
    • 不幸的是,这并没有解决问题。 GetPixelDataAsyncSetPixelData 似乎工作正常,但 pixelencoder.FlushAsync(); 仍然抛出 ArgumentException。我已将链接添加到导致我的问题出现此问题的图像。
    • @FlorianMoser,抱歉回复晚了,我只是用您提供的图像测试了我的第一个代码块,我无法重现问题?从您的第二个链接中,我发现您下载了该图像,可以下载吗?我没有测试下载图像然后对其进行转换,我只是将您的图像放入图片库并使用 FileOpenPicker 选择此图像,它工作正常。我的操作系统版本是 10586。
    • 我正在开发技术预览版 (14393.5),并为最小和最大版本 10586 构建。问题仍然发生在我的机器上,我添加了更多单元测试来确认这一点。我认为您的示例和我的代码之间的唯一区别是使用的流,也许那里有问题,我会尽快尝试更多。
    • 我无法再重现此错误
    猜你喜欢
    • 1970-01-01
    • 2019-12-19
    • 2012-02-14
    • 2013-11-18
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    相关资源
    最近更新 更多