1. 程式人生 > >C/C++二進位制讀寫png檔案

C/C++二進位制讀寫png檔案

為了弄OpenGl的紋理程式碼,發現書上沒有圖片畫素的獲取,然後就想寫個來獲取png的,結果花了一天的時間沒弄清楚為什麼出現數據個別正確其他的卻是205

突然想起來以前弄軟工的時候雖然那個網站只完成了登入註冊和文字顯示,但是想在資料庫中儲存圖片的時候瞭解到1存圖片地址,2存圖片二進位制資料。

沒錯就是二進位制。然後拿起C++的翻開找啊找,弄了個ifstream ios::binary的,成功資料正常。

時隔一天才又想起來r和rb好像是有區別的。沒錯,那些知識確實沒有記住。然後就把C的也改ok了

以下程式碼只有最簡單的讀寫。地址定位啥的,個別註釋中有。如果要改動png的格式甚麼的就要再瞭解一下png的資料結構

如果要十進位制的話就跟著註釋改一下

mm.png


20180706 看到一個新浪的 http://www.cnblogs.com/weiyikang/p/6828647.html  應用的libpng

2017-04-23後面的程式碼還沒有涉及到畫素問題(本來是要的,奈何png好像壓縮方法還不只一個。然後我開始實習了就還沒有繼續深究。http://www.libpng.org/pub/png/libpng-1.2.5-manual.html 這個連結裡面可能有其他內容或這庫。我只是收藏還沒有看。不確定)

這博文只是說明png用是二進位制檔案讀寫(不是ASCII碼讀寫。)還有裡面的長度的數值的取值方式。註釋掉的裡面有欄位定位,我自己弄的而且弄一半。

另一片文章測試了png的CRC檢測欄位是否正確http://blog.csdn.net/u014646950/article/details/51144476  

其實我也不怎麼懂。然後就是卡死在不知道png是二進位制讀寫的。其他討論私信或者QQ(主頁左上角臨時會話,或者空間說說留言。空間半開放。QQ郵箱也是可以的)

#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;
}