Skip to content

Commit e370c00

Browse files
committed
PyPNM 2.23.13.13 update
1 parent 00718d5 commit e370c00

File tree

2 files changed

+119
-88
lines changed

2 files changed

+119
-88
lines changed

pypnm/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
3 Sep 2025 "Victory II" update. Fully interchangeable with previous PyPNM 1.17.9.2
55
9 May 2025 "Victory" build.
66
7-
Use `from pypnm import pnmlpnm` to access functions.
7+
Use ``from pypnm import pnmlpnm`` to access functions.
88
99
PyPNM Documentation: https://dnyarri.github.io/pypnm/pypnm.pdf"""

pypnm/pnmlpnm.py

Lines changed: 118 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,109 @@
11
#!/usr/bin/env python3
22

3-
"""PPM and PGM image files reading, displaying and writing for Python >= 3.11.
4-
-------------------------------------------------------------------------------
3+
"""
4+
=====
5+
PyPNM
6+
=====
7+
--------------------------------------------------------------------------
8+
PPM and PGM image files reading, displaying and writing for Python >=3.11.
9+
--------------------------------------------------------------------------
10+
11+
NOTE: This is main `PyPNM for Python >= 3.11`_ build; it actually works with
12+
any Python supporting f-strings, but Tkinter included with CPython < 3.11
13+
could not handle 16 bpc images. If you need more compatibility with
14+
old Python and Tkinter versions, please consider using `PyPNM for Python >= 3.4`_.
515
616
Overview
7-
---------
17+
--------
18+
19+
PyPNM module comprise a set of functions for dealing with `PPM`_ and `PGM`_ image files.
20+
Functions included are listed below
21+
22+
:pnm2list: reading binary or ASCII RGB PPM or L PGM file and returning image data
23+
as nested list of int.
24+
:list2bin: getting image data as nested list of int and creating binary PPM (P6) or PGM (P5)
25+
data structure in memory. Suitable for generating data to display with Tkinter
26+
``PhotoImage (data=...)`` class.
27+
:list2pnmbin: getting image data as nested list of int and writing binary PPM (P6) or PGM (P5)
28+
image file.
29+
Note that bytes generations procedure is different from that used in ``list2bin``.
30+
:list2pnmascii: getting image data as nested list of int and writing ASCII PPM (P3) or PGM (P2) files.
31+
:list2pnm: getting image data as nested list of int and writing either binary or ASCII PNM file depending on ``bin`` argument value.
32+
:create_image: creating empty nested 3D list for image representation.
833
9-
PyPNM module is a pack of functions for dealing with PPM and PGM image files.
10-
Functions included are:
34+
Usage
35+
-----
1136
12-
- `pnm2list`: reading binary or ASCII RGB PPM or L PGM file and returning image data
13-
as nested list of int.
14-
- `list2bin`: getting image data as nested list of int and creating binary PPM (P6) or PGM (P5)
15-
data structure in memory. Suitable for generating data to display with Tkinter `PhotoImage (data=...)` class.
16-
- `list2pnmbin`: getting image data as nested list of int and writing binary PPM (P6) or PGM (P5) image file.
17-
Note that bytes generations procedure is different from that used in `list2bin`.
18-
- `list2pnmascii`: getting image data as nested list of int and writing ASCII PPM (P3) or PGM (P2) files.
19-
- `list2pnm`: getting image data as nested list of int and writing either binary or ASCII PNM
20-
depending on `bin` argument value.
21-
- `create_image`: creating empty nested 3D list for image representation.
37+
After ``from pypnm import pnmlpnm``, use something like
2238
23-
Installation
24-
-------------
39+
::
2540
26-
Via PyPI:
41+
X, Y, Z, maxcolors, list_3d = pnmlpnm.pnm2list(in_filename)
2742
28-
`python -m pip install --upgrade PyPNM`
43+
for reading data from PPM/PGM, where:
2944
30-
then in your program import section:
45+
:X, Y, Z: image dimensions (int);
46+
:maxcolors: maximum value of color per channel for current image (int);
47+
:list_3d: image pixel data as list(list(list(int)));
3148
32-
`from pypnm import pnmlpnm`
49+
and
3350
34-
If you acquired module in some other, non-PyPI way, you may simply put module into your main program folder.
51+
::
3552
36-
Usage
37-
------
53+
pnm_bytes = pnmlpnm.list2bin(list_3d, maxcolors)
3854
39-
After `from pypnm import pnmlpnm`, use something like:
55+
for writing data from ``list_3d`` nested list to ``pnm_bytes`` bytes object in memory,
4056
41-
`X, Y, Z, maxcolors, list_3d = pnmlpnm.pnm2list(in_filename)`
57+
or
4258
43-
for reading data from PPM/PGM, where:
59+
::
4460
45-
- `X`, `Y`, `Z`: image dimensions (int);
46-
- `maxcolors`: maximum of color per channel for current image (int);
47-
- `list_3d`: image pixel data as list(list(list(int)));
61+
pnmlpnm.list2pnm(out_filename, list_3d, maxcolors, bin)
4862
49-
and:
63+
for writing data from ``list_3d`` nested list to PPM/PGM file ``out_filename``,
64+
where ``bin`` is a bool switch defining where resulting file will be binary or ASCII.
5065
51-
`pnm_bytes = pnmlpnm.list2bin(list_3d, maxcolors)`
66+
Copyright and redistribution
67+
----------------------------
5268
53-
for writing data from `list_3d` nested list to `pnm_bytes` bytes object in memory,
69+
Written by Ilya Razmanov (https://dnyarri.github.io) to facilitate developing
70+
image editing programs in Python by simplifying work with PPM/PGM files
71+
and displaying arbitrary image-like data with Tkinter ``PhotoImage`` class.
5472
55-
or:
73+
May be freely used, redistributed and modified.
5674
57-
`pnmlpnm.list2pnm(out_filename, list_3d, maxcolors, bin)`
75+
In case of introducing useful modifications, please report to the developer.
5876
59-
for writing data from `list_3d` nested list to PPM/PGM file `out_filename`,
60-
where `bin` is a bool switch defining where resulting file will be binary or ASCII.
77+
References
78+
----------
6179
62-
Copyright and redistribution
63-
-----------------------------
80+
1. `Netpbm specifications`_
81+
2. `PyPNM for Python >= 3.11`_ at GitHub
82+
3. `PyPNM for Python >= 3.4`_ at GitHub
83+
4. `PyPNM at PyPI`_
84+
5. `PyPNM Documentation`_
6485
65-
Written by `Ilya Razmanov<https://dnyarri.github.io/>`_ aka Ilyich the Toad
66-
to facilitate working with PPM/PGM files and displaying arbitrary image-like data
67-
with Tkinter `PhotoImage` class.
86+
.. _Netpbm specifications: https://netpbm.sourceforge.net/doc/
6887
69-
May be freely used, redistributed and modified.
88+
.. _PPM: https://netpbm.sourceforge.net/doc/ppm.html
7089
71-
In case of introducing useful modifications, report upstairs at once.
90+
.. _PGM: https://netpbm.sourceforge.net/doc/pgm.html
7291
73-
References
74-
-----------
92+
.. _PyPNM for Python >= 3.11: https://github.com/Dnyarri/PyPNM/
93+
94+
.. _PyPNM for Python >= 3.4: https://github.com/Dnyarri/PyPNM/tree/py34
95+
96+
.. _PyPNM at PyPI: https://pypi.org/project/PyPNM/
7597
76-
1. Netpbm specifications: https://netpbm.sourceforge.net/doc/
77-
2. PyPNM for Python >= 3.11 at GitHub: https://github.com/Dnyarri/PyPNM/
78-
3. PyPNM for Python >= 3.4 at GitHub: https://github.com/Dnyarri/PyPNM/tree/py34
79-
4. PyPNM at PyPI: https://pypi.org/project/PyPNM/
80-
5. PyPNM Documentation: https://dnyarri.github.io/pypnm/pypnm.pdf
98+
.. _PyPNM Documentation: https://dnyarri.github.io/pypnm/pypnm.pdf
8199
82100
"""
83101

84102
__author__ = 'Ilya Razmanov'
85103
__copyright__ = '(c) 2024-2025 Ilya Razmanov'
86104
__credits__ = 'Ilya Razmanov'
87105
__license__ = 'unlicense'
88-
__version__ = '2.21.3.12'
106+
__version__ = '2.23.13.13'
89107
__maintainer__ = 'Ilya Razmanov'
90108
__email__ = 'ilyarazmanov@gmail.com'
91109
__status__ = 'Production'
@@ -104,17 +122,20 @@
104122
def pnm2list(in_filename: str) -> tuple[int, int, int, int, list[list[list[int]]]]:
105123
"""Read PGM or PPM file to nested image data list.
106124
107-
Usage:
125+
Usage
108126
109-
`X, Y, Z, maxcolors, list_3d = pnmlpnm.pnm2list(in_filename)`
127+
::
128+
129+
X, Y, Z, maxcolors, list_3d = pnmlpnm.pnm2list(in_filename)
110130
111131
for reading data from PPM/PGM, where:
112132
113-
- `X`, `Y`, `Z`: image dimensions (int);
114-
- `maxcolors`: maximum of color per channel for current image (int),
115-
255 for 8 bit and 65535 for 16 bit input. Note that 1 bit images get promoted to 8 bit L upon import.
116-
- `list_3d`: image pixel data as list(list(list(int)));
117-
- `in_filename`: PPM/PGM file name (str).
133+
:X, Y, Z: image dimensions (int);
134+
:maxcolors: maximum of color per channel for current image (int),
135+
255 for 8 bit and 65535 for 16 bit input.
136+
Note that 1 bit images get promoted to 8 bit L upon import.
137+
:list_3d: image pixel data as list(list(list(int)));
138+
:in_filename: PPM/PGM file name (str).
118139
119140
"""
120141

@@ -347,18 +368,22 @@ def _p1(in_filename: str) -> tuple[int, int, int, int, list[list[list[int]]]]:
347368
def list2bin(list_3d: list[list[list[int]]], maxcolors: int, show_chessboard: bool = False) -> bytes:
348369
"""Convert nested image data list to PGM P5 or PPM P6 bytes in memory.
349370
350-
Usage:
371+
Usage
372+
373+
::
351374
352-
`image_bytes = pnmlpnm.list2bin(list_3d, maxcolors, show_chessboard)`
375+
image_bytes = pnmlpnm.list2bin(list_3d, maxcolors, show_chessboard)
353376
354377
where:
355378
356-
- `list_3d`: Y * X * Z list (image) of lists (rows) of lists (pixels) of ints (channel values);
357-
- `maxcolors`: maximum of color per channel for current image (int);
358-
- `show_chessboard`: optional bool, set `True` to show LA and RGBA images against chessboard pattern;
359-
`False` or missing show existing L or RGB data for transparent areas as fully opaque.
360-
Default is `False` for backward compatibility.
361-
- `image_bytes`: PNM-structured binary data.
379+
:list_3d: Y * X * Z list (image) of lists (rows) of lists (pixels) of ints (channel values);
380+
:maxcolors: maximum of color per channel for current image (int);
381+
:show_chessboard: optional bool, set ``True`` to show LA and RGBA images against chessboard pattern;
382+
``False`` or missing show existing L or RGB data for transparent areas as fully opaque.
383+
Default is ``False`` for backward compatibility.
384+
:image_bytes: PNM-structured binary data.
385+
386+
**Warning**: Feeds PNM bytes to Tkinter "as is", which makes old Tkinter versions crash.
362387
363388
"""
364389

@@ -367,7 +392,7 @@ def _chess(x: int, y: int) -> int:
367392
368393
Photoshop chess pattern preset parameters:
369394
- Small: 4 px; Medium: 8 px, Large: 16 px
370-
- Light: (0.8, 1.0); Medium: (0.4, 0.6); Dark: (0.2, 0.4) of maxcolors
395+
- Light: (0.8, 1.0); Medium: (0.4, 0.6); Dark: (0.2, 0.4) of ``maxcolors``
371396
372397
"""
373398
return int(maxcolors * 0.8) if ((y // 8) % 2) == ((x // 8) % 2) else maxcolors
@@ -408,17 +433,19 @@ def _chess(x: int, y: int) -> int:
408433
╚═════════════╝ """
409434

410435
def list2pnmbin(out_filename: str, list_3d: list[list[list[int]]], maxcolors: int) -> None:
411-
"""Write binary PNM `out_filename` file; writing performed per row to reduce RAM usage.
436+
"""Write binary PNM ``out_filename`` file; writing performed per row to reduce RAM usage.
437+
438+
Usage
412439
413-
Usage:
440+
::
414441
415-
`pnmlpnm.list2pnmbin(out_filename, list_3d, maxcolors)`
442+
pnmlpnm.list2pnmbin(out_filename, list_3d, maxcolors)
416443
417444
where:
418445
419-
- `list_3d`: X * Y * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
420-
- `maxcolors`: maximum of color per channel for current image (int);
421-
- `out_filename`: PNM file name.
446+
:list_3d: X * Y * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
447+
:maxcolors: maximum of color per channel for current image (int);
448+
:out_filename: PNM file name.
422449
423450
"""
424451

@@ -450,17 +477,19 @@ def list2pnmbin(out_filename: str, list_3d: list[list[list[int]]], maxcolors: in
450477
╚═══════════════╝ """
451478

452479
def list2pnmascii(out_filename: str, list_3d: list[list[list[int]]], maxcolors: int) -> None:
453-
"""Write ASCII PNM `out_filename` file; writing performed per sample to reduce RAM usage.
480+
"""Write ASCII PNM ``out_filename`` file; writing performed per sample to reduce RAM usage.
454481
455-
Usage:
482+
Usage
456483
457-
`pnmlpnm.list2pnmascii(out_filename, list_3d, maxcolors)`
484+
::
485+
486+
pnmlpnm.list2pnmascii(out_filename, list_3d, maxcolors)
458487
459488
where:
460489
461-
- `list_3d`: Y * X * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
462-
- `maxcolors`: maximum of color per channel for current image (int);
463-
- `out_filename`: PNM file name.
490+
:list_3d: Y * X * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
491+
:maxcolors: maximum of color per channel for current image (int);
492+
:out_filename: PNM file name.
464493
465494
"""
466495

@@ -496,18 +525,20 @@ def list2pnmascii(out_filename: str, list_3d: list[list[list[int]]], maxcolors:
496525
╚══════════╝ """
497526

498527
def list2pnm(out_filename: str, list_3d: list[list[list[int]]], maxcolors: int, bin: bool = True) -> None:
499-
"""Write PNM `out_filename` file using either `list2pnmbin` or `list2pnmascii` depending on `bin` switch.
528+
"""Write PNM ``out_filename`` file using either ``list2pnmbin`` or ``list2pnmascii`` depending on ``bin`` switch.
529+
530+
Usage
500531
501-
Usage:
532+
::
502533
503-
`pnmlpnm.list2pnm(out_filename, list_3d, maxcolors, bin)`
534+
pnmlpnm.list2pnm(out_filename, list_3d, maxcolors, bin)
504535
505536
where:
506537
507-
- `list_3d`: X * Y * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
508-
- `maxcolors`: maximum of color per channel for current image (int);
509-
- `bin`: whether output file is binary (bool);
510-
- `out_filename`: PNM file name.
538+
:list_3d: X * Y * Z list (image) of lists (rows) of lists (pixels) of ints (channels);
539+
:maxcolors: maximum of color per channel for current image (int);
540+
:bin: whether output file is binary (bool);
541+
:out_filename: PNM file name.
511542
512543
"""
513544

0 commit comments

Comments
 (0)