Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/PdfImagePlugin.py: 7%

99 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1# 

2# The Python Imaging Library. 

3# $Id$ 

4# 

5# PDF (Acrobat) file handling 

6# 

7# History: 

8# 1996-07-16 fl Created 

9# 1997-01-18 fl Fixed header 

10# 2004-02-21 fl Fixes for 1/L/CMYK images, etc. 

11# 2004-02-24 fl Fixes for 1 and P images. 

12# 

13# Copyright (c) 1997-2004 by Secret Labs AB. All rights reserved. 

14# Copyright (c) 1996-1997 by Fredrik Lundh. 

15# 

16# See the README file for information on usage and redistribution. 

17# 

18 

19## 

20# Image plugin for PDF images (output only). 

21## 

22 

23import io 

24import os 

25import time 

26 

27from . import Image, ImageFile, ImageSequence, PdfParser, __version__ 

28 

29# 

30# -------------------------------------------------------------------- 

31 

32# object ids: 

33# 1. catalogue 

34# 2. pages 

35# 3. image 

36# 4. page 

37# 5. page contents 

38 

39 

40def _save_all(im, fp, filename): 

41 _save(im, fp, filename, save_all=True) 

42 

43 

44## 

45# (Internal) Image save plugin for the PDF format. 

46 

47 

48def _save(im, fp, filename, save_all=False): 

49 is_appending = im.encoderinfo.get("append", False) 

50 if is_appending: 

51 existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="r+b") 

52 else: 

53 existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b") 

54 

55 resolution = im.encoderinfo.get("resolution", 72.0) 

56 

57 info = { 

58 "title": None 

59 if is_appending 

60 else os.path.splitext(os.path.basename(filename))[0], 

61 "author": None, 

62 "subject": None, 

63 "keywords": None, 

64 "creator": None, 

65 "producer": None, 

66 "creationDate": None if is_appending else time.gmtime(), 

67 "modDate": None if is_appending else time.gmtime(), 

68 } 

69 for k, default in info.items(): 

70 v = im.encoderinfo.get(k) if k in im.encoderinfo else default 

71 if v: 

72 existing_pdf.info[k[0].upper() + k[1:]] = v 

73 

74 # 

75 # make sure image data is available 

76 im.load() 

77 

78 existing_pdf.start_writing() 

79 existing_pdf.write_header() 

80 existing_pdf.write_comment(f"created by Pillow {__version__} PDF driver") 

81 

82 # 

83 # pages 

84 ims = [im] 

85 if save_all: 

86 append_images = im.encoderinfo.get("append_images", []) 

87 for append_im in append_images: 

88 append_im.encoderinfo = im.encoderinfo.copy() 

89 ims.append(append_im) 

90 number_of_pages = 0 

91 image_refs = [] 

92 page_refs = [] 

93 contents_refs = [] 

94 for im in ims: 

95 im_number_of_pages = 1 

96 if save_all: 

97 try: 

98 im_number_of_pages = im.n_frames 

99 except AttributeError: 

100 # Image format does not have n_frames. 

101 # It is a single frame image 

102 pass 

103 number_of_pages += im_number_of_pages 

104 for i in range(im_number_of_pages): 

105 image_refs.append(existing_pdf.next_object_id(0)) 

106 page_refs.append(existing_pdf.next_object_id(0)) 

107 contents_refs.append(existing_pdf.next_object_id(0)) 

108 existing_pdf.pages.append(page_refs[-1]) 

109 

110 # 

111 # catalog and list of pages 

112 existing_pdf.write_catalog() 

113 

114 page_number = 0 

115 for im_sequence in ims: 

116 im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence] 

117 for im in im_pages: 

118 # FIXME: Should replace ASCIIHexDecode with RunLengthDecode 

119 # (packbits) or LZWDecode (tiff/lzw compression). Note that 

120 # PDF 1.2 also supports Flatedecode (zip compression). 

