Вопрос по image, windows-runtime, c#, windows-store-apps – Обработка изображений WinRT

8

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

... также все плохо реализуют библиотеки изображений, хотя BitmapEncoder / BitmapDecoder довольно хороши. stb_image.c в большинстве случаев и на большинстве платформ работает намного лучше, чем любые доступные нативные библиотеки, поскольку он обеспечивает минимальный и правильный интерфейс. (байты, размеры, форматы, без хрома и шаблонов). jheriko
«Я понятия не имею, являются ли это rgba, rgb, abgr, bgra, какими бы они ни были». На самом деле вы точно знаете, что это за ваш выбор формата. Поработайте один раз и для PNG, и вы сможете применить логику ко всем PNG. jheriko

Ваш Ответ

1   ответ
2
From what I have seen - when you are planning on loading the WriteableBitmap with a stream - you don't need to check the image dimensions - just do new WriteableBitmap(1,1), then call SetSource(). Not sure why you were thinking var pixels = new byte[fileStream.Length]; would work, since the fileStream has the compressed image bytes and not a pixel array.

s array:

var pixelStream = pixelBuffer.AsStream();
var bytes = new byte[this.pixelStream.Length];
this.pixelStream.Seek(0, SeekOrigin.Begin);
this.pixelStream.Read(bytes, 0, Bytes.Length);

I had started working on a WinRT port of WriteableBitmapEx - maybe it could help you: http://bit.ly/WriteableBitmapExWinRT. I have not tested it well and it is based on an older version of WBX, but it is fairly complete in terms of feature support. Might be a tad slower than it is possible too.

Поиск потока не работал, все равно было все нулевые байты. Сожалею. Tesserex
Ах, мне не нужен декодер, мне просто нужно искать начало. Спасибо! Я сделаю это. И я проверю вашу библиотеку! Tesserex
Возможно, вам нужно подождать, пока изображение загрузится, прежде чем вы сможете получить доступ к пиксельному буферу? Я хотел бы начать с ожидания Task.Delay (1000), прежде чем получить доступ к PixelBuffer. Если это помогает - возможно, есть событие, которое нужно ждать, как bitmap.Loaded.

Похожие вопросы