Se produjo un error genérico en GDI +, imagen JPEG a MemoryStream

326

Esto parece ser un error infame en toda la web. Tanto es así que no he podido encontrar una respuesta a mi problema ya que mi escenario no encaja. Se produce una excepción cuando guardo la imagen en la transmisión.

Extrañamente, esto funciona perfectamente con un png pero da el error anterior con jpg y gif, que es bastante confuso.

El problema más similar se relaciona con guardar imágenes en archivos sin permisos. Irónicamente, la solución es usar un flujo de memoria como lo estoy haciendo ...

public static byte[] ConvertImageToByteArray(Image imageToConvert)
{
    using (var ms = new MemoryStream())
    {
        ImageFormat format;
        switch (imageToConvert.MimeType())
        {
            case "image/png":
                format = ImageFormat.Png;
                break;
            case "image/gif":
                format = ImageFormat.Gif;
                break;
            default:
                format = ImageFormat.Jpeg;
                break;
        }

        imageToConvert.Save(ms, format);
        return ms.ToArray();
    }
}

Más detalles a la excepción. La razón por la que esto causa tantos problemas es la falta de explicación :(

System.Runtime.InteropServices.ExternalException was unhandled by user code
Message="A generic error occurred in GDI+."
Source="System.Drawing"
ErrorCode=-2147467259
StackTrace:
   at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters    encoderParams)
   at System.Drawing.Image.Save(Stream stream, ImageFormat format)
   at Caldoo.Infrastructure.PhotoEditor.ConvertImageToByteArray(Image imageToConvert) in C:\Users\Ian\SVN\Caldoo\Caldoo.Coordinator\PhotoEditor.cs:line 139
   at Caldoo.Web.Controllers.PictureController.Croppable() in C:\Users\Ian\SVN\Caldoo\Caldoo.Web\Controllers\PictureController.cs:line 132
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
 InnerException: 

OK cosas que he probado hasta ahora.

  1. Clonando la imagen y trabajando en eso.
  2. Recuperando el codificador para ese MIME pasando eso con la configuración de calidad jpeg.
madcapnmckay
fuente
relacionado: stackoverflow.com/questions/4671449/…
Patrick Szalapski
3
Para mí, el problema era que esa carpeta no existía. Solucionado simplemente creando la carpeta.
hazjack
Para mí fue un índice fuera de rango que se tragó.
Billy Jake O'Connor

Respuestas:

189

OK. Parece que encontré la causa por pura suerte y no tiene nada de malo con ese método en particular, es una copia de seguridad de la pila de llamadas.

Anteriormente cambio el tamaño de la imagen y como parte de ese método devuelvo el objeto redimensionado de la siguiente manera. He insertado dos llamadas al método anterior y un guardado directo en un archivo.

// At this point the new bitmap has no MimeType
// Need to output to memory stream
using (var m = new MemoryStream())
{
       dst.Save(m, format);

       var img = Image.FromStream(m);

       //TEST
       img.Save("C:\\test.jpg");
       var bytes = PhotoEditor.ConvertImageToByteArray(img);


       return img;
 }

Parece que la secuencia de memoria que el objeto se creó el tiene que ser abierta en el momento de guardar el objeto. No estoy seguro de por qué es esto. ¿Alguien puede iluminarme y cómo puedo evitar esto?

Solo regreso de una secuencia porque después de usar el código de cambio de tamaño similar a este, el archivo de destino tiene un tipo MIME desconocido (img.RawFormat.Guid) y me gustaría que el tipo MIME sea correcto en todos los objetos de imagen, ya que dificulta la escritura genérica manejo de código de lo contrario.

EDITAR

Esto no apareció en mi búsqueda inicial, pero aquí está la respuesta de Jon Skeet

