Coverage for pyguymer3/media/images2pdf.py: 4%
24 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 images2pdf(
5 imgs,
6 pdf,
7 /,
8 *,
9 author = "My Author",
10 keywords = "My Keywords",
11 mode = "RGB",
12 optimise = True,
13 progressive = False,
14 quality = 95,
15 resolution = 300,
16 screenHeight = -1,
17 screenWidth = -1,
18 subject = "My Subject",
19 title = "My Title",
20):
21 """Convert a sequence of images to a PDF slide pack.
23 This function makes a PDF slide pack from either a list of PIL Images or a
24 list of file paths.
26 Parameters
27 ----------
28 imgs : list of PIL.Image.Image or list of str
29 the list of input PIL Images or list of paths to the input images
30 pdf : str
31 the path to the output PDF
32 author : str, optional
33 The author field in the output PDF metadata
34 keywords : str, optional
35 The keywords field in the output PDF metadata
36 mode : str, optional
37 the mode of the JPGs in the outout PDF
38 optimise : bool, optional
39 optimise the JPGs in the output PDF
40 progressive : bool, optional
41 save progressive JPGs in the output PDF
42 quality : int, optional
43 the quality of the JPGs in the output PDF
44 resolution : int, optional
45 the resolution of the JPGs in the output PDF (has no effect on the JPGs,
46 but the physical size of the PDF is derived from the pixel size of the
47 JPGs)
48 screenHeight : int, optional
49 the height of the screen to downscale the input images to fit within,
50 currently only implemented if "imgs" is a list of str (integers less
51 than 100 imply no downscaling)
52 screenWidth : int, optional
53 the width of the screen to downscale the input images to fit within,
54 currently only implemented if "imgs" is a list of str (integers less
55 than 100 imply no downscaling)
56 subject : str, optional
57 The subject field in the output PDF metadata
58 title : str, optional
59 The title field in the output PDF metadata
61 Notes
62 -----
63 Copyright 2017 Thomas Guymer [1]_
65 References
66 ----------
67 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3
68 """
70 # Import special modules ...
71 try:
72 import PIL
73 import PIL.Image
74 PIL.Image.MAX_IMAGE_PIXELS = 1024 * 1024 * 1024 # [px]
75 except:
76 raise Exception("\"PIL\" is not installed; run \"pip install --user Pillow\"") from None
78 # **************************************************************************
80 # Initialize list ...
81 tmpImgs = []
83 # Loop over input ...
84 for img in imgs:
85 # Find out what the user supplied ...
86 match img:
87 case str():
88 # Open image as RGB (even if it is paletted) ...
89 with PIL.Image.open(img) as iObj:
90 tmpImg = iObj.convert("RGB")
92 # Check if the user wants to scale the image down to fit within
93 # a screen size ...
94 if screenWidth >= 100 and screenHeight >= 100:
95 # Resize image in place ...
96 tmpImg.thumbnail(
97 (screenWidth, screenHeight),
98 resample = PIL.Image.Resampling.LANCZOS,
99 )
101 # Convert image to whatever mode the user asked for ...
102 tmpImgs.append(tmpImg.convert(mode))
103 case PIL.Image.Image():
104 # Copy image as RGB (even if it is paletted) ...
105 tmpImg = img.convert("RGB")
107 # Check if the user wants to scale the image down to fit within a
108 # screen size ...
109 if screenWidth >= 100 and screenHeight >= 100:
110 # Resize image in place ...
111 tmpImg.thumbnail(
112 (screenWidth, screenHeight),
113 resample = PIL.Image.Resampling.LANCZOS,
114 )
116 # Convert image to whatever mode the user asked for ...
117 tmpImgs.append(tmpImg.convert(mode))
118 case _:
119 # Crash ...
120 raise TypeError(f"\"img\" is an unexpected type ({repr(type(img))})") from None
122 # Save it as a PDF ...
123 # NOTE: See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#pdf
124 tmpImgs[0].save(
125 pdf,
126 append_images = tmpImgs[1:],
127 author = author,
128 keywords = keywords,
129 optimise = optimise, # NOTE: Passed to the JPEG encoder.
130 progressive = progressive, # NOTE: Passed to the JPEG encoder.
131 quality = quality, # NOTE: Passed to the JPEG encoder.
132 resolution = resolution,
133 save_all = True,
134 subject = subject,
135 title = title,
136 )