Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

idontknow

unregistriert

1

08.09.2010, 17:00

Bitmap erstellen!

moin!

Ich hab mir eine Funktion geschrieben die ein DWORD Array das die Pixeldaten beinhaltet in eine Bitmap Datei schreiben soll. Das ganze scheint irgendwo falsch zu laufen, aber ich finde den Fehler nicht. Das Resultat ist jedenfalls dass ich die Bitmap nicht im Windows standard Viewer betrachten kann, also muss irgendwas mit dem erstellen falsch gelaufen sein ich finde den Fehler aber leider nicht.

Benutzt habe ich folgende Links:
http://de.wikipedia.org/wiki/Windows_Bit….28Version_3.29
+ MSDN

Hier mein Testcode:

C-/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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <Windows.h>
#include <string>
#include <fstream>

void createBitmap(const std::string& filename, unsigned int width, unsigned int height, DWORD* pixeldata)
{
    std::fstream fileStream(filename, std::ios::binary | std::ios::out);
    BITMAPFILEHEADER fileHeader = {0x4D42,
                               56 + width * height * 3,
                               0,
                               0,
                               56};
    BITMAPINFOHEADER fileInfoHeader = {40, width, height * (-1), 1, 24, BI_RGB, 0, 0, 0, 0, 0};

    /* BitmapFileHeader */
    fileStream.write(reinterpret_cast<char*>(&fileHeader.bfType), sizeof(WORD));
    fileStream.write(reinterpret_cast<char*>(&fileHeader.bfSize), sizeof(DWORD));
    fileStream.write(reinterpret_cast<char*>(&fileHeader.bfReserved1), sizeof(WORD));
    fileStream.write(reinterpret_cast<char*>(&fileHeader.bfReserved2), sizeof(WORD));
    fileStream.write(reinterpret_cast<char*>(&fileHeader.bfOffBits), sizeof(DWORD));

    /* BitmapInfoHeader */
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biSize), sizeof(DWORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biWidth), sizeof(LONG));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biHeight), sizeof(LONG));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biPlanes), sizeof(WORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biBitCount), sizeof(WORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biCompression), sizeof(DWORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biSizeImage), sizeof(DWORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biXPelsPerMeter), sizeof(LONG));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biYPelsPerMeter), sizeof(LONG));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biClrUsed), sizeof(DWORD));
    fileStream.write(reinterpret_cast<char*>(&fileInfoHeader.biClrImportant), sizeof(DWORD));
    
    DWORD *pdataptr = pixeldata;
    for(unsigned int y = 0; y < height; ++y)
    {
        pdataptr = pixeldata + width * y;
        unsigned int x = 0;
        for(; x < width; ++x)
        {
            pdataptr += x;
            DWORD pixel = *pdataptr;
            char bgr[3] = {(pixel & 0x000000ff) >>  0,
                           (pixel & 0x0000ff00) >>  8,
                           (pixel & 0x00ff0000) >> 16};
            fileStream.write(reinterpret_cast<char*>(&bgr), sizeof(char) * 3);
        }
        if((x * 3) % 4 != 0)
        {
            for(int i = 0; i < ((x * 3) % 4); ++i)
            {
                char c = 0;
                fileStream.write(reinterpret_cast<char*>(&c), sizeof(char));
            }
        }
    }
    
     
    fileStream.close();
}

int main()
{
    DWORD bmp[4] = {0x00ff0000,
                    0x00ff0000,
                    0x00ff0000,
                    0x00ff0000};
    createBitmap("mybmp.bmp", 2, 2, &bmp[0]);
    return 0;
}


mfg :)

2

08.09.2010, 17:31

Warum schreibst du denn alle Elemente des Headers einzeln in die Datei ? Kannst doch einfach den ganzen Header auf einmal reinschreiben

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

3

08.09.2010, 17:36

o Die Bilddaten starten am Offset 54, du hast dich da um 2 Byte vertan
o Bei der Dateigröße vergisst du die Paddingbytes
o Du gibst keinen Wert für die Datasize an
o Du gibst keine sinnvollen Werte für die X- und Y-Resolution an
o Du berechnest die Anzahl der Paddingbytes falsch
@D13_Dreinig

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »David_pb« (08.09.2010, 17:49)


idontknow

unregistriert

4