121 

122 bits = 8 

123 params = None 

124 decode = None 

125 

126 if im.mode == "1": 

127 filter = "DCTDecode" 

128 colorspace = PdfParser.PdfName("DeviceGray") 

129 procset = "ImageB" # grayscale 

130 elif im.mode == "L": 

131 filter = "DCTDecode" 

132 # params = f"<< /Predictor 15 /Columns {width-2} >>" 

133 colorspace = PdfParser.PdfName("DeviceGray") 

134 procset = "ImageB" # grayscale 

135 elif im.mode == "P": 

136 filter = "ASCIIHexDecode" 

137 palette = im.getpalette() 

138 colorspace = [ 

139 PdfParser.PdfName("Indexed"), 

140 PdfParser.PdfName("DeviceRGB"), 

141 255, 

142 PdfParser.PdfBinary(palette), 

143 ] 

144 procset = "ImageI" # indexed color 

145 elif im.mode == "RGB": 

146 filter = "DCTDecode" 

147 colorspace = PdfParser.PdfName("DeviceRGB") 

148 procset = "ImageC" # color images 

149 elif im.mode == "CMYK": 

150 filter = "DCTDecode" 

151 colorspace = PdfParser.PdfName("DeviceCMYK") 

152 procset = "ImageC" # color images 

153 decode = [1, 0, 1, 0, 1, 0, 1, 0] 

154 else: 

155 raise ValueError(f"cannot save mode {im.mode}") 

156 

157 # 

158 # image 

159 

160 op = io.BytesIO() 

161 

162 if filter == "ASCIIHexDecode": 

163 ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)]) 

164 elif filter == "DCTDecode": 

165 Image.SAVE["JPEG"](im, op, filename) 

166 elif filter == "FlateDecode": 

167 ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)]) 

168 elif filter == "RunLengthDecode": 

169 ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)]) 

170 else: 

171 raise ValueError(f"unsupported PDF filter ({filter})") 

172 

173 # 

174 # Get image characteristics 

175 

176 width, height = im.size 

177 

178 existing_pdf.write_obj( 

179 image_refs[page_number], 

180 stream=op.getvalue(), 

181 Type=PdfParser.PdfName("XObject"), 

182 Subtype=PdfParser.PdfName("Image"), 

183 Width=width, # * 72.0 / resolution, 

184 Height=height, # * 72.0 / resolution, 

185 Filter=PdfParser.PdfName(filter), 

186 BitsPerComponent=bits, 

187 Decode=decode, 

188 DecodeParams=params, 

189 ColorSpace=colorspace, 

190 ) 

191 

192 # 

193 # page 

194 

195 existing_pdf.write_page( 

196 page_refs[page_number], 

197 Resources=PdfParser.PdfDict( 

198 ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)], 

199 XObject=PdfParser.PdfDict(image=image_refs[page_number]), 

200 ), 

201 MediaBox=[ 

202 0, 

203 0, 

204 width * 72.0 / resolution, 

205 height * 72.0 / resolution, 

206 ], 

207 Contents=contents_refs[page_number], 

208 ) 

209 

210 # 

211 # page contents 

212 

213 page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % ( 

214 width * 72.0 / resolution, 

215 height * 72.0 / resolution, 

216 ) 

217 

218 existing_pdf.write_obj(contents_refs[page_number], stream=page_contents) 

219 

220 page_number += 1 

221 

222 # 

223 # trailer 

224 existing_pdf.write_xref_and_trailer() 

225 if hasattr(fp, "flush"): 

226 fp.flush() 

227 existing_pdf.close() 

228 

229 

230# 

231# -------------------------------------------------------------------- 

232 

233 

234Image.register_save("PDF", _save) 

235Image.register_save_all("PDF", _save_all) 

236 

237Image.register_extension("PDF", ".pdf") 

238 

239Image.register_mime("PDF", "application/pdf")