madcapnmckay
fuente
44
No me di cuenta de que cuando obtienes un mapa de bits de una secuencia de memoria no debes cerrar la secuencia. muy útil, gracias
mcdon
38
Gracias. Esto probablemente salvó lo último de mi cabello.
NotMe
66
¡Gracias! esto me ahorró mucho tiempo, una cosa, sin embargo, ¿le importaría resaltar la causa del error al comienzo de su respuesta, ya que yo (y supongo que la mayoría de los errores) lo omití en la lectura original a través de las respuestas, tal vez algo así como " NO CIERRE LA TRANSMISIÓN DE MEMORIA SI TIENE LA INTENCIÓN DE USAR LA IMAGEN OTRA VEZ "sería genial; D
DorD
66
¿Cuál es su variable "dst"?
WEFX
1
@madcapnmckay, explique cuál es la variable 'dst' y su importancia
Mike T
131

Si obtiene ese error, entonces puedo decir que su aplicación no tiene permiso de escritura en algún directorio.

Por ejemplo, si está intentando guardar la imagen de la secuencia de memoria en el sistema de archivos, puede recibir ese error.

Por favor, si está utilizando XP, asegúrese de agregar permiso de escritura para la cuenta aspnet en esa carpeta.

Si está utilizando el servidor de Windows (2003,2008) o Vista, asegúrese de agregar permiso de escritura para la cuenta de servicio de red.

Espero que ayude a alguien.

Savindra
fuente
77
No lo hiciste! Perdí 2 horas con los malditos permisos de escritura ... Vine aquí para publicar esto. Espero que obtengas más votos a favor. :)
Gleno
2
Esta fue la solución para mí. +1 totalmente!
Grandizer
55
Puede hacer File.WriteAllText ("filename.jpg", "") y luego File.DeleteFile ("filename.jpg") antes de guardar el mapa de bits. En mi punto de referencia, esto solo lleva 0,001 segundos y obtienes un agradable 'No tienes permiso para guardar filename.jpg allí'
Despertar el
@Despertar Te refieres a File.Delete (), ¡pero ese es un truco muy útil! Definitivamente voy a usar esto cada vez que guarde un mapa de bits.
D Coetzee
2
En mi caso, el directorio no existía.
mensaje silenciado el
54

También agregaré esta causa del error con la esperanza de que ayude a algún futuro viajero de Internet. :)

GDI + limita la altura máxima de una imagen a 65500

Hacemos un cambio de tamaño básico de la imagen, pero al cambiar el tamaño intentamos mantener la relación de aspecto. Tenemos un tipo de control de calidad que es demasiado bueno en este trabajo; decidió probar esto con una foto de UNO de ancho que tenía 480 píxeles de alto. Cuando la imagen se ajustó para cumplir con nuestras dimensiones, la altura era al norte de 68,000 píxeles y nuestra aplicación explotó A generic error occurred in GDI+.

Puede verificar esto usted mismo con la prueba:

  int width = 480;
  var height = UInt16.MaxValue - 36; //succeeds at 65499, 65500
  try
  {
    while(true)
    {
      var image = new Bitmap(width, height);
      using(MemoryStream ms = new MemoryStream())
      {
        //error will throw from here
        image.Save(ms, ImageFormat.Jpeg);
      }
      height += 1;
    }
  }
  catch(Exception ex)
  {
    //explodes at 65501 with "A generic error occurred in GDI+."
  }

Es una pena que no haya un .net amigable ArgumentExceptionen el constructor de Bitmap.

Fred
fuente
17
Gracias, este viajero del tiempo de Internet está muy agradecido por dejar este mensaje.
Tom West el
De mis pruebas, 65535 es en realidad el valor máximo. A los 65536 empiezo a ver el error genérico.
ChaseMedallion
Solo intenté esto de nuevo: Win10 .net 4.5 y .net 4.6.1, y explotó en 65501, lo que parece aún más aleatorio. El código también está lleno de errores de sintaxis, se actualizará :)
Fred
37

Este artículo explica en detalle qué sucede exactamente: dependencias del constructor de mapas de bits e imágenes

