利用C/C++二进制读写png文件的方法示例

时间:2021-05-19

前言

二进制文件不是以ASCII代码存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件。因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件。

对二进制文件的操作也需要先打开文件,用完后要关闭文件。在打开时要用ios::binary指定为以二进制形式传送和存储。二进制文件除了可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件。这是和ASCII文件不同的地方。

需求

最近为了弄OpenGl的纹理代码,发现书上没有图片像素的获取,然后就想写个来获取png的,结果花了一天的时间没弄清楚为什么出现数据个别正确其他的却是205

突然想起来以前弄软工的时候虽然那个网站只完成了登入注册和文本显示,但是想在数据库中存储图片的时候了解到1存图片地址,2存图片二进制数据。

没错就是二进制。然后拿起C++的翻开找啊找,弄了个ifstream iOS::binary的,成功数据正常。
时隔一天才又想起来r和rb好像是有区别的。没错,那些知识确实没有记住。然后就把C的也改ok了

以下代码只有最简单的读写。地址定位啥的,个别注释中有。如果要改动png的格式甚么的就要再了解一下png的数据结构
如果要十进制的话就跟着注释改一下

mm.png

实例代码如下

#include<iostream> #include<fstream> using namespace std; typedef unsigned char byte; //=============================== //=============== //二进制读入。书上写ASCII码读取和二进制读取,如果对象是字母,那么一致。如果是数字,那么不一致 //书中说明【文件中数据的组织形式,分为ASCII文件(一个字节存放一个ASCII代码)和二进制文件(内部文件,存储形式原样在磁盘上存放),】 //字符,内存存储=ASCII=二进制形式 //数值数据,内存存储和ASCII码不同。 //样例内存整数100000. //---------------------------------------------------------------- //内存地址 0x00 01 02 03 //内存 00000000 00000000 00100111 00010000【大端模式下】 //---------------------------------------------------------------- //二进制 00000000 00000000 00100111 00010000 //---------------------------------------------------------------- //ASCII 00110001 00110000 00110000 00110000 00110000 00110000【6个字节】 //ASCII码对应 1的49 0的48 0的48 0的48 0的48 0的48 //---------------------------------------------------------------- //只有含‘写'的不存在的文件会新建,其他会报错 //r只读;w只写;a尾增(附加/写);文本ASCII //rb读;wb写;ab尾增;二进制 //以下读写↓ //r+;w+;a+;文本ASCII //rb+;wb+;ab+二进制 void writeImage(byte*imgbuf, int size) { //FILE* fp = fopen(shaderFile, "wb"); //由于vs甚么安全性的原因,不让使用fopen,用下面的fopen_s代替; FILE*imgPo; fopen_s(&imgPo, "mag.png", "wb");//这里是用二进制读取,read-r;binary-b;因为只弄r结果出错!!弄了后面那个的再来看这个才发现是这个的问题!! if (imgPo == NULL)return; fwrite(imgbuf, sizeof(char),size,imgPo); fclose(imgPo); } void readImageFile(const char* Imgname) { //FILE* fp = fopen(shaderFile, "rb"); //由于vs甚么安全性的原因,不让使用fopen,用下面的fopen_s代替; FILE*imgP; fopen_s(&imgP,Imgname,"rb");//这里是用二进制读取,read-r;binary-b;因为只弄r结果出错!!弄了后面那个的再来看这个才发现是这个的问题!! if (imgP == NULL)return ; fseek(imgP, 0L, SEEK_END); long size = ftell(imgP); byte*imgbuf = new byte[size+ 1]; fseek(imgP,0x0L,SEEK_SET);//图片源 fread(imgbuf, sizeof(imgbuf[0]), size, imgP); fclose(imgP); writeImage(imgbuf, size); } //=========================================================== void WriteImage(byte*imgbuf, int size) { ofstream imgFo("Image2.png", ios::binary); if (!imgFo) { cerr << "open error!" << endl; abort(); } imgFo.write((char*)imgbuf, size);//一次性写入后面注释的是循环写入 /* for (int i = 0; i < size; i++) { char ct = (imgbuf[i] & 0xFF); imgFo.write(&ct, sizeof(char)); //byte ct = (imgbuf[i] & 0xFF); //imgFo.write((char*)&ct, sizeof(byte)); //尝试这样输出的是否正确. //byte是我自己给名的unsigned char,出来的是对的,用char也可以。都是一个字节。 }*/ imgFo.close(); } void ReadImageFile(const char* Imgname) { ifstream imgF(Imgname, ios::binary); if (!imgF) { cerr << "open error!" << endl; abort(); } imgF.seekg(0, ios::end); int size = imgF.tellg(); //查了C++Library Reference才知道怎么得到size。 /*int pixscnt; byte width[4], height[4]; imgF.seekg(0x10); imgF.read((char*)&width, sizeof(width)); imgF.seekg(0x14); imgF.read((char*)&height, sizeof(height)); for (int i = 0; i < 4; i++) cout << (width[i] & 0xff) << ":"; for (int i = 0; i < 4; i++) cout << (height[i] & 0xff) << ":"; pixscnt = (width[2] * (0x100) + width[3])*(height[2] * (0x100) + height[3]); cout << pixscnt << endl;//像素 cout << size << endl;*/ byte*imgbuf = new byte[size]; //imgF.seekg(0x10); imgF.seekg(0,ios::beg); imgF.read((char*)imgbuf, size);//一次性读入,书上的不知是错的还是旧的不可行。后面注释的是循环读入 /*for (int i = 0; i<size; i++) imgF.read( (char*)&imgbuf[i], sizeof(byte));*/ imgF.close(); WriteImage(imgbuf, size); } int main() { readImageFile("mm.png");//C/C++的 ReadImageFile("mm.png");//C++的 system("pause"); return 0; }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章