WinRT图像处理

Tes*_*rex 8 c# image windows-runtime windows-store-apps

我和我的一个朋友在昨晚的大部分时间里花了很多时间试图在地铁应用程序中使用一些图像.我们在共享魅力的应用程序中获得了图像,然后我想与他们做一些其他的工作,裁剪图像并将它们保存回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);
}
Run Code Online (Sandbox Code Playgroud)

一些在线搜索表明,目前,Windows.UI.Xaml.Media.Imaging.WriteableBitmap只有a 才能让你访问图像中的像素数据.这个问题包含一个有用的答案,其中包含将图像保存到文件的扩展方法,因此我们使用了这些方法.

当我稍后再次尝试打开文件时,我们的问题最严重.我做过类似的事情:

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();
Run Code Online (Sandbox Code Playgroud)

这有一个问题.如果我想要字节数,这个流有多长?

    // CRASH! Length isn't supported on an IRandomAccessStream.
    var pixels = new byte[fileStream.Length];
Run Code Online (Sandbox Code Playgroud)

好的,再试一次.

    var pixels = new byte[stream.Length];
Run Code Online (Sandbox Code Playgroud)

这是有效的,除了...如果图像被压缩,流比你想象的短,所以你最终会得到一个越界异常.现在假装它是一个未压缩的位图.

    await _stream.ReadAsync(pixels, 0, pixels.Length);
Run Code Online (Sandbox Code Playgroud)

好吧猜猜看.即使我说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
Run Code Online (Sandbox Code Playgroud)

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

那么,为什么这个过程如此痛苦呢?这只是反映了现在图书馆的不成熟,我能指望它会变得更好吗?或者已经有一些标准的方法吗?我希望它像在里面那样容易System.Drawing.这为您提供了所需的所有数据,并且可以正确地加载任何图像类型,而无需让您自己处理流.

Fil*_*kun 2

  1. 据我所见 - 当您计划使用流加载 WriteableBitmap 时 - 您不需要检查图像尺寸 - 只需执行 new WriteableBitmap(1,1),然后调用 SetSource()。
  2. 不知道为什么你会想到 var Pixels = 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);
    
    Run Code Online (Sandbox Code Playgroud)
  4. 我已经开始研究WriteableBitmapEx的 WinRT 端口- 也许它可以帮助您:http://bit.ly/WriteableBitmapExWinRT。我没有很好地测试它,它是基于旧版本的WBX,但在功能支持方面相当完整。也可能比可能的速度慢一点。