git:https://github.com/baogejin/BmpHandler
昨天晚上看到公司的小伙伴在墙上贴像素图像,忽然就对图像的处理感到有兴趣了。
网上看了几篇博客,发现基本上都是bmp格式的(其他格式压缩了不好处理)
自己也模仿着写了写,并且为了便于扩展,封装了一个类,拿出来分享一下
BmpHandler.h
#ifndef BMPHANDLER_H_INCLUDED
#define BMPHANDLER_H_INCLUDED
//------------------------------------------------------------
//头文件
#include<stdio.h>
#include<windows.h>
#include<wingdi.h>//这个前面必须include<windows.h>,否则报错
//------------------------------------------------------------
//CBmpHandler类
class CBmpHandler
{
private:
//图像数据
int m_iBmpWidth;//图像的宽
int m_iBmpHeight;//图像的高
int m_iBitCount;//图像类型,每像素位数
int m_iLineSize;//图像每行的字节数
RGBQUAD* m_stColorTable;//颜色表指针
unsigned char* m_szBmpBuf;//图像数据的指针
private:
//私有函数
public:
//----------------------------------------
//基本函数
//构造函数
CBmpHandler();
//析构函数
~CBmpHandler();
//加载bmp图片
bool loadBmp(char* szFileName);
//保存图片
bool saveBmpAs(char* szFileName);
//----------------------------------------
//以下是图像处理函数,新功能请在下面添加
//更改亮度,参数范围-255~255
bool change_brightness(int iValue);
};
#endif // BMPHANDLER_H_INCLUDED
BmpHandler.cpp
#include "BmpHandler.h"
//构造函数
CBmpHandler::CBmpHandler()
{
}
//析构函数
CBmpHandler::~CBmpHandler()
{
if(m_iBitCount == 8)delete []m_stColorTable;
delete []m_szBmpBuf;
}
//加载图片
bool CBmpHandler::loadBmp(char* szFileName)
{
//打开bmp文件
FILE *fp = fopen(szFileName, "rb");
//没有读到,返回失败
if(!fp)return false;
//跳过位图文件头结构 BITMAPFILEHEADER
fseek(fp, sizeof(BITMAPFILEHEADER), 0);//BITMAPFILEHEADER需要include<wingdi.h>
//获取图片信息结构 BITMAPINFOHEADER
BITMAPINFOHEADER stInfoHeader;
fread(&stInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
//获取图像宽、高
m_iBmpWidth = stInfoHeader.biWidth;
m_iBmpHeight = stInfoHeader.biHeight;
int iSize = stInfoHeader.biSizeImage;
//获取每像素位数,计算一行所占字节数
m_iBitCount = stInfoHeader.biBitCount;
m_iLineSize = (m_iBmpWidth*m_iBitCount/8+3)/4*4;//这里确保了是4的倍数
if(m_iBitCount == 8)
{
//是灰度图片,申请颜色表所需空间,读颜色表进内存
m_stColorTable = new RGBQUAD[256];
fread(m_stColorTable, sizeof(RGBQUAD), 256, fp);
}
//申请位图数据所需空间,读位图数据进内存
m_szBmpBuf = new unsigned char[m_iLineSize*m_iBmpHeight];
fread(m_szBmpBuf, 1, m_iLineSize*m_iBmpHeight, fp);
//关闭文件
fclose(fp);
return true;
}
//保存图片
bool CBmpHandler::saveBmpAs(char* szFileName)
{
//没有图像数据
if(!m_szBmpBuf)return false;
//颜色表大小,以字节为单位,灰度图颜色表大小1024,彩色图为0
int iColorTableSize = 0;
if(m_iBitCount == 8)iColorTableSize = 1024;
//以二进制写的形式打开文件
FILE* fp = fopen(szFileName, "wb");
//打开文件失败
if(!fp)return false;
//申请位图文件头结构变量,填写文件头信息
BITMAPFILEHEADER stFileHeader;
stFileHeader.bfType = 0x4D42;//bmp类型,为什么头文件里没有宏定义
stFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + iColorTableSize + (m_iLineSize*m_iBmpHeight);//bfSize是4个部分之和
stFileHeader.bfReserved1 = 0;
stFileHeader.bfReserved2 = 0;
stFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + iColorTableSize;//bfOffBits是前3部分之和
fwrite(&stFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);//写文件头进文件
//申请位图信息头结构变量,填写信息头信息
BITMAPINFOHEADER stInfoHeader;
stInfoHeader.biBitCount = m_iBitCount;
stInfoHeader.biClrImportant = 0;
stInfoHeader.biClrUsed = 0;
stInfoHeader.biCompression = 0;
stInfoHeader.biHeight = m_iBmpHeight;
stInfoHeader.biWidth = m_iBmpWidth;
stInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
stInfoHeader.biSizeImage = m_iLineSize*m_iBmpHeight;
stInfoHeader.biXPelsPerMeter = 0;
stInfoHeader.biYPelsPerMeter = 0;
fwrite(&stInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
//如果是灰度图,有颜色表,写入文件
if(m_iBitCount == 8)fwrite(m_stColorTable, sizeof(RGBQUAD), 256, fp);
//写位图数据进文件
fwrite(m_szBmpBuf, m_iLineSize*m_iBmpHeight, 1, fp);
//关闭文件
fclose(fp);
return true;
}
//更改亮度,参数范围-255~255
bool CBmpHandler::change_brightness(int iValue)
{
//没有图片资源
if(!m_szBmpBuf)return false;
//参数超出范围
if(iValue < -255 || iValue > 255)return false;
for(int i=0;i<m_iBmpHeight;i++)
{
for(int j=0;j<m_iBmpWidth;j++)
{
//遍历所有像素
for(int k=0;k<3;k++)
{
//修改rgb值,用int临时变量防止越界
int iTmp = (int)m_szBmpBuf[i*m_iLineSize+j*3+k];
iTmp += iValue;
if(iTmp < 0)iTmp = 0;
if(iTmp > 255)iTmp = 255;
m_szBmpBuf[i*m_iLineSize+j*3+k] = (char)iTmp;
}
}
}
return true;
}
整理了一番,觉得调理比网上的代码清晰多了,同时要添加新的处理方法也是十分的方便,使用起来也相对简单,例如:
#include "BmpHandler.h"
int main()
{
char szFileName[] = "DSC_9725.bmp";
char szOutName[] = "out.bmp";
CBmpHandler bmp;
bmp.loadBmp(szFileName);
bmp.change_brightness(50);
bmp.saveBmpAs(szOutName);
return 0;
}
大家感兴趣的话可以添加各种各样的处理函数