[C] Bitmap erstellen

Hallo!

Ich hätte mal eine Frage. Ich programmiere in letzter Zeit immer mehr.
Mein letztes Werk war ein Programm welches mir eine eingegebene Zahl in BitCode ausgibt und weiter umwandelt.

Aber jetzt würde ich gerne eine Bitmap datei erstellen.
Ich habe zwar folgende Seite: BMP File Format

Aber irgentwie komme ich nicht ganz weiter. Verstehe das ganze System nicht ganz. Hat jemand zufällig eine Beispiel datei wo einfach nur ein schwarzes Bitmap erstellt wird oder so?

Das wäre echt toll. Komme gerade echt nicht weiter :/

glg
 
Bitmap ist ein gewachsenes und eher unschönes Format für Bilder. Schau dir mal TGA/TARGA an, dass ist sehr einfach und selbst in C, wenn man keine Kompression unterstützen will, in wenigen Zeilen abgefrühstückt.
 
Najo...das weiß ich.
Aber hab schon von ein paar leuten gehört das das dort gerne mal gebraucht wird wo ich später hin soll...also würde ich mir das gerne mal anschaun.
Aber verstehe da gerade nicht sehr viel.
Jetzt hab ich mir gedacht wenn ich mal ein kleines Beispiel sehn würde würds sicher leichter gehn.
 
Bei uns in Österreich.
Weiß auch nicht für was. Aber sollte es eben können.

Also kann mir td allem jemand helfen? Auch wenn man es eigentlich nicht mehr verwendet?
 
Cheat1: Grafik/Img-Bibliotheken nutzen. Das Rad jedes mal neu zu erfinden ist nicht unbedingt der Sinn der Sache ;)

Cheat2: 2-3 kleine Bitmaps erstellen (Paint &Co), darauf achten, dass es als 24-Bitter abgespeichert wird und im Hexeditor ansehen.

Cheat3: vorgefertigte Header nutzen: man erstellt eine BMP mit gewünschten Eigenschaften und übernimmt den Header, den man dann dann ggf. nur ein wenig anpassen muss (width/height setzen). Nicht vergessen, dass die Pixelzeilenlänge ein Vielfaches von 4 sein muss (ggf. muss also mit 0 aufgefüllt werden).
 
Also, ein Problem bei der möglichen Umsetzung sehe ich schon in der Definitionen auf der verlinkten Seite:
Code:
typedef struct tagBITMAPFILEHEADER {    /* bmfh */
    UINT    bfType;
    DWORD   bfSize;
Was ist ein UINT? Für 'unsigned int' dürfte c99 nur eine "Mindestgröße" von 2^16 Werten "empfehlen", gcc/VS auf den üblichen Desktops (egal ob Pinguin/BSD/Win) werden für "unsigned int" einen 32-bit Wert nehmen.
MSDN sagt dazu: Windows Data Types (Windows)
An unsigned INT. The range is 0 through 4294967295 decimal.

Um es kurz zu machen:
In der MSDN ist der Header anders definiert
Code:
typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
Word = uint16_t = 16bit Typ.
Würde also eher:
Bitmap Storage (Windows)
BMP file format - Wikipedia, the free encyclopedia
anschauen.

Dann: ein Bitmap hat grob gesehen 3 mögliche Ausführungen:
  1. mit Farbtabelle/Palette - dann gibt es eine Tabelle mit 2 bis 256 RGBA Werten und
    • im 256 Farben Modus (8-bit) steht 1 Byte pro Pixel als Index für die Palette.
    • im 2 Farben Modus aka "Monochrome" (1-bit) umfasst die Palette nur maximal 2 Werte und somit kann 1 Bit als Index für die Farbtabelle genutzt werden, so dass in einem Byte 8 Pixel Platz finden
    • im 16 Farben Modus das gleiche - nur dass 4 Bits pro Index/Pixel genutzt werden
  2. ohne Palette - dann stehen entweder im "Truecolor aka 24 Bits" 3 Bytes (RGB) oder 32-Bits (RGBA) Werte pro Pixel.
  3. 16-Bit - RGB(A) wird in 16-Bit "gequetscht"

BMP Header ist nicht soo kompliziert (nur eben Umfangreich - zumindest wenn man einen Reader basteln möchte):
Höhe/Breite, Palettengröße, Bildgröße, wieviele Bits-Per-Pixel man nutzen möchte und ob/welche Palette dabei ist.

Übliche Fallstricke:
Jede Bildzeile muss auf ein Vielfaches von 4 aufgefüllt werden. Egal wieviele Bits pro Pixel man verwendet (außer bei 32 - da ist die Eigenschaft automatisch erfüllt :) )
Gibt man die Höhe als positiven Wert an, werden die Bildzeilen in umgekehrter Reihenfolge (letzte zuerst) erwartet.
Gibt man die Höhe als negativen Wert an, gilt die "normale" Reihenfolge.
-----------------------------------

