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

前言

二进制文件不是以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;
 /*
class PngMsg
{
private :
 unsigned char markMsg[8]; //十进制,相当于16进制89.50.4e.47.0d.0a.1a.0a;
 char widthloc;
 char heigtMsgloc;
 char BitDepthloc;//图像深度
 char ColorTypeloc;
 char CompressionMethodloc;//压缩方法(LZ77派生算法)
 char FilterMethodloc;//滤波器方法
 char InterlaceMethodloc;
public:
 PngMsg()
 {
 markMsg[0] = 137;markMsg[1] = 80; markMsg[2] = 78;markMsg[3] = 71; markMsg[4] = 13;markMsg[5] = 10; markMsg[6] = 26; markMsg[7] = 10;
 widthloc = 'a';
 heigtMsgloc = 'b';
 BitDepthloc = 'c';//图像深度
 ColorTypeloc = 'd';
 CompressionMethodloc = 'e';//压缩方法(LZ77派生算法)
 FilterMethodloc = 'f';//滤波器方法
 InterlaceMethodloc = 'g';
 }
 long int getMsg(char loc)
 {
 if (loc == 'a')return 0x10;
 if (loc == 'b')return 0x14;
 if (loc == 'c')return 0x15;
 if (loc == 'd')return 0x16;
 if (loc == 'e')return 0x17;
 if (loc == 'f')return 0x18;
 if (loc == 'g')return 0x19;
 }
 unsigned char width[4];//图像宽度,单位像素
 unsigned char height[4];//图像高度,单位像素
 unsigned char BitDepth;
 //图像深度
 //索引彩色1.2.4.8;灰度1.2.4.8.16;真彩色8.16
 unsigned char ColorType;
 //0灰度1.2.4.8.16;2真彩色8.16;3索引彩色1.2.4.8
 //4带α通道数据的灰度8.16;6带α通道数据的真彩色8.16
 unsigned char CompressionMethod;//压缩方法(LZ77派生算法)
 unsigned char FilterMethod;//滤波器方法
 unsigned char InterlaceMethod;//0:非隔行扫描;1:Adam7
};*/ 

//=============================== 

//===============
//二进制读入。书上写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);
 /*for (int j = 0; j < size; j++)
 cout << (imgbuf[j] & 0xff) << ":";*/
 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();
 /*for (int i = 0; i < size; i++)
 {
 cout << hex << (imgbuf[i] & 0xff) << ":";
 if (i % 4 == 0)cout << endl;
 } */
WriteImage(imgbuf, size);
} 

int main()
{
 readImageFile("mm.png");//C/C++的
 ReadImageFile("mm.png");//C++的
 system("pause");
 return 0;
} 

总结

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

(0)

