2010-05-10 11 views
12

Come posso salvare un'immagine con la sua codifica originale?Come salvare un'immagine nel suo formato originale?

Sembra che l'unico modo per salvare un'immagine sia utilizzando un BitmapEncoder ma non so come ottenere il formato corretto dall'immagine.

Esempio:

Clipboard.GetImage() restituisce un InteropBitmap che non sembra contenere tutte le informazioni sul formato originale.

Ho anche provato utilizzando un metodo di estensione:

public static void Save(this BitmapImage image, System.IO.Stream stream) 
{ 
    var decoder = BitmapDecoder.Create(image.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); 
    var encoder = BitmapEncoder.Create(decoder.CodecInfo.ContainerFormat); 
    foreach (var frame in decoder.Frames) 
    { 
     encoder.Frames.Add(BitmapFrame.Create(frame)); 
    } 
    encoder.Save(stream); 
} 

ma il problema è che

  1. l'ImageSource non è sempre una BitmapImage (Clipboard.GetImage()) per esempio e
  2. l'image.StreamSource può essere nullo in alcuni casi (sembra essere quando l'immagine viene caricata tramite un Uri relativo)

Qualche suggerimento?

+0

Puoi spiegare il contesto in cui stai vivendo questo? Mi sembra che se stai salvando un'immagine, salvala nel formato che desideri. BitmapImage sembra essere un formato e l'immagine originale è già stata convertita. –

risposta

19

La domanda fondamentale qui è "Come posso prendere un ImageSource arbitrario e sapere in quale formato è stato codificato in origine?"

La risposta è che non è sempre possibile farlo, ma per scopi pratici è disponibile una soluzione alternativa. Come mostra il tuo codice sopra, una volta che hai imparato quale formato utilizzare per il resto è facile.

Il motivo per cui non è sempre possibile trovare il formato originale è che è possibile (con un codice molto complicato!) Creare una sottoclasse di BitmapSource per creare un nuovo ImageSource che recuperi i dati da qualsiasi luogo. Ad esempio, potrei implementare una PseudoRandomBitmapSource che restituisce pixel casuali. In questo caso il "formato originale" è probabilmente il seme utilizzato per il generatore di numeri casuali.

Se avete a che fare con uno dei costruita nel classi Imagesource, il modo per scoprire la codifica originale dipende da quale classe esatto che si sta utilizzando:

  1. Per BitmapImage, è possibile utilizzare StreamSource o UriSource , qualunque sia impostato. Ciascuno di questi può essere passato a un sovraccarico BitmapDecoder.Create. Il codice di esempio mostra come eseguire questa operazione per StreamSource. È esattamente la stessa cosa per UriSource, tranne per il nuovo Uri(BaseUri, UriSource) e per il passaggio al sovraccarico BitmapDecoder.Create che richiede un Uri.

  2. Per ColorConvertedBitmap, CroppedBitmap, FormatConvertedBitmap, e TransformedBitmap c'è una "sorgente" proprietà pubblica, che è possibile utilizzare per ottenere il sorgente sottostante, quindi controllare in modo ricorsivo la sua codifica usando questo algoritmo.

  3. Per CachedBitmap, è possibile accedere alla bitmap di origine solo attraverso un campo interno. Puoi accedere usando il reflection se hai abbastanza privilegi, altrimenti sei sfortunato.

  4. Per RenderTargetBitmap, WritableBitmap, D3DImage, e DrawingImage non c'è codifica originale poiché l'immagine viene costruita "al volo" da un formato di vettore o un algoritmo.

  5. Per BitmapFrame, utilizzare la proprietà Decoder per ottenere il decodificatore, quindi utilizzare CodecInfo.ContainerFormat.

  6. Per InteropBitmap o UnmanagedBitmapWrapper è molto complicato. Fondamentalmente è necessario utilizzare reflection per leggere la proprietà interna di WicSourceHandle, quindi chiamare DangerousGetHandle() per ottenere un IntPtr che in realtà è un IUnkown non gestito. Utilizzo del codice non gestito, QueryInterface per IWICBitmapDecoder. In caso di esito positivo è possibile chiamare IWICBitmapDecoder.GetContainerFormat per ottenere il formato Guid (codice ancora non gestito). In caso contrario, tutte le informazioni sulla fonte originale sono andate perse.

Come si può vedere, ci sono un bel paio di situazioni in cui non si può ottenere la fonte (ad esempio, un InteropBitmap per un'immagine bitmap completamente decodificati) o in cui trovare la fonte richiede tecniche e privilegi speciali (codice non gestito per InteropBitmap, o riflessione su campi interni per CachedBitmap).

Poiché è spesso impossibile ottenere il formato originale, è una buona idea cercare i modi per conservare queste informazioni quando vengono passate nel codice. Se controlli la fonte dell'immagine, può essere semplice come creare una classe ImageSourceAndFormat:

public class BitmapSourceAndFormat 
{ 
    public ImageSource Source { get; set; } 
    public Guid OriginalFormat { get; set; } 
} 

Ciò è particolarmente utile se si sta mettendo l'immagine negli appunti. Oltre ad aggiungere l'immagine al DataObject normalmente, puoi anche aggiungere un oggetto BitmapSourceAndFormat. Se si esegue questa operazione, l'operazione Incolla riceverà un DataObject contenente entrambi questi formati. Il tuo codice quindi deve solo prima controllare l'oggetto BitmapSourceAndFormat. Se trovato, può semplicemente accedervi per ottenere il formato originale. In caso contrario, deve ricorrere ai mezzi sopra descritti.

Un'ultima nota: per le paste di appunti è possibile controllare le stringhe di formato dei dati disponibili. Alcuni utili sono: Bitmap, Dib, Tiff, Gif, Jpeg e FileName. Per "Tiff", "Gif" e "Jpeg" è possibile codificare il formato richiesto. Per "FileName" puoi aprire tu stesso il file per far passare uno stream ad un BitmapDecoder. Per "Dib" o "Bitmap" senza altro, sai che il formato originale è andato perso.

+0

wow - questa è una risposta eccellente. Grazie mille! Ottimi consigli su copia/incolla! –

+0

+ grazie per non solo dirmi quello che volevo sapere, ma anche dirmi qual è la mia domanda fondamentale! Avrei dovuto descriverlo meglio –

Problemi correlati