Frozen X codE

The Stealth Coder Blog ^^

Tag Archives: bitmap

Penjelasan Fungsi LoadBMP()

Bismillah… pertama kalinya nulis tutorial nih ^^.

I. Intro
Tutorial yang akan saya jelaskan berikut merupakan potongan kode yang diambil dari sini.

II. Basic

// **********
// CRaster::LoadBMPFile (FileName);
//   - loads a BMP file into a CRaster object
//   * supports non-RLE-compressed files of 1, 2, 4, 8 & 24 bits-per-pixel
int CRaster::LoadBMP (char * szFile)
{
	BITMAPFILEHEADER bmfh;
	BITMAPINFOHEADER bmih;

	// Open file.
	ifstream bmpfile (szFile , ios::in | ios::binary);
	if (! bmpfile.is_open()) return 1;		// Error opening file

	// Load bitmap fileheader & infoheader
	bmpfile.read ((char*)&bmfh,sizeof (BITMAPFILEHEADER));
	bmpfile.read ((char*)&bmih,sizeof (BITMAPINFOHEADER));

	// Check filetype signature
	if (bmfh.bfType!='MB' ) return 2;		// File is not BMP

	// Assign some short variables:
	BPP=bmih.biBitCount;
	Width=bmih.biWidth;
	Height= (bmih.biHeight>0) ? bmih.biHeight : -bmih.biHeight; // absoulte value
	BytesPerRow = Width * BPP / 8;
	BytesPerRow += (4-BytesPerRow%4) % 4;	// int alignment

	// If BPP aren't 24, load Palette:
	if (BPP==24) pbmi=(BITMAPINFO*)new char [sizeof(BITMAPINFO)];
	else
	{
		pbmi=(BITMAPINFO*) new char[sizeof(BITMAPINFOHEADER)+(1<<BPP)*sizeof(RGBQUAD)&#93;;
		Palette=(RGBQUAD*)((char*)pbmi+sizeof(BITMAPINFOHEADER));
		bmpfile.read ((char*)Palette,sizeof (RGBQUAD) * (1<<BPP));
	}
	pbmi->bmiHeader=bmih;

	// Load Raster
	bmpfile.seekg (bmfh.bfOffBits,ios::beg);

	Raster= new char[BytesPerRow*Height];

	// (if height is positive the bmp is bottom-up, read it reversed)
	if (bmih.biHeight>0)
		for (int n=Height-1;n>=0;n--)
			bmpfile.read (Raster+BytesPerRow*n,BytesPerRow);
	else
		bmpfile.read (Raster,BytesPerRow*Height);

	// so, we always have a up-bottom raster (that is negative height for windows):
	pbmi->bmiHeader.biHeight=-Height;

	bmpfile.close();

	return 0;
}

Fungsi diatas merupakan sebuah potongan kode dari sebuah kelas C++ yang berfungsi untuk meload file berformat Microsoft Bitmap(.bmp) kemudian menggambarnya ke sebuah window, namun yang akan dibahas disini hanya seputar masalah load file .bmp nya saja tanpa menjelaskan cara untuk menggambarnya ke sebuah window.

III. Inti
Ok let’s begin our tutorial 🙂 . Pertama-tama yang perlu diketahui adalah bahwa Microsoft sudah menyediakan sebuah struktur untuk membaca file bawaan Mikocok ini. Kedua struktur tersebut adalah 2 tipe data yang ditulis pada seupil kode diatas. Yap… kedua struktur data tersebut adalah: 

  • BITMAPFILEHEADER
  • BITMAPINFOHEADER

Lakukan deklarasi objek dari kedua struktur tersebut:

BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;

Yang merupakan dua tipe data pertama yang di deklararasikan di awal fungsi. Kalo mo tau apa isi dua struktur ini silakan ke cari sendiri di msdn kekekekkee… Secara garis besar isi dari dua struktur ini adalah seputar informasi file(BITMAPFILEHEADER) dan informasi spesifik bitmap(BITMAPINFOHEADER). 

Nah setelah melakukan deklarasi objek dari kedua struktur tersebut selanjutnya adalah membaca file .bmp nya:

// Open file.
	ifstream bmpfile (szFile , ios::in | ios::binary);
	if (! bmpfile.is_open()) return 1;		// Error opening file

	// Load bitmap fileheader & infoheader
	bmpfile.read ((char*)&bmfh,sizeof (BITMAPFILEHEADER));
	bmpfile.read ((char*)&bmih,sizeof (BITMAPINFOHEADER));

Masih bisa dipahami kan? masih kode C++ standard nih… 

Next step is mendapatkan informasi dari file yang telah dibaca.

// Assign some short variables:
	BPP=bmih.biBitCount;
	Width=bmih.biWidth;
	Height= (bmih.biHeight>0) ? bmih.biHeight : -bmih.biHeight; // absoulte value
	BytesPerRow = Width * BPP / 8;
	BytesPerRow += (4-BytesPerRow%4) % 4;	// int alignment

Potongan kode di atas adalah informasi-informasi yang dibutuhkan untuk menampilkan file bitmap ke dalam window.
bmih.biBitCount merupakan informasi mengenai jumlah bit dalam satu pixel. Sekaligus juga bisa menunjukkan kedalaman warna. Informasi ini berguna nantinya untuk mendapatkan byte dari satu baris(sebetulnya kurang tepat kalo dibilang baris, cuman ini bertujuan supaya mudah dipahami kodenya)yang digunakan untuk membaca byte-byte dari raster image tersebut nantinya.

Untuk sementara kita skip dulu baris kode ini:

// If BPP aren't 24, load Palette:
	if (BPP==24) pbmi=(BITMAPINFO*)new char [sizeof(BITMAPINFO)];
	else
	{
		pbmi=(BITMAPINFO*) new char[sizeof(BITMAPINFOHEADER)+(1<<BPP)*sizeof(RGBQUAD)&#93;;
		Palette=(RGBQUAD*)((char*)pbmi+sizeof(BITMAPINFOHEADER));
		bmpfile.read ((char*)Palette,sizeof (RGBQUAD) * (1<<BPP));
	}&#91;/sourcecode&#93;

Kita langsung ke potongan kode yang ini:

&#91;sourcecode language='cpp'&#93;// Load Raster
	bmpfile.seekg (bmfh.bfOffBits,ios::beg);

	Raster= new char&#91;BytesPerRow*Height&#93;;

	// (if height is positive the bmp is bottom-up, read it reversed)
	if (bmih.biHeight>0)
		for (int n=Height-1;n>=0;n--)
			bmpfile.read (Raster+BytesPerRow*n,BytesPerRow);
	else
		bmpfile.read (Raster,BytesPerRow*Height);

	// so, we always have a up-bottom raster (that is negative height for windows):
	pbmi->bmiHeader.biHeight=-Height;

Sebagaimana yang terlihat Raster= new char[BytesPerRow*Height];. Raster ini adalah buffer yang digunakan untuk menyimpan raster image(per 1 byte) dari file bitmap yang akan dibaca, makanya dialokasikan memory sebanyak “luas” dari image tersebut. 

Sebelum melihat loop yang merupakan pembacaan dari raster image, kita wajib kudu harus meletakkan pointer file ke awal raster. Dimana awal raster? jawabannya adalah berada setelah header file dan header info bitmap tersebut. Analoginya kira-kira seperti ini:
-------------bmfh----------------|---------------bmih---------------|-----raster--------------------------------------------------------------------sampai end of file.
Bisa dimengerti ga’ ya? kekekekekke… *garuk-garuk kepala*. Nah untuk mendapatkan awal byte dari raster maka struktur dari microsoft tadi telah menyiapkan satu variabel untuk ini, yaitu bfOffBits yang berada di struktur BITMAPFILEHEADER. Maka untuk memindahkan pointer file kita tinggal melakukan call sebagai berikut bmpfile.seekg (bmfh.bfOffBits,ios::beg);. Ok next…

Berikutnya adalah pembacaan binary dari raster image. Kalo kalian liat potongan kode diatas kalian pasti heran kenapa loop untuk membaca file-nya terbalik. Itu karena ternyata si pembuat format file ini menyimpannya secara terbalik terhadap sumbu “y”. Aneh ya, saia juga bingung. Makanya untuk bisa ditampilkan secara betul di windows kita harus membacanya dari “baris” paling bawah.

IV. Kesimpulan
Untuk membaca file bitmap, langkah-langkah yang diperlukan adalah:

    1. Mendeklarasikan objek dari dua struktur untuk membaca file bitmap tersebut.
    2. Mengisi variabel dari dua struktur tersebut sebagai informasi file dan image.
    3. Me-load raster image dari file yang akan ditampilkan.

Satu lagi, bahwa file bitmap disimpan terbalik terhadap sumbu “y” jadi kita harus melakukan pembacaan dari “bawah” ke “atas” agar mendapatkan tampilan yang benar.

nb: kalo ada yang salah tolong isi komen ya… ^^. Untuk selanjutnya sih maunya tentang kompresi huffman, tapi banyakan malesnya daripada pengen nulisnya. kekekekkeke…

Best regards, Frozen X – The Stealth Coder.