请选择 进入手机版 | 继续访问电脑版
查看: 8771|回复: 2591

[C/C++] [红客焦点]用纯C++实现位图的旋转

[复制链接]
  • TA的每日心情
    擦汗
    2019-10-17 06:41
  • 签到天数: 182 天

    [LV.7]常住居民III

    发表于 2016-4-2 18:32:07 | 显示全部楼层 |阅读模式
    本帖最后由 小圈圈 于 2016-4-2 18:51 编辑

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

    使用道具 举报

    该用户从未签到

    发表于 2016-4-2 19:19:27 | 显示全部楼层
    谢谢楼主的分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-2 20:48:09 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-2 21:45:03 | 显示全部楼层
    我是来水经验的……
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 03:54:23 | 显示全部楼层
    支持,看起来还是可以的
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 03:54:24 | 显示全部楼层
    非常感谢
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 03:56:40 | 显示全部楼层
    支持,看起来还是可以的
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 05:28:07 | 显示全部楼层
    支持,看起来还是可以的
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 06:15:43 | 显示全部楼层
    谢谢楼主的分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-4-3 06:36:18 | 显示全部楼层
    支持,看起来还是可以的
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    快速回复 返回顶部 返回列表