⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bmpimageio.c

📁 数字图像处理二维傅里叶变换代码
💻 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 + -