我和一个朋友昨晚大部分时间都在试图在 Metro 应用程序中处理一些图像时差点把头发扯下来。我们通过分享功能将图像放入应用程序,然后我想用它们做一些其他的工作,裁剪图像并将它们保存回 appdata 文件夹。事实证明这非常令人沮丧。
我的问题,在这一切结束时,将是“这样做的正确方法是什么,而不觉得我正在拼凑一堆不匹配的拼图?”
当与应用程序共享多个图像时,它们以Windows.Storage.StorageFile
s 列表的形式出现。这是一些用于处理该问题的代码。
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
. 这为您提供了您曾经需要的所有数据,并愉快地正确加载了任何图像类型,而无需您自己处理流。