今天想说的是如何用C++语言操作图片(其实案例代码是用C++写的,如果想用别的语言操作图片,看完本片就会了)。更准确的说是如何从图片文件本身去操作,而不受限于用什么语言。可能这句话有很多人不是很理解,下面我将仔细阐述一下。
就拿我第一各带图形的程序来说吧。例如下面这个五子棋游戏,下面这张图就是这个项目的主界面。
当时,我是用的C语言图形库叫Easxy(感兴趣的可以了解一下)。里面有个loadimage函数,是专门读取jpg格式的图片文件。我当时费劲半天找到这个函数,以为自己会操作图片了。结果没过多久,我又用C++ Win32想写个带图形的程序,结果费牛劲找到了GDI、GDI+两个图像库,里面分别有LoadBitmap函数和Image对象是处理图形的,才解决了问题。后来也用其他编程语言都写过带图形的程序,反正都很费劲才解决我想要的问题。
对本人而言,更倾向于底层造轮子的。所以,后来专门对图片进行研究了一番,才知道我对图片理解错了。我们在编程时操作图片时,不要依赖于程序语言的提供的函数接口,而更应该是从图片文件本身来处理问题。哪些各种编程语言之所以提供这些接口,更多是提高开发效率,而且大多数程序员也不关注图片具体原理。目前我们熟悉的图片格式有BMP(又称位图,计算机原始图,未经压缩),JPG(JPEG编码),JPGE(JPEG),PNG(没有具体了解,感兴趣的可以了解一下)等。所以我们要想操作图片,我们必须了解这些格式的图片是怎么存储的(编码),这样我们才能对图片进行解析。
下面BMP格式的图片进行举例说明,分别对缩放,裁剪,灰度等(三个进行说明)。因为BMP是最容易处理的,知其一,后续任何格式都知道怎么操作了(就是麻烦点而已)。
一问:如何读取、存储BMP图片文件?
首先,我们得知道BMP的编码格式,不知道到去网上查。BMP是包含三个部分(文件头[14字节],图片信息头[40字节],调色板数据[1024字节][可选],颜色数据)。调色板数据,只有位深(位深,简单来说一个像素点的大小,比如8位的图就是灰度图;24位的图片,一般是RGB彩色图;32位的图片就是RGBA带透明度的彩色图)为8位的图片才有。知道这些后,我设计出数据结构,然后按照二进制方式读取、写入文件即可。
//灰度类型
enum GrayType
{
GT_NIL, //无类型
GT_AVE, //平均值灰度
GT_STD, //标准值灰度
GT_BYTE8 //8字节灰度(24和32才有意义)
};
//图片数据结构
class PictureData
{
public:
PictureFormat m_enumType; //类型
unsigned int m_unHeight; //高度
unsigned int m_unWidth; //宽度
unsigned long m_ulPixelLen; //像素长度
unsigned char *m_ptuchPixel; //像素数据
unsigned short m_unPixelBit; //像素位数
public:
bool m_bIsGray; //是否灰度处理过
public:
//构造 赋值 拷贝 析构
PictureData(void);
PictureData& operator =(const PictureData& obj);
PictureData(const PictureData& obj);
virtual ~PictureData(void);
};
下面是读取代码:
//byteData 图片文件的二进制数据
//byteLen 字节长度
//PictureData 保存图片信息的数据结构
//erroInfo 错误信息
//这里之所以这样传参,是因为本人进行封装了的,拆分一下应该不难,如果觉得有困难,那说明你还得继续学习啊
bool Picture::LoadBMP(const unsigned char *byteData, unsigned long byteLen, PictureData &pictureData, string* errorInfo)
{
//偏移量
unsigned long offset = 0;
char szLog[1024] = {
0 };
//格式
pictureData.m_enumType = PictureFormat::PF_BMP;
//位图头部结构(2字节对齐)
#pragma pack(push, 2)
struct S_BMP_FILE_HEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
};
#pragma pack(pop)
//位图信息结构
struct S_BMP_INFO_HEADER {
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;
};
//读取文件头
S_BMP_FILE_HEADER fileHeader;
::memset(&fileHeader, 0, sizeof(S_B