目标:用纯C++将位图顺时针旋转90度
位图(Bitmap),顾名思义,就是用一个个像素点表示图片,每个像素点只有一种颜色,它的特点是放大后图像变成一个个色块
关于位图的科普文章大家可以看这篇http://www.cnblogs.com/lzlsky/archive/2012/08/16/2641698.html 挺全面的
要实现位图的旋转,就要改变像素的信息,大致分为以下几步
以二进制方式读取位图 ->按顺序获取位图的文件头和信息头 ->分配堆内存获取并存储像素信息->将原图中的每一个像素的信息写入旋转后图片的堆内存对应的位置->写入整个旋转后图片的信息
其中特别强调的是#pragma pack(1)这个预处理指令一定要有,它的功能是让编译器紧凑排列结构体中的内容,比如结构体中有char和int两种变量,正常来说char占1字节而int占4字节。而默认情况下编译器会给char类型分配4个字节的内存,这是为了和后面的int类型融合。加上#pragma pack(1)后就只给变量分配原来的内存了,我们接下来要按位读取数据,这个预处理指令,必须加!!
接下来定义文件头和信息头,用fstream流读取图片,注意ifstream::read方法的第一个参数只能为char*类型,然而我们要读取其他类型的数据呢?不要管他,强制转换为char*即可,这个我试过了。
为原图和旋转后的像素信息分配内存,将位图宽高交换后写入新的文件头,信息头
上面还用到了一个补位函数fill0 ,因为微软规定位图像素信息每行的大小必须是4个字节的倍数,若不是需要用0补齐,我们获取需要补的字节数fill。
我们读取到行尾时跳过fill个字节,写入到行尾时写入fill个字节的0
然后进行位图的旋转,这里需要知道一点,就是位图的像素是按从下到上,从左到右的顺序存储的
比如像素是
A B C D
E F G H
I J K L
那么它在图片中写入的其实是IJKL EFGH ABCD
旋转后的像素为
I E A
J F B
K G C
L H D
在图片中写入的是LHD KGC JFB IEA
因此旋转图片的代码如下:
最后写入新的像素数据,关闭流指针,别忘了删除new出来的堆内存
然后大功告成了吗?事实上并没有 现在我们只能读取未压缩的图片,压缩后的图片由于信息头和像素数据之间有一段掩码信息,会导致图片损坏
这里有人会说读完信息头后跳过掩码信息,然而掩码信息的大小是不固定的,这怎么办?
细心地人可能注意到了上面有这段代码
我们先读取信息头的大小biSize,然后将流指针返回信息头的初始位置,再读取信息头,读取的大小为biSize 之后发现流指针正好指向像素数据的开始位置
这说明biSize涵盖了原来信息头和后面的掩码信息大小,将掩码信息读入信息头并一并输出即可转换压缩后的图片
附效果图
源代码
0402旋转位图.zip(2.48 KB, 下载次数: 4, 售价: 1 i币)