C/C++實現bmp文件讀寫


  • 之前知道點bmp圖的格式,然后對8位操作過,然后今天弄了一下24位真彩色的。
  • C++讀取、旋轉和保存bmp圖像文件編程實現
  • 主要是理解bmp文件的格式8/24位的區別
  • 8位圖有調色板,24位在文件頭和信息頭之后就是圖像數據區,但是保存24位圖的時候,直接在文件頭和信息頭之后寫圖像數據,會有圖像錯位,查看bfOffBits=138 不等於54!

BMP文件格式詳解(BMP file format)

  • 實驗輸入圖片

實驗一


#include <stdio.h>  
#include <stdlib.h>  

typedef struct
{
	//unsigned short    bfType;  
	unsigned long    bfSize;
	unsigned short    bfReserved1;
	unsigned short    bfReserved2;
	unsigned long    bfOffBits;
} ClBitMapFileHeader;

typedef struct
{
	unsigned long  biSize;
	long   biWidth;
	long   biHeight;
	unsigned short   biPlanes;
	unsigned short   biBitCount;
	unsigned long  biCompression;
	unsigned long  biSizeImage;
	long   biXPelsPerMeter;
	long   biYPelsPerMeter;
	unsigned long   biClrUsed;
	unsigned long   biClrImportant;
} ClBitMapInfoHeader;

typedef struct
{
	unsigned char rgbBlue; //該顏色的藍色分量  
	unsigned char rgbGreen; //該顏色的綠色分量  
	unsigned char rgbRed; //該顏色的紅色分量  
	unsigned char rgbReserved; //保留值  
} ClRgbQuad;

typedef struct
{
	int width;
	int height;
	int channels;
	unsigned char* imageData;
}ClImage;

ClImage* clLoadImage(char* path);
bool clSaveImage(char* path, ClImage* bmpImg);


