8

友人と私は、昨夜の大部分を地下鉄アプリでいくつかの画像を操作しようとして髪を引き裂くところだった. 共有チャームを使用してアプリに画像を取得した後、画像をトリミングして appdata フォルダーに保存し直すなど、他の作業を行いたいと考えました。これは非常にイライラさせられました。

私の質問は、これらすべての最後に、「ミスマッチのジグソー パズルのピースをたくさん組み合わせているように感じずに、これを行う適切な方法は何ですか?」ということになります。

アプリで複数の画像を共有する場合、それらは のリストとして表示されWindows.Storage.StorageFileます。これを処理するために使用されるコードを次に示します。

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);
}

オンラインで検索したところ、現在、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();

ここで問題が発生します。バイトを取り出したい場合、このストリームの長さはどれくらいですか?

    // 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ポートの作業を開始しました。私は十分にテストしておらず、古いバージョンの WBX に基づいていますが、機能サポートに関してはかなり完全です。可能よりも少し遅いかもしれません。

于 2012-04-04T22:45:40.197 に答える