Un amico e io abbiamo passato la parte migliore della scorsa notte quasi strappandoci i capelli cercando di lavorare con alcune immagini in un'app della metropolitana. Abbiamo inserito le immagini nell'app con l'incantesimo di condivisione, quindi ho voluto lavorare con loro, ritagliare le immagini e salvarle nella cartella appdata. Questo si è rivelato estremamente frustrante.Gestione immagini WinRT
La mia domanda, alla fine di tutto questo, sarà "Qual è il modo corretto di farlo, senza sentire come sto martellando insieme un mucchio di pezzi di puzzle non corrispondenti?"
Quando si condividono più immagini con l'app, vengono visualizzate come un elenco di Windows.Storage.StorageFile
s. Ecco un codice usato per gestirlo.
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);
}
qualche ricerca on-line ha indicato che attualmente, un Windows.UI.Xaml.Media.Imaging.WriteableBitmap
è l'unica cosa in grado di lasciare che si accede ai dati dei pixel nell'immagine. This question include una risposta utile piena di metodi di estensione per il salvataggio delle immagini in un file, quindi li abbiamo utilizzati.
I nostri problemi sono stati i peggiori quando ho provato ad aprire nuovamente i file in seguito. Ho fatto qualcosa di simile a prima:
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();
Ecco un problema. Quanto è lungo questo flusso, se voglio che i byte escano da esso?
// CRASH! Length isn't supported on an IRandomAccessStream.
var pixels = new byte[fileStream.Length];
Ok riprovare.
var pixels = new byte[stream.Length];
questo funziona, tranne ... se l'immagine viene compressa, il flusso è più breve di quanto si pensi, così si finirà per ottenere un'eccezione di limiti. Per ora fingere che sia una bitmap non compressa.
await _stream.ReadAsync(pixels, 0, pixels.Length);
Beh, indovinate. Anche se ho detto bitmap.SetSource(fileStream);
per leggere i dati, il mio array di byte è ancora pieno di zeri. Non ho idea del perché. Se passo questo stesso bitmap
in una mia interfaccia utente attraverso il gruppo di dati di esempio, l'immagine si presenta bene. Quindi ha chiaramente ottenuto i dati dei pixel in quella bitmap da qualche parte, ma non riesco a leggerlo da bitmap.PixelBuffer
? Perchè no?
Infine, ecco cosa ha funzionato.
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
Così ora ho per dati di immagine, ma ho ancora un grosso problema. Per fare qualsiasi cosa con esso, devo fare ipotesi sul suo formato. Non ho idea se sia rgba, rgb, abgr, bgra, qualunque cosa possano essere. Se penso che la mia elaborazione non vada a buon fine, fallisce. Ho avuto dozzine di esecuzioni di test sputando zero byte e immagini danneggiate, immagini capovolte (???), colori sbagliati, ecc. Mi sarei aspettato di trovare alcune di queste informazioni nello properties
che ho ricevuto chiamando lo await file.Properties.GetImagePropertiesAsync();
, ma senza fortuna. Questo contiene solo la larghezza e l'altezza dell'immagine, oltre ad alcune altre cose inutili. Documentazione minima here.
Quindi, perché questo processo è così doloroso? Sta riflettendo l'immaturità delle biblioteche in questo momento e posso aspettarmi che migliori? O esiste già un modo standard per farlo? Vorrei che fosse facile come in System.Drawing
. Questo ti ha dato tutti i dati di cui hai mai avuto bisogno e hai felicemente caricato qualsiasi tipo di immagine senza doverti fare da solo con i flussi.
"Non ho idea se sia rgba, rgb, abgr, bgra, qualunque cosa possano essere.". In realtà sai esattamente cosa è nella tua scelta di formato. Risolvilo una volta e per PNG e puoi applicare la logica a tutti i PNG. – jheriko
... anche tutti implementano le librerie di imaging abbastanza male, sebbene BitmapEncoder/BitmapDecoder siano piuttosto carini. stb_image.c fa un lavoro molto migliore nella maggior parte dei casi e sulla maggior parte delle piattaforme rispetto a qualsiasi libreria nativa disponibile perché fornisce un'interfaccia minima e corretta. (byte, dimensioni, formati, senza cromo e piastra di riscaldamento). – jheriko