www.pudn.com > Hough.rar > BMP.cpp
#include "stdafx.h"
#include <stdio.h>
#include "BMPFormat.h"
/**************************************************************************************
* 函数名:ReadBinaryBMP
* 功能:读二值BMP图像
* 说明:1、从fullfilename文件中读取数据,把BMP头赋给headBMP, 把信息头赋给infoHead,
* 把调色板数据读到pRgbPlates指定的内存块中,
* 把图像数据读到pImgData指定的内存块中,图像数据的个数为dataCount,
* 把剩余数据读到pLeftData指定的内存块中,剩余数据的个数为leftDataCount,
* 出错信息赋给errorMsg, 状态信息赋给info 。
* 2、在本函数内用malloc()函数分别为调色板、图像数据、其余数据分配了内存,
* 并把相应指针赋给pRgbPlates、pImgData、pLeftData,在函数外部的适当地方
* 应该用free()释放pRgbPlates、pImgData、pLeftData指向的内存。
* 输入参数:
* fullfilename --- 带路径的BMP文件名
* 输出参数:
* headBMP --- BMP头
* infoHead --- 信息头
* pRgbPlates --- 指向调色板
* rgbPlateDataCount --- 调色板所占的字节数 (对于8位图像,应该有256个调色板项,每项4个字节)
* pImgData --- 指向图像数据内存块
* dataCount --- 图像数据所占的字节数
* pLeftData --- 图像文件中多余的字节数据
* leftDataCount --- 图像文件中多余的字节个数
* errorMsg --- 错误信息
* info --- 非错误信息
* 返回值:
* 未发生错误,返回TRUE; 发生错误,返回FALSE;
* 当返回TRUE时,info中存放的是函数执行过程中的状态信息。
* 当返回FALSE时,errorMsg中存放的是函数执行过程中的出错信息。
****************************************************************************************/
BOOL ReadBinaryBMP(CString fullfilename, BmpHead&amt; headBMP, InfoHead&amt; infoHead,
BYTE*&amt; pRgbPlates, long&amt; rgbPlateDataCount,
BYTE*&amt; pImgData, long&amt; dataCount,
/*BYTE*&amt; pLeftData, long&amt; leftDataCount, */
CString&amt; errorMsg, CString&amt; info)
{
// BmpHead headBMP;
// InfoHead infoHead;
FILE* p;
p = fopen(fullfilename,"rb");
if (p == NULL)
{
errorMsg.Format("*** Error: file >s open failed! *** \n", fullfilename);
return FALSE;
}
info.Format("file >s open success.\n",fullfilename);
/********** read BMP head ********************/
WORD mark;
fread(&amt;mark,1,2,p);
//fseek(p,2,SEEK_CUR);
if(mark != 19778) //'BM'
{
errorMsg = "*** Error: the picture is not of the format of bmp! *** \n";
return FALSE;
}
fread(&amt;headBMP,1,12,p);
//headBMP.show();
CString msg;
msg.Format("Image Size:>d \n",headBMP.imageSize);
info += msg;
msg.Format("Image Data Start Position : >d \n",headBMP.startPosition);
info += msg;
fread(&amt;infoHead,1,40,p);
if (infoHead.bitColor != 8)
{
fclose(p);
errorMsg.Format("*** Error: This is not a picture of 8 bits *** \n");
return FALSE;
}
if (infoHead.height > 0)
{
// 倒向图像,图像数据存储从左到右,从下至上,即从左下角到右上角。大部分bmp图像都是倒向图像
msg.Format("Normal Image, That is, \n The pixel data is stored from left to right, from bottom to top. \n");
}
else
{
// 正向图像,图像数据存储从左到右,从上到下,即从左上角到右下角
msg.Format("Special Image, That is, \n The pixel data is stored form left to right, from top to bottom. \n");
}
info += msg;
msg.Format("Image Size : >d * >d \n", infoHead.width, infoHead.height);
info += msg;
if ((infoHead.width > 4) != 0)
{
// 当infoHead.width不是4的倍数时,在保存图像数据到文件中时,每一行的最后要补充0,使每一行的字节数为4的倍数。
msg.Format("The image width is not the multiple of 4, \n so that zeros will be added at each end of the image row. \n");
info += msg;
}
else
{
msg.Format("The image width is the multiple of 4, \n so that no zero was added at end of each row. \n");
}
/*********** read Palette **************/
rgbPlateDataCount = 256 * sizeof(RGBMixPlate); // 256个调色板项,每项4个字节
pRgbPlates = new BYTE[rgbPlateDataCount];
fread(pRgbPlates, 1, rgbPlateDataCount, p);
/*********** read Image Date **************/
if ((infoHead.realSize != 0) &amt;&amt; ((infoHead.width > 4) == 0))
{
dataCount = infoHead.realSize;
}
else // infoHead.realSize == 0 或 (infoHead.width > 4) != 0
{
dataCount = infoHead.width * infoHead.height * (infoHead.bitColor/8);
}
pImgData = new BYTE[dataCount];
if (infoHead.width > 4 == 0) // 宽度(以像素计)是4的倍数,则图像数据区中的每一行末尾不用添加0
{
fread(pImgData, 1, dataCount, p); // 直接把所有数据读进内存
msg.Format("No zero need to be added at end of row. \n Image data have been read at one time. \n");
info += msg;
}
else // 宽度(以像素计)不是4的倍数,则图像数据区中的每一行末尾要添加0,使每行的像素数是4的倍数
{
// 在图像数据的每一行末尾要添加0的个数(以像素为单位)
int nAddedZerosCount = (infoHead.width/4 + 1) * 4 - infoHead.width;
msg.Format("At each end of row, >d byte of zeros have been added. \n", nAddedZerosCount);
info += msg;
for (int i=0; i<infoHead.height; i++)
{
//int numread = fread(pImgData, 1, infoHead.width, p);
int numread = fread((pImgData + i*infoHead.width*(infoHead.bitColor/8)), 1, infoHead.width, p);
int result = fseek(p, nAddedZerosCount, SEEK_CUR); // 在读每一行时,跳过后面添加的0
}
}
msg.Format("Image Data Size: >d \n", dataCount);
info += msg;
if(!fclose(p)) // 关闭文件成功
{
msg.Format("file closed.\n");
info += msg;
}
return TRUE;
}
/**************************************************************************************
* 函数名:WriteBinaryBMP
* 功能:写二值BMP图像
* 说明:1、将内存中的BMP数据(包含BMP头、信息头、调色板、图像数据)写到fullfilename文件中。
* 出错信息赋给errorMsg, 状态信息赋给info 。
* 2、在本函数内用free()释放了pRgbPlates、pImgData、pLeftData指向的内存。
* 输入参数:
* fullfilename --- 带路径的BMP文件名
* headBMP --- BMP头
* infoHead --- 信息头
* pRgbPlates --- 指向调色板
* rgbPlateDataCount --- 调色板所占的字节数 (对于8位图像,应该有256个调色板项,每项4个字节)
* pImgData --- 指向图像数据内存块
* dataCount --- 图像数据所占的字节数
* pLeftData --- 图像文件中多余的字节数据
* leftDataCount --- 图像文件中多余的字节个数
* 输出参数:
* errorMsg --- 错误信息
* info --- 非错误信息
* 返回值:
* 未发生错误,返回TRUE; 发生错误,返回FALSE;
* 当返回TRUE时,info中存放的是函数执行过程中的状态信息。
* 当返回FALSE时,errorMsg中存放的是函数执行过程中的出错信息。
****************************************************************************************/
BOOL WriteBinaryBMP(CString fullfilename, BmpHead headBMP, InfoHead infoHead,
BYTE* pRgbPlates, long rgbPlateDataCount,
BYTE* pImgData, long dataCount,
/*BYTE* pLeftData, long leftDataCount, */
CString&amt; errorMsg, CString&amt; info)
{
FILE *p1 = fopen(fullfilename,"wb");
if (NULL == p1)
{
errorMsg.Format("*** Error: open new file failed.\n ***");
return FALSE;
}
char hh[2] = {0x42, 0x4D};
fwrite(hh,1,2,p1); //BMP文件开头两字节, 0x4d42 = "BM"
fwrite(&amt;headBMP, 1, 12, p1); //BMP文件头
fwrite(&amt;infoHead, 1, 40, p1); //BMP文件头信息
fwrite(pRgbPlates, 1, rgbPlateDataCount, p1); //写调色板信息
if (infoHead.width > 4 == 0) // 当图像的宽度不是4的倍数时(以像数为单位)
{
fwrite(pImgData, 1, dataCount, p1); //直接写图像数据到文件
}
else
{
int nActualBytesCountPerRow = (infoHead.width/4 + 1) * 4;
BYTE * pRowData = new BYTE[nActualBytesCountPerRow];
// 在图像数据的每一行末尾要添加0的个数(以字节为单位)
int nAddedZerosCount = nActualBytesCountPerRow - infoHead.width;
for (int i=0; i<infoHead.height; i++)
{
for (int j=0; j<infoHead.width; j++)
{
pRowData[j] = pImgData[i*infoHead.width + j];
}
for (j = infoHead.width; j<nActualBytesCountPerRow; j++)
{
pRowData[j] = 0x00;
}
fwrite(pRowData, 1, nActualBytesCountPerRow, p1);
}
delete pRowData;
}
fclose(p1);
//释放分配的内存
free(pRgbPlates);
free(pImgData);
info += "数据成功写入目标文件中";
return TRUE;
}