PyPNM - Pythonic Portable Any Map I/O

Introduction

Portable Pixel Map (PPM) and Portable Gray Map (PGM) (particular cases on PNM format group) are simplest file formats for RGB and L images, correspondingly. In theory, you may import ASCII PGM even in Excel, turning Excel into image editor. Unfortunately, this simplicity lead to some consequences:

As a result, novice Python user (like me) may find it difficult to get reliable input/output modules for PPM and PGM image formats; therefore current PyPNM package was developed, combining input/output functions for 8-bits and 16-bits per channel binary and ascii PGM and PPM files, i.e. P2, P5, P3 and P6 PNM file types. P1 and P4 (1 bit) PBM formats are supported only for reading.

You may easily acquire PyPNM module either from Github or from PyPI.

Update: in ver. 1.13.10.7 last incompatibility with non-standard hand-made files fixed.

Format compatibility

Image format

File format

Read

Write

16 bits per channel RGB

P6 Binary PPM

16 bits per channel RGB

P3 ASCII PPM

8 bits per channel RGB

P6 Binary PPM

8 bits per channel RGB

P3 ASCII PPM

16 bits per channel L

P5 Binary PGM

16 bits per channel L

P2 ASCII PGM

8 bits per channel L

P5 Binary PGM

8 bits per channel L

P2 ASCII PGM

1 bit ink on/off

P4 Binary PBM

1 bit ink on/off

P1 ASCII PBM

Image representation

Is seems logical to represent an RGB image as nested 3D structure - X, Y-sized matrix of three-component RGB vectors. Since in Python list seem to be about the only variant for mutable structures like that, it is suitable to represent image as list(list(list(int))) structure (for example, this structure was used for ScaleNx, and worked well). Therefore, it would be convenient to have module read/write image data from/to such a common structure.

Note that for L images memory structure is still list(list(list(int))), with innermost list having only one component, thus enabling further image editing with the same nested Y, X, Z loop regardless of color mode. I understand that this may sound surprising for professional image I/O programmers, but for normal people writing a loop once and for all is expected behaviour.

Also, since this module is supposed to be used for image editing rather than just reading, when reading 1 bit PBM files into image this module promotes data to 8 bit L, inverting values and multiplying by 255, so that source 1 (ink on) is changed to 0 (black), and source 0 (ink off) is changed to 255 (white). For the same reason writing 1 bit PBM files is not planned - 1 bit images are next to useless for editing.

pnmlpnm.py

Module pnmlpnm.py contains 100% pure Python implementation of everything one may need to read/write from/to a variety of PGM and PPM files. I/O functions are written as functions/procedures, as simple as possible, and listed below:

Detailed functions arguments description is provided in docstrings, but in general looks simple like that - you feed the function with your image data list and a filename, and get PNM file with that name written.

viewer.py

Test PPM image opened in viewer

Program viewer.py is a small illustrative utility: using pnmlpnm package, it reads different flavours of PGM and PPM files, and allows saving them as different types of PGM/PNM, i.e. it can read ascii PPM and write it as binary PPM or vs. Also this program shows images using pnmlpnm and Tkinter. No, there is no mistake: it does not feed PPM files to Tkinter directly. Instead, it uses nested 3D list data loaded using pnmlpnm to generate in-memory bytes object of PPM structure using preview_data = pnmlpnm.list2bin(image3D, maxcolors), and then feeds this in-memory bytes object to Tkinter as preview = PhotoImage(data=preview_data) (note using data=, not file=). This way it shows, for example, ascii PPM which Tkinter itself cannot handle.

Funfact: Icon in viewer.py is not the icon, but bytes of PPM produced with pnmlpnm.py and then hardcoded into viewer as byte string. It's 2x2 pixels of basic colors, so when rescaling Tkinter turns it into a four-point gradient.

All this means that you may use pnmlpnm and Tkinter to visualize any data that can be represented as greyscale or RGB without huge external packages and writing files on disk; all you need is Tkinter, included into standard CPython distributions, and highly compatible pure Python pnmlpnm.py taking only 14 kbytes.


Now when you have initial understanding of what pnmlpnm module is and how it may be used to work with PGM and PPM files, it's time to pull it from Github and start working with images yourself.


...or move back to main page.