pgmtoppm "#FFFFFF" j.pbm > j.ppm
ppmtobmp j.ppm > j.bmp
Depending on the identification of the file format, portable pixmap systems can distinguish three similar file formats, each with two versions:
In each case, the lower-numbered version (P1, P2 or P3) refers to a human-readable, ASCII-based format similar to the one in the example above; and the higher-numbered version (P4, P5 or P6) refers to a binary format, not human-readable but more efficient at saving some space in the file, as well as easier to parse due to the lack of whitespace.
....X.
....X.
....X.
....X.
....X.
....X.
X...X.
.XXX..
......
......
The most basic (monochrome) PBM format represents it as follows:
P1
# This is an example bit map file j.pbm
6 10
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
1 0 0 0 1 0
0 1 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
The string P1 identifies the file format. The hash sign introduces a comment. The next two numbers give the width and the height. Then follows the matrix with the pixel values (in the monochrome case here, only zeros and ones).
Here is the resulting image: . Here it is again magnified 20 times:
The PGM and PPM formats (both ASCII and binary versions) have an additional parameter for the maximum value in a line between the X and Y dimensions and the actual pixel data.
P2
# feep.pgm from NetPBM man page on PGM
24 7
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0
0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0
0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
P3
#the P3 means colors are in ascii, then 3 columns and 2 rows, then 255 for max color, then RGB triplets
3 2
255
255 0 0
0 255 0
0 0 255
255 255 0
255 255 255
0 0 0
The image (expanded):
The above image was expanded without interpolation, using the imagemagick command
convert -sample %6400 tiny6pixel.ppm tiny6pixel.pngThe P6 format of the same image will store a color with one byte. The file will be smaller but the color information will not be readable by humans:
P6
#any comment string
3 2
255!@#$%^&*()_+|{}:"<
The PPM format is not compressed and so is extravagantly wasteful of space and bandwidth.
For example, the above 192x128 PNG image has a file size of 552 bytes. When converted to a 192x128 PPM image, the file size is 73848 bytes. The PPM format is generally a vehicle to a more efficient format, notably the PNG (Portable Network Graphics) format. The PPM format can be converted to PNG, for example, without loss of information.
The PPM format is certainly simple to write from scratch. The following Python code makes the above example image. It can be adapted to making useful images by reading or constructing an array of numerical data, and programming a conversion of the data to color triplets.
triplets=[[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 255, 255], [0, 0, 0] ]
width=3; height=2
comment='any comment string'
ftype='P6' #use 'P3' for ascii, 'P6' for binary ppmfile=open('testimage.ppm','wb')
ppmfile.write("%sn" % (ftype))
ppmfile.write("#%sn" % comment )
ppmfile.write("%d %dn" % (width, height))
ppmfile.write("255n") if ftype=='P3':
ppmfile.close()
for red,green,blue in triplets:
ppmfile.write("%d %d %dn" % (red,green,blue))
elif ftype=='P6': #print 1 byte per color
for red,green,blue in triplets:
ppmfile.write("%c%c%c" % (red,green,blue))
Similar code in C :
int main(int argc, char** argv){
FILE* f;
char* x;
int i, j, k, l, m, r, c;
if(argc != 4){
printf("Usage: %s cols rows fname.ppmnn", *argv);
return 1;
}
f = fopen(argv[3], "w");
c = atoi(argv[1]);
r = atoi(argv[2]);
x = (char*)malloc(r*c);
for(i=0;i
x[i] = 0;
}
i = 0;
i = 2;
while(i < r*c/2){
for(k=2*i;k
x[k] = 1;
}
i ++;
}
fprintf(f, "P3n%dn%dn255n", c, r);
for(l = 0; l < c; l++){
for(m = 0; m < r; m++){
if(!x[c*l+m])
fprintf(f, "%d 255 %d", (256*l)/c, (256*m)/r);
else
if(xor((l/10)%2,(m/10)%2))
fprintf(f, "%d 0 %d", (255*l*m)/(r*c), 255-(255*l*m)/(r*c));
else
fprintf(f, "0 0 0");
fprintf(f, "n");
}
fprintf(f, "n");
}
free(x);
fclose(f);
return 0;
}