ppm,一种简单的图片文件格式
veekxt 发布于 2015-05-06 00:00:00

ppm是一种简单的图像格式,它的格式就像这样:
(文章所有的“==>”之后为我的注释,并不是文件中有的,<>中的数据应当有实际的值替换)

P6 ==>图片格式说明,p6是二进制存储,p3是assic码存储
#somethingcomment ==>注释
240 320 ==>宽和高
255 ==>意义不明,可能是为了标记头的结束
<二进制或assic的r,g,b数据> ==>由左至右,由上到下的数据顺序
<换行符> ==>文件的结束,同时注意上文中的几个换行,没写出来,比如P6和240之间的。

先说第一种类型P3,他是纯的文本文件,一个实际的例子:

P3
# my ppm file
1 2 ==>宽1高2
255
120 ==>第一个点的red值
120 ==>green 120 ==>blue
255 ==>第二个点
0 ==>...
0

用文本文件就能很容易地查看。 然后是P6,它与P3的区别仅在于第一行说明和数据的格式,比如255会以二进制0xff存储,只占一个字节,但两个数据间没有“\n”。注意文件头不论类型始终是文本的。

接下来只讨论P6格式,并用c语言封装一些易用的读写方法。

头文件ppm.h

#ifndef	_PPM_H
#define	_PPM_H	1
#include<stdio.h>

//定义XTCOLOR来作颜色类型
typedef unsigned int XTCOLOR;

//结构体,用来保存一个图片文件的信息
typedef struct img_ppm_s
{
    FILE *f;
    int type;
    int width;
    int height;
}img_ppm;

//三个rgb值转换成XTCOLOR类型
XTCOLOR xtrgb(int r,int g,int b);

//根据文件指针写入一个颜色
void write_to_file(FILE *p,XTCOLOR fillcolor);

//创建一个图片文件
img_ppm create_ppm(char * filename,int type,int width,int height,XTCOLOR bk_color);

//封装:在指定的图片坐标画一个点
void point_ppm(img_ppm * ppm,int x,int y,XTCOLOR fillcolor);


#endif

###函数实现ppm.c


#include "ppm.h"

XTCOLOR xtrgb(int r,int g,int b)
{
    return (r<<16)+(g<<8)+b;//整合三个数据,r放在最高位
}

//根据文件指针写入一个颜色
void write_to_file(FILE *p,XTCOLOR fillcolor)
{
    unsigned char rgbcolor[3];
    rgbcolor[0]=fillcolor>>16;
    rgbcolor[1]=fillcolor>>8;
    rgbcolor[2]=fillcolor;
    fwrite(rgbcolor,1,3,p);
}

//创建一个图片文件,用指定颜色初始化
img_ppm create_ppm(char * filename,int type,int width,int height,XTCOLOR bk_color)
{
    FILE *p=fopen(filename,"wb");
	//写入文件头
	//这里的长和宽指定了宽度,为了统一文件头的大小
    fprintf(p,"P%d\n%-5d %5d\n255\n",type,width,height);
	//创建一个img_ppm并返回
    img_ppm ppm;
    ppm.height=height;
    ppm.width=width;
    ppm.type=type;
    ppm.f=p;
    for(int i=0;i<width;i++)
        for(int j=0;j<height;j++)
        {
            write_to_file(p,bk_color);
        }
	//写入文件尾
    fprintf(p,"\n");
    return ppm;
}

//封装的画点函数
void point_ppm(img_ppm * ppm,int x,int y,XTCOLOR fillcolor)
{
	//找到对应坐标应该到达的文件位置。这就是统一文件头大小的原因,统一用19L
    fseek(ppm->f,19L+3*(y*ppm->width+x),SEEK_SET);
	//写入
    write_to_file(ppm->f,fillcolor);
}

一个demo,main.c


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ppm.h"

int main()
{
img_ppm mytest=create_ppm("E:/test.ppm",6,1024,1024,0x000000);
//用坐标做颜色参数画个有个规律的图
//我也预料不到图是啥样。。。
//使用封装的point可能会有些慢
for(int j=0;j<1024;++j)
for(int i=0;i<1024;++i)

point_ppm(&mytest,i,j,xtrgb(i*i%255,j*j%255,150+j*i%155));
	point_ppm(&mytest,rand()%1024,rand()%1024,xtrgb(100+rand()%155,100+rand()%155,255));
fclose(mytest.f);
printf("EXIT\n");
return 0;
}

###生成的图片