Coverage for pyguymer3/image/save_array_as_PNG.py: 59%
22 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-16 08:31 +0000
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-16 08:31 +0000
1#!/usr/bin/env python3
3# Define function ...
4def save_array_as_PNG(
5 arrUint8,
6 fname,
7 /,
8 *,
9 calcAdaptive: bool = True,
10 calcAverage: bool = True,
11 calcNone: bool = True,
12 calcPaeth: bool = True,
13 calcSub: bool = True,
14 calcUp: bool = True,
15 debug: bool = __debug__,
16 dpi: None | int = None,
17 modTime = None,
18 palUint8 = None,
19):
20 """Save an array as a PNG image.
22 Parameters
23 ----------
24 arrUint8 : numpy.ndarray
25 A "height * width * colour" unsigned 8-bit integer NumPy array.
26 fname : str
27 output file name
28 calcAdaptive : bool, optional
29 See :py:func:`pyguymer3.image.makePng` for the documentation.
30 calcAverage : bool, optional
31 See :py:func:`pyguymer3.image.makePng` for the documentation.
32 calcNone : bool, optional
33 See :py:func:`pyguymer3.image.makePng` for the documentation.
34 calcPaeth : bool, optional
35 See :py:func:`pyguymer3.image.makePng` for the documentation.
36 calcSub : bool, optional
37 See :py:func:`pyguymer3.image.makePng` for the documentation.
38 calcUp : bool, optional
39 See :py:func:`pyguymer3.image.makePng` for the documentation.
40 debug : bool, optional
41 Print debug messages.
42 dpi : None or float or int, optional
43 See :py:func:`pyguymer3.image.makePng` for the documentation.
44 modTime : None or datetime.datetime, optional
45 See :py:func:`pyguymer3.image.makePng` for the documentation.
46 palUint8 : None or numpy.ndarray, optional
47 See :py:func:`pyguymer3.image.makePng` for the documentation.
49 Notes
50 -----
51 Copyright 2017 Thomas Guymer [1]_
53 References
54 ----------
55 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3
56 """
58 # Import standard modules ...
59 import sys
61 # Import sub-functions ...
62 from .makePng import makePng
64 # **************************************************************************
66 # Check system ...
67 assert sys.byteorder == "little", "the system is not little-endian"
69 # Check input ...
70 assert arrUint8.dtype == "uint8", f"the NumPy array is not 8-bit (\"{arrUint8.dtype}\")"
71 assert arrUint8.ndim == 3, f"the NumPy array is not 3D (\"{arrUint8.ndim:d}\")"
72 match arrUint8.shape[2]:
73 case 1:
74 if palUint8 is None:
75 pass
76 else:
77 assert palUint8.dtype == "uint8", f"the NumPy palette is not 8-bit (\"{palUint8.dtype}\")"
78 assert palUint8.ndim == 2, f"the NumPy palette is not 2D (\"{palUint8.ndim:d}\")"
79 assert palUint8.shape[0] <= 256, f"the NumPy palette has more than 256 colours (\"{palUint8.shape[0]:,d}\")"
80 assert palUint8.shape[1] == 3, "the NumPy palette does not have 3 colour channels"
81 assert arrUint8.max() < palUint8.shape[0], f"the NumPy array references more colours than are in the NumPy palette (\"{arrUint8.max():d}\" -vs- \"{palUint8.shape[0]:d}\")"
82 case 3:
83 pass
84 case _:
85 raise ValueError(f"the NumPy array does not have either 1 or 3 colour channels (\"{arrUint8.shape[2]:d}\")") from None
87 # **************************************************************************
89 # Make PNG source ...
90 src = makePng(
91 arrUint8,
92 calcAdaptive = calcAdaptive,
93 calcAverage = calcAverage,
94 calcNone = calcNone,
95 calcPaeth = calcPaeth,
96 calcSub = calcSub,
97 calcUp = calcUp,
98 choices = "all",
99 debug = debug,
100 dpi = dpi,
101 levels = [9,],
102 memLevels = [9,],
103 modTime = modTime,
104 palUint8 = palUint8,
105 strategies = None,
106 wbitss = [15,],
107 )
109 # Write PNG ...
110 with open(fname, "wb") as fObj:
111 fObj.write(src)