Nội dung bài viết
Đăng ký học lập trình C++
Tại STDIO bạn được dạy nền tảng lập trình tốt nhất.
Đăng ký học
Trần Khánh Nguyên Bitmap là một tập tin định dạng ảnh khá phổ biến còn được biết đến với tên tiếng anh là Windows bitmap. Các tập tin đồ họa lưu dưới dạng ảnh Bitmap thường có đuôi là .BMP hoặc .DIB. Bài viết này sẽ hướng dẫn các bạn một số thao tác cơ bản để làm quen với ảnh Bitmap và các xử lí cơ bản đối với một file ảnh Bitmap.

Giới thiệu

Bitmap là một tập tin định dạng ảnh khá phổ biến còn được biết đến với tên tiếng anh là Windows bitmap. Các tập tin đồ họa lưu dưới dạng ảnh bitmap thường có đuôi là .BMP hoặc .DIB. Bài viết này sẽ hướng dẫn các bạn một số thao tác cơ bản để làm quen với ảnh bitmap và các xử lí cơ bản đối với một file ảnh Bitmap.

Tiền đề bài viết

Trong quá trình học tập tại STDIO, được sự gợi ý của anh Brian Vu và sự giúp đỡ của anh Rye Nguyễn về vấn đề trên nên tôi đã tìm hiểu và viết bài chia sẻ những gì mình tìm hiểu được đến tất cả các bạn.

Đối tượng hướng đến

Bài viết hướng đến tất cả các bạn đang tìm hiểu về vấn đề trên và có kiến thức cơ bản về lập trình C/C++.

Các thuộc tính tiêu biểu của một tập tin ảnh bitmap

Các thuộc tính tiêu biểu của một tập tin ảnh bipmap cũng như một tập tin ảnh nói chung là:

  • Số bit trên mỗi điểm ảnh (bits per pixel) thường được ký hiệu bởi n. Một ảnh BMP n-bit có 2n màu. Giá trị n càng lớn thì ảnh càng có nhiều màu, và càng rõ nét hơn. Giá trị tiêu biểu của n là 1 (ảnh đen trắng), 4 (ảnh 16 màu), 8 (ảnh 256 màu), 16 (ảnh 65536 màu) và 24 (ảnh 16 triệu màu). Ảnh BMP 24-bit có chất lượng hình ảnh trung thực nhất.
  • Chiều cao của ảnh (height), cho bởi điểm ảnh (pixel).
  • Chiều rộng của ảnh (width), cho bởi điểm ảnh.

Cấu trúc tập tin bitmap

  • Tập tin bitmap (Device Independent Bitmap) là tập tin ảnh với định dạng cơ bản nhất.
  • Tập tin hình ảnh thường không nén bằng bất kì thuật toán nào, khi lưu ảnh các điểm ảnh sẽ được ghi trực tiếp vào tập tin – một điểm ảnh sẽ được mô tả bởi một hay nhiều byte tùy thuộc vào giá trị n của ảnh. Do đó, một hình ảnh lưu dưới dạng BMP thường có kích cỡ rất lớn, gấp nhiều lần so với các ảnh được nén (chẳng hạn GIF, JPEG hay PNG).

Cấu trúc tập tin ảnh BMP bao gồm 4 phần:

  • Bitmap Header (14 bytes): Giúp nhận dạng tập tin bitmap.
  • Bitmap Information (40 bytes): Lưu một số thông tin chi tiết giúp hiển thị ảnh.
  • Color Palette (4*x bytes), x là số màu của ảnh: Định nghĩa các màu sẽ được sử dụng trong ảnh.
  • Bitmap Data: Lưu dữ liệu ảnh.

Cấu trúc Header

Cấu trúc header file

{

     bfType[2] : Kí hiệu cho biết định dạng file là bitmap, là 2 kí tự "BM".

     bfSize[4]  : Kích thước file.

     bfReserved1[2] : Không sử dụng.

     bfReserved2[2] : Không sử dụng.

     bfOffBits[4] : Vị trí bắt đầu của nội dung file.

  } 

struct bmfh
{ 
      char           bfType[2];
      unsigned char  bfSize[4];
      unsigned char  bfReserved1[2];
      unsigned char  bfReserved2[2]; 
      unsigned char  bfOffBits[4];
};

Cấu trúc bitmap Information

Cấu trúc header ảnh

 {

biSize[4] : Kích thước phần còn lại của header ảnh.

biWidth[4]  : Chiều rộng của bitmap

biHeight[4] : Chiều cao của bitmap

biPlanes[2] : Number of Planes. Set to 1

biBitCount[2] : Xác định độ phân giải màu sắc của bitmap. giá trị có thể là 1 (trắng đen), 4 (16 màu), 8 (256 màu) , 24 (16,7 triệu màu). 

stuff1[16] : Loại nén (4 bytes) , kích thước ảnh 4 , độ phân giải theo chiều ngang 4 , dọc 4.

biClrUsed[4] : Số lượng màu sắc sử dụng

biClrImportant[4] : Number of  “Important” color

}

struct bmih 
{
     unsigned char biSize[4];
     unsigned char biWidth[4];
     unsigned char biHeight[4];
     unsigned char biPlanes[2];
     unsigned char biBitCount[2];
     unsigned char stuff1[16]; 
     unsigned char biClrUsed[4];
     unsigned char biClrImportant[4];
};

Color Palette

Color Palette định nghĩa các màu sử dụng trong ảnh:

  • Gồm nhiều bộ có kích thước 4 bytes xếp liền nhau theo cấu trúc: Blue – Green – Red – Reserved.
  • Kích thước của bảng màu (4*x bytes) , x là số màu sử dụng trong ảnh.
  • Note :
    • Bảng màu của màn hình có thứ tự : Red – Green – Blue.
    • Bảng màu của bitmap có thứ tự :  Blue – Green – Red.
    • Nên khi đọc bảng màu của ảnh bitmap cần phải chuyển đổi cho đúng thứ tự.

Bitmap Data

Bitmap data dùng để lưu dữ liệu ảnh.

  • Chứa giá trị màu của các điểm ảnh trong .bmp
  • Các điểm ảnh được lưu theo thứ tự từ trái qua phải trên 1 dòng  và các dòng được lưu theo thứ tự dưới lên trên.
  •  Mỗi byte trong vùng bitmap data biểu diễn 1 hoặc nhiều điểm ảnh tùy theo số bits trên 1 pixel.

Padding bytes

Thực tế khi một mảng các pixel được nạp vào bộ nhớ, mỗi hàng phải bắt đầu tại một địa chỉ bộ nhớ mà địa chỉ đó là bội số của 4. Nhưng do ta chỉ có sử dụng 3 byte cho mỗi pixel nên mỗi dòng có thể kết thúc với địa chỉ không chia hết cho 4. Vì vậy trong mỗi dòng sẽ có những padding bytes để hạn chế/bù đắp số byte thiếu và đảm bảo rằng kết thúc mỗi dòng địa chỉ bộ nhớ luôn là bội số của 4. Ví dụ như ảnh có kích thước 10x14 (14 là width) thì padding sẽ là 2 vì 14 x 3 = 42 (nhân 3 vì 3 là số byte trong mỗi pixel) và 42 % 4 = 2. Còn nếu bức ảnh có kích thước 3x4 (4 là width) thì padding sẽ là 0 vì 4x3 = 12 và 12 % 4 = 0.

Các xử lí cơ bản với một tập tin bitmap

Cấu trúc pixel

struct Pix
{
	unsigned char B;
	unsigned char G;
	unsigned char R;

};

Cấu trúc bitmap

struct BitMap
{
	short		 m_signature;
	long		     m_reserved1;
	long		     m_reserved2;

	long		     m_dataOffSet;

	long		     m_size;
	long		     m_width;
	long		     m_height;
	short		 m_planes;
	short		 m_bpp;

	long		     m_compression;
	long		     m_sizeImage;

	long		     m_xPixelsPreMeter;
	long		     m_yPixelsPreMeter;

	long		     m_colorsUsed;
	long		     m_colorsImportant;
};

Đọc 1 file bitmap

void readBMP(const char* filePath, BitMap &header, char* &data)
{
	FILE* f = fopen(filePath, "rb");
	if (!f)
	{
		printf("Cannot open file for reading!!!");
		exit(-1);
	}

	fread(&header, sizeof(header), 1, f);

	int _padding = header.m_width % 4;
	int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding * header.m_height; //(header.m_bpp)/8 ( số kênh màu )

	data = new char[_size];
	fread(data, sizeof(char), _size, f);

	fclose(f);
}

Ghi 1 file bitmap

void writeBMP(const char* filePath, BitMap &header, char* &data)
{
	FILE* f = fopen(filePath, "wb");
	if (!f)
	{
		printf("Cannot open file for writing!!!");
		exit(-1);
	}

	fwrite(&header, sizeof(header), 1, f);

	int _padding = header.m_width % 4;
	int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding * header.m_height;

	fwrite(data, sizeof(char), _size, f);

	fclose(f);
}

Chuyển data của 1 ảnh bitmap vào một mảng các Pixel 

Pix* convertDataToPixelArray(char* &data, BitMap &header)
{
	int _size = header.m_width * header.m_height;
	Pix* _pixels = new Pix[_size];

	int _padding = header.m_width % 4;

	char* _temp = data;

	for (int i = 0; i < header.m_height; i++)
	{
		for (int j = 0; j < header.m_width; j++)
		{
			_pixels[i * header.m_height + j].B = *(_temp++);
			_pixels[i * header.m_height + j].G = *(_temp++);
			_pixels[i * header.m_height + j].R = *(_temp++);
		}

		_temp += _padding;
	}

	return _pixels;
}

Chuyển dữ liệu từ mảng các Pixel vào data của 1 ảnh bitmap

char* convertPixelArrayToData(Pix* &pixels, BitMap &header)
{
	int _padding = header.m_width % 4;
	int _size = header.m_width * header.m_height * (header.m_bpp / 8) + _padding * header.m_height;

	char* _data = new char[_size];
	char* _temp = _data;

	for (int i = 0; i < header.m_height; i++)
	{
		for (int j = 0; j < header.m_width; j++)
		{
			*(_temp++) = pixels[i * header.m_height + j].B;
			*(_temp++) = pixels[i * header.m_height + j].G;
			*(_temp++) = pixels[i * header.m_height + j].R;
		}

		for (int k = 0; k < _padding; k++)
		{
			*(_temp++) = 0;
		}
	}

	return _data;
}

Chuyển ảnh sang trắng đen

void grayscale(Pix* &pixels, int size)
{
	for (int i = 0; i < size; i++)
	{
		int _val = (pixels[i].R + pixels[i].G + pixels[i].B) / 3;
		pixels[i].R = pixels[i].G = pixels[i].B = _val;
	}
}

Ví dụ

Ở đây tôi có ví dụ là load một file bitmap lên xử lí chuyển sang màu trắng đen và lưu lại ở một tập tin bitmap khác. Các bạn có thể download ở tập tin tôi đính kèm bên dưới.

STDIO_Bitmap

THẢO LUẬN
ĐÓNG