C++ BMP Yazma

C++ bir BMP resmini açıp her pixelindeki değeri bir matrise atamayı bir önceki yazımda anlatmıştım. Bu yazımda nxn bir matristen nxn boyutunda bir BMP resmi oluşturup kaydeden bir program yazacağız. Bilindiği üzere 24-BMP de renkler 54.bayttan sonra başlar. Yani bizim elimizdeki bu matrisi 54.bayttan sonrasına yazmamız gerekiyor.İlk 54 baytta ise resme ait başlıklar olacaktır. BMP resmi okumak için sadece bazı adresleri okumak yeterliydi ancak yazmak söz konusu ise tüm adreslere olması gereken değeri yazmamız zorunludur. Aksi takdirde görüntüleyici program BMP resmini açamayacaktır.Bu nedenle ilk 54 baytın içerisinde neler olduğunu tek tek bilmemiz gerekmektedir.


Aşağıdaki tabloda her adresin içerisinde ne bilgisinin tutulduğu,kaç bit olduğunu ve C++ veri türünü görebilirsiniz (Burada verilen veri tipleri standart veri tipleridir. Kod içerisinde görülen veri tipleri char=unsigned char,word=unsigned short,dword=unsigned int veri tipleridir.).


ADRES BAYT VERİ TİPİ TUTULAN BİLGİ
0 2 unsigned short ‘BM’=19778 verisi tutulur.Resmin BMP resmi olup olmadığını anlamamzı sağlar
2 4 unsigned int BMP dosyasının boyutunu gösterir.
6 2 unsigned short Saklı alandır.İçerisinde 0 verisi tutulur.
8 2 unsigned short Saklı alandır.İçerisinde 0 verisi tutulur.
10 4 unsigned int Renk matrisinin başlangıç adresini tutar.24-BMP için bu değer 54 dür.
14 4 unsigned int BMP  başlığının boyutunu tutar.24-BMP için bu değer 40 dır.
18 4 unsigned int BMP resminin genişliği tutulur.
22 4 unsigned int BMP resminin yüksekliği tutulur.
26 2 unsigned short Resimdeki düzlem sayısını tutar.Bu değer sabit olup 1 dir.
28 2 unsigned short Resmin renk derinliğini tutar.(8-16-24-32)
30 4 unsigned int Resmin sıkıştırma algoritmasını tutar.
34 4 unsigned int Resmin bir satır uzunluğu tutulur.Bu değer genişlik+padding değerine eşittir.
38 4 unsigned int Resmin yataydaki 1 metresi için tutulan pixel sayısını gösterir.(0)
42 4 unsigned int Resmin düşeydeki 1 metresi için tutulan pixel sayısını gösterir.(0)
46 4 unsigned int Resim paletindeki renk sayısı tutulur.n-BMP için 2^n renk tutulur.
50 4 unsigned int Resimdeki önemli renklerin sayısını tutar.(0)


Bu değerleri bmp dosyasına yazmamız için öncelikle ofstream ile bir bmp dosyası binary olarak açılır. Açılan bu dosyada imleç seekg ile istenen adrese konumlandırılarak adresde tutmamız gereken değerler yazılır. BMP dosyasının boyutu ve satır uzunluğu resmin yüksekliği ve genişliği cinsinden;
satır_uzunluğu=genişlik+padding=genislik+(4-(3*genislik)%4) dir.Burada padding 4 çıkabilir.Bu durumda padding anlamını yitirir bu yüzden padding=0 alınır (Ayrıntılı bilgi için bir önceki yazıma bakabilirsiniz.).
dosya_boyutu=satır_uzunluğu*yükseklik+54 bayt dır. İlk 54 baytı yazıldıktan sonra renkler yazılırken dikkat edilmesi gereken bir nokta padding baytlarıdır. Her satır yazıldıktan sonra padding baytı sayısı kadar 0 imlecin bulunduğu yerden itibaren yazılmalıdır. Argüman olarak dosya adını alan ve pixels[m][n] matrisindeki renk değerlerini bu dosyaya bmp formatında kaydeden kod parçası aşağıda verilmiştir.


bool BMPF::writebmp(char *filename) {
    ofstream bmp(filename,ios::binary);
    
    int i,j;
    byte padding=4-(3*bminfo.width)%4;
    if(padding==4) { padding=0; }
    byte pad=0;
    dword row=padding+(bminfo.bppixel*bminfo.width)/8;
    
    header.bftype=19778;
    header.bfsize=(dword)54+row*bminfo.height;
    header.bfres1=0;
    header.bfres2=0;
    header.bfoffset=54;
    bminfo.bisize=40;
    bminfo.biplane=1;
    bminfo.bppixel=24;
    bminfo.comtype=0;
    bminfo.rawsize=row*bminfo.height;
    bminfo.xpmeter=0;
    bminfo.ypmeter=0;
    bminfo.ncolors=pow2(bminfo.bppixel);
    bminfo.icolors=0;
    
    bmp.write((char*)&header.bftype,2);
    bmp.write((char*)&header.bfsize,4);
    bmp.write((char*)&header.bfres1,2);
    bmp.write((char*)&header.bfres2,2);
    bmp.write((char*)&header.bfoffset,4);
    bmp.write((char*)&bminfo.bisize,4);
    bmp.write((char*)&bminfo.width,4);
    bmp.write((char*)&bminfo.height,4);
    bmp.write((char*)&bminfo.biplane,2);
    bmp.write((char*)&bminfo.bppixel,2);
    bmp.write((char*)&bminfo.comtype,4);
    bmp.write((char*)&bminfo.rawsize,4);
    bmp.write((char*)&bminfo.xpmeter,4);
    bmp.write((char*)&bminfo.ypmeter,4);
    bmp.write((char*)&bminfo.ncolors,4);
    bmp.write((char*)&bminfo.icolors,4);
    
    for(j=bminfo.height-1;j>=0;j--) {
                      for(i=0;i
    bmp.write((char*)&pixels[i][j],(int) bminfo.bppixel/8);     }
    bmp.write((char*)&pad,(int)padding); }
    return true; }

Bir önceki yazımda bahsettiğim gibi bu kodlarıda hızlandırmak istersek mavi ile yazılı satırlar yerine aşağıdaki satırları kullanmamız daha mantıklı olacaktır.


int buffersize=bminfo.width*3+padding;
    byte *buffer;
    buffer=new byte [buffersize];
    for(i=0;ibuffer[i]=0; }
    j=bminfo.height-1;
    while(j>-1) {
    for(i=0;i
     { memcpy( (char*) buffer+3*i,  (char*) &(pixels[i][j]), 3 ); }                           
    bmp.write((char*)buffer,buffersize);
    j--;        }

1 yorum:

Görüntü işleme ile ilgili yeni yazıları ve bu sitede yer alan yazıların güncellenmiş sürümlerini www.imlab.io veya cescript.github.io adreslerinden takip edebilirsiniz.

X