Ich habe mal ein paar alte Projekte mit BMPs rausgekramt und als Demo zwei Arrays mit Daten als Mono/16/256 und True/Deepcolor Bilder ausgeben lassen.

Der Grundgedanke ist folgender:
Man hat Daten, die man als Bild interpretiert/dargestellt haben möchte:
Code:
uint8_t some_data[] = { 
  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 
  3, 3, 3, 3, 3, 2, 0, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 0, 3, 3, 3, 3, 3, 
  3, 3, 1, 2, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 1, 2, 2, 3, 3, 0, 0, 3, 3, 3,
  3, 3, 3, 3, 1, 2, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 0, 0, 3,
  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
Code:
typedef struct 
{
    uint8_t *raw_data;
    size_t width;
    size_t height;
    RGBA *palette;
    size_t palette_size;
} MyPic;
Man braucht (abgesehen von Breite/Höhe) noch eine Zuordnung von Wert zu einer Farbe - das ist mit einem Farbarray/Palette am schnellsten gelöst.
Einfachheitshalber bleibe ich bei den Daten erstmal bei Bytes (also maximal 256 Werte). Jeder Wert kann also als Index in einer Palette genutzt werden.
Code:
    RGBA monochrome_classic[2] = {
        {0, 0, 0, 0}, {255, 255, 255, 0}
    };
    RGBA colored[4] = {
        {60, 61, 100, 0},
        {217, 217, 228, 0},    
        {196, 198, 212, 0},        
        {100, 76, 74, 0}
    };

    MyPic pic = {
        some_data, 
        13, 10,  /* width, height */ 
        monochrome_classic,
        sizeof(monochrome_classic)
    };
    
    create_bitmap("simple_mono_classic.bmp", &pic, C2_MODE);

    pic.palette = colored;
    pic.palette_size = sizeof(colored);
    create_bitmap("simple_colored.bmp", &pic, C16_MODE);
    create_bitmap("simple_colored.bmp", &pic, C256_MODE);
Es werden also mehrere, simple Paletten erstellt (die erste schwarz-weiß) und Daten als Bitmaps (Monochrom/16/256 Farben) ausgegeben:
attachment.php
attachment.php
attachment.php


Dass die Ausgabe ein stilisiertes Habo-Logo darstellt, ist natürlich reiner Zufall ;)

Dann wird als Demo ein größeres Array mit Daten eingebunden:
Code:
    pic.raw_data = big_pic_raw;
    pic.width = BIG_PIC_WIDTH;
    pic.height = BIG_PIC_WIDTH;
    pic.palette = (RGBA*)big_pic_pal;
    pic.palette_size = big_pic_pal_len;
    create_bitmap("big_color.bmp", &pic, C256_MODE);
attachment.php

(24/32 Bit Ausgabe sieht genauso aus.

Und zum Schluss gibt es noch einen Sinus/Cosinus Plot - als Beispiel, wie man z.B "unbequeme" Werte (die also weder direkt RGBs sind und auch nicht unbedingt zwischen 0-255 liegen) behandeln kann:
attachment.php
Dieser Code sollte nur ganz grob zeigen, dass es geht (sonst "etwas" dreckig geschrieben :rolleyes: )

PS: Anmerkung zu der Umsetzung:
die Funktion "write_packed" funktioniert auch im "8-Bit pro Pixel" Modus.
Dieser ist aber extra als "write_indexed" umgesetzt
Code:
/* 8 bits per pixel */
static void write_indexed(FILE *fd, MyPic *pic)
{
    /* (4 - width_bytes % 4) % 4 */
    uint8_t to_pad = (0 - pic->width) & 0x3;
    uint32_t row;
    for (row = 0; row < pic->height * pic->width; row += pic->width) {
        bin_out(fd, &pic->raw_data[row], pic->width);
        if (to_pad) {
            bin_out(fd, "\x00\x00\x00\x00", to_pad);
        }
    }
}
da in disem Modus keine Bitmanipulationen benötigt werden und der Code damit deutlich verständlicher sein dürfte.
 
Zurück
Oben