2009-04-07 5 views
2

Ich habe ein Bild, das ich im Speicher als Format24bppRgb erstellt habe.Konvertiere ein 24-Bit im Speicherbild in eine indizierte Farbe

Ich speichere dies als PNG und es ist 24kb.

Wenn ich das selbe Bild mit Photoshop als 24bit PNG speichere kommt es ungefähr gleich groß, aber wenn ich es als 8bit PNG mit nur 32 Farben speichere geht es bis 5kb runter.

Wie kann ich eine indizierte Version einer PNG-Datei mit C#/GDI +/System.Drawing erstellen?

Es fällt mir schwer, Antworten auf diese Frage zu finden, die nicht nur für Graustufenbilder gelten oder eine externe Bibliothek erfordern. Ist das nicht möglich innerhalb von GDI +?

Antwort

0

Sie versuchen, 16777216 Farben auf 32 zu reduzieren. Dies ist ein nicht-triviales Problem, und es gibt viele Möglichkeiten, dies zu tun, die alle ihre Plus- und Minuspunkte haben. Dies ist nicht unbedingt erforderlich, besonders da Vollfarbdisplays allgegenwärtig sind.

Dieser Microsoft-Artikel enthält einige Informationen zu GIF-Dateien, die auch für PNG relevant sein sollten.

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q319061

+0

aber Photoshop macht es so einfach aussehen :-) Ich freue mich auf FreeImage.NET jetzt –

+1

Or Das Bild kann trotzdem 32 Farben haben. In diesem Fall verlieren Sie nichts. – axk

2

I beendete die FreeImageAPI DLL, mit einem C# Wrapper zu verbrauchen. Ich versuche, Bibliotheken von Drittanbietern zu vermeiden, aber ich denke nicht, dass es eine andere Wahl gibt. Es scheint eine ziemlich normale und gut benutzte Bibliothek zu sein.

In meinem Fall habe ich ein System.Drawing.Image Objekt 'image', die dynamisch erstellt wurde - was ich möchte den Httpcontext Ausgangsstrom als ein komprimiertes Bild speichern. Beachten Sie, dass Image nicht die erforderliche GetHbitmap() Methode hat, aber Bitmap tut.

// convert image to a 'FreeImageAPI' image 
var fiBitmap = FreeImageAPI.FreeImageBitmap.FromHbitmap((image as Bitmap).GetHbitmap()); 
fiBitmap.ConvertColorDepth(FreeImageAPI.FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP); 

// see http://stackoverflow.com/questions/582766 
MemoryStream ms = new MemoryStream(); 
fiBitmap.Save(ms, FreeImageAPI.FREE_IMAGE_FORMAT.FIF_PNG, FreeImageAPI.FREE_IMAGE_SAVE_FLAGS.PNG_Z_BEST_COMPRESSION); 
context.HttpContext.Response.OutputStream.Write(ms.ToArray(), 0, (int)ms.Length); 

Mein 24kb Bitmap erst jetzt 9kb :-)

Tipp: Achten Sie darauf, beide haben 'FreeImageNET' und 'Freeimage' dlls in Ihrem bin zur Verfügung, wenn Sie es starten. Zum gegenwärtigen Zeitpunkt enthalten die C# -Beispielprojekte einen Verweis auf 'Library.DLL', die in ihrer Zip-Datei nicht zu existieren scheint. Die Verwendung von FreeImageNET.dll und FreeImage.dll funktioniert jedoch. Sie erhalten eine ärgerliche Datei nicht gefunden Fehler, wenn Sie nicht wissen, dass FreeImageNet! = FreeImage!

+0

Wie installiere ich es auf Windows 7 64 Bit? –

+0

Seien Sie vorsichtig mit bitmap.GetHbitmap(). Sie müssen diesen Speicher manuell freigeben oder er wird auslaufen. 1.[DllImport ("gdi32.dll")] private statisch extern bool DeleteObject (IntPtr hObject); 2. IntPtr hBitmap = bitmap.GetHbitmap(); 3. FreeImageBitmap freeImageBitmap = FreeImageBitmap.VonHbitmap (hBitmap); 4. (Mach Sachen) 5. DeleteObject (hBitmap); –

1

Sie können dies mit nQuant (die Sie mit Nuget installieren können, oder siehe Referenzen unten) tun. Im folgenden Beispiel wird ein Image auf der Festplatte konvertiert und an Ihre Anforderungen angepasst.

public static bool TryNQuantify(string inputFilename, string outputFilename) 
    { 
     var quantizer = new nQuant.WuQuantizer(); 
     var bitmap = new Bitmap(inputFilename); 
     if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb) 
     { 
      ConvertTo32bppAndDisposeOriginal(ref bitmap); 
     } 

     try 
     { 
      using (var quantized = quantizer.QuantizeImage(bitmap)) 
      { 
       quantized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png); 
      } 
     } 
     catch 
     { 
      return false; 
     } 
     finally 
     { 
      bitmap.Dispose(); 
     } 
     return true; 
    } 

    private static void ConvertTo32bppAndDisposeOriginal(ref Bitmap img) 
    { 
     var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
     using (var gr = Graphics.FromImage(bmp)) 
      gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height)); 
     img.Dispose(); 
     img = bmp; 
    } 

Weitere Informationen finden Sie unter:

+0

Das ist gut, wenn Sie einen Alpha-Kanal wollen, der kein 1-Bit-Kanal ist. Sie erhalten ein 8-Bit-Bild mit Alpha, ähnlich wie bei tinypng.com. Aber sei gewarnt, es ist ziemlich langsam –

+0

Das funktionierte gut für mich, aber es ist wichtig zu beachten, dass wenn ich Bilder mit einer Höhe von mehr als 4550 Pixel behandelt hatte, konnte kein Bild erzeugt werden und die Ausgabe war ein leeres graues Bild. – BornToCode