利用C/C++二進(jìn)制讀寫(xiě)png文件的方法示例
前言
二進(jìn)制文件不是以ASCII代碼存放數(shù)據(jù)的,它將內(nèi)存中數(shù)據(jù)存儲(chǔ)形式不加轉(zhuǎn)換地傳送到磁盤(pán)文件,因此它又稱為內(nèi)存數(shù)據(jù)的映像文件。因?yàn)槲募械男畔⒉皇亲址麛?shù)據(jù),而是字節(jié)中的二進(jìn)制形式的信息,因此它又稱為字節(jié)文件。
對(duì)二進(jìn)制文件的操作也需要先打開(kāi)文件,用完后要關(guān)閉文件。在打開(kāi)時(shí)要用ios::binary指定為以二進(jìn)制形式傳送和存儲(chǔ)。二進(jìn)制文件除了可以作為輸入文件或輸出文件外,還可以是既能輸入又能輸出的文件。這是和ASCII文件不同的地方。
需求
最近為了弄OpenGl的紋理代碼,發(fā)現(xiàn)書(shū)上沒(méi)有圖片像素的獲取,然后就想寫(xiě)個(gè)來(lái)獲取png的,結(jié)果花了一天的時(shí)間沒(méi)弄清楚為什么出現(xiàn)數(shù)據(jù)個(gè)別正確其他的卻是205

突然想起來(lái)以前弄軟工的時(shí)候雖然那個(gè)網(wǎng)站只完成了登入注冊(cè)和文本顯示,但是想在數(shù)據(jù)庫(kù)中存儲(chǔ)圖片的時(shí)候了解到1存圖片地址,2存圖片二進(jìn)制數(shù)據(jù)。
沒(méi)錯(cuò)就是二進(jìn)制。然后拿起C++的翻開(kāi)找啊找,弄了個(gè)ifstream iOS::binary的,成功數(shù)據(jù)正常。
時(shí)隔一天才又想起來(lái)r和rb好像是有區(qū)別的。沒(méi)錯(cuò),那些知識(shí)確實(shí)沒(méi)有記住。然后就把C的也改ok了
以下代碼只有最簡(jiǎn)單的讀寫(xiě)。地址定位啥的,個(gè)別注釋中有。如果要改動(dòng)png的格式甚么的就要再了解一下png的數(shù)據(jù)結(jié)構(gòu)
如果要十進(jìn)制的話就跟著注釋改一下
mm.png

