Обработка изображений WinRT

Мы с другом провели большую часть прошлой ночи, чуть не вырвав себе волосы, пытаясь работать с некоторыми изображениями в приложении метро. Мы добавили изображения в приложение с помощью чудо-кнопки «Поделиться», а затем мне захотелось поработать с ними, обрезать изображения и сохранить их обратно в папку 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);
}

Поиск в Интернете показал, что в настоящее время Windows.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);для чтения данных, мой массив байтов по-прежнему полон нулей. Понятия не имею почему. Если я передам это же растровое изображение в свой пользовательский интерфейс через группу образцов данных, изображение будет отображаться нормально. Таким образом, он явно где-то получил данные о пикселях в этом растровом изображении, но я не могу прочитать их из растрового изображения . 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, какими бы они ни были. Если я ошибаюсь, моя обработка просто терпит неудачу. У меня были десятки тестовых запусков, выдающих нулевой байт и поврежденные изображения, перевернутые изображения (???), неправильные цвета и т. д. Я ожидал найти некоторую информацию в свойствах, которые Я получил вызов await file.Properties.GetImagePropertiesAsync();, но не повезло. Это содержит только ширину и высоту изображения, а также некоторые другие бесполезные вещи. Минимум документацииздесь.

Итак, почему этот процесс такой болезненный? Является ли это просто отражением незрелости библиотек прямо сейчас, и могу ли я ожидать, что она станет лучше? Или уже есть какой-то стандартный способ сделать это? Хотелось бы, чтобы это было так же просто, как в System.Drawing.Это дало вам все данные, которые вам когда-либо были нужны, и с радостью правильно загрузило любой тип изображения, не заставляя вас самостоятельно иметь дело с потоками.

8
задан Community 23 May 2017 в 12:16
поделиться