08.09.2010, 18:19

Warum schreibst du denn alle Elemente des Headers einzeln in die Datei ? Kannst doch einfach den ganzen Header auf einmal reinschreiben

Wie denn? Dazu muesste ich die Structs selber deklarieren und die Member in der entsprechenden Reihenfolge definieren, da ich aber WinAPI Structs nehme fällt das weg.

Die Bilddaten starten am Offset 54, du hast dich da um 2 Byte vertan und bei der Dateigröße vergisst du die Paddingbytes.


hmm. Dachte die beiden Header hätten zusammen 56 Byte. Na gut dummer Fehler, danke :)


o Die Bilddaten starten am Offset 54, du hast dich da um 2 Byte vertan
o Bei der Dateigröße vergisst du die Paddingbytes
o Du gibst keinen Wert für die Datasize an
o Du gibst keine sinnvollen Werte für die X- und Y-Resolution an
o Du berechnest die Anzahl der Paddingbytes falsch


1: -
2: Jo, werds adden
3: die Dateigröße im ersten header ist laut Wikipedia egal und im Infoheader kann man aufgrund von der BI_RGB Kompression 0 angeben.
4: Dachte auch die muss ich nich angeben :x.
5: hmm. okey werds nomal überdenken =)

Danke!

5

08.09.2010, 18:21

C-/C++-Quelltext

1
2
3
4
5
6
     BITMAPFILEHEADER fileHeader;
     BITMAPINFOHEADER infoHeader;


     file.write((char*)&fileHeader, sizeof(fileHeader));
     file.write((char*)&infoHeader, sizeof(infoHeader));


wo liegt das Problem ?

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

6

08.09.2010, 18:21

hmm. Dachte die beiden Header hätten zusammen 56 Byte. Na gut dummer Fehler, danke :)


Man beachte auch die anderen genannten Punkte (ich hatte in der zwischenzeit editiert). :)

Edit:
3: die Dateigröße im ersten header ist laut Wikipedia egal und im Infoheader kann man aufgrund von der BI_RGB Kompression 0 angeben.


Und wenn ich jetzt einen Bitmaploader schreibe und diese Felder auswerte? Die Felder existieren und sollten meiner Meinung nach korrekt gefüllt werden (zumindest bezüglich der Dateigröße... der Rest scheint per Vereinbarung ok zu sein).
@D13_Dreinig

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »David_pb« (08.09.2010, 18:32)


idontknow

unregistriert

7

08.09.2010, 18:55

Warum soll die Berechnung der Padding Bytes falsch sein? :o

edit: berechnung sollte stimmen, immerhin gehts wenn ich geändert habe was du angemerkt hast :). Danke!

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

8

08.09.2010, 18:58

Warum soll die Berechnung der Padding Bytes falsch sein? :o


Weil eine Scanline auf ein vielfaches von 4 "gepadded" werden muss. Wenn du jetzt einen Pixel (mit 3 Kanälen) schreibst fehlt ein Paddingbyte. Du würdest allerdings 3 zusätzliche Bytes schreiben.

edit: berechnung sollte stimmen, immerhin gehts wenn ich geändert habe was du angemerkt hast :). Danke!


Möglicherweisse weil der Faktor 4 in der Bildbreite steckt??
@D13_Dreinig

idontknow

unregistriert

9

08.09.2010, 19:21

Nein. Bild ist 2x2 Pixel macht 6 Bytes pro Zeile, muss also mit 2Bytes aufgefüllt werden.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

10

08.09.2010, 19:27

Nein. Bild ist 2x2 Pixel macht 6 Bytes pro Zeile, muss also mit 2Bytes aufgefüllt werden.


Ja eben... das ist ein Fall der ("zufällig") funktioniert. Versuchs mal mit 1xn, oder 3xn Pixeln... Du paddest nämlich genau falsch rum:

Quellcode

1
2
3
4
5
6
(3 * 1) % 4 = 3 <- falsch, richtig: 1 weil 3 + 1 = 4 (% 4) == 0
(3 * 2) % 4 = 2 <- stimmt
(3 * 3) % 4 = 1 <- falsch, richtig: 3 weil 9 + 3 = 12 (% 4) == 0
(3 * 4) % 4 = 0 <- stimmt

// usw...
@D13_Dreinig

Werbeanzeige