參考:
Netpbm項目主頁: http://sourceforge.NET/projects/netpbm
Netpbm wiki: http://en.wikipedia.org/wiki/Netpbm
Netpbm format wiki: http://en.wikipedia.org/wiki/Netpbm_format
ppm文件格式: http://hi.baidu.com/sunboya198/item/80fb8e16d39ae9098fbde4d6
1. PPM介紹
PPM(Portable PixMap)是portable像素圖片,是有netpbm項目定義的一系列的portable圖片格式中的一個。這些圖片格式都相對比較容易處理,跟平臺無關,所以稱之爲portable,簡單理解,就是比較直接的圖片格式,比如PPM,其實就是把每一個點的RGB分別保存起來。所以,PPM格式的文件是沒有壓縮的,相對比較大,但是由於圖片格式簡單,一般作爲圖片處理的中間文件(不會丟失文件信息),或者作爲簡單的圖片格式保存。
2. PPM格式分析
netpbm的幾種圖片格式是通過其表示的顏色類型來區別的,PBM是位圖,只有黑色和白色,PGM是灰度圖片,PPM是代表完整的RGB顏色的圖片。
(1) 文件頭
文件頭由三個部分(或者認爲是四個部分)組成:這幾個部分之間用回車或換行分隔(但是PPM標準中要求是空格)
第一部分是文件magic number:
每一個netpbm圖片由兩個字節的magic number (ASCII)組成,來標識文件的類型(PMB/PGM/PPM)以及文件的編碼(ASCII或binary).
所以PPM格式的起始兩個字節爲P3或者P6.
關於編碼(ASCII或binary): 其區別是ASCII編碼的文件是對於閱讀友好的,可以字節用文本編輯器打開,並讀取其對應的圖片的數據(比如RGB的值),然後中間會有空格回車等隔開。binary就是按照二進制的形式,順序存儲圖片信息,沒有空格回車分隔。所以很顯然,binary格式的圖片處理起來更快(不需要判斷空格回車),而且圖片會更小,但是ASCII閱讀調試更爲直接。
第二部分是圖像寬度和高度(空格隔開),用ASCII表示。
第三部分是描述像素的最大顏色組成,允許描述超過一個字節(0-255)的顏色值。
另外,在上面的三個部分裏面,都可以使用"#"插入註釋,註釋是#到行尾(回車或換行)部分。
(2) 圖像數據部分
對於ASCII格式,就是按照RGB的順序排列,以ASCII存儲,並且,RGB中間用空格隔開,圖片每一行用回車隔開。
對於binary格式,就是每一個像素點的RGB值分別順序存儲並且按二進制寫入文件(fwrite),沒有任何分隔。
比如下面這個圖片 (一共六個像素點,圖片寬度爲3,高度爲2):
代碼如下:
- #include <stdio.h>
- #include <stdlib.h>
- int writePPMHeader(FILE *f, char magic, int w, int h, int color) {
- if (f==NULL) {
- printf("FILE error\n");
- exit(0);
- }
- if (magic=='A') {// ASCII
- fprintf(f, "P3\n");
- } else if (magic=='B') {
- fprintf(f, "P6\n");
- } else {
- printf("Magic can only be A(ASCII) or B(binary)\n");
- exit(0);
- }
- fprintf(f, "%d %d\n", w, h);
- fprintf(f, "%d\n", color);
- return 0;
- }
- int writePPMdataP3(FILE* f, unsigned char* img, int w, int h) {
- int i,j;
- for(i=0;i<h;i++) { // every rwo
- for(j=0;j<w;j++) { // every line
- fprintf(f, "%d ",img[i*w*3+3*j]);
- fprintf(f, "%d ",img[i*w*3+3*j+1]);
- fprintf(f, "%d ",img[i*w*3+3*j+2]);<span style="white-space:pre"> </span>// PS: 對於j=w-1的時候,最後一個空格可以不寫,但是這裏就不考慮了
- }
- fprintf(f, "\n");
- }
- }
- int writePPMdataP6(FILE* f, unsigned char* img, int w, int h) {
- int i,j;
- for(i=0;i<w;i++) {
- for(j=0;j<h;j++) {
- fwrite(img, w*h, 3, f);
- }
- }
- }
- #define WIDTH 3
- #define HEIGHT 2
- unsigned char img[WIDTH*HEIGHT*3]={255,0,0,0,255,0,0,0,255,255,255,0,255,255,255,0,0,0};
- int main() {
- char *filename1 = "testP3.ppm";
- char *filename2 = "testP6.ppm";
- FILE *f3 = fopen(filename1, "w");
- if (f3==NULL) {
- printf("FILE error\n");
- exit(0);
- }
- FILE *f6 = fopen(filename2, "w");
- if (f6==NULL) {
- printf("FILE error\n");
- exit(0);
- }
- writePPMHeader(f3, 'A', WIDTH, HEIGHT, 255);
- writePPMdataP3(f3, img, WIDTH, HEIGHT);
- writePPMHeader(f6, 'B', WIDTH, HEIGHT, 255);
- writePPMdataP6(f6, img, WIDTH, HEIGHT);
- fclose(f3);
- fclose(f6);
- return 0;
- }
測試如下:
PPM文件格式分三種:
1. PPM灰度文件
文件頭由3行文本組成,可由fgets讀出
1)第一行爲“P2",表示文件類型
2)第二行爲圖像的寬度和高度
3)第三行爲最大的象素值255
接下來是圖像數據塊。按行順序存儲。每個象素佔4個字節,灰度通道爲4字節ASCII碼錶示的整數,高字節在前。左上角爲座標原點。
2. 16位PPM文件(至少適用於讀取由DCRAW生成的PPM文件)
文件頭由3行文本組成,可由fgets讀出
1)第一行爲“P6",表示文件類型
2)第二行爲圖像的寬度和高度
3)第三行爲最大的象素值
接下來是圖像數據塊。按行順序存儲。每個象素佔3個字節,依次爲紅綠藍通道,每個通道爲1字節整數。左上角爲座標原點。
3. PPM彩色文件
文件頭由3行文本組成,可由fgets讀出
1)第一行爲“P3",表示文件類型
2)第二行爲圖像的寬度和高度
3)第三行爲最大的象素值255
接下來是圖像數據塊。按行順序存儲。每個象素佔12個字節,依次爲紅綠藍通道,每個通道爲4字節ASCII碼錶示的整數,高字節在前。左上角爲座標原點。
可移植像素圖格式(PPM),可移植灰度圖格式(PGM)和可移植位圖格式(PBM)是便於跨平臺的圖像格式。有時候也被統稱爲PNM格式。
歷史
PBM格式由Jef Poskanzer在20世紀80年代發明,爲了便於通過電子郵件,用ASCII碼錶示單色位圖,能夠承受一般的文本格式的變動。
第一個處理PBM格式的工具庫是Pbmplus。它由這個格式的發明人Jef Poskanzer開發,在1988年發佈。主要包含Jef編寫的將PBM轉化爲已存在的其他圖像格式的工具。在1988年末,Jef開發出PGM、PPM格式以及相關工具,並加入Pbmplus中。Pbmplus的最終發佈日期是1991年12月10日。
在1993年,Netpbm庫開始開發,用來替代不再維護的Pbmplus。它是Pbmplus的簡單的重新包裝,附加全世界開發者提供的額外功能和修訂,可能是目前用的最普遍的處理PBM、PGM和PPM格式的工具庫。
文件格式描述
這三種格式在顏色的表示上有差異。PBM是單色,PGM是灰度圖,PPM使用RGB顏色。
每個文件的開頭兩個字節(ASCII碼)作爲文件描述子,指出具體格式和編碼形式。具體見下表:
文件描述子 | 類型 | 編碼 |
---|---|---|
P1 | 位圖 | ASCII |
P2 | 灰度圖 | ASCII |
P3 | 像素圖 | ASCII |
P4 | 位圖 | 二進制 |
P5 | 灰度圖 | 二進制 |
P6 | 像素圖 | 二進制 |