Entwickler-Ecke

WinForms - Image einer PictureBox mit 8-Bit Farbtiefe speichern


Rassi - Mi 02.09.09 17:20
Titel: Image einer PictureBox mit 8-Bit Farbtiefe speichern
Hallo.

Ich möchte das Image einer PictureBox abspeichern.

C#-Quelltext
1:
pictureBox1.Image.Save(textBox1.Text, System.Drawing.Imaging.ImageFormat.Jpeg);                    

Dieses Image hat eine Farbtiefe von 24Bit.
Gespeichert werden soll es aber mit 8-Bit.
Wie mache ich das?

Gruß
Rasmus


Christian S. - Mi 02.09.09 17:52

Du willst also ein Graustufenbild haben?


Rassi - Mi 02.09.09 17:56

Hallo.
Ja, so ist es.
Das Umwandeln in Graustufen, habe ich auch schon.
Wichtig ist, dass das Bild mit einer Farbtiefe von 8-Bit gespeichert wird.
Wenn ich es, wie oben gezeigt, abspeichere, wird immer ein Bild mit einer Bittiefe von 24Bit gespeichert (Dateiinfo, siehe Anhang).
Ich brauche aber 8-Bit.

Gruß
Rasmus


Th69 - Do 03.09.09 11:25

Ich denke, dafür wirst du ein neues Bitmap erstellen müssen, welche das entsprechende PixelFormat (Format8bppIndexed) hat und dann die Daten kopieren.
Als Konstruktor dafür müßte

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
public Bitmap(
    int width,
    int height,
    int stride,
    PixelFormat format,
    IntPtr scan0
)

s.a. http://msdn.microsoft.com/en-us/library/zy1a2d14.aspx gehen.
Und anschließend noch die Palette anpassen.

An die Pixel-Daten kommst du mittels Bitmap.LockBits().Scan0 (ich nehme an, dein Image ist eine Bitmap).

Und dann für das neue Bitmap Save(..., ImageFormat.Jpeg) aufrufen.


Rassi - Fr 04.09.09 10:01

Hallo.
Danke für den Tip.
@Th69:
Ich habe im Netz folgende Funktion gefunden. Diese stützt sich auf deine Tips.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
public static Bitmap ConvertBitmap(Bitmap bitmap, PixelFormat format)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException("bitmap");
            }

            Bitmap result = null;
            try
            {
                //Größe des Quell-Bitmap ermitteln.
                Rectangle rect = new Rectangle(00, bitmap.Width, bitmap.Height);

                //Ziel-Bitmap in dem gewünschten Pixel-Format erstellen.
                result = new Bitmap(bitmap.Width, bitmap.Height, format);

                //Das Ziel-Bitmap im Speicher sperren. An dstDate die Sperr-Informationen übergeben.
                BitmapData dstData = result.LockBits(rect, ImageLockMode.WriteOnly, format);
                try
                {
                    //Neues BitmapData erzeugen.
                    BitmapData srcData = new BitmapData();

                    //Adresse der ersten Pixeldaten umkopieren.
                    srcData.Scan0 = dstData.Scan0;

                    //Schrittbreite des Bitmaps umkopieren.
                    srcData.Stride = dstData.Stride;

                    //Das Quell-Bitmap im Speicher sperren. Sperrinformationen von srcData (Ziel-Bitmap) weitergeben.
                    bitmap.LockBits(rect, ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer, format, srcData);

                    //Sperrung des Quell-Bitmaps aufheben.
                    bitmap.UnlockBits(srcData);

                }
                finally
                {
                    ////Sperrung des Ziel-Bitmaps aufheben.
                    result.UnlockBits(dstData);
                }
            }
            catch
            {
                if (result != null)
                {
                    result.Dispose();
                }
                //                throw;
            }
            return result;
        }


Nur wird ein Fehler in der Codezeile 25 ausgelöst (Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.):

C#-Quelltext
1:
bitmap.LockBits(rect, ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer, format, srcData);                    



Die Funktion rufe ich wie folgt auf:

C#-Quelltext
1:
Bitmap Bild_neu = ConvertBitmap(Bild_original, PixelFormat.Format8bppIndexed);                    

Hierbei ist das Pixelformat von Bild_original = Format32bppPArgb.


Könnt ihr mir helfen, diese Funktion so hinzubekommen, dass es funktioniert?

Ich habe mal Kommentare dazugeschrieben. Völlig offen für mich ist, wie das Quell-Bitmap zum Ziel-Bitmap kopiert wird. Das wird sicherlich genau in der Zeile 25 gemacht. Kann mir das jemand erklären?


Gruß
Rasmus


Th69 - Fr 04.09.09 19:45

Hallo Rasmus,

den Code hast du von mycsharp.de (http://www.mycsharp.de/wbb2/thread.php?threadid=74364), oder?

Warum der Code bei dir eine Exception wirft, weiß ich nicht genau, evtl. wegen der Umwandlung von einem RGB-Bild zu einem Palettenbild. Du verwendest doch jetzt Format8bppIndexed?

Evtl. ist es aber noch einfacher, indem du die Clone-Methode (http://msdn.microsoft.com/de-de/library/ms141944.aspx) aufrufst, d.h.

C#-Quelltext
1:
2:
3:
4:
Rectangle rect = new Rectangle(00, bitmap.Width, bitmap.Height);
Bitmap result = bitmap.Clone(rect, PixelFormat.Format8bppIndexed);

result.Save(...);

Dann brauchst du nicht von Hand mit dem BitmapData-Objekt rumhantieren.

Ich hoffe, es klappt jetzt...