c# - interopservices - error genérico gdi+ system drawing image save
Se produjo un error genérico en GDI+, imagen JPEG a MemoryStream (28)
Esto parece ser un error infame en toda la web. Tanto que no he podido encontrar una respuesta a mi problema porque mi escenario no encaja. Se produce una excepción cuando guardo la imagen en la secuencia.
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 está relacionado 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:
Bien, cosas que he probado hasta ahora.
- Clonando la imagen y trabajando en eso.
- Recuperar el codificador para ese MIME que pasa eso con la configuración de calidad jpeg.
¡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 .Save ... porque el uso () mantiene el archivo abierto, así que no puedo sobrescribirlo. Tal vez esto ayude a alguien en el futuro.
Agregaré esta causa del error también 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 UN pixel de ancho que tenía 480 píxeles de alto. Cuando la imagen se amplió para cumplir con nuestras dimensiones, la altura era de 68,000 píxeles y nuestra aplicación explotó con A generic error occurred in GDI+
.
Puedes comprobarlo tú mismo con test:
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 lástima que no se haya generado una .net ArgumentException
amigable en el constructor de Bitmap
.
De acuerdo con la respuesta de @savindra, si realiza 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.
Descubrí que si una de las carpetas principales donde estaba guardando el archivo tenía un espacio final, GDI + lanzaría la excepción genérica.
En otras palabras, si intenté guardar en "C: / Documents and Settings / myusername / Local Settings / Temp / ABC DEF M1 Trending Values / Images / picture.png", se lanzó la excepción genérica.
El nombre de mi carpeta se generaba a partir de un nombre de archivo que tenía un espacio al final, por lo que era fácil .Trim () eso y seguir adelante.
El mismo problema al que me enfrentaba. Pero en mi caso, estaba tratando de guardar el archivo en la unidad C y no era accesible. Así que lo intenté para guardar en la unidad D que era completamente accesible y lo logré.
Así que primero revise sus carpetas en las que está tratando de guardar. Debe tener todos los derechos (de lectura y escritura) para esa carpeta en particular.
En mi caso, el problema estaba en la ruta que estaba guardando (la raíz C:/
). Cambiarlo a D:/111/
hizo que la excepción desapareciera.
Esta es una expansión / calificación de la respuesta de Fred que dice: "GDI limita la altura de una imagen a 65534". Nos topamos con este problema con una de nuestras aplicaciones .NET y, después de haber visto la publicación, nuestro equipo de subcontratación levantó el control y dijo que no podían solucionar el problema sin grandes cambios.
Según mis pruebas, es posible crear / manipular imágenes con una altura mayor que 65534, pero el problema surge al guardar en una secuencia o archivo EN CIERTOS FORMATOS . En el siguiente código, la llamada al método t.Save () lanza a nuestro amigo la excepción genérica cuando la altura del píxel es 65501 para mí. Por razones de curiosidad, repetí la prueba de ancho y el mismo límite aplicado 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 ocurre si escribe en un flujo de memoria.
Para redondearlo, puede repetir el código anterior y sustituir ImageFormat.Tiff o ImageFormat.Bmp por ImageFormat.Jpeg.
Esto me lleva a alturas / anchuras de 100,000 para mí, no probé los límites. Da la casualidad de que Tiff era una opción viable para nosotros.
Ser advertido
Los flujos / archivos TIFF en memoria consumen más memoria que sus homólogos de JPG.
Este artículo explica en detalle qué sucede exactamente: las dependencias del mapa de bits y el constructor de imágenes.
En resumen, durante toda la vida de una Image
construida a partir de un flujo , el flujo no debe ser destruido.
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 cierre del formulario o cierre de la página web.
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();
}
Me doy cuenta de 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 compruebe qué imageToConvert.MimeType()
está devolviendo realmente.
ACTUALIZAR
¿Hay alguna otra inicialización que deba hacer al objeto MemoryStream?
Me encontré con el problema también. El problema se debió a la disposición de la corriente de carga. Pero no lo dispuse, estaba dentro de .Net framework. Todo lo que tenía que hacer era usar:
image_instance = Image.FromFile(file_name);
en lugar de
image_instance.Load(file_name);
image_instance es de tipo System.Windows.Forms.PictureBox! PictureBox''s Load () elimina el flujo desde el que se cargó la imagen, y no lo sabía.
OK, parece que encontré la causa solo por pura suerte y no hay nada de malo con ese método en particular, es más una copia de seguridad de la pila de llamadas.
Antes, redimensiono 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 el flujo de memoria en el que se creó el objeto debe estar abierto en el momento en que se guarda el objeto. No estoy seguro de por qué esto es. ¿Alguien puede iluminarme y cómo puedo solucionar esto?
Solo vuelvo de una secuencia porque después de usar el código de cambio de tamaño similar a this el archivo de destino tiene un tipo de mime desconocido (img.RawFormat.Guid) y el ID como el tipo de Mime es correcto en todos los objetos de imagen, ya que hace que sea difícil escribir en genérico manejo de código de lo contrario.
EDITAR
Esto no surgió en mi búsqueda inicial, pero here''s la respuesta de Jon Skeet
Otra causa de este error: la ruta que indica en el método Guardar de la instancia de Bitmap no existe o no ha proporcionado una ruta completa / válida.
¡Solo tuve este error porque estaba pasando un nombre de archivo y no una ruta completa!
¡Sucede!
Para mí estaba usando Image.Save(Stream, ImageCodecInfo, EncoderParameters)
y aparentemente esto estaba causando el infame A generic error occurred in GDI+
.
Estaba intentando usar EncoderParameter
para guardar los jpegs en calidad 100%. Esto funcionaba perfectamente en "mi máquina" (¡doh!) Y no en producción.
Cuando utilicé Image.Save(Stream, ImageFormat)
, ¡el error desapareció! Así que, como un idiota, continué usando este último, aunque los guarda con la calidad predeterminada, que supongo que es solo el 50%.
Espero que esta información ayude a alguien.
Por si acaso si alguien está haciendo cosas tan estúpidas como yo. 1. Asegúrese de que el camino existe. 2. Asegúrate 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 que su ruta es peor que "Se produjo un error genérico en GDI +"
RESUELTO - Tuve este problema exacto. La solución, para mí, fue 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 la predeterminada para los servidores IIS de esta empresa de alojamiento en particular. Lo subí a 400MB y pude subir imágenes sin error.
Puede que este no sea su problema, pero si lo es, es una solución fácil.
Se produce un error debido a un 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")
Si está intentando guardar una imagen en una ubicación remota, asegúrese de agregar la cuenta de usuario NETWORK_SERVICE
en la configuración de seguridad y de otorgarle permisos de lectura y escritura. De lo contrario no va a funcionar.
Si está recibiendo 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 obtener ese error.
Por favor, si está utilizando XP, asegúrese de agregar permiso de escritura para la cuenta aspnet en esa carpeta.
Si está usando Windows Server (2003, 2008) o Vista, asegúrese de agregar permiso de escritura para la cuenta de servicio de red.
Espero que ayude a alguien.
Si su código es el siguiente, entonces 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 ser porque estamos regresando del bloque de uso
Solo para lanzar otra posible solución en la pila, mencionaré el caso que encontré con este mensaje de error. El método Bitmap.Save
pasaría por esta excepción al guardar un mapa de bits que había transformado y estaba mostrando. Descubrí que no lanzaría la excepción si la declaración tuviera un punto de interrupción, ni tampoco si el Bitmap.Save
fue precedido por Thread.Sleep(500)
así que supongo que hay algún tipo de contención de recursos en curso.
Basta con copiar la imagen en un nuevo objeto de mapa de bits para evitar que aparezca esta excepción:
new Bitmap(oldbitmap).Save(filename);
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 son correctos, intente escribir un archivo de texto. Esto lleva solo unos segundos 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.
También obtuve este error al guardar archivos JPEG, pero solo para ciertas imágenes.
Mi código 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.
Apreciarí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);
}
También recibo este error porque estoy tratando de guardar imágenes con el mismo nombre de las imágenes guardadas anteriormente.
Asegúrate de no guardar imágenes con nombre duplicado.
Utilice para thar, por ejemplo, una función ''Aleatoria'' ( ¿Cómo funciona el generador de números aleatorios de C #? ) O, por ejemplo, genere un Guid ( http://betterexplained.com/articles/the-quick-guide-to-guids/ )
Tenía 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 se puede eliminar la corriente, por ejemplo,
using (var m = new MemoryStream())
{
var img = new Bitmap(Image.FromStream(m));
return img;
}
Espero que esto ayude.
Tuvimos el mismo problema al generar un PDF en el servidor de producción.
Recicle el grupo de aplicaciones solucione el problema.
Espero que esto ayude a alguien.
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);
}
- 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.
- He estado implementando directamente algunos de los archivos .dll en el servidor de prueba.
- Implementar la solución completa solucionó el problema, por lo que probablemente fue una extraña discrepancia de compilación