ClImage* clLoadImage(char* path)
{
	ClImage* bmpImg;
	FILE* pFile;
	unsigned short fileType;
	ClBitMapFileHeader bmpFileHeader;
	ClBitMapInfoHeader bmpInfoHeader;
	int channels = 1;
	int width = 0;
	int height = 0;
	int step = 0;
	int offset = 0;
	unsigned char pixVal;
	ClRgbQuad* quad;
	int i, j, k;

	bmpImg = (ClImage*)malloc(sizeof(ClImage));
	pFile = fopen(path, "rb");
	if (!pFile)
	{
		free(bmpImg);
		return NULL;
	}

	fread(&fileType, sizeof(unsigned short), 1, pFile); 
	if (fileType == 0x4D42) //string "BM"
	{
		//printf("bmp file! \n");  

		fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
		/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
		printf("bmp文件頭信息:\n");
		printf("文件大小:%d \n", bmpFileHeader.bfSize);
		printf("保留字:%d \n", bmpFileHeader.bfReserved1);
		printf("保留字:%d \n", bmpFileHeader.bfReserved2);
		printf("位圖數據偏移字節數:%d \n", bmpFileHeader.bfOffBits);*/

		fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
		/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
		printf("bmp文件信息頭\n");
		printf("結構體長度:%d \n", bmpInfoHeader.biSize);
		printf("位圖寬度:%d \n", bmpInfoHeader.biWidth);
		printf("位圖高度:%d \n", bmpInfoHeader.biHeight);
		printf("位圖平面數:%d \n", bmpInfoHeader.biPlanes);
		printf("顏色位數:%d \n", bmpInfoHeader.biBitCount);
		printf("壓縮方式:%d \n", bmpInfoHeader.biCompression);
		printf("實際位圖數據占用的字節數:%d \n", bmpInfoHeader.biSizeImage);
		printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter);
		printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter);
		printf("使用的顏色數:%d \n", bmpInfoHeader.biClrUsed);
		printf("重要顏色數:%d \n", bmpInfoHeader.biClrImportant);
		printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/

		if (bmpInfoHeader.biBitCount == 8)
		{
			//printf("該文件有調色板,即該位圖為非真彩色\n\n");  
			channels = 1;
			width = bmpInfoHeader.biWidth;
			height = bmpInfoHeader.biHeight;
			offset = (channels*width) % 4;
			if (offset != 0)
			{
				offset = 4 - offset;
			}
			//bmpImg->mat = kzCreateMat(height, width, 1, 0);  
			bmpImg->width = width;
			bmpImg->height = height;
			bmpImg->channels = 1;
			bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);
			step = channels*width;

			quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
			fread(quad, sizeof(ClRgbQuad), 256, pFile);
			free(quad);

			for (i = 0; i<height; i++)
			{
				for (j = 0; j<width; j++)
				{
					fread(&pixVal, sizeof(unsigned char), 1, pFile);
					bmpImg->imageData[(height - 1 - i)*step + j] = pixVal;   //每次一個像素處理
				}
				if (offset != 0)
				{
					for (j = 0; j<offset; j++)
					{
						fread(&pixVal, sizeof(unsigned char), 1, pFile);
					}
				}
			}
		}
		else if (bmpInfoHeader.biBitCount == 24)
		{
			//printf("該位圖為位真彩色\n\n");  
			channels = 3;
			width = bmpInfoHeader.biWidth;
			height = bmpInfoHeader.biHeight;

			bmpImg->width = width;
			bmpImg->height = height;
			bmpImg->channels = 3;
			bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width * 3 * height);
			step = channels*width;

			offset = (channels*width) % 4;
			if (offset != 0)
			{
				offset = 4 - offset;
			}

			fseek(pFile, bmpFileHeader.bfOffBits - sizeof(bmpInfoHeader) - sizeof(bmpFileHeader), SEEK_CUR);  //138-54?感覺應該沒有138才對啊

			for (i = 0; i<height; i++)
			{
				for (j = 0; j<width; j++)
				{
					for (k = 0; k<3; k++)
					{
						fread(&pixVal, sizeof(unsigned char), 1, pFile);
						bmpImg->imageData[(height - 1 - i)*step + j * 3 + k] = pixVal;  //
					}
					//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));  
				}
				if (offset != 0)
				{
					for (j = 0; j<offset; j++)
					{
						fread(&pixVal, sizeof(unsigned char), 1, pFile);
					}
				}
			}
		}
	}

	return bmpImg;
}

bool clSaveImage(char* path, ClImage* bmpImg)
{
	FILE *pFile;
	unsigned short fileType;
	ClBitMapFileHeader bmpFileHeader;
	ClBitMapInfoHeader bmpInfoHeader;
	int step;
	int offset;
	unsigned char pixVal = '\0';
	int i, j;
	ClRgbQuad* quad;

	pFile = fopen(path, "wb");
	if (!pFile)
	{
		return false;
	}

	fileType = 0x4D42;
	fwrite(&fileType, sizeof(unsigned short), 1, pFile);

	if (bmpImg->channels == 3)//24位,通道,彩圖  
	{
		step = bmpImg->channels*bmpImg->width;
		offset = step % 4;
		if (offset != 4)
		{
			step += 4 - offset;
		}

		bmpFileHeader.bfSize = bmpImg->height*step + 54;
		bmpFileHeader.bfReserved1 = 0;
		bmpFileHeader.bfReserved2 = 0;
		bmpFileHeader.bfOffBits = 54;
		fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);

		bmpInfoHeader.biSize = 40;
		bmpInfoHeader.biWidth = bmpImg->width;
		bmpInfoHeader.biHeight = bmpImg->height;
		bmpInfoHeader.biPlanes = 1;
		bmpInfoHeader.biBitCount = 24;
		bmpInfoHeader.biCompression = 0;
		bmpInfoHeader.biSizeImage = bmpImg->height*step;
		bmpInfoHeader.biXPelsPerMeter = 0;
		bmpInfoHeader.biYPelsPerMeter = 0;
		bmpInfoHeader.biClrUsed = 0;
		bmpInfoHeader.biClrImportant = 0;
		fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);

		for (i = bmpImg->height - 1; i>-1; i--)
		{
			for (j = 0; j<bmpImg->width; j++)
			{
				pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3];
				fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
				pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3 + 1];
				fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
				pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3 + 2];
				fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
			}
			if (offset != 0)
			{
				for (j = 0; j<offset; j++)
				{
					pixVal = 0;
					fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
				}
			}
		}
	}
	else if (bmpImg->channels == 1)//8位,單通道,灰度圖  
	{
		step = bmpImg->width;
		offset = step % 4;
		if (offset != 4)
		{
			step += 4 - offset;
		}

		bmpFileHeader.bfSize = 54 + 256 * 4 + bmpImg->width;
		bmpFileHeader.bfReserved1 = 0;
		bmpFileHeader.bfReserved2 = 0;
		bmpFileHeader.bfOffBits = 54 + 256 * 4;
		fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);

		bmpInfoHeader.biSize = 40;
		bmpInfoHeader.biWidth = bmpImg->width;
		bmpInfoHeader.biHeight = bmpImg->height;
		bmpInfoHeader.biPlanes = 1;
		bmpInfoHeader.biBitCount = 8;
		bmpInfoHeader.biCompression = 0;
		bmpInfoHeader.biSizeImage = bmpImg->height*step;
		bmpInfoHeader.biXPelsPerMeter = 0;
		bmpInfoHeader.biYPelsPerMeter = 0;
		bmpInfoHeader.biClrUsed = 256;
		bmpInfoHeader.biClrImportant = 256;
		fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);

		quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
		for (i = 0; i<256; i++)
		{
			quad[i].rgbBlue = i;
			quad[i].rgbGreen = i;
			quad[i].rgbRed = i;
			quad[i].rgbReserved = 0;
		}
		fwrite(quad, sizeof(ClRgbQuad), 256, pFile);
		free(quad);

		for (i = bmpImg->height - 1; i>-1; i--)
		{
			for (j = 0; j<bmpImg->width; j++)
			{
				pixVal = bmpImg->imageData[i*bmpImg->width + j];
				fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
			}
			if (offset != 0)
			{
				for (j = 0; j<offset; j++)
				{
					pixVal = 0;
					fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
				}
			}
		}
	}
	fclose(pFile);

	return true;
}
 

int main(int argc, char* argv[])
{
	ClImage* img = clLoadImage("F:\\RANJIEWEN\\CLQ_C_code\\HOG_SVM_master\\000001.bmp");
	bool flag = clSaveImage("E:/result.bmp", img);
	if (flag)
	{
		printf("save ok... \n");
	}

	while (1);
	return 0;
}
  • 在存24w位圖的時候沒有加fseek(pFile, bmpFileHeader.bfOffBits - sizeof(bmpInfoHeader) - sizeof(bmpFileHeader), SEEK_CUR); //138-54?感覺應該沒有138才對啊存圖不對,有錯位

實驗二


#include<iostream>
#include <stdlib.h>
#include <windows.h>
#include <fstream>
using namespace std;


//---------------------------------------------------------------------------------------
//以下該模塊是完成BMP圖像(彩色圖像是24bit RGB各8bit)的像素獲取,並存在文件名為xiang_su_zhi.txt中
unsigned char *pBmpBuf;//讀入圖像數據的指針

int bmpWidth;//圖像的寬
int bmpHeight;//圖像的高
RGBQUAD *pColorTable;//顏色表指針

int biBitCount;//圖像類型,每像素位數

//-------------------------------------------------------------------------------------------
//讀圖像的位圖數據、寬、高、顏色表及每像素位數等數據進內存,存放在相應的全局變量中
bool readBmp(char *bmpName)
{
	FILE *fp = fopen(bmpName, "rb");//二進制讀方式打開指定的圖像文件

	if (fp == 0)
		return 0;

	//跳過位圖文件頭結構BITMAPFILEHEADER

	fseek(fp, sizeof(BITMAPFILEHEADER), 0);

	//定義位圖信息頭結構變量,讀取位圖信息頭進內存,存放在變量head中

	BITMAPINFOHEADER head;

	fread(&head, sizeof(BITMAPINFOHEADER), 1, fp); //獲取圖像寬、高、每像素所占位數等信息

	bmpWidth = head.biWidth;

	bmpHeight = head.biHeight;

	biBitCount = head.biBitCount;//定義變量,計算圖像每行像素所占的字節數(必須是4的倍數)

	int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;//灰度圖像有顏色表,且顏色表表項為256

	if (biBitCount == 8)
	{

		//申請顏色表所需要的空間,讀顏色表進內存

		pColorTable = new RGBQUAD[256];

		fread(pColorTable, sizeof(RGBQUAD), 256, fp);

	}

	//申請位圖數據所需要的空間,讀位圖數據進內存

	pBmpBuf = new unsigned char[lineByte * bmpHeight];

	fread(pBmpBuf, 1, lineByte * bmpHeight, fp);

	fclose(fp);//關閉文件

	return 1;//讀取文件成功
}

//-----------------------------------------------------------------------------------------
//給定一個圖像位圖數據、寬、高、顏色表指針及每像素所占的位數等信息,將其寫到指定文件中
bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)
{

	//如果位圖數據指針為0,則沒有數據傳入,函數返回

	if (!imgBuf)
		return 0;

	//顏色表大小,以字節為單位,灰度圖像顏色表為1024字節,彩色圖像顏色表大小為0

	int colorTablesize = 0;

	if (biBitCount == 8)
		colorTablesize = 1024;

	//待存儲圖像數據每行字節數為4的倍數

	int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;

	//以二進制寫的方式打開文件

	FILE *fp = fopen(bmpName, "wb");

	if (fp == 0)
		return 0;

	//申請位圖文件頭結構變量,填寫文件頭信息

	BITMAPFILEHEADER fileHead;

	fileHead.bfType = 0x4D42;//bmp類型

	//bfSize是圖像文件4個組成部分之和

	fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;

	fileHead.bfReserved1 = 0;

	fileHead.bfReserved2 = 0;

	//bfOffBits是圖像文件前3個部分所需空間之和

	fileHead.bfOffBits = 54 + colorTablesize;

	//寫文件頭進文件

	fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);

	//申請位圖信息頭結構變量,填寫信息頭信息

	BITMAPINFOHEADER head;

	head.biBitCount = biBitCount;

	head.biClrImportant = 0;

	head.biClrUsed = 0;

	head.biCompression = 0;

	head.biHeight = height;

	head.biPlanes = 1;

	head.biSize = 40;

	head.biSizeImage = lineByte*height;

	head.biWidth = width;

	head.biXPelsPerMeter = 0;

	head.biYPelsPerMeter = 0;

	//寫位圖信息頭進內存

	fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);

	//如果灰度圖像,有顏色表,寫入文件 

	if (biBitCount == 8)
		fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);

	//寫位圖數據進文件

	fwrite(imgBuf, height*lineByte, 1, fp);

	//關閉文件

	fclose(fp);

	return 1;

}

//----------------------------------------------------------------------------------------
//以下為像素的讀取函數
void doIt()
{

	//讀入指定BMP文件進內存

	char readPath[] = "F:\\RANJIEWEN\\CLQ_C_code\\HOG_SVM_master\\000001.bmp";

	readBmp(readPath);

	//輸出圖像的信息

	cout << "width=" << bmpWidth << " height=" << bmpHeight << " biBitCount=" << biBitCount << endl;

	//循環變量,圖像的坐標

	//每行字節數

	int lineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;

	//循環變量,針對彩色圖像,遍歷每像素的三個分量

	int m = 0, n = 0, count_xiang_su = 0;

	//將圖像左下角1/4部分置成黑色

	ofstream outfile("圖像像素.txt", ios::in | ios::trunc);

	if (biBitCount == 8) //對於灰度圖像
	{
		//------------------------------------------------------------------------------------
		//以下完成圖像的分割成8*8小單元,並把像素值存儲到指定文本中。由於BMP圖像的像素數據是從
		//左下角:由左往右,由上往下逐行掃描的
		int L1 = 0;
		int hang = 63;
		int lie = 0;
		//int L2=0;
		//int fen_ge=8;
		for (int fen_ge_hang = 0; fen_ge_hang<8; fen_ge_hang++)//64*64矩陣行循環
		{
			for (int fen_ge_lie = 0; fen_ge_lie<8; fen_ge_lie++)//64*64列矩陣循環
			{
				//--------------------------------------------
				for (L1 = hang; L1>hang - 8; L1--)//8*8矩陣行
				{
					for (int L2 = lie; L2<lie + 8; L2++)//8*8矩陣列
					{
						m = *(pBmpBuf + L1*lineByte + L2);
						outfile << m << " ";
						count_xiang_su++;
						if (count_xiang_su % 8 == 0)//每8*8矩陣讀入文本文件
						{
							outfile << endl;
						}
					}
				}
				//---------------------------------------------
				hang = 63 - fen_ge_hang * 8;//64*64矩陣行變換
				lie += 8;//64*64矩陣列變換
				//該一行(64)由8個8*8矩陣的行組成
			}
			hang -= 8;//64*64矩陣的列變換
			lie = 0;//64*64juzhen
		}
	}

	//double xiang_su[2048];
	//ofstream outfile("xiang_su_zhi.txt",ios::in|ios::trunc);
	if (!outfile)
	{
		cout << "open error!" << endl;
		exit(1);
	}
	else if (biBitCount == 24)
	{//彩色圖像
		for (int i = 0; i<bmpHeight; i++)
		{
			for (int j = 0; j<bmpWidth; j++)
			{
				for (int k = 0; k<3; k++)//每像素RGB三個分量分別置0才變成黑色
				{
					//*(pBmpBuf+i*lineByte+j*3+k)-=40;
					m = *(pBmpBuf + i*lineByte + j * 3 + k);
					outfile << m << " ";
					count_xiang_su++;
					if (count_xiang_su % 8 == 0)
					{
						outfile << endl;
					}
					//n++;
				}
				n++;
			}


		}
		cout << "總的像素個素為:" << n << endl;
		cout << "----------------------------------------------------" << endl;
	}

	//將圖像數據存盤

	char writePath[] = "E://nvcpy.BMP";//圖片處理后再存儲

	saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);

	//清除緩沖區,pBmpBuf和pColorTable是全局變量,在文件讀入時申請的空間

	delete[]pBmpBuf;

	if (biBitCount == 8)
		delete[]pColorTable;
}

void main()
{
	doIt();
}
  • 沒有fseek,24位圖錯位

實驗三

  • 我自己使用的8/24分別寫成函數的

#include "readbmp.h"
#include "stdio.h"
#include "string.h"
#include "malloc.h"

//typedef unsigned short WORD;
//typedef unsigned int DWORD;
//typedef int LONG;
//typedef struct tagBITMAPFILEHEADER {
//	WORD    bfType;
//	DWORD   bfSize;
//	WORD    bfReserved1;
//	WORD    bfReserved2;
//	DWORD   bfOffBits;
//} BITMAPFILEHEADER;
//typedef struct tagBITMAPINFOHEADER{
//	DWORD      biSize;
//	LONG        biWidth;
//	LONG        biHeight;
//	WORD       biPlanes;
//	WORD       biBitCount;
//	DWORD      biCompression;
//	DWORD      biSizeImage;
//	LONG        biXPelsPerMeter;
//	LONG        biYPelsPerMeter;
//	DWORD      biClrUsed;
//	DWORD      biClrImportant;
//} BITMAPINFOHEADER;


#include "windows.h"  //BITMAPFILEHEADER包含文件

myMat *loadBitmapFromFile24(const char *filePath, U8 **bits)     //24
{
	myMat *img;
	img = (myMat*)malloc(sizeof(myMat));
	if (!img) {
		fprintf(stderr, "Unable to allocate memory\n");
		exit(1);
	}

	FILE *fp = fopen(filePath, "rb");
	if (fp == NULL) {
		exit(-1);
	}
	BITMAPFILEHEADER bfh;
	if (fread(&bfh, sizeof(bfh), 1, fp) != 1) {
		fclose(fp);
		exit(-1);
	}
	BITMAPINFOHEADER bih;
	if (fread(&bih, sizeof(bih), 1, fp) != 1) {
		fclose(fp);
		exit(-1);
	}
	if (bih.biBitCount != 24) {
		fclose(fp);
		printf("unsupported bitmap format.\n");
		exit(-1);
	}
	int imageSize = (bih.biWidth*3 + 3) / 4 * 4 * bih.biHeight;

	img->width = bih.biWidth;
	img->height = bih.biHeight;
	img->type = myCV_8U;
	img->dims = 2;
	img->channels = 3;
	img->step = imageSize / bih.biHeight;
	img->totalsize = imageSize;
	img->data = (uchar*)malloc(img->totalsize);
	img->dataend = img->datalimit = (uchar*)img->data + img->totalsize;

	fseek(fp, bfh.bfOffBits - sizeof(bfh) - sizeof(bih), SEEK_CUR);  //138-54?感覺應該沒有138才對啊

	if (fread(img->data, 1, imageSize, fp) != imageSize) {
		fclose(fp);
		exit(-1);
	}
	fclose(fp);

	U8 *buffer = (U8 *)malloc(imageSize);
	buffer = img->data;
	*bits = buffer;

	return img;
}

myMat *loadBitmapFromFile8(const char *filePath, U8 **bits)     //----8
{
	myMat *img;
	img = (myMat*)malloc(sizeof(myMat));
	if (!img) {
		fprintf(stderr, "Unable to allocate memory\n");
		exit(1);
	}

	FILE *fp = fopen(filePath, "rb");
	if (fp == NULL) {
		exit(-1);
	}
	BITMAPFILEHEADER bfh;
	if (fread(&bfh, sizeof(bfh), 1, fp) != 1) {
		fclose(fp);
		exit(-1);
	}
	BITMAPINFOHEADER bih;
	if (fread(&bih, sizeof(bih), 1, fp) != 1) {
		fclose(fp);
		exit(-1);
	}
	if (bih.biBitCount != 8) {
		fclose(fp);
		printf("unsupported bitmap format.\n");
		exit(-1);
	}
	int imageSize = (bih.biWidth + 3) / 4 * 4 * bih.biHeight;

	img->width = bih.biWidth;
	img->height = bih.biHeight;
	img->type = myCV_8U;
	img->dims = 2;
	img->channels = 1;
	img->step = imageSize / bih.biHeight;
	img->totalsize = imageSize ;
	img->data = (uchar*)malloc(img->totalsize);
	img->dataend = img->datalimit = (uchar*)img->data + img->totalsize;

	fseek(fp, bfh.bfOffBits - sizeof(bfh) - sizeof(bih), SEEK_CUR);

	U8 *buffer = (U8 *)malloc(imageSize );

	if (fread(img->data, 1, imageSize, fp) != imageSize) {
		fclose(fp);
		exit(-1);
	}
	
	fclose(fp);

	*bits = buffer;

	return img;
}

int CreateImage(IplImage_ *_img, int _width, int _height, U8 *_image_data)
{
	if (_img->valid)
	{
		return -1;	//這個圖像結構體已經有用了
	}
	if (_width & 3)	//是否是4的整數倍
	{
		_img->width_step = (_width & (~3)) + 4;
	}
	else
	{
		_img->width_step = _width;
	}
	_img->width = _width;
	_img->height = _height;
	_img->image_data = _image_data;
	_img->valid = 1;
	return 0;
}