相关推荐

  • 使用C/C++语言生成一个随机迷宫游戏

    迷宫相信大家都走过,毕竟书本啊啥啥啥的上面都会有迷宫,主要就是考验你的逻辑思维.那么我们学习C/C++也是需要学习到逻辑思维方式的,那今天我就来分享一下,如何用C/C++打造一个简单的随机迷宫游戏.(代码的话我只截取了如何创建迷宫的代码,如果想要全套代码的话可以加群:558502932,群内有很多C/C++学习资料提供学习,大家一起交流进步) 完整版的迷宫游戏效果如下: 代码如下: //创建迷宫 void CreateMaze(int x,int y) { //定义4个方向 int dir[4]

  • C/C++中宏定义(#define)

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利. 宏的定义在程序中是非常有用的,但是使用不当,就会给自身造成很大的困扰.通常这种困扰为:宏使用在计算方面. 本例子主要是在宏的计算方面,很多时候,大家都知道定义一个计算的宏,对于编译和编程

  • C/C++实现八大排序算法汇总

    概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 1. 插入排序-直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已

  • C/C++在Java、Android和Objective-C三大平台下实现混合编程

    Android和iOS开发都支持C++开发,可以一套代码多平台使用.同时C++难以反编译的特性也可以为Android开发带来代码的保密,另一native特性也可以提高代码的运行效率. 一.为什么使用C/C++ 便于移植,用C/C++写得库可以方便在其他的平台上再次使用. 代码的保护,由于java层代码很容易被反编译,而C/C++库反汇难度较大. 提高程序的执行效率,将要求高性能的应用逻辑使用C/C++开发,从而提高应用程序的执行效率. 访问现有开源库,需要访问底层的API或引用一些只有C/C++

  • C/C++ 读取16进制文件的方法

    1.为什么有这种需求 因为有些情况需要避免出现乱码.不管什么编码都是二进制的,这样表示为16进制就可以啦. 2.如何读取16进制文件 最近编程用这一问题,网上查了一下,感觉还是自己写吧. 16进制数据一般是:text=0x340xb5...,就是0x开头,之后是两个数字十六进制数. 如果直接使用sscanf(text,"0x",&num),会把连续的数字读进去直到遇到'x'. 如使用sscanf读取text第一个读到的十六进制数是0x340,误判啦.最后,因为是4个一组,就先把

  • C/C++ ip地址与int类型的转换实例详解

    C/C++ ip地址与int类型的转换实例详解 前言 最近看道一个面试题目,大体意思就是将ip地址,例如"192.168.1.116"转换成int类型,同时还能在转换回去 思路 ip地址转int类型,例如ip为"192.168.1.116",相当于"."将ip地址分为了4部分,各部分对应的权值为256^3, 256^2, 256, 1,相成即可 int类型转ip地址,思路类似,除以权值即可,但是有部分字符串的操作 实现代码 #include &l

  • C/C++字符串查找函数全面了解

    C/C++ string库(string.h)提供了几个字符串查找函数,如下: memchr 在指定内存里定位给定字符 strchr 在指定字符串里定位给定字符 strcspn 返回在字符串str1里找到字符串str2里的任意一个字符之前已查找的字符数量 strrchr 在字符串里定位给定字符最后一次出现的位置 strpbrk 在字符串str1里定位字符串str2里任意一个首次出现的字符 strspn 返回字符串str1从开始字符到第一个不在str2中的字符个数 strstr 在字符串str1中

  • C/C++中运算符的优先级、运算符的结合性详解

    一.运算符的优先级 在C++ Primer一书中,对于运算符的优先级是这样描述的: Precedence specifies how the operands are grouped. It says nothing about the order in which the operands are evaluated. 意识是说优先级规定操作数的结合方式,但并未说明操作数的计算顺序.举个例子: 6+3*4+2 如果直接按照从左到右的计算次序得到的结果是:38,但是在C/C++中它的值为20.

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

    前言 二进制文件不是以ASCII代码存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件.因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件. 对二进制文件的操作也需要先打开文件,用完后要关闭文件.在打开时要用ios::binary指定为以二进制形式传送和存储.二进制文件除了可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件.这是和ASCII文件不同的地方. 需求 最近为了弄OpenGl的纹理代码,发现书上没有图片像素

  • Python使用pandas和xlsxwriter读写xlsx文件的方法示例

    python使用pandas和xlsxwriter读写xlsx文件 已有xlsx文件如下: 1. 读取前n行所有数据 # coding: utf-8 import pandas as pd # 1. 读取前n行所有数据 df = pd.read_excel('school.xlsx')#读取xlsx中第一个sheet data1 = df.head(7) # 读取前7行的所有数据,dataFrame结构 data2 = df.values #list形式,读取表格所有数据 print("获取到所

  • iOS读写json文件的方法示例

    前言 本文主要给大家介绍了关于iOS读写json文件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 一.获取沙盒路径 每个iOS应用都有自己专属的应用沙盒,应用沙盒就是文件系统中的目录.但是iOS系统会将每个应用的沙盒目录与文件系统的其他部分隔离,应用必须待在自己的沙盒里,并只能访问自己的沙盒. 沙盒目录 包含内容 Documents 存放应用运行时生成的并且需要保留的数据,iCloud同步时会同步该目录 Library/Caches 存放应用运行时生成的数据,iCl

  • Python利用递归和walk()遍历目录文件的方法示例

    前言 经常需要检查一个"目录或文件夹"内部有没有我们想要的文件或者文件夹,就需要我们循环迭代出所有文件和子文件夹,Python中遍历指定目录下所有的文件和文件夹,包含多级目录,有两种方法,一种是通过递归思想去遍历,另一种是os模块的walk()函数下面话不多说,就来一起看看详细的介绍: 列出目录结构 一.递归方法 #coding:utf-8 import os allfile=[] def getallfile(path): allfilelist=os.listdir(path) f

  • Pandas读写CSV文件的方法示例

    读csv 使用pandas读取 import pandas as pd import csv if name == '__main__': # header=0--表示csv文件的第一行默认为dataframe数据的行名称, # index_col=0--表示使用第0列作为dataframe的行索引, # squeeze=True--表示如果文件只包含一列,则返回一个序列. file_dataframe = pd.read_csv('../datasets/data_new_2/csv_file

  • C#实现利用Windows API读写INI文件的方法

    本文实例讲述了C#实现利用Windows API读写INI文件的方法.分享给大家供大家参考.具体如下: 写入时,如果没有INI文件,自动创建INI 如果在创建时,GetLastError:5 检查IniPath是否添加了文件名称.ini using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Runtime.InteropServices; namespace

  • Python读写压缩文件的方法

    问题 你想读写一个gzip或bz2格式的压缩文件. 解决方案 gzip 和 bz2 模块可以很容易的处理这些文件. 两个模块都为 open() 函数提供了另外的实现来解决这个问题. 比如,为了以文本形式读取压缩文件,可以这样做: # gzip compression import gzip with gzip.open('somefile.gz', 'rt') as f: text = f.read() # bz2 compression import bz2 with bz2.open('so

  • Python读写ini文件的方法

    本文实例讲述了Python读写ini文件的方法.分享给大家供大家参考.具体如下: 比如有一个文件update.ini,里面有这些内容: [ZIP] EngineVersion=0 DATVersion=5127 FileName=dat-5127.zip FilePath=/pub/antivirus/datfiles/4.x/ FileSize=13481555 Checksum=6037,021E MD5=aaeb519d3f276b810d46642d782d8921 那就可以通过下面这些

  • Python读写unicode文件的方法

    本文实例讲述了Python读写unicode文件的方法.分享给大家供大家参考.具体实现方法如下: #coding=utf-8 import os import codecs def writefile(fn, v_ls): f = codecs.open(fn, 'wb', 'utf-8') for i in v_ls: f.write(i + os.linesep) f.close() def readfile(fn): f = codecs.open(fn,'r','utf-8') ls =

  • python使用xlrd模块读写Excel文件的方法

    本文实例讲述了python使用xlrd模块读写Excel文件的方法.分享给大家供大家参考.具体如下: 一.安装xlrd模块 到python官网下载http://pypi.python.org/pypi/xlrd模块安装,前提是已经安装了python 环境. 二.使用介绍 1.导入模块 复制代码 代码如下: import xlrd 2.打开Excel文件读取数据 复制代码 代码如下: data = xlrd.open_workbook('excelFile.xls') 3.使用技巧 获取一个工作表

随机推荐