8

我和一个朋友昨晚大部分时间都在试图在 Metro 应用程序中处理一些图像时差点把头发扯下来。我们通过分享功能将图像放入应用程序,然后我想用它们做一些其他的工作,裁剪图像并将它们保存回 appdata 文件夹。事实证明这非常令人沮丧。

我的问题,在这一切结束时,将是“这样做的正确方法是什么,而不觉得我正在拼凑一堆不匹配的拼图?”

当与应用程序共享多个图像时,它们以Windows.Storage.StorageFiles 列表的形式出现。这是一些用于处理该问题的代码。

var storageItems = await _shareOperation.Data.GetStorageItemsAsync();

foreach (StorageFile item in storageItems)
{
    var stream = await item.OpenReadAsync();
    var properties = await item.Properties.GetImagePropertiesAsync();

    var image = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height);
    image.SetSource(stream);

    images.Add(image);
}

一些网上搜索表明,目前,aWindows.UI.Xaml.Media.Imaging.WriteableBitmap是唯一能够让您访问图像中的像素数据的东西。这个问题包括一个有用的答案,其中包含将图像保存到文件的扩展方法,因此我们使用了这些方法。

当我稍后再次尝试打开文件时,我们的问题是最严重的。我做了类似于以前的事情:

var files = await ApplicationData.Current.LocalFolder.GetFilesAsync();

foreach (var file in files)
{
    var fileStream = await file.OpenReadAsync();
    var properties = await file.Properties.GetImagePropertiesAsync();
    var bitmap = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height);
    bitmap.SetSource(fileStream);

    System.IO.Stream stream = bitmap.PixelBuffer.AsStream();

问题来了。如果我想要其中的字节,这个流有多长?

    // CRASH! Length isn't supported on an IRandomAccessStream.
    var pixels = new byte[fileStream.Length];

好的再试一次。

    var pixels = new byte[stream.Length];

这可行,除非...如果图像被压缩,则流比您预期的要短,因此您最终会得到一个超出范围的异常。现在假设它是一个未压缩的位图。

    await _stream.ReadAsync(pixels, 0, pixels.Length);

好吧,猜猜是什么。即使我说bitmap.SetSource(fileStream);为了读入数据,我的字节数组仍然充满了零。我不知道为什么。如果我通过bitmap示例数据组将其传递到我的 UI 中,则图像显示得很好。所以它清楚地在某处获得了该位图中的像素数据,但我无法读取它bitmap.PixelBuffer?为什么不?

最后,这就是最终实际工作的结果。

    var decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, fileStream);
    var data = await decoder.GetPixelDataAsync();
    var bytes = data.DetachPixelData();

    /* process my data, finally */

} // end of that foreach I started a while ago

所以现在我有图像数据,但我仍然有一个大问题。为了对它做任何事情,我必须对其格式做出假设。我不知道是 rgba、rgb、abgr、bgra,不管它们是什么。如果我猜错了,我的处理就会失败。我已经进行了数十次测试运行吐出零字节和损坏的图像、颠倒的图像 (???)、错误的颜色等。我本希望在properties我从调用中得到的一些信息中找到这些信息await file.Properties.GetImagePropertiesAsync();,但没有运气。那只包含图像的宽度和高度,以及其他一些无用的东西。这里的文档最少。

那么,为什么这个过程如此痛苦呢?这只是反映了图书馆现在的不成熟,我可以期待它变得更好吗?还是已经有一些标准的方法来做到这一点?我希望它像System.Drawing. 这为您提供了您曾经需要的所有数据,并愉快地正确加载了任何图像类型,而无需您自己处理流。

4

1 回答 1

2
  1. 从我所看到的 - 当您计划使用流加载 WriteableBitmap 时 - 您不需要检查图像尺寸 - 只需执行 new WriteableBitmap(1,1),然后调用 SetSource()。
  2. 不知道你为什么在想 var pixel = new byte[fileStream.Length]; 会起作用,因为 fileStream 具有压缩的图像字节而不是像素数组。
  3. 您可能需要寻找到流的开头以获取像素数组:

    var pixelStream = pixelBuffer.AsStream();
    var bytes = new byte[this.pixelStream.Length];
    this.pixelStream.Seek(0, SeekOrigin.Begin);
    this.pixelStream.Read(bytes, 0, Bytes.Length);
    
  4. 我已经开始研究WriteableBitmapEx的 WinRT 端口- 也许它可以帮助你:http ://bit.ly/WriteableBitmapExWinRT 。我没有很好地测试它,它基于旧版本的WBX,但在功能支持方面相当完整。可能也比可能的慢一点。

于 2012-04-04T22:45:40.197 回答