void ReleaseImage(IplImage_ *_img)
{
	_img->width_step = 0;
	_img->width = 0;
	_img->height = 0;
	_img->image_data = 0;
	_img->valid = 0;
}

void SaveGrayBitmap24(const char *fileName, const U8 *imageData, int width, int height)
{
	BITMAPFILEHEADER bfh;
	BITMAPINFOHEADER bih;
	DWORD palette[256];
	int i, imageSize;
	FILE *fp = fopen(fileName, "wb");
	int widthS = (width*3 + 3) / 4 * 4;
	imageSize = widthS* height;

	if (fp == NULL)
	{
		return;
	}

	memset(&bfh, 0, sizeof(bfh));
	bfh.bfType = 0x4d42;
	bfh.bfSize = imageSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);;
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	fwrite(&bfh, sizeof(bfh), 1, fp);

	memset(&bih, 0, sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biWidth = width;
	bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = 24;
	bih.biCompression = 0;
	bih.biSizeImage = imageSize;
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;
	fwrite(&bih, sizeof(bih), 1, fp);

	for (i = 0; i < height; i++)
	{
		fwrite(imageData + (height - i - 1)*widthS, 1, widthS, fp);
	}

	fclose(fp);
}

void SaveGrayBitmap8(const char *fileName, const U8 *imageData, int width, int height)  //8
{
	BITMAPFILEHEADER bfh;
	BITMAPINFOHEADER bih;
	DWORD palette[256];
	int i, imageSize;

	FILE *fp = fopen(fileName, "wb");
	int widthS = (width + 3) / 4 * 4;
	imageSize = widthS* height;

	if (fp == NULL)
	{
		return;
	}

	memset(&bfh, 0, sizeof(bfh));
	bfh.bfType = 0x4d42;
	bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * 4 + imageSize;
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * 4;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	fwrite(&bfh, sizeof(bfh), 1, fp);

	memset(&bih, 0, sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biWidth = width;
	bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = 8;
	bih.biCompression = 0;
	bih.biSizeImage = imageSize;
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;
	fwrite(&bih, sizeof(bih), 1, fp);

	for (i = 0; i < 256; i++)
	{
		palette[i] = (i << 16) | (i << 8) | i;
	}
	fwrite(palette, sizeof(palette), 1, fp);

	for (i = 0; i < height; i++)
	{
		fwrite(imageData + (height - i - 1)*widthS, 1, widthS, fp);
	}

	fclose(fp);
}

實驗四

  • C++類實現
void SaveToBmpGray::save(const unsigned char* src, int height, int width, std::string path, std::string name)
{
	int imagDataSize = height*width; // imag data size

	//位圖第三部分,調色板
	RGBQUAD rgbQuad[256];
	for (int i = 0; i < 256; ++i)
	{
		rgbQuad[i].rgbBlue = (BYTE)i;
		rgbQuad[i].rgbGreen = (BYTE)i;
		rgbQuad[i].rgbRed = (BYTE)i;
		rgbQuad[i].rgbReserved = i;
	}

	//位圖第一部分,位圖文件頭
	BITMAPFILEHEADER *bfHeader{ new BITMAPFILEHEADER };
	bfHeader->bfType = (WORD)0x4d42;  // string"BM"  
	bfHeader->bfSize = (DWORD)(imagDataSize + sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgbQuad)); // file size
	bfHeader->bfReserved1 = 0; // reserved  
	bfHeader->bfReserved2 = 0; // reserved  
	bfHeader->bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgbQuad)); // real data 位置  

	//位圖第二部分,位圖信息頭  
	BITMAPINFOHEADER *biHeader{ new BITMAPINFOHEADER };
	biHeader->biSize = sizeof(BITMAPINFOHEADER);
	biHeader->biWidth = width;
	biHeader->biHeight = -height;//BMP圖片從最后一個點開始掃描,顯示時圖片是倒着的,所以用-height,這樣圖片就正了  
	biHeader->biPlanes = 1;//為1,不用改  
	biHeader->biBitCount = 8; // 每個像素占用的bit
	biHeader->biCompression = BI_RGB;//不壓縮  
	biHeader->biSizeImage = imagDataSize;
	biHeader->biXPelsPerMeter = 0;//像素每米  
	biHeader->biYPelsPerMeter = 0;
	biHeader->biClrUsed = 0;//已用過的顏色,24位的為0  
	biHeader->biClrImportant = 0;//每個像素都重要 

	//打開文件並保存
	//文件路徑
	std::string fpath;
	fpath += path;
	if (name.empty())
		fpath += "IMG_";
	else
		fpath += name + "_";
	SYSTEMTIME st;
	GetLocalTime(&st);
	char time[20];
	sprintf_s(time, sizeof(st), "%4d%2d%2d_%2d%2d%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	for (int i = 0; time[i]; ++i)
	{
		if (time[i] == ' ') time[i] = '0';
	}
	fpath += time;
	fpath += ".bmp";
	std::fstream file(fpath, std::ios::out | std::ios::binary);
	file.write((char*)bfHeader, sizeof(BITMAPFILEHEADER));
	file.write((char*)biHeader, sizeof(BITMAPINFOHEADER));
	file.write((char*)rgbQuad, sizeof(rgbQuad));
	file.write((char*)src, imagDataSize);
	file.close();
}

