📄 bmpimageio.c
字号:
//***************************************************************************
//
//文件名: BmpImageIo.c
//程序语言: C
//功能: Bmp图像输入输出函数
//说明: 无
//完成日期: 2005-4-12
//修改日期: 2006-4-3
//作者: 张斯聪
//版本: 1.3a
//
// Copyright (c) 2005, Neural Network and Image Recognition Research Group,
// Beijing University of Technology,
// All rights reserved.
//***************************************************************************
#include "BmpImageIo.h"
//初始化图象颜色和灰度矩阵的地址为空,使释放空间时有判断依据
void initialBmpImage(BmpImage* pBmpImage)
{
pBmpImage->pR = NULL;
pBmpImage->pG = NULL;
pBmpImage->pB = NULL;
pBmpImage->pGray = NULL;
}
//向pOutFile指向的文件中输出3个相同字节的信息
void put3Byte(int data, FILE* pOutFile)
{
fwrite(&data, 1, 3, pOutFile);
}
//读取Bmp文件
//pInFileName为输入文件名,带后缀名
//pBmpImage为保存图像的BmpImage数据类型结构体指针
void readBmp(const char* pInFileName, BmpImage* pBmpImage)
{
int i, j;
FILE* pInFile;
size_t counter;
size_t imageWidth;
BITMAPFILEHEADER bitMapFileHeader;
BITMAPINFOHEADER bitMapInfoHeader;
//读输入文件,若失败,程序中断
if((pInFile = fopen(pInFileName, "rb+")) == NULL)
{
printf("\nreadBmp: can not open head of %s !\n", pInFileName);
exit(0);
}
//读Bmp文件头
fread(&bitMapFileHeader, 14, 1, pInFile);
fread(&bitMapInfoHeader, 40, 1, pInFile);
//最前面4个字节如果不是0x4d42,程序中断
if(bitMapFileHeader.bfType != 0x4d42)
{
//关闭文件
fclose(pInFile);
printf("\nreadBmp: sorry %s is not a BMP file !\n", pInFileName);
exit(0);
}
//如果是压缩文件,程序中断
if(bitMapInfoHeader.biCompression != 0)
{
//关闭文件
fclose(pInFile);
printf("\nreadBmp: sorry this function can not read compressed BMP file !\n");
exit(0);
}
//如果不是24位图像,转换图像文件为24位真彩色
//原文件保存为“BackUp_源文件名”
if(bitMapInfoHeader.biBitCount != 24)
{
//关闭文件
fclose(pInFile);
//第二个参数:FALSE,保留原文件;TRUE,删除原文件
convertTo24BitColor(pInFileName, 1);
if((pInFile = fopen(pInFileName, "rb+")) == NULL)
{
printf("\nreadBmp: can not open head of %s !\n", pInFileName);
exit(0);
}
}
if(pBmpImage->pR != NULL)
{
//如果已分配空间与读入图像大小不符,释放原有空间,开辟新空间
if(pBmpImage->width != (size_t)bitMapInfoHeader.biWidth ||
pBmpImage->height != (size_t)bitMapInfoHeader.biHeight)
{
BmpImageDeleteRgbGray(pBmpImage);
//保存图像宽、高
pBmpImage->width = bitMapInfoHeader.biWidth;
pBmpImage->height = bitMapInfoHeader.biHeight;
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pR);
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pG);
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pB);
}
}
else
{
//保存图像宽、高
pBmpImage->width = bitMapInfoHeader.biWidth;
pBmpImage->height = bitMapInfoHeader.biHeight;
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pR);
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pG);
newByteMatrix(pBmpImage->height, pBmpImage->width, &pBmpImage->pB);
}
//计算图像信息实际占用自字节宽度
imageWidth = pBmpImage->width * 3;
//计算Bmp文件每行占用自字节宽度
counter = (imageWidth + 3) >> 2 << 2;
//Bmp文件每行补零(ASCII码为0)个数
counter -= imageWidth;
//从图像的左下角到右上角,按行读取图像信息
//每像素颜色按照BGR顺序存放
for(i = pBmpImage->height - 1; i >= 0; --i)
{
for(j = 0; j < (int)pBmpImage->width; ++j)
{
pBmpImage->pB[i][j] = getc(pInFile);
pBmpImage->pG[i][j] = getc(pInFile);
pBmpImage->pR[i][j] = getc(pInFile);
}
//跳过没用信息
fseek(pInFile, counter, SEEK_CUR);
}
//关闭文件
fclose(pInFile);
}
//输出Bmp文件
//pOutFileName为输出文件名,带后缀名
//pBmpImage为保存图像的BmpImage数据类型结构体指针
void writeBmp(const char* pOutFileName, BmpImage* pBmpImage)
{
int i, j;
FILE* pOutFile;
size_t counter;
size_t imageWidth;
BITMAPFILEHEADER bitMapFileHeader;
BITMAPINFOHEADER bitMapInfoHeader;
//打开输出文件,若失败,程序中断
//输出文件不存在:新建
//输出文件存在:覆盖
if((pOutFile = fopen(pOutFileName, "wb+")) == NULL)
{
printf("\nwriteBmpHead: can not write head to %s !\n", pOutFileName);
exit(0);
}
//计算图像信息实际占用自字节宽度
counter = pBmpImage->width * 3;
//计算Bmp文件每行占用自字节宽度
imageWidth = (counter + 3) >> 2 << 2;
//生成文件头BITMAPFILEHEADER
bitMapFileHeader.bfType = 0x4d42;
bitMapFileHeader.bfReserved1 = 0;
bitMapFileHeader.bfReserved2 = 0;
bitMapFileHeader.bfOffBits = 54;
//生成文件头BITMAPINFOHEADER
bitMapInfoHeader.biSize = 40;
bitMapInfoHeader.biWidth = pBmpImage->width;
bitMapInfoHeader.biHeight = pBmpImage->height;
bitMapInfoHeader.biPlanes = 1;
bitMapInfoHeader.biBitCount = 24;
bitMapInfoHeader.biCompression = 0;
bitMapInfoHeader.biSizeImage = imageWidth * pBmpImage->height;
bitMapFileHeader.bfSize = bitMapInfoHeader.biSizeImage + 54;
bitMapInfoHeader.biXPelsPerMeter = 0;
bitMapInfoHeader.biYPelsPerMeter = 0;
bitMapInfoHeader.biClrUsed = 0;
bitMapInfoHeader.biClrImportant = 0;
//输出文件头
fwrite(&bitMapFileHeader, 14, 1, pOutFile);
fwrite(&bitMapInfoHeader, 40, 1, pOutFile);
//Bmp文件每行补零(ASCII码为0)个数
counter = imageWidth - counter;
//从图像的左下角到右上角,按行输出图像信息
//每像素颜色按照BGR顺序存放
for(i = pBmpImage->height - 1; i >= 0; --i)
{
for(j = 0; j < (int)pBmpImage->width; ++j)
{
putc(pBmpImage->pB[i][j], pOutFile);
putc(pBmpImage->pG[i][j], pOutFile);
putc(pBmpImage->pR[i][j], pOutFile);
}
//每行补零
fwrite("\0", counter, 1, pOutFile);
}
//关闭文件
fclose(pOutFile);
}
//Bmp文件颜色数转换程序,将任意颜色转换为24位真彩色
//inFileName待转换图像的文件名,带后缀
//ifDel是否删除原图像文件
//1,删除
//非1,24位真彩图片替换原文件,非24位真彩图片另存:文件名前面加"BackUp_"
BYTE convertTo24BitColor(const char* pInFileName, int isDel)
{
int width, height;
int colorNum;
int colorPaletteSize;
int inFileCounter, outFileCounter;
int inFileWidth, outFileWidth;
int fileNameLength = strlen(pInFileName);
int i, j = (fileNameLength + 7) * sizeof(char);
BYTE temp;
BYTE low4Bit, high4Bit;
BYTE** pColorPalette;
char* pOutFileName = (char*)malloc(j);
char* pTempInFileName = (char*)malloc(j);
FILE* pInFile;
FILE* pOutFile;
BITMAPFILEHEADER bitMapFileHeader;
BITMAPINFOHEADER bitMapInfoHeader;
//打开输入文件,若失败,程序中断
if((pInFile = fopen(pInFileName, "rb+")) == NULL)
{
printf("\nconvertTo24BitColor: can not open %s !\n", pInFileName);
return 0;
}
//读Bmp文件头
fread(&bitMapFileHeader, 14, 1, pInFile);
fread(&bitMapInfoHeader, 40, 1, pInFile);
i = bitMapInfoHeader.biBitCount;
if(i == 24)
{
//关闭输入文件
fclose(pInFile);
//释放内存
free(pOutFileName);
free(pTempInFileName);
//如果输入文件是24位真彩图像,程序返回
printf("\nconvertTo24BitColor: %s is already 24Bit color!\n", pInFileName);
return 0;
}
//将新的数据另存为名为Bmp24Bit_pInFileName.bmp的中转文件
strcpy(pOutFileName, pInFileName);
strcpy(pOutFileName + fileNameLength - 4, "_24Bit.bmp");
//打开输出文件,若失败,程序中断
if((pOutFile = fopen(pOutFileName, "wb+")) == NULL)
{
//关闭输入文件
fclose(pInFile);
//释放内存
free(pOutFileName);
free(pTempInFileName);
printf("\nconvertTo24BitColor: can not write to %s !\n", pOutFileName);
return 0;
}
//计算颜色数
colorNum = 1 << bitMapInfoHeader.biBitCount;
//保存图像宽、高
width = bitMapInfoHeader.biWidth;
height = bitMapInfoHeader.biHeight;
//计算调色板所占字节数
//每个调色板颜色都按R、g、b、保留字存顺序存放,占4个字节
colorPaletteSize = colorNum << 2;
//计算非真彩图像每行信息所占字节数
inFileCounter = (width * bitMapInfoHeader.biBitCount + 7) >> 3;
//计算非真彩图像每行实际所占字节数
inFileWidth = (inFileCounter + 3) >> 2 << 2;
//计算非真彩图像每行无效数据所占字节数inFileCounter
inFileCounter = inFileWidth - inFileCounter;
//计算24位真彩图像信息实际占用自字节宽度
outFileCounter = width * 3;
//计算24位真彩Bmp文件每行占用自字节宽度
outFileWidth = (outFileCounter + 3) >> 2 << 2;
//计算新24位真彩图像每行无效数据所占字节数outFileCounter
outFileCounter = outFileWidth - outFileCounter;
//更新文件头
bitMapFileHeader.bfSize = 54 + outFileWidth * height;
bitMapInfoHeader.biSizeImage = width * height * 3;
bitMapFileHeader.bfOffBits = 54;
bitMapInfoHeader.biBitCount = 24;
//输出新文件头信息到中转文件
fwrite(&bitMapFileHeader, 14, 1, pOutFile);
fwrite(&bitMapInfoHeader, 40, 1, pOutFile);
//判断颜色数
switch(i)
{
case 1:
{
//将输入文件指针跳过文件头及调色板
fseek(pInFile, colorPaletteSize, SEEK_CUR);
//输出24位色颜色信息
//从图像的左下角到右上角,按行输出图像信息
//每像素颜色按照BGR顺序存放
for(i = 0; i < height; ++i)
{
j = 0;
while(1)
{
//文件中每字节由高到低按顺序存放像素颜色信息
//输出也要按照由高位到低位的顺序进行
temp = getc(pInFile);
//第8位
put3Byte((temp & 128) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第7位
put3Byte((temp & 64) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第6位
put3Byte((temp & 32) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第5位
put3Byte((temp & 16) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第4位
put3Byte((temp & 8) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第3位
put3Byte((temp & 4) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第2位
put3Byte((temp & 2) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
//第1位
put3Byte((temp & 1) ? 255 : 0, pOutFile);
++j;
if(j == width) break;
}
//隔过输入文件无效数据
fseek(pInFile, inFileCounter, SEEK_CUR);
//向输出文件补零
fwrite("\0", outFileCounter, 1, pOutFile);
}
break;
}
case 4:
{
//建立调色板数组pColorPalette
newByteMatrix(colorNum, 4, &pColorPalette);
//读取调色板颜色信息
for(i = 0; i <colorNum; ++i)
fread(pColorPalette[i], 4, 1, pInFile);
//输出24位色颜色信息
for(i = 0; i < height; ++i)
{
j = 0;
while(1)
{
//文件中每字节由高到低按顺序存放像素颜色信息
//输出也要按照由高位到低位的顺序进行
temp = getc(pInFile);
low4Bit = temp % 16;
high4Bit = temp >> 4;
putc(pColorPalette[high4Bit][0], pOutFile);
putc(pColorPalette[high4Bit][1], pOutFile);
putc(pColorPalette[high4Bit][2], pOutFile);
++j;
if(j == width) break;
putc(pColorPalette[low4Bit][0], pOutFile);
putc(pColorPalette[low4Bit][1], pOutFile);
putc(pColorPalette[low4Bit][2], pOutFile);
++j;
if(j == width) break;
}
//隔过输入文件无效数据
fseek(pInFile, inFileCounter, SEEK_CUR);
//向输出文件补零
fwrite("\0", outFileCounter, 1, pOutFile);
}
//删除调色板数组
deleteByteMatrix(colorNum, &pColorPalette);
break;
}
case 8:
{
//建立调色板数组pColorPalette
newByteMatrix(colorNum, 4, &pColorPalette);
//读取调色板颜色信息
for(i = 0; i < colorNum; ++i)
fread(pColorPalette[i], 4, 1, pInFile);
//输出24位色颜色信息
for(i = 0; i < height; ++i)
{
for(j = 0; j < width; ++j)
{
temp = getc(pInFile);
putc(pColorPalette[temp][0], pOutFile);
putc(pColorPalette[temp][1], pOutFile);
putc(pColorPalette[temp][2], pOutFile);
}
//隔过输入文件无效数据
fseek(pInFile, inFileCounter, SEEK_CUR);
//向输出文件补零
fwrite("\0", outFileCounter, 1, pOutFile);
}
//删除调色板数组
deleteByteMatrix(colorNum, &pColorPalette);
break;
}
default:
{
//关闭输入文件
fclose(pInFile);
//关闭中转文件
fclose(pOutFile);
//释放内存
free(pOutFileName);
free(pTempInFileName);
//如果输入文件是24位真彩图像,程序返回
printf("\nconvertTo24BitColor: %s has wrong color number!\n", pInFileName);
return 0;
}
}
//关闭输入文件
fclose(pInFile);
//关闭中转文件
fclose(pOutFile);
//判断是否保存输入文件
if(isDel == 1)
{
DeleteFile(pInFileName);
}
else
{
//将输出文件和源文件换名
//源文件名加前缀"BackUp_"
strcpy(pTempInFileName, pInFileName);
strcpy(pTempInFileName + fileNameLength - 4, "_Old.bmp");
rename(pInFileName, pTempInFileName);
}
rename(pOutFileName, pInFileName);
//释放内存
free(pOutFileName);
free(pTempInFileName);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -