Pregunta

¿Cómo puedo guardar una imagen con su codificación original?

Parece que la única manera de salvar una imagen es mediante el uso de un BitmapEncoder pero no sabe cómo puedo obtener el formato correcto de la imagen.

Ejemplo:

Clipboard.GetImage () devuelve un InteropBitmap que no parece contener ninguna información sobre el formato original.

También he intentado usar un método de extensión:

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

pero el problema es que

  1. el ImageSource no siempre es una BitmapImage (Clipboard.GetImage ()) por ejemplo, y
  2. el image.StreamSource puede ser nulo en algunos casos (que parece ser cuando la imagen se carga a través de un pariente Uri)

¿Alguna sugerencia?

¿Fue útil?

Solución

La cuestión fundamental aquí es "¿Cómo se toma una ImageSource arbitraria y aprender qué formato se ha codificado originalmente en?"

La respuesta es que no siempre se puede hacer esto, pero para la mayoría de los propósitos prácticos hay una solución disponible. Por ejemplo el código de arriba muestra, una vez que ha aprendido qué formato utilizar el resto es fácil.

La razón por la que no siempre se puede averiguar el formato original es que es posible (con un poco de código muy difícil!) A la subclase BitmapSource para crear un nuevo ImageSource que obtiene sus datos desde cualquier lugar que desee. Por ejemplo, podría implementar un PseudoRandomBitmapSource que devuelve píxeles aleatorios. En este caso el "formato original" es probablemente la semilla utilizada para el generador de números aleatorios.

Si se trata de uno de los incorporados en las clases ImageSource, la forma de averiguar la codificación original depende de qué clase exacto que esté utilizando:

  1. Para BitmapImage, puede utilizar StreamSource o UriSource, lo que se ha establecido. Cualquiera de estos puede ser pasado a una sobrecarga BitmapDecoder.Create. Su código de ejemplo muestra cómo hacer esto para StreamSource. Es exactamente el mismo para UriSource excepto que necesita para nueva Uri(BaseUri, UriSource) y pasa que a la sobrecarga BitmapDecoder.Create que tiene un URI.

  2. Para ColorConvertedBitmap, CroppedBitmap, FormatConvertedBitmap y TransformedBitmap hay un público "Fuente" propiedad que se puede utilizar para obtener el código fuente subyacente, a continuación, comprobar de forma recursiva su codificación que utiliza este algoritmo.

  3. Para CachedBitmap, sólo se puede llegar a la fuente de mapa de bits a través de un campo interno. Se puede acceder utilizando la reflexión si tiene suficientes privilegios, de lo contrario, estás de suerte.

  4. Para RenderTargetBitmap, WritableBitmap, D3DImage, y DrawingImage no hay codificación original ya que la imagen se está construyendo "sobre la marcha" de un formato de vector o un algoritmo.

  5. Para BitmapFrame, utilizar la propiedad decodificador para obtener el decodificador, a continuación, utilizar CodecInfo.ContainerFormat.

  6. Para InteropBitmap o UnmanagedBitmapWrapper es muy complicado. Básicamente, usted tiene que utilizar la reflexión para leer la propiedad WicSourceHandle interna, a continuación, llamar DangerousGetHandle () para obtener un IntPtr que es en realidad un IUnkown no administrado. El uso de código no administrado, QueryInterface para IWICBitmapDecoder. Si tiene éxito puede llamar IWICBitmapDecoder.GetContainerFormat para obtener el formato GUID (esto sigue siendo código no administrado). Si no es así, toda la información acerca de la fuente original se ha perdido.

Como se puede ver, hay un buen número de situaciones en las que no se puede conseguir la fuente (por ejemplo, un InteropBitmap de un mapa de bits totalmente decodificado) o donde conseguir la fuente requiere técnicas especiales y privilegios (código no administrado para InteropBitmap, o la reflexión en campos internos para CachedBitmap).

Debido a que es a menudo difícil de imposible conseguir el formato original, es una buena idea para buscar la manera de preservar esta información a medida que se pasa en el código. Si el control de la fuente de la imagen, puede ser tan simple como crear una clase ImageSourceAndFormat:

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

Esto es particularmente útil si se va a poner la imagen en el portapapeles. Además de añadir la imagen a la DataObject normalmente, también se puede añadir un objeto BitmapSourceAndFormat. Si hace esto, la operación de pegado recibirá un DataObject contiene estos dos formatos. Su código a continuación, sólo tiene que comprobar si el objeto BitmapSourceAndFormat primero. Si lo encuentra, simplemente se puede acceder a él para obtener el formato original. Si no, se debe recurrir a los medios descritos anteriormente.

Una última nota: Para pastas del portapapeles, puede comprobar las cadenas de formato de datos disponibles. Algunas de las más útiles son: Bitmap, Dib, TIFF, GIF, JPEG, y el nombre de archivo. Por "tiff", "gif" y "JPEG" que puede codificar el formato requerido. Por "Nombre de archivo", se puede abrir el archivo usted mismo para conseguir un flujo depara pasar a un BitmapDecoder. Por "Dib" o "mapa de bits" sin nada más, se conoce el formato original se ha perdido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top