void SaveToBmp24::save(const unsigned char* src, int height, int width, std::string path, std::string name)
{
	int imagDataSize = height*width * 3; // imag data size

	//位圖第一部分,位圖文件頭
	BITMAPFILEHEADER *bfHeader{ new BITMAPFILEHEADER };
	bfHeader->bfType = 0x4d42;  // string"BM"  
	bfHeader->bfSize = imagDataSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // file size
	bfHeader->bfReserved1 = 0; // reserved  
	bfHeader->bfReserved2 = 0; // reserved  
	bfHeader->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); // real data 位置  

	//位圖第二部分,位圖信息頭  
	BITMAPINFOHEADER *biHeader{ new BITMAPINFOHEADER };
	biHeader->biSize = sizeof(BITMAPINFOHEADER);
	biHeader->biWidth = width;
	biHeader->biHeight = height;//BMP圖片從最后一個點開始掃描,顯示時圖片是倒着的,所以用-height,這樣圖片就正了  
	biHeader->biPlanes = 1;//為1,不用改  
	biHeader->biBitCount = 24; // 每個像素占用的bit
	biHeader->biCompression = BI_RGB;//不壓縮  
	biHeader->biSizeImage = imagDataSize;
	biHeader->biXPelsPerMeter = 0;//像素每米  
	biHeader->biYPelsPerMeter = 0;
	biHeader->biClrUsed = 0;//已用過的顏色,24位的為0  
	biHeader->biClrImportant = 0;//每個像素都重要 

	//打開文件並保存
	//文件路徑
	std::string fpath;
	fpath += path;
	if (name.empty())
		fpath += "IMG_";
	else
		fpath += name + "_";
	SYSTEMTIME st;
	GetLocalTime(&st);
	char time[20];
	sprintf_s(time, sizeof(st), "%4d%2d%2d_%2d%2d%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	for (int i = 0; time[i]; ++i)
	{
		if (time[i] == ' ') time[i] = '0';
	}
	fpath += time;
	fpath += ".bmp";
	std::fstream file(fpath, std::ios::out | std::ios::binary);
	file.write((char*)bfHeader, sizeof(BITMAPFILEHEADER));
	file.write((char*)biHeader, sizeof(BITMAPINFOHEADER));
	file.write((char*)src, imagDataSize);
	file.close();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM