DC als Bitmap speichern

Hi C++ Experten
Ich habe eine Funktion geschrieben, die den Gerätekontext des Fenster als Bitmap abspeichern soll. Leider funktioniert das ganze noch nicht so richtig, da die Datei:

  1. 7 statt ~1 MB (x*3*y (24Bit) -> 600*3*600) groß ist

  2. Die ganze Bitmap stark verzerrt und schwarz-weiss ist
    (statt 24Bit-Farben)

Meiner Meinung nach müsste der Fehler irgendwo bei den beiden Bitap-Headern liegen (BITMAPFILEHEADER + BITMAPINFOHEADER).

Kennt sich jemand damit aus ?

Danke im voraus,
Daniel R.

Der Quellcode meiner Funktion:
(Die Funktion ExtractColour() extrahiert ,wie der Name schon sagt, den Rot- Grün- oder Blauwert aus einer COLORREF-Variable)

bool CDreiecksdiagramDlg::SaveBitmap()
{
CRect rect;
GetClientRect(&rect);

CClientDC dc(this);

int x = rect.right*3; // 24Bit pro pixel
int y = rect.bottom;

char* pixel = new char[x*y];

// Pixel
int xpos = 0;
int ypos = rect.bottom; // Upside-down format
int index=0;

while(ypos>0)
{
while(xpos

Hallo!

Dein Problem liegt daran, dass DIBs und das BMP-Format nicht einfach die Pixel sequenziell im Speicher oder ober in der Datei liegen haben, sondern zeilenweise gespeichert und DWORD-aligned sind (siehe auch in der Online-Hilfe zu DIBs). Damit dürften dir ein paar Bytes fehlen und die Verzerrung/Farbverschiebung verursachen.

Ich würde das Schreiben der Bilddaten folgendermaßen durchführen:

// Fileheader + Infoheader
file.Write(&fileheader,sizeof(fileheader));
file.Write(&infoheader,sizeof(infoheader));

// (hier: Palette für 16-256 Farben)

// Zeilenlänge in Bytes mit DWORD-Alignment
int nFullLength=4\*(( x/8+31 )/32 );

// Alle Zeilen druchlaufen
for( int nLine=0; nLine

Es wäre insgesamt aber performanter, nur eine Zeile DWORD-aligned anzulegen und in einer Zeilenschleife mit den Zeilendaten zu füllen sowie direkt in einem Durchgang zu schreiben. Du schreibst die Daten BYTE für BYTE, was deutlich länger dauert.

Grüße Safog


> <small>[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]</small>

Hallo Safog
Vielen Dank für deine schnelle Antwort. In deinen Code war leider ein kleiner Fehler. Du hast mir aber trotzdem sehr weitergeholfen, da ich wahrscheinlich nie draufgekommen währe, dass die Anzahl der Bytes in einer Scanline ein Vielfaches von 4 sein muss.

// Zeilenlänge in Bytes mit DWORD-Alignment
int nFullLength=4\*(( x/8+31 )/32 );




// mein Code
int nFullLength = x; // z.B 13
nFullLength += 4-x%4; // 13%4=1 4-1=3 -\> noch 3 Byte schreiben

Hallo Daniel!

Du hast recht! Ich habe wohl etwas zu schnell eines meiner Makros zur Bestimmung der Scan-Line-Breite in Bytes aus der Gesamt-Bitanzahl modifiziert:

#define WIDTHBYTES( nBits ) ( 4\*((( nBits )+31 )/32 ))

Damit ist man von der Bitanzahl unabhängig! Richtigerweise müsste es daher heißen:

// Zeilenlänge in Bytes mit DWORD-Alignmentint nFullLength=4\*(( 8\*x+31 )/32 );

oder noch besser:

// Zeilenlänge in Bytes mit DWORD-Alignment
int nFullLength=WIDTHBYTES( infoheader.biWidth\*infoheader.biBitCount );

Grüße Safog

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]