En resumen, durante toda la vida de un Imageconstruido a partir de una corriente , la corriente no debe ser destruida.

Entonces, en lugar de

using (var strm = new ... )  {
    myImage = Image.FromStream(strm);
}

prueba esto

Stream imageStream;
...

    imageStream = new ...;
    myImage = Image.FromStream(strm);

y cierre imageStream al cerrar el formulario o cerrar la página web.

Ivan Mesic
fuente
Sí, este me atrapó. Estaba siendo concienzudo y envolví mi transmisión en usingy luego intenté copiar la imagen en una transmisión de memoria y recibí el terrible mensaje "Error genérico en GDI +".
Will Appleby
Su enlace me estaba dando redirecciones infinitas; Este funciona. Estaba teniendo un problema con el ahorro PixelFormat.Format32bppArgbpero no PixelFormat.Format1bppIndexed. El artículo que vinculó explica por qué: GDI + puede optar por volver a decodificar datos de mapa de bits de la secuencia de origen en lugar de mantener todo en la memoria. Supongo que no vuelve a decodificar imágenes de 1bpp.
labreuer
Incluso el nuevo enlace ya no funciona. Una simple búsqueda en Google no pareció revelar la página correcta. ¡Pero me alegró mucho encontrar esta respuesta! Mi
solución
28

También obtendrá esta excepción si intenta guardar en una ruta no válida o si hay un problema de permisos.

Si no está 100% seguro de que la ruta del archivo esté disponible y los permisos sean correctos, intente escribir un archivo de texto. Esto toma solo unos segundos para descartar lo que sería una solución muy simple.

var img = System.Drawing.Image.FromStream(incomingStream);

// img.Save(path);
System.IO.File.WriteAllText(path, "Testing valid path & permissions.");

Y no olvides limpiar tu archivo.

Kirk Broadhurst
fuente
Este fue el problema para mí ... Desearía que el error fuera menos vago, me hubiera ahorrado mucho tiempo.
Oofpez
¡Si! La carpeta en la que está guardando debe existir. Ahora hago una comprobación para eso primero, antes de intentar guardar una imagen. (Aún así, el error me sorprende, aproximadamente una vez al año.)
Magnus Smith el
Mi ruta era un directorio, en lugar de un archivo.
Asen Kasimov el
20

Guardar imagen en variable de mapa de bits

using (var ms = new MemoryStream())
{
    Bitmap bmp = new Bitmap(imageToConvert);
    bmp.Save(ms, format);
    return ms.ToArray();
}
Amir Atashin
fuente
Esto ha resuelto mi problema. ¿Podría explicar por qué guardar la imagen en Bitmap ahuyenta la excepción?
jmc
Me salvó el día ... no sé qué causó el problema, pero Bitmap save funciona ... System.Drawing.Image no se guardará en la secuencia de memoria, pero Bitmap sí.
San
Esta fue la mejor solución para mí. Crear un nuevo mapa de bits y convertirlo.
uzay95
17

Por si acaso si alguien está haciendo cosas tan estúpidas como yo. 1. Asegúrese de que el camino existe. 2. asegúrese de tener permisos para escribir. 3. asegúrese de que su ruta sea correcta, en mi caso me faltaba el nombre del archivo en TargetPath :(

debería haber dicho, su ruta es una mierda que "Se produjo un error genérico en GDI +"

ahsant
fuente
16

También recibí este error al guardar archivos JPEG, pero solo para ciertas imágenes.

Mi codigo final:

  try
  {
    img.SaveJpeg(tmpFile, quality); // This is always successful for say image1.jpg, but always throws the GDI+ exception for image2.jpg
  }
  catch (Exception ex)
  {
    // Try HU's method: Convert it to a Bitmap first
    img = new Bitmap(img); 
    img.SaveJpeg(tmpFile, quality); // This is always successful
  }

No creé las imágenes, así que no puedo decir cuál es la diferencia.
Agradecería si alguien pudiera explicar eso.

Esta es mi función SaveJpeg solo para tu información:

private static void SaveJpeg(this Image img, string filename, int quality)
{
  EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)quality);
  ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
  EncoderParameters encoderParams = new EncoderParameters(1);
  encoderParams.Param[0] = qualityParam;
  img.Save(filename, jpegCodec, encoderParams);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
    var encoders = ImageCodecInfo.GetImageEncoders();
    var encoder = encoders.SingleOrDefault(c => string.Equals(c.MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase));
    if (encoder == null) throw new Exception($"Encoder not found for mime type {mimeType}");
    return encoder;
}
Aximili
fuente
1
Esto resolvió días de tirar del cabello. Es el código más wtf que creo que he escrito :)
Jeff Dunlop
13

