Introduction

Although the class of Portable Any Map (PNM) format images -- which includes ASCII and Binary versions of Portable Bit Map (PBM), Portable Grey Map (PGM) and Portable Pixel Map (PPM) images -- represents the "lowest common denominator" of image formats, they are relatively uncommon in modern Windows environments. They also tend to be poorly supported on the free graphics programs for Windows, such as Paint and Paint.NET. Furthermore, I was not (in an admittedly short search) able to find a suitable C# class library for working with these formats programmatically.

Fortunately, the formats are quite simple, so it was relatively easy to build a PixelMap class to encapsulate these images and expose a couple of System.Drawing.Bitmap properties (BitMap and GreyMap) that can be used easily by other classes. Also, the simple Windows application that I created to test the PixelMap class rapidly evolved into a fairly competent viewer and converter that can save the current image as a BMP, JPG, TIFF, GIF, or PNG file.

Using the code

To use the PixelMap class you should:

Copy the PixelMap.cs file into your own project.

Change the namespace in the PixelMap.cs file to the name of your project namespace.

Compile. The PixelMap class should now be available in your project.

The PixelMapViewer application demonstrates the usage of the PixelMap class. It also provides a handy viewing and converting application in its own right.

Points of interest

There are ASCII and Binary versions of each of the PBM, PGM, and PPM formats. The binary versions are much, much smaller and faster than the ASCII versions. They ought to be used unless there is a compelling reason to make the image file "human readable." Personally, I prefer to "read" my images by "looking at the pictures." This PixelMap class does not support the binary PBM format (Magic Number P4) at this time.

Since PBM, PGM, and PPM are UNIX-centric formats, their pixel order is BGR, rather than the RGB order that Windows programmers would tend to expect.

The "stride" of the image (normally calculated as stride = Image.Width * BytesPerPixel) should be a multiple of 4. If this is not the case, then in many programs the output images will become corrupted as they are processed. However, this is not a problem with the PixelMap class since it has been designed to work correctly with "off-size" images. However, it does have to use much less efficient (i.e. slow) algorithms relative to the normal direct-memory algorithms that it uses for well-sized images.

Share

About the Author

Stephen Bogner is a Senior Research Engineer with Defence R&D Canada. As the Head Autonomous Applications Group, Autonomous Intelligent Systems Section, he only programs when it can't be avoided, and then only in C#.

Comments and Discussions

First of all, thank you very much for this code. I just have one question. The binary P4-Format in a pbm is currently not supported. However this is exactly the one i would need Do you know where an easy implementation of this format can be found, so i could implement it myself or do you implement it anyway in the near future?
Thanx for your answer

If you modify the P3 and P6 code to instead interpret the 24-bit RGB as 32-bit ARGB and just always set the alpha to 255, the stride will always be divisible by 4, and this works significantly faster than SetPixel. Might use a bit more memory (then again, it might not, depending on how it's actually stored behind the scenes, I didn't check), but the speed is probably worth it.

Well, I could opened all my images in the *.ppm format, however, for some images in *.pgm format the algorithm seems to be not working. It doesn't throw an error or something like that while it is running but the result is not what I was waiting or at least what it was supposed to be.
I don't get the *.pgm images in a grey scales, I get it in some colors. It is like when you use Adobe Fireworks and you make a kind of a crazy effect that turns the image in brilliant colors.
I'm pretty sure that you will not understand me at all, but I don't know here how can I send you my image. Then you would be able to only open that image with your software.
For *.ppm, it is working perfectly. It has been a great utility for me. But I would like to know if maybe it has a solution. To get the images in *.pgm I use a free sotware called infranview. I change the format from jpeg or other to pgm.

The program uses a mapped palette to initially show the .pgm images. This is a sort of "false color" version that highlights differences more graphically. However, to make it show "greyscale" images correctly use the "Show - Greymap" menu command.

Thanks a lot, it helped me. It works perfectly.
A question: Do you know how to make 3D graphs with C#. I have the list of the points with X,Y and Z coordinates, but I haven't found some info about how to do it.
Thanks again!

I just tried your class in linux(Suse 10.3). It didn't work. I ran the class in Mono 1.9.
I guess your mapping function from pgm to bitmap didn't correspond with things in linux.
I wonder if you have any concern to this.
Best regards.
Tuan

Thanks for the excellent class. I'd written my own PNM viewer but it had plenty of problems and yours works marvellously.
I needed to port it to VB and had the usual fun with C# using names like magicnumber and MagicNumber as two different variables, but apart from some oddities over Char issues it worked fine.