2010-02-26 12 views
9

Ich habe this jpeg, das öffnet sich gut in Picasa, Photoshop, Webbrowser usw. aber in .Net es weigert sich einfach zu arbeiten.Wie kann ich .Net erhalten, um dieses Bild zu speichern?

Image image = Image.FromFile(@"myimage.jpg"); 
image.Save(@"myimage2.jpg"); 
// ExternalException - A generic error occurred in GDI+. 

Gibt es eine Möglichkeit, es in .Net zu erholen, damit ich mit ihm zu arbeiten (ich brauche es, um die Größe), ohne an der Quelle das Problem zu lösen?

Volle Ausnahmedetails:

 
source: System.Drawing 
type: System.Runtime.InteropServices.ExternalException 
message: A generic error occurred in GDI+. 
stack trace:  
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) 
    at System.Drawing.Image.Save(String filename, ImageFormat format) 
    at System.Drawing.Image.Save(String filename) 
    at ConsoleApplication20.Program.Main(String[] args) in C:\Users\sam\Desktop\S 
ource\ConsoleApplication20\ConsoleApplication20\Program.cs:line 16 

Dieses Problem auf Windows 7.

+2

@ Sam Saffron: Sie sagen, „ohne das Problem an der Quelle Fixierung“, bedeutet das, dass das Bild nicht den Standard für JPEG folgt? Wenn dies der Fall ist, können Sie nicht erwarten, dass .NET mit Bildern arbeitet, die nicht dem Standard entsprechen, auch wenn andere Anwendungen weniger streng sind. Haben Sie auch die InnerException-Eigenschaft überprüft? Dort könnte es mehr Informationen darüber geben, warum genau das Laden fehlschlug. – casperOne

+0

Es lädt, es speichert einfach nicht. Ich weiß, dass es das Richtige ist, einen Roboter über alle Videobilder laufen zu lassen und es zu reparieren, aber das liegt außerhalb meiner Kontrolle, und dieses Ding brauchte 30 Minuten, um es zu finden. Alles, was ich bekomme, ist ein GDI-Fehler, ohne weitere Informationen oder innere Ausnahme und Explorer scheint keine Probleme zu haben, es zu öffnen, die noch seltsamer ist. –

+0

Ich habe gerade den gleichen Code in VB versucht und es funktioniert mit Ihrem bestimmten Bild. Hat sich das während des Uploads geändert? –

Antwort

3

Es scheint unter Windows XP und Vista zu funktionieren, aber nicht 7. Windows

konnte ich this issue on Microsoft Connect finden. Es ist nicht identisch mit Ihrem Problem, aber es sieht sehr ähnlich - ein ExternalException beim Versuch, eine JPEG-Datei erneut zu speichern. Derzeit bei 16 Repros mit einigen Kommentaren, dass das Problem in der endgültigen Version noch besteht.

Es scheint also nicht ein Fehler in .NET Framework, sondern ein Fehler in Windows 7 - speziell ein Fehler in der GdipSaveImageToStream API.

Die Problemumgehung, wie bereits erwähnt, besteht darin, eine Konvertierung in ein anderes Format zu erzwingen. Das tun sowohl Marc als auch Darins Antworten. Es gibt offensichtlich einige "zusätzliche" Informationen in der JPEG-Datei, die den Fehler in Win7 auslösen. Wenn Sie in ein anderes Format konvertieren oder eine Bitmap-Kopie erstellen, wird diese Information (EXIF möglicherweise?) Eliminiert.

+0

Ich habe den Verdacht, dass es irgendwo in den Kopfzeilen ist, aber ich kann es in dieser Sekunde nicht testen. Ich schlage vor, dass jemand versucht, mit jhead verschiedene Header aus der Image-Datei zu entfernen und zu sehen, ob der Code im OP ohne einen oder mehrere Header erfolgreich ist. Das Tool ist hier: http://www.sentex.net/~mwandel/jhead/ – Aaronaught

+0

Dies ist die vollständigste Antwort auf meine Frage jetzt in Erwägung, dies auf MS zu veröffentlichen –

0

reproduzierbar ist Versuchen Sie, Ihre Berechtigungen zu überprüfen. Nicht speichern kann verursacht werden, indem Sie nicht die richtige Berechtigung zum Schreiben/Ändern haben, und könnte diesen Fehler erzeugen.

+0

Es sind keine Berechtigungen. Ich habe es mit einem anderen Bild getestet und es funktioniert gut. Es ist nur dieses bestimmte Bild, das etwas falsch daran hat. –

4

Versuchen Angabe explizit das Format:

using (Image image = Image.FromFile(@"test.jpg")) 
{ 
    image.Save(@"myimage2.gif", ImageFormat.Gif); 
} 