Descubrí que si una de las carpetas principales donde guardaba el archivo tenía un espacio final, GDI + arrojaría la excepción genérica.

En otras palabras, si intenté guardar en "C: \ Documents and Settings \ myusername \ Local Settings \ Temp \ ABC DEF M1 Trended Values ​​\ Images \ picture.png", arrojó la excepción genérica.

El nombre de mi carpeta se generaba a partir de un nombre de archivo que tenía un espacio final, por lo que era fácil .Trim () eso y seguir adelante.

Igilima
fuente
3
increíble: nunca hubiera pensado mirar la ruta del directorio tan de cerca
jharr100
11

si su código es el siguiente, también se produce este error

private Image GetImage(byte[] byteArray)
{
   using (var stream = new MemoryStream(byteArray))
   {
       return Image.FromStream(stream);
    }
}

El correcto es

private Image GetImage(byte[] byteArray)
{
   var stream = new MemoryStream(byteArray))
   return Image.FromStream(stream);        
}

Esto puede deberse a que estamos regresando del bloque using

dhinesh
fuente
para mí fue el regreso en el bloque de uso. Todavía uso usar pero devuelvo el valor fuera del bloque. ¡Gracias!
Dragouf
1
Descubrí "por las malas" que si está guardando nuevamente esa imagen en una nueva transmisión (como HttpContext.Response.OutputStream, por ejemplo), también tendrá que hacer una transmisión.Flush (), si no se produce el error de nuevo.
Lucian
11

Esta es una expansión / calificación de la respuesta de Fred que declaró: "GDI limita la altura de una imagen a 65534". Nos encontramos con este problema con una de nuestras aplicaciones .NET, y después de ver la publicación, nuestro equipo de outsourcing levantó las manos en el aire y dijo que no podían solucionar el problema sin cambios importantes.

Según mis pruebas, es posible crear / manipular imágenes con una altura superior a 65534, pero el problema surge cuando se guarda en una secuencia o archivo EN DETERMINADOS FORMATOS . En el siguiente código, la llamada al método t.Save () arroja a nuestro amigo la excepción genérica cuando la altura del píxel es 65501 para mí. Por curiosidad, repetí la prueba de ancho y el mismo límite se aplicó al ahorro.

    for (int i = 65498; i <= 100000; i++)
    {
        using (Bitmap t = new Bitmap(800, i))
        using (Graphics gBmp = Graphics.FromImage(t))
        {
            Color green = Color.FromArgb(0x40, 0, 0xff, 0);
            using (Brush greenBrush = new SolidBrush(green))
            {
                // draw a green rectangle to the bitmap in memory
                gBmp.FillRectangle(greenBrush, 0, 0, 799, i);
                if (File.Exists("c:\\temp\\i.jpg"))
                {
                    File.Delete("c:\\temp\\i.jpg");
                }
                t.Save("c:\\temp\\i.jpg", ImageFormat.Jpeg);
            }
        }
        GC.Collect();
    }

El mismo error también se produce si escribe en una secuencia de memoria.

Para evitarlo, puede repetir el código anterior y sustituir ImageFormat.Tiff o ImageFormat.Bmp por ImageFormat.Jpeg.

