Er is een algemene fout opgetreden in GDI+, JPEG-afbeelding naar MemoryStream

Dit lijkt een beetje een beruchte fout op internet. Zozeer zelfs dat ik geen antwoord op mijn probleem heb kunnen vinden omdat mijn scenario niet past. Er wordt een uitzondering gegenereerd wanneer ik de afbeelding in de stream opsla.

Vreemd genoeg werkt dit perfect met een png, maar geeft de bovenstaande fout met jpg en gif, wat nogal verwarrend is.

De meeste vergelijkbare problemen hebben betrekking op het opslaan van afbeeldingen in bestanden zonder toestemming. Ironisch genoeg is de oplossing om een geheugenstroom te gebruiken zoals ik doe….

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

Meer details over de uitzondering. De reden dat dit zoveel problemen veroorzaakt, is het gebrek aan uitleg 🙁

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 dingen die ik tot nu toe heb geprobeerd.

  1. De afbeelding klonen en daaraan werken.
  2. De encoder ophalen voor die MIME die dat doorgeeft met de jpeg-kwaliteitsinstelling.

Antwoord 1, autoriteit 100%

Ok, ik schijn de oorzaak te hebben gevonden door puur geluk en er is niets mis met die specifieke methode, het is een grotere back-up van de call-stack.

Eerder wijzig ik het formaat van de afbeelding en als onderdeel van die methode retourneer ik het verkleinde object als volgt. Ik heb twee aanroepen ingevoegd naar de bovenstaande methode en een directe opslag in een bestand.

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

Het lijkt erop dat de geheugenstroom waarop het object is gemaakt moetopen zijn op het moment dat het object wordt opgeslagen. Ik weet niet zeker waarom dit is. Is er iemand die mij duidelijkheid kan verschaffen en hoe ik dit kan omzeilen.

Ik kom alleen terug van een stream omdat na het gebruik van de resize-code vergelijkbaar met dithet doelbestand heeft een onbekend mime-type (img.RawFormat.Guid) en id wil dat het Mime-type correct is voor alle afbeeldingsobjecten, omdat het anders moeilijk is om generieke verwerkingscode te schrijven.

BEWERKEN

Dit kwam niet naar voren in mijn eerste zoekopdracht, maar hier ishet antwoord van Jon Skeet


Antwoord 2, autoriteit 67%

Als je die foutmelding krijgt, kan ik zeggen dat je toepassing geen schrijfrechten heeft voor een map.

Als u bijvoorbeeld probeert de afbeelding van de geheugenstroom naar het bestandssysteem op te slaan, kunt u die fout krijgen.

Als u XP gebruikt, zorg er dan voor dat u schrijfrechten toevoegt voor het aspnet-account in die map.

Als u Windows Server (2003,2008) of Vista gebruikt, zorg er dan voor dat u schrijfrechten toevoegt voor het netwerkserviceaccount.

Ik hoop dat het iemand helpt.


Antwoord 3, autoriteit 28%

Ik zal deze oorzaak van de fout ook toevoegen in de hoop dat het een toekomstige internetreiziger helpt. 🙂

GDI+ beperkt de maximale hoogte van een afbeelding tot 65500

We passen het formaat van afbeeldingen enigszins aan, maar bij het wijzigen van het formaat proberen we de beeldverhouding te behouden. We hebben een QA-man die een beetje te goed is in dit werk; hij besloot dit te testen met een EEN pixel brede foto die 480 pixels hoog was. Toen de afbeelding werd geschaald om aan onze afmetingen te voldoen, was de hoogte ten noorden van 68.000 pixels en explodeerde onze app met A generic error occurred in GDI+.

Je kunt dit zelf verifiëren met 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+."
  }

Het is jammer dat er geen gebruiksvriendelijke .net ArgumentExceptionin de constructor van Bitmapis gegooid.


Antwoord 4, autoriteit 19%

Dit artikel legt in detail uit wat er precies gebeurt: afhankelijkheden van bitmap- en afbeeldingsconstructor

Kortom, voor een levensduur van een Imageopgebouwd uit een stream, mag de stream niet worden vernietigd.