Alle ImageFormat.Png, ImageFormat.Bmp und ImageFormat.Gif funktionieren. ImageFormat.Jpeg löst eine Ausnahme aus. Das Originalbild ist im Format JFIF, da es mit FF D8 FF E0 Byte beginnt.

+0

yerp das war mein Workaround, ich denke, es ist fair von Versuch und Irrtum die Bedingung des Habens von Problem jpegs ist ziemlich selten, so Schaltformate ist trivial und nicht so teuer. –

+0

wird JFIF in .Net nicht vollständig unterstützt? –

+0

@Sam Saffron: JFIF ist das eigentliche Dateiformat für JPEG-kodierte Bilder. Es wird von GDI + unterstützt und daher von .NET 'Image' und verwandten Klassen unterstützt, die nur Wrapper um GDI + sind. – Aaronaught

12

Dies scheint zu funktionieren:

using (Image image = Image.FromFile(@"c:\dump\myimage.jpg")) 
    using (Image clone = new Bitmap(image)) 
    { 
     clone.Save(@"c:\dump\myimage2.jpg", ImageFormat.Jpeg); 
    } 

image ist eigentlich ein Bitmap sowieso, also sollte es ähnlich sein. Seltsamer myimage2 5k kleiner ist - die Freuden von jpeg ;-p

Eine schöne daran ist, dass Sie in der gleichen Zeit können die Größe (Ihre eigentliche Absicht):

using (Image image = Image.FromFile(@"c:\dump\myimage.jpg")) 
    using (Image clone = new Bitmap(image, 
     new Size(image.Size.Width/2, image.Size.Height/2))) 
    { 

     clone.Save(@"c:\dump\myimage2.jpg", ImageFormat.Jpeg); 
    } 
+0

Ich denke, es gibt eine Möglichkeit, anzugeben, wie viel komprimieren Sie die JPEG, so ist meine Vermutung, dass es eine Spur von Treue verliert, dennoch funktioniert diese Abhilfe. Ich habe dies gestern überprüft http://code.google.com/p/videobrowser/source/diff?spec=svn0944fd56b5b6aaee6ba4a82593c286d1361cc280&r=0944fd56b5b6aaee6ba4a82593c286d1361cc280&format=side&path=/MediaBrowser/Library/ImageManagement/ImageCache.cs –

+0

Ich denke, ich könnte in Ihre Lösung passen Denken Sie immer noch, dass dies ein echter Bug in .net ist? Hast du den Fehler auch bekommen? –

+0

@Sam - Ja, ich habe den Fehler mit dem ursprünglichen Code, und ja, ich denke, das ist ein GDI-Fehler. Und nein, ich würde nicht erwarten, dass es in nächster Zeit repariert wird. –

2

Bitmap WPF mit Versuchen statt Das WinForm-Image unterstützt mehr Pixel-, Bild- und Dateiformate.

-1

Dieser Fehler occurrs, wenn Sie entweder

a. no permissions to write the file 
b. you are trying to write an image that is locked 
    (often, by a UI control ie. picturebox) 

haben Sie finden das Original entsorgen müssen, und dann über sie mit Ihrer Größe veränderten Klon speichern, wie in Marcs Antwort. Ich dachte nur, ich würde dir sagen, warum es passiert.

+0

Zum Downvoter: Anscheinend ist der Copy/Paste-Code weit überlegen, als zu wissen, warum das Problem überhaupt auftritt. gut gemacht –

+0

Ich werde überprüfen, dass die oben genannten Gründe in der Tat gültig sind. Es gibt andere Gründe, aber ich sehe keine Notwendigkeit für eine Abstimmung nach unten. Dieser Beitrag hätte mir vor ein paar Tagen geholfen, als ich mich mit einem früheren Teil des Problems befasste, der mich nach diesem Thema suchte. – DCastenholz

2

Ich versuchte gestern auf 32-Bit-XP und kann nicht das Problem reproduziert. Heute habe ich 64bit Win7 ausprobiert und bekomme genau den Fehler, den du beschrieben hast, was großartig für mein Debugging ist.

suchte ich den Header und die JPEG ist ein Standard-JPEG aber mit EXIF-Header. Von dem, was ich gelesen habe, ist es nicht ungewöhnlich, dass der EXIF-Header korrupt ist und einige Programme ignorieren es einfach. In .NET erlaubt es zu lesen und (vielleicht sogar zu schreiben), aber nicht zu schreiben. Sie können hier mehr darüber lesen.
http://blogs.msdn.com/calvin_hsia/archive/2005/07/24/442873.aspx

Ein Weg, um es zu entfernen ist, das Bild zu klonen wie von Marc vorgeschlagen, die das neue Bild ohne EXIF-Header erstellen werden, damit das erklärt, warum die Dateigröße tatsächlich kleiner ist. Es gibt Verfahren programmatisch EXIF-Header zu entfernen, einige haben in Stackoverflow wie unten vorgeschlagen: simple way to remove EXIF data from a JPEG with .NET

Das vorgeschlagene Problem mit dem Byte-Marker zu lesen und dem Strom überspringen wird auch konsequent nicht arbeiten, wie wir mit beschädigten EXIF-Header handeln. Ich habe versucht, RemovePropertyItem ist eine Option, aber es funktioniert immer noch nicht, und meine Vermutung ist, weil es beschädigte Eigenschaft Element, das verwiesen wird (wenn ich den JPEG-Header überprüfen gibt es 6 Eigenschaften, lädt .NET nur 4). Sie sind andere Bibliothek wie exiv2net, die erkundet werden können, aber ich vermute, das Ergebnis wird ähnlich sein.

kurz In der Antwort wird sein, das Bild zu klonen, wie Marc vorgeschlagen. Dies ist vielleicht nicht die Lösung, sondern eine Einsicht in das Problem.

3

Dies ist eine seit langem bestehende Fehler in dem .NET-Framework selbst, dass ich erwarte, dass keine Zeit bald behoben zu sehen. Es gibt mehrere ähnliche Fehler, die ich auch auf, dass die mit ‚allgemeiner Fehler in GDI + aufgetreten‘ werfen gekommen sind, wenn Sie die PropertyItem Sammlung für einige JPEGs zugreifen (die EXIF-Codes prüfen), dann von diesem Punkt an Sie nicht in der Lage sein wird, Speichere das Bild. Auch, ohne Grund und Recht, einige JPEGs, wie die, die Sie hier haben, werden einfach nicht speichern. Beachten Sie, dass das Speichern als anderes Format nicht immer funktioniert, auch wenn dies in diesem Fall der Fall ist.

Die Problemumgehung, die ich in einer App von mir verwendet habe, die Bilder aus dem ganzen Web verbraucht (und daher mehr als ihren gerechten Anteil an diesen Arten von Problemen sieht), ist die ExternalException abzufangen und das Bild in ein neues zu kopieren Bitmap wie in einem der vorhergehenden Antworten, aber einfach dies als neue JPEG-Speichern wird die Qualität sinken ziemlich viel so verwende ich Code ähnlich wie die unter die Qualität hoch zu halten:

namespace ImageConversionTest 
{ 
    using System.Drawing; 
    using System.Runtime.InteropServices; 
    using System.Drawing.Imaging; 
    using System.Globalization; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      using(Image im = Image.FromFile(@"C:\20128X.jpg")) 
      { 
       string saveAs = @"C:\output.jpg"; 

       EncoderParameters encoderParams = null; 
       ImageCodecInfo codec = GetEncoderInfo("image/jpeg"); 
       if(codec != null) 
       { 
        int quality = 100; // highest quality 
        EncoderParameter qualityParam = new EncoderParameter( 
         System.Drawing.Imaging.Encoder.Quality, quality); 
        encoderParams = new EncoderParameters(1); 
        encoderParams.Param[0] = qualityParam; 
       } 

       try 
       { 
        if(encoderParams != null) 
        { 
         im.Save(saveAs, codec, encoderParams); 
        } 
        else 
        { 
         im.Save(saveAs, ImageFormat.Jpeg); 
        } 
       } 
       catch(ExternalException) 
       { 
        // copy and save separately 
        using(Image temp = new Bitmap(im)) 
        { 
         if(encoderParams != null) 
         { 
          temp.Save(saveAs, codec, encoderParams); 
         } 
         else 
         { 
          temp.Save(saveAs, ImageFormat.Jpeg); 
         } 
        } 
       } 
      } 
     } 

     private static ImageCodecInfo GetEncoderInfo(string mimeType) 
     { 
      // Get image codecs for all image formats 
      ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); 

      // Find the correct image codec 
      foreach(ImageCodecInfo codec in codecs) 
      { 
       if(string.Compare(codec.MimeType, mimeType, true, CultureInfo.InvariantCulture) == 0) 
       { 
        return codec; 
       } 
      } 
      return null; 
     } 
    } 
} 

Hinweis, dass Sie verliere die EXIF-Informationen, aber ich lasse das für jetzt (Sie werden immer noch in der Lage sein, die EXIF-Codes zu lesen, auch wenn das Speichern des Quellbildes fehlschlägt). Ich habe es schon lange aufgegeben, herauszufinden, was .NET an bestimmten Bildern nicht mag (und Beispiele verschiedener Fehlerfälle haben, sollte jemand jemals die Herausforderung annehmen wollen), aber der obige Ansatz funktioniert, was gut ist .

Verwandte Themen