實(shí)例代碼如下
#include<iostream>
#include<fstream>
using namespace std;
typedef unsigned char byte;
/*
class PngMsg
{
private :
unsigned char markMsg[8]; //十進(jìn)制,相當(dāng)于16進(jìn)制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帶α通道數(shù)據(jù)的灰度8.16;6帶α通道數(shù)據(jù)的真彩色8.16
unsigned char CompressionMethod;//壓縮方法(LZ77派生算法)
unsigned char FilterMethod;//濾波器方法
unsigned char InterlaceMethod;//0:非隔行掃描;1:Adam7
};*/
//===============================
//===============
//二進(jìn)制讀入。書(shū)上寫(xiě)ASCII碼讀取和二進(jìn)制讀取,如果對(duì)象是字母,那么一致。如果是數(shù)字,那么不一致
//書(shū)中說(shuō)明【文件中數(shù)據(jù)的組織形式,分為ASCII文件(一個(gè)字節(jié)存放一個(gè)ASCII代碼)和二進(jìn)制文件(內(nèi)部文件,存儲(chǔ)形式原樣在磁盤(pán)上存放),】
//字符,內(nèi)存存儲(chǔ)=ASCII=二進(jìn)制形式
//數(shù)值數(shù)據(jù),內(nèi)存存儲(chǔ)和ASCII碼不同。
//樣例內(nèi)存整數(shù)100000.
//----------------------------------------------------------------
//內(nèi)存地址 0x00 01 02 03
//內(nèi)存 00000000 00000000 00100111 00010000【大端模式下】
//----------------------------------------------------------------
//二進(jìn)制 00000000 00000000 00100111 00010000
//----------------------------------------------------------------
//ASCII 00110001 00110000 00110000 00110000 00110000 00110000【6個(gè)字節(jié)】
//ASCII碼對(duì)應(yīng) 1的49 0的48 0的48 0的48 0的48 0的48
//----------------------------------------------------------------
//只有含‘寫(xiě)'的不存在的文件會(huì)新建,其他會(huì)報(bào)錯(cuò)
//r只讀;w只寫(xiě);a尾增(附加/寫(xiě));文本ASCII
//rb讀;wb寫(xiě);ab尾增;二進(jìn)制
//以下讀寫(xiě)↓
//r+;w+;a+;文本ASCII
//rb+;wb+;ab+二進(jìn)制
void writeImage(byte*imgbuf, int size)
{
//FILE* fp = fopen(shaderFile, "wb");
//由于vs甚么安全性的原因,不讓使用fopen,用下面的fopen_s代替;
FILE*imgPo;
fopen_s(&imgPo, "mag.png", "wb");//這里是用二進(jìn)制讀取,read-r;binary-b;因?yàn)橹慌猺結(jié)果出錯(cuò)??!弄了后面那個(gè)的再來(lái)看這個(gè)才發(fā)現(xiàn)是這個(gè)的問(wèn)題?。?
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");//這里是用二進(jìn)制讀取,read-r;binary-b;因?yàn)橹慌猺結(jié)果出錯(cuò)??!弄了后面那個(gè)的再來(lái)看這個(gè)才發(fā)現(xiàn)是這個(gè)的問(wèn)題??!
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);//一次性寫(xiě)入后面注釋的是循環(huán)寫(xiě)入
/* 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,出來(lái)的是對(duì)的,用char也可以。都是一個(gè)字節(jié)。
}*/
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);//一次性讀入,書(shū)上的不知是錯(cuò)的還是舊的不可行。后面注釋的是循環(huán)讀入
/*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;
}
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
- C++使用read()和write()讀寫(xiě)二進(jìn)制文件
- C++?二進(jìn)制文件讀寫(xiě)方式及示例詳解
- C\C++實(shí)現(xiàn)讀寫(xiě)二進(jìn)制文件的方法詳解
- C++用read()和write()讀寫(xiě)二進(jìn)制文件的超詳細(xì)教程
- C++讀寫(xiě)(CSV,Yaml,二進(jìn)制)文件的方法詳解
- C/C++中二進(jìn)制文件&順序讀寫(xiě)詳解及其作用介紹
- C/C++讀寫(xiě)文本文件、二進(jìn)制文件的方法
- 詳解C++編程中對(duì)二進(jìn)制文件的讀寫(xiě)操作
- C++實(shí)現(xiàn)文本與二進(jìn)制文件讀寫(xiě)操作的示例
相關(guān)文章
基于C語(yǔ)言實(shí)現(xiàn)的貪吃蛇游戲完整實(shí)例代碼
這篇文章主要介紹了基于C語(yǔ)言實(shí)現(xiàn)的貪吃蛇游戲完整實(shí)例代碼,對(duì)于學(xué)習(xí)游戲開(kāi)發(fā)的朋友有一定的借鑒價(jià)值,需要的朋友可以參考下2014-08-08
Qt編寫(xiě)地圖實(shí)現(xiàn)閃爍點(diǎn)圖的示例代碼
閃爍點(diǎn)圖的核心有三個(gè)要素,城市的名稱、城市的經(jīng)緯度、對(duì)應(yīng)值的大小,當(dāng)值越大閃爍點(diǎn)也就越大,本文就來(lái)實(shí)現(xiàn)一下地圖閃爍點(diǎn)圖,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12
C++實(shí)現(xiàn)大整數(shù)乘法(字符串乘法)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)大整數(shù)乘法、字符串乘法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
C語(yǔ)言實(shí)現(xiàn)運(yùn)籌學(xué)中的馬氏決策算法實(shí)例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)運(yùn)籌學(xué)中的馬氏決策算法,簡(jiǎn)單介紹了馬氏決策的概念,并結(jié)合實(shí)例形式分析了C語(yǔ)言實(shí)現(xiàn)馬氏決策算法的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-09-09
基于C語(yǔ)言實(shí)現(xiàn)點(diǎn)餐系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)點(diǎn)餐系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
linux c 查找使用庫(kù)的cflags與libs的方法詳解
本篇文章是對(duì)在linux中使用c語(yǔ)言查找使用庫(kù)的cflags與libs的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