Dus, in plaats van

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

probeer dit

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

en sluit imageStreamop het formulier sluiten of webpagina sluiten.


Antwoord 5, autoriteit 15%

Je krijgt deze uitzondering ook als je probeert op te slaan op een ongeldig pad of als er een probleem is met de rechten.

Als je er niet 100% zeker van bent dat het bestandspad beschikbaar is en de rechten correct zijn, probeer dan een naar een tekstbestand te schrijven. Dit duurt slechts een paar seconden om uit te sluiten wat een heel eenvoudige oplossing zou zijn.

var img = System.Drawing.Image.FromStream(incomingStream);
// img.Save(path);
System.IO.File.WriteAllText(path, "Testing valid path & permissions.");

En vergeet niet je bestand op te schonen.


Antwoord 6, autoriteit 11%

Afbeelding opslaan in bitmapvariabele

using (var ms = new MemoryStream())
{
    Bitmap bmp = new Bitmap(imageToConvert);
    bmp.Save(ms, format);
    return ms.ToArray();
}

Antwoord 7, autoriteit 8%

Voor het geval iemand net zulke domme dingen doet als ik.
1. zorg ervoor dat het pad bestaat.
2. zorg ervoor dat je toestemming hebt om te schrijven.
3. zorg ervoor dat je pad correct is, in mijn geval miste ik de bestandsnaam in het TargetPath 🙁

het had moeten zeggen, je pad is waardeloos dan “Er is een algemene fout opgetreden in GDI+”


Antwoord 8, autoriteit 8%

Ik kreeg deze fout ook bij het opslaan van JPEG’s, maar alleen voor bepaalde afbeeldingen.

Mijn definitieve code:

 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
  }

Ik heb de afbeeldingen niet gemaakt, dus ik kan niet zien wat het verschil is.
Ik zou het op prijs stellen als iemand dat zou kunnen uitleggen.

Dit is mijn SaveJpeg-functie ter informatie:

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

Antwoord 9, autoriteit 6%

Had een vergelijkbaar probleem en heb ook geprobeerd de afbeelding te klonen, wat niet werkt. Ik ontdekte dat de beste oplossing was om een nieuw Bitmap-object te maken van de afbeelding die uit de geheugenstroom was geladen. Op die manier kan de stroom b.v.

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

Hopelijk helpt dit.


Antwoord 10, autoriteit 6%

Ik ontdekte dat als een van de bovenliggende mappen waarin ik het bestand aan het opslaan was een volgspatie had, GDI+ de algemene uitzondering zou genereren.

Met andere woorden, als ik probeerde op te slaan in “C:\Documents and Settings\myusername\Local Settings\Temp\ABC DEF M1 Trended Values \Images\picture.png” dan kreeg ik de algemene uitzondering.

Mijn mapnaam werd gegenereerd op basis van een bestandsnaam die toevallig een spatie had, dus het was gemakkelijk om die te .Trim() en verder te gaan.


Antwoord 11, autoriteit 6%

als uw code als volgt is, treedt deze fout ook op

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

De juiste is

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

Dit kan zijn omdat we terugkeren van het gebruiksblok


Antwoord 12, autoriteit 6%

Dit is een uitbreiding / kwalificatie van Fred’s reactie waarin stond: “GDI beperkt de hoogte van een afbeelding tot 65534”. We kwamen dit probleem tegen met een van onze .NET-applicaties en na het zien van de post stak ons outsourcingteam de handen in de lucht en zei dat ze het probleem niet konden oplossen zonder grote veranderingen.

Op basis van mijn testen is het mogelijk om afbeeldingen te maken/manipuleren met een hoogte groter dan 65534, maar het probleem doet zich voor bij het opslaan in een stream of bestand IN BEPAALDE FORMATEN. In de volgende code gooit de t.Save() methode-aanroep onze vriend de generieke uitzondering wanneer de pixelhoogte voor mij 65501 is. Uit nieuwsgierigheid heb ik de test voor breedte herhaald en dezelfde limiet toegepast op opslaan.

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

Dezelfde fout treedt ook op als u naar een geheugenstroom schrijft.

Om dit te omzeilen, kun je de bovenstaande code herhalen en ImageFormat.Tiff of ImageFormat.Bmp vervangen door ImageFormat.Jpeg.

Dit loopt voor mij op tot hoogtes / breedtes van 100.000 – ik heb de limieten niet getest. Toevallig was Tiff een haalbare optie voor ons.

WEES GEWAARSCHUWD

De TIFF-streams/bestanden in het geheugen verbruiken meer geheugen dan hun JPG-tegenhangers.


Antwoord 13, autoriteit 3%

Fout vanwege toestemming. zorg ervoor dat de map ALLE TOESTEMMING heeft.

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")

Antwoord 14, autoriteit 2%

OPGELOST – Ik had precies dit probleem. De oplossing was voor mij om het schijfquotum voor IUSR op de IIS-server te verhogen. In dit geval hebben we een catalogus-app met afbeeldingen van items en dergelijke. Het uploadquotum voor de “anonieme webgebruiker” was ingesteld op 100 MB, wat de standaard is voor de IIS-servers van dit specifieke hostingbedrijf. Ik heb het verhoogd tot 400 MB en kon afbeeldingen zonder fouten uploaden.

Dit is misschien niet jouw probleem, maar als dat zo is, is het een gemakkelijke oplossing.


Antwoord 15, autoriteit 2%

In mijn geval zat het probleem in het pad dat ik aan het opslaan was (de root C:\). Door het te veranderen in D:\111\verdween de uitzondering.


Antwoord 16, autoriteit 2%

Een andere oorzaak voor deze fout: het pad dat u aangeeft in de methode Opslaan van de Bitmap-instantie bestaat niet of u heeft geen volledig/geldig pad opgegeven.

Ik kreeg net deze fout omdat ik een bestandsnaam doorgaf en geen volledig pad!

Het gebeurt!


Antwoord 17, autoriteit 2%

Mijn beurt!

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

Ik heb het op de .Save… omdat het gebruik() het bestand open houdt, dus ik kan het niet overschrijven. Misschien helpt dit iemand in de toekomst.


Antwoord 18, autoriteit 2%

Hetzelfde probleem waarmee ik werd geconfronteerd. Maar in mijn geval probeerde ik het bestand op de C-schijf op te slaan en het was niet toegankelijk. Dus ik probeerde het op te slaan in de D-schijf die volledig toegankelijk was en het is me gelukt.

Controleer dus eerst uw mappen waarin u probeert op te slaan. U moet alle (lees- en schrijf)rechten hebben voor die specifieke map.


Antwoord 19

Eenvoudig, een nieuwe instantie van Bitmap maken lost het probleem op.

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

Antwoord 20

Ik merk dat je “jpeg”-case eigenlijk is:

           default:
                format = ImageFormat.Jpeg;
                break;

Weet je zeker dat het formaat jpeg is en niet iets anders?

Ik zou het proberen:

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

Of controleer wat imageToConvert.MimeType()daadwerkelijk retourneert.

UPDATE

Is er nog een andere initialisatie die u moet doen voor het MemoryStream-object?


Antwoord 21

  • Ik had dit probleem op een testserver, maar niet op de liveserver.
  • Ik was de afbeelding aan het schrijven naar een stream, dus het was geen toestemmingsprobleem.
  • Ik had enkele van de .dll’s rechtstreeks op de testserver geïmplementeerd.
  • Het implementeren van de volledige oplossing loste het probleem op, dus het was waarschijnlijk een rare compilatie die niet overeenkwam

Antwoord 22

Om nog een mogelijke oplossing op de stapel te gooien, noem ik het geval dat ik tegenkwam met deze foutmelding. De methode Bitmap.Savezou deze uitzondering veroorzaken bij het opslaan van een bitmap die ik had getransformeerd en aan het weergeven was. Ik ontdekte dat het de uitzondering niet zou genereren als de instructie een breekpunt had, en ook niet als de Bitmap.Savewerd voorafgegaan door Thread.Sleep(500), dus ik stel dat er een of andere bronconflict gaande is.

Het volstaat om de afbeelding naar een nieuw Bitmap-object te kopiëren om te voorkomen dat deze uitzondering verschijnt:

new Bitmap(oldbitmap).Save(filename);

Antwoord 23

Een andere oorzaak van deze fout en die mijn probleem oplost, is dat uw toepassing geen schrijfrechten heeft voor een map.

dus om het antwoord van savindra aan te vullen: https://stackoverflow.com/a/7426516/6444829.

Zo verleent u bestandstoegang aan IIS_IUSERS

Om toegang te verlenen tot een ASP.NET-toepassing, moet u toegang verlenen tot de IIs_IUSERS.

Lees-, schrijf- en wijzigingsrechten toekennen aan een specifiek bestand of een specifieke map

  1. Zoek en selecteer in Windows Verkenner het gewenste bestand.

  2. Klik met de rechtermuisknop op het bestand en klik vervolgens op Eigenschappen.

  3. Klik in het dialoogvenster Eigenschappen op het tabblad Beveiliging.

  4. Bekijk op het tabblad Beveiliging de lijst met gebruikers.
    (Als uw toepassing als een netwerkservice wordt uitgevoerd, voegt u het netwerkserviceaccount toe aan de lijst en verleent u deze toestemming.

  5. Klik in het dialoogvenster Eigenschappen op IIs_IUSERS en selecteer in het gedeelte Machtigingen voor NETWERKSERVICE de machtigingen Lezen, Schrijven en Wijzigen.

  6. Klik op Toepassen en vervolgens op OK.

dit werkte voor mij in mijn IIS van Windows Server 2016 en lokale IIS Windows 10.


Antwoord 24

We hadden een soortgelijk probleem bij het genereren van een PDFof het wijzigen van het formaat van een afbeelding met behulp van ImageProcessor lib op de productieserver.

Recycle de applicatiepoolverhelp het probleem.


Antwoord 25

Als je een afbeelding probeert op te slaan op een externe locatie, zorg er dan voor dat je het gebruikersaccount NETWORK_SERVICEtoevoegt aan de beveiligingsinstellingen en geef die gebruiker lees- en schrijfrechten. Anders gaat het niet werken.


Antwoord 26

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

Antwoord 27

Ik krijg deze foutmelding ook omdat ik afbeeldingen probeer op te slaan met dezelfde naam als eerder opgeslagen afbeeldingen.

Zorg ervoor dat u geen afbeeldingen met een dubbele naam opslaat.

Gebruik voor bijvoorbeeld een ‘Random’-functie (Hoe werkt de willekeurige nummergenerator werken?)
of genereer bijvoorbeeld een Guid (http://betterexplained.com/articles/ the-quick-guide-to-guids/)


Antwoord 28

in mijn geval was het pad verkeerd

gebruik dit gewoon

String path = Server.MapPath("~/last_img.png");//Path

Antwoord 29

Voor mij gebruikte ik de Image.Save(Stream, ImageCodecInfo, EncoderParameters)en blijkbaar veroorzaakte dit de beruchte A generic error occurred in GDI+-fout.

p>

Ik probeerde EncoderParameterte gebruiken om de jpeg’s in 100% kwaliteit op te slaan. Dit werkte perfect op “mijn machine” (doh!) en niet op productie.

Toen ik in plaats daarvan de Image.Save(Stream, ImageFormat)gebruikte, verdween de fout! Dus als een idioot bleef ik de laatste gebruiken, hoewel het ze opslaat in standaardkwaliteit waarvan ik aanneem dat het slechts 50% is.

Ik hoop dat deze informatie iemand helpt.


Antwoord 30

Ik ben het probleem ook tegengekomen. Het probleem was te wijten aan het weggooien van de laadstroom. Maar ik heb het niet weggegooid, het zat in het .Net-framework. Ik hoefde alleen maar te gebruiken:

image_instance = Image.FromFile(file_name);

in plaats van

image_instance.Load(file_name);

image_instance is van het type System.Windows.Forms.PictureBox!
PictureBox’s Load() beschikt over de stream waaruit de afbeelding is geladen, en dat wist ik niet.

Other episodes