Esto se extiende hasta alturas / anchos de 100,000 para mí, no probé los límites. Como sucede. Tiff fue una opción viable para nosotros.

Ser advertido

Las secuencias / archivos TIFF en memoria consumen más memoria que sus contrapartes JPG.

vipes
fuente
10

Tuve un problema muy similar y también intenté clonar la imagen que no funciona. Descubrí que la mejor solución era crear un nuevo objeto de mapa de bits a partir de la imagen que se cargó desde el flujo de memoria. De esa manera, la corriente se puede eliminar, por ejemplo

using (var m = new MemoryStream())
{
    var img = new Bitmap(Image.FromStream(m));
    return img;
}

Espero que esto ayude.

HU
fuente
6

Se produjo un error debido al permiso. asegúrese de que la carpeta tenga TODO EL PERMISO.

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        return image;
    }

 img.Save("YOUR PATH TO SAVE IMAGE")
Gaurang m
fuente
Estoy de acuerdo con usted.
Resolví
5

RESUELTO - Tuve este problema exacto. La solución, para mí, era aumentar la cuota de disco para IUSR en el servidor IIS. En este caso, tenemos una aplicación de catálogo con imágenes de artículos y demás. La cuota de carga para el "Usuario web anónimo" se estableció en 100 MB, que es el valor predeterminado para los servidores IIS de esta empresa de hosting en particular. Lo subí a 400 MB y pude subir imágenes sin error.

Este podría no ser su problema, pero si lo es, es una solución fácil.

Marco
fuente
4

En mi caso, el problema estaba en la ruta que estaba guardando (la raíz C:\). Cambiarlo para que D:\111\la excepción desaparezca.

Y yo
fuente
4

Otra causa de este error: la ruta que indica en el método Save de la instancia de mapa de bits no existe o no ha proporcionado una ruta completa / válida.

¡Acabo de tener este error porque estaba pasando un nombre de archivo y no una ruta completa!

¡Sucede!

MytyMyky
fuente
4

¡Mi turno!

using (System.Drawing.Image img = Bitmap.FromFile(fileName))
{
      ... do some manipulation of img ...
      img.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}

Lo tengo en .Guardar ... porque el uso () mantiene abierto el archivo, por lo que no puedo sobrescribirlo. Quizás esto ayude a alguien en el futuro.

Andy
fuente
4

Mismo problema que estaba enfrentando. Pero en mi caso, estaba tratando de guardar el archivo en la unidad C y no estaba accesible. Así que intenté guardarlo en la unidad D, que era completamente accesible y lo logré.

Así que primero verifique las carpetas en las que está intentando guardar. Debe tener todos los derechos (de lectura y escritura) para esa carpeta en particular.

Jaimin
fuente
porque normalmente c no permite sin permiso del administrador.
Aneeq Azam Khan
2

Noté que su caso "jpeg" es en realidad:

            default:
                format = ImageFormat.Jpeg;
                break;

¿Estás seguro de que el formato es JPEG y no otra cosa?

Lo intentaría:

            case "image/jpg": // or "image/jpeg" !
                format = ImageFormat.Jpeg;
                break;

O revise lo imageToConvert.MimeType()que realmente está regresando.

ACTUALIZAR

¿Hay alguna otra inicialización que necesite hacer al objeto MemoryStream?

ChrisF
fuente
Gracias. Definitivamente se llama con el formato correcto. Cargo un jpg, depuro y confirmo que el mimo se reconoce como image / jpeg y el formato es JPG.
madcapnmckay
3
Oh, bueno, siempre trato de eliminar lo obvio primero. No puedo contar la cantidad de veces que no lo he hecho y ha vuelto para morderme más tarde.
ChrisF
2
  • Tuve este problema en un servidor de prueba pero no en el servidor en vivo.
  • Estaba escribiendo la imagen en una secuencia, por lo que no era un problema de permiso.
  • Había estado implementando directamente algunos de los archivos .dll en el servidor de prueba.
  • La implementación de la solución completa solucionó el problema, por lo que probablemente fue una extraña falta de coincidencia
Chris Halcrow
fuente
2

Solo para lanzar otra posible solución al montón, mencionaré el caso con el que me encontré con este mensaje de error. El método Bitmap.Savearrojaría esta excepción al guardar un mapa de bits que había transformado y que estaba mostrando. Descubrí que no arrojaría la excepción si la declaración tenía un punto de interrupción, ni lo haría si Bitmap.Savefuera precedida porThread.Sleep(500) lo que supongo que está sucediendo algún tipo de contención de recursos.

Simplemente copiar la imagen a un nuevo objeto de mapa de bits fue suficiente para evitar que aparezca esta excepción:

new Bitmap(oldbitmap).Save(filename);
Segfault
fuente
2

Tuvimos un problema similar al generar PDFo cambiar el tamaño de la imagen usando ImageProcessor lib en el servidor de producción.

Reciclar el grupo de aplicaciones soluciona el problema.

tech-gayan
fuente
1

Si está intentando guardar una imagen en una ubicación remota, asegúrese de agregar la NETWORK_SERVICEcuenta de usuario en la configuración de seguridad y otorgarle permisos de lectura y escritura. De lo contrario, no va a funcionar.

JAH
fuente
1
byte[] bts = (byte[])page1.EnhMetaFileBits; 
using (var ms = new MemoryStream(bts)) 
{ 
    var image = System.Drawing.Image.FromStream(ms); 
    System.Drawing.Image img = image.GetThumbnailImage(200, 260, null, IntPtr.Zero);      
    img.Save(NewPath, System.Drawing.Imaging.ImageFormat.Png);
}
jeka
fuente
1

Simple, crear una nueva instancia de Bitmap resuelve el problema.

string imagePath = Path.Combine(Environment.CurrentDirectory, $"Bhatti{i}.png");
Bitmap bitmap = new Bitmap(image);
bitmap.Save(imagePath);
Hassan Rahman
fuente
0

Para mí estaba usando el Image.Save(Stream, ImageCodecInfo, EncoderParameters)y aparentemente esto estaba causando la infameA generic error occurred in GDI+ error.

Estaba tratando de usar EncoderParameter para guardar los archivos JPEG en 100% de calidad. Esto funcionaba perfectamente en "mi máquina" (¡sí!) Y no en la producción.

Cuando usé el Image.Save(Stream, ImageFormat) en lugar, ¡el error desapareció! Entonces, como un idiota, seguí usando este último, aunque los guarda en la calidad predeterminada, que supongo que es solo el 50%.

Espero que esta información ayude a alguien.

Ε Г И І И О
fuente
0

También encontré el problema. El problema se debió a la eliminación de la corriente de carga. Pero no lo eliminé, estaba dentro de .Net framework. Todo lo que tenía que hacer era usar:

image_instance = Image.FromFile(file_name);

en vez de

image_instance.Load(file_name);

image_instance es de tipo System.Windows.Forms.PictureBox! PictureBox's Load () elimina la secuencia desde la que se cargó la imagen, y no lo sabía.

Klaus
fuente
0

Según la respuesta de @savindra, si utiliza RHM en su aplicación e intenta ejecutarse como administrador, entonces debería resolver su problema.

El mío parecía ser un problema de permiso.

AltF4_
fuente
0

Los posibles problemas que causan tal error son:

  1. El directorio no existe (el método al que está llamando no creará automáticamente este directorio para usted)
  2. Los permisos de seguridad para escribir en el directorio de salida no permiten que el usuario que ejecuta la aplicación escriba

Espero que esto ayude, esta fue la solución para mi problema, ¡simplemente me aseguré de que el directorio de salida exista antes de guardar la imagen de salida!

Ihab Hajj
fuente