Prezentprogramo 3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. hovercraft/__init__.py +435 -0
  2. hovercraft/generate.py +473 -0
  3. hovercraft/parse.py +275 -0
  4. hovercraft/position.py +269 -0
  5. hovercraft/template.py +237 -0
  6. hovercraft/templates/default/css/highlight.css +61 -0
  7. hovercraft/templates/default/css/hovercraft.css +67 -0
  8. hovercraft/templates/default/js/MathJax/es5/a11y/assistive-mml.js +1 -0
  9. hovercraft/templates/default/js/MathJax/es5/a11y/complexity.js +1 -0
  10. hovercraft/templates/default/js/MathJax/es5/a11y/explorer.js +1 -0
  11. hovercraft/templates/default/js/MathJax/es5/a11y/semantic-enrich.js +1 -0
  12. hovercraft/templates/default/js/MathJax/es5/a11y/sre.js +1 -0
  13. hovercraft/templates/default/js/MathJax/es5/adaptors/liteDOM.js +1 -0
  14. hovercraft/templates/default/js/MathJax/es5/core.js +1 -0
  15. hovercraft/templates/default/js/MathJax/es5/input/asciimath.js +1 -0
  16. hovercraft/templates/default/js/MathJax/es5/input/mml/entities.js +1 -0
  17. hovercraft/templates/default/js/MathJax/es5/input/mml/extensions/mml3.js +1 -0
  18. hovercraft/templates/default/js/MathJax/es5/input/mml.js +1 -0
  19. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/action.js +1 -0
  20. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/all-packages.js +34 -0
  21. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/ams.js +1 -0
  22. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/amscd.js +1 -0
  23. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/autoload.js +1 -0
  24. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/bbox.js +1 -0
  25. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/boldsymbol.js +1 -0
  26. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/braket.js +1 -0
  27. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/bussproofs.js +1 -0
  28. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/cancel.js +1 -0
  29. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/cases.js +1 -0
  30. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/centernot.js +1 -0
  31. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/color.js +1 -0
  32. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/colortbl.js +1 -0
  33. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/colorv2.js +1 -0
  34. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/configmacros.js +1 -0
  35. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/empheq.js +1 -0
  36. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/enclose.js +1 -0
  37. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/extpfeil.js +1 -0
  38. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/gensymb.js +1 -0
  39. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/html.js +1 -0
  40. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/mathtools.js +1 -0
  41. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/mhchem.js +34 -0
  42. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/newcommand.js +1 -0
  43. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/noerrors.js +1 -0
  44. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/noundefined.js +1 -0
  45. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/physics.js +1 -0
  46. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/require.js +1 -0
  47. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/setoptions.js +1 -0
  48. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/tagformat.js +1 -0
  49. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/textcomp.js +1 -0
  50. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/textmacros.js +1 -0
  51. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/unicode.js +1 -0
  52. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/upgreek.js +1 -0
  53. hovercraft/templates/default/js/MathJax/es5/input/tex/extensions/verb.js +1 -0
  54. hovercraft/templates/default/js/MathJax/es5/input/tex-base.js +1 -0
  55. hovercraft/templates/default/js/MathJax/es5/input/tex-full.js +34 -0
  56. hovercraft/templates/default/js/MathJax/es5/input/tex.js +1 -0
  57. hovercraft/templates/default/js/MathJax/es5/latest.js +1 -0
  58. hovercraft/templates/default/js/MathJax/es5/loader.js +1 -0
  59. hovercraft/templates/default/js/MathJax/es5/mml-chtml.js +1 -0
  60. hovercraft/templates/default/js/MathJax/es5/mml-svg.js +1 -0
  61. hovercraft/templates/default/js/MathJax/es5/node-main.js +1 -0
  62. hovercraft/templates/default/js/MathJax/es5/output/chtml/fonts/tex.js +1 -0
  63. hovercraft/templates/default/js/MathJax/es5/output/chtml.js +1 -0
  64. hovercraft/templates/default/js/MathJax/es5/output/svg/fonts/tex.js +1 -0
  65. hovercraft/templates/default/js/MathJax/es5/output/svg.js +1 -0
  66. hovercraft/templates/default/js/MathJax/es5/startup.js +1 -0
  67. hovercraft/templates/default/js/MathJax/es5/tex-chtml-full-speech.js +34 -0
  68. hovercraft/templates/default/js/MathJax/es5/tex-chtml-full.js +34 -0
  69. hovercraft/templates/default/js/MathJax/es5/tex-chtml.js +1 -0
  70. hovercraft/templates/default/js/MathJax/es5/tex-mml-chtml.js +1 -0
  71. hovercraft/templates/default/js/MathJax/es5/tex-mml-svg.js +1 -0
  72. hovercraft/templates/default/js/MathJax/es5/tex-svg-full.js +34 -0
  73. hovercraft/templates/default/js/MathJax/es5/tex-svg.js +1 -0
  74. hovercraft/templates/default/js/MathJax/es5/ui/lazy.js +1 -0
  75. hovercraft/templates/default/js/MathJax/es5/ui/menu.js +1 -0
  76. hovercraft/templates/default/js/MathJax/es5/ui/safe.js +1 -0
  77. hovercraft/templates/default/js/gotoSlide.js +51 -0
  78. hovercraft/templates/default/js/hovercraft.js +58 -0
  79. hovercraft/templates/default/js/impress.js +5009 -0
  80. hovercraft/templates/default/template.cfg +11 -0
  81. hovercraft/templates/default/template.xsl +161 -0
  82. hovercraft/templates/reST.xsl +535 -0
  83. hovercraft/templates/simple/css/highlight.css +61 -0
  84. hovercraft/templates/simple/css/hovercraft.css +67 -0
  85. hovercraft/templates/simple/js/hovercraft.js +58 -0
  86. hovercraft/templates/simple/js/impress.js +5009 -0
  87. hovercraft/templates/simple/template.cfg +10 -0
  88. hovercraft/templates/simple/template.xsl +162 -0
  89. prezentprogramo-3.1.dist-info/METADATA +143 -0
  90. prezentprogramo-3.1.dist-info/RECORD +94 -0
  91. prezentprogramo-3.1.dist-info/WHEEL +5 -0
  92. prezentprogramo-3.1.dist-info/entry_points.txt +5 -0
  93. prezentprogramo-3.1.dist-info/licenses/LICENSE.txt +254 -0
  94. prezentprogramo-3.1.dist-info/top_level.txt +1 -0
hovercraft/generate.py ADDED
@@ -0,0 +1,473 @@
1
+ import os
2
+ import re
3
+ import shutil
4
+ from lxml import etree, html
5
+
6
+ # from pkg_resources import resource_string
7
+ import importlib.resources
8
+ from pyhtml2pdf import converter
9
+ from screeninfo import get_monitors
10
+ from .parse import rst2xml, SlideMaker
11
+ from .position import position_slides
12
+ from .template import (
13
+ Template,
14
+ CSS_RESOURCE,
15
+ JS_RESOURCE,
16
+ JS_POSITION_HEADER,
17
+ JS_POSITION_BODY,
18
+ OTHER_RESOURCE,
19
+ DIRECTORY_RESOURCE,
20
+ )
21
+
22
+
23
+ class ResourceResolver(etree.Resolver):
24
+ def resolve(self, url, pubid, context):
25
+ if url.startswith("resource:"):
26
+ prefix, filename = url.split(":", 1)
27
+ # return self.resolve_strinog(resource_string(__name__, filename), context)
28
+ ref = importlib.resources.files(__name__).joinpath(filename)
29
+ return self.resolve_string(ref.read_bytes(), context)
30
+
31
+
32
+ def rst2html(
33
+ filepath,
34
+ template_info,
35
+ auto_console=False,
36
+ skip_help=False,
37
+ skip_notes=False,
38
+ mathjax=False,
39
+ slide_numbers=False,
40
+ default_movement_from_args=False,
41
+ ):
42
+ # Read the infile
43
+ with open(filepath, "rb") as infile:
44
+ rststring = infile.read()
45
+
46
+ presentation_dir = os.path.split(filepath)[0]
47
+
48
+ # First convert reST to XML
49
+ xml, dependencies = rst2xml(rststring, filepath)
50
+ tree = etree.fromstring(xml)
51
+
52
+ # Fix up the resulting XML so it makes sense
53
+ sm = SlideMaker(tree, skip_notes=skip_notes)
54
+ tree = sm.walk()
55
+
56
+ data_width = None
57
+ # Pick up CSS information from the tree:
58
+ for attrib, value in tree.attrib.items():
59
+
60
+ if attrib.startswith("data-width"):
61
+ data_width = value
62
+
63
+ if attrib.startswith("css"):
64
+
65
+ if "-" in attrib:
66
+ dummy, media = attrib.split("-", 1)
67
+ else:
68
+ media = "all"
69
+ css_files = tree.attrib[attrib].split()
70
+ for css_file in css_files:
71
+ target = f'css/{css_file.split("/")[-1]}'
72
+ if media in ("console", "preview"):
73
+ # The "console" media is used to style the presenter
74
+ # console and does not need to be included in the header,
75
+ # but must be copied. So we add it as a non css file,
76
+ # even though it's a css-file.
77
+ template_info.add_resource(
78
+ os.path.abspath(os.path.join(presentation_dir, css_file)),
79
+ OTHER_RESOURCE,
80
+ target=target,
81
+ )
82
+ else:
83
+ # Add as a css resource:
84
+ template_info.add_resource(
85
+ os.path.abspath(os.path.join(presentation_dir, css_file)),
86
+ CSS_RESOURCE,
87
+ target=target,
88
+ extra_info=media,
89
+ )
90
+
91
+ elif attrib.startswith("js"):
92
+ if attrib == "js-header":
93
+ media = JS_POSITION_HEADER
94
+ else:
95
+ # Put javascript in body tag as default.
96
+ media = JS_POSITION_BODY
97
+ js_files = tree.attrib[attrib].split()
98
+ for js_file in js_files:
99
+ target = f'js/{js_file.split("/")[-1]}'
100
+ template_info.add_resource(
101
+ os.path.abspath(os.path.join(presentation_dir, js_file)),
102
+ JS_RESOURCE,
103
+ target=target,
104
+ extra_info=media,
105
+ )
106
+
107
+ if sm.need_mathjax and mathjax:
108
+ if mathjax.startswith("http"):
109
+ template_info.add_resource(
110
+ None, JS_RESOURCE, target=mathjax, extra_info=JS_POSITION_HEADER
111
+ )
112
+ else:
113
+ # Local copy
114
+ template_info.add_resource(mathjax, DIRECTORY_RESOURCE, target="mathjax")
115
+ template_info.add_resource(
116
+ None,
117
+ JS_RESOURCE,
118
+ target="mathjax/MathJax.js?config=TeX-MML-AM_CHTML",
119
+ extra_info=JS_POSITION_HEADER,
120
+ )
121
+
122
+ # Set step width
123
+ set_step_width(tree, data_width)
124
+
125
+ # Position all slides
126
+ position_slides(tree, default_movement_from_args, data_width)
127
+
128
+ # Add the template info to the tree:
129
+ tree.append(template_info.xml_node())
130
+
131
+ # If the console-should open automatically, set an attribute on the document:
132
+ if auto_console:
133
+ tree.attrib["auto-console"] = "True"
134
+
135
+ # If the console-should open automatically, set an attribute on the document:
136
+ if skip_help:
137
+ tree.attrib["skip-help"] = "True"
138
+
139
+ # If the slide numbers should be displayed, set an attribute on the document:
140
+ if slide_numbers:
141
+ tree.attrib["slide-numbers"] = "True"
142
+
143
+ # We need to set up a resolver for resources, so we can include the
144
+ # reST.xsl file if so desired.
145
+ parser = etree.XMLParser()
146
+ parser.resolvers.add(ResourceResolver())
147
+
148
+ # Transform the tree to HTML
149
+ xsl_tree = etree.fromstring(template_info.xsl, parser)
150
+ transformer = etree.XSLT(xsl_tree)
151
+ tree = transformer(tree)
152
+ result = html.tostring(tree)
153
+
154
+ return template_info.doctype + result, dependencies
155
+
156
+
157
+ def set_step_width(tree, data_width):
158
+ step_divs = tree.findall("step")
159
+ width = None
160
+ if data_width:
161
+ width = data_width
162
+ else:
163
+ presentation_monitor = get_monitors()[
164
+ -1
165
+ ] # Assuming the last monitor is for presentation
166
+ width = presentation_monitor.width
167
+ tree.attrib["data-width"] = str(width)
168
+
169
+ # Add width style to each found div
170
+ for div in step_divs:
171
+ div.set("style", f"width: {width}px;") # Adding width style
172
+
173
+
174
+ def copy_resource(filename, sourcedir, targetdir, sourcepath=None, targetpath=None):
175
+ if filename[0] == "/" or ":" in filename:
176
+ # Absolute path or URI: Do nothing
177
+ return None # No monitoring needed
178
+ if sourcepath is None:
179
+ sourcepath = os.path.join(sourcedir, filename)
180
+ if targetpath is None:
181
+ targetpath = os.path.join(targetdir, filename)
182
+
183
+ if os.path.exists(targetpath) and os.path.getmtime(sourcepath) <= os.path.getmtime(
184
+ targetpath
185
+ ):
186
+ # File has not changed since last copy, so skip.
187
+ return sourcepath # Monitor this file
188
+
189
+ targetdir = os.path.split(targetpath)[0]
190
+ if not os.path.exists(targetdir):
191
+ os.makedirs(targetdir)
192
+
193
+ shutil.copy2(sourcepath, targetpath)
194
+ return sourcepath # Monitor this file
195
+
196
+
197
+ def generate(args):
198
+ """Generates the presentation and returns a list of files used"""
199
+
200
+ source_files = {args.presentation}
201
+
202
+ # Parse the template info
203
+ template_info = Template(args.template)
204
+ if args.css:
205
+ presentation_dir = os.path.split(args.presentation)[0]
206
+ target_path = os.path.relpath(args.css, presentation_dir)
207
+ template_info.add_resource(
208
+ args.css, CSS_RESOURCE, target=target_path, extra_info="all"
209
+ )
210
+ source_files.add(args.css)
211
+ if args.js:
212
+ presentation_dir = os.path.split(args.presentation)[0]
213
+ target_path = os.path.relpath(args.js, presentation_dir)
214
+ template_info.add_resource(
215
+ args.js, JS_RESOURCE, target=target_path, extra_info=JS_POSITION_BODY
216
+ )
217
+ source_files.add(args.js)
218
+
219
+ # Make the resulting HTML
220
+ htmldata, dependencies = rst2html(
221
+ args.presentation,
222
+ template_info,
223
+ args.auto_console,
224
+ args.skip_help,
225
+ args.skip_notes,
226
+ args.mathjax,
227
+ args.slide_numbers,
228
+ args.default_movement,
229
+ )
230
+ source_files.update(dependencies)
231
+
232
+ # Create targetdir directory
233
+ if not os.path.exists(args.targetdir):
234
+ os.makedirs(args.targetdir)
235
+
236
+ # Copy supporting files
237
+ source_files.update(template_info.copy_resources(args.targetdir))
238
+
239
+ # Copy files from the source:
240
+ sourcedir = os.path.split(os.path.abspath(args.presentation))[0]
241
+ tree = html.fromstring(htmldata)
242
+
243
+ # Copy images to targetdir/img directory and update html tree
244
+ for image in tree.iterdescendants("img"):
245
+ img_src = image.attrib["src"]
246
+ filename = img_src.split("/")[-1]
247
+ targetpath = os.path.join(args.targetdir, f"img/{filename}")
248
+ source_files.add(
249
+ copy_resource(
250
+ img_src,
251
+ sourcedir,
252
+ args.targetdir,
253
+ sourcepath=None,
254
+ targetpath=targetpath,
255
+ )
256
+ )
257
+ image.attrib["src"] = f"img/{filename}"
258
+
259
+ for source in tree.iterdescendants("source"):
260
+ filename = source.attrib["src"]
261
+ source_files.add(copy_resource(filename, sourcedir, args.targetdir))
262
+
263
+ # Code for handling iframe sources
264
+ for iframe in tree.iterdescendants("iframe"):
265
+ iframe_src = iframe.attrib.get("src")
266
+ if iframe_src:
267
+ filename = iframe_src.split("/")[-1]
268
+ targetpath = os.path.join(args.targetdir, f"iframe/{filename}")
269
+ source_files.add(
270
+ copy_resource(
271
+ iframe_src,
272
+ sourcedir,
273
+ args.targetdir,
274
+ sourcepath=None,
275
+ targetpath=targetpath,
276
+ )
277
+ )
278
+ iframe.attrib["src"] = f"iframe/{filename}"
279
+
280
+ RE_CSS_URL = re.compile(rb"""url\(['"]?(.*?)['"]?[\)\?\#]""")
281
+
282
+ # Copy any files referenced by url() in the css-files:
283
+ for resource in template_info.resources:
284
+ if resource.resource_type != CSS_RESOURCE:
285
+ continue
286
+ # path in CSS is relative to CSS file; construct source/dest accordingly
287
+ css_base = template_info.template_root if resource.is_in_template else sourcedir
288
+ css_sourcedir = os.path.dirname(os.path.join(css_base, resource.filepath))
289
+ css_targetdir = os.path.dirname(
290
+ os.path.join(args.targetdir, resource.final_path())
291
+ )
292
+ uris = RE_CSS_URL.findall(template_info.read_data(resource))
293
+ uris = [uri.decode() for uri in uris]
294
+ if resource.is_in_template and template_info.builtin_template:
295
+ for filename in uris:
296
+ template_info.add_resource(
297
+ filename, OTHER_RESOURCE, target=css_targetdir, is_in_template=True
298
+ )
299
+ else:
300
+ for filename in uris:
301
+ source_files.add(copy_resource(filename, css_sourcedir, css_targetdir))
302
+
303
+ # Write the HTML out
304
+ htmldata = html.tostring(tree)
305
+ with open(os.path.join(args.targetdir, "index.html"), "wb") as outfile:
306
+ outfile.write(htmldata)
307
+
308
+ # All done!
309
+
310
+ return {os.path.abspath(f) for f in source_files if f}
311
+
312
+
313
+ def prepare_for_pdf(html_file_path):
314
+ # Read the HTML content from the file
315
+ with open(html_file_path, "r") as html_file:
316
+ html_content = html_file.read()
317
+
318
+ html_content = html_content.replace(
319
+ "<head>",
320
+ """<head>
321
+ <style>
322
+ .pdfContainer
323
+ {
324
+ justify-content: center;
325
+ align-items: center;
326
+ display: flex;
327
+ width: 100%;
328
+ height: 100%;
329
+ page-break-after: always;
330
+ }
331
+ .substep
332
+ {
333
+ opacity: 1 !important;
334
+ }
335
+ </style>""",
336
+ )
337
+
338
+ # Find and delete the specific div
339
+ tree = html.fromstring(html_content)
340
+ divs_to_delete = tree.xpath('//div[@id="impress"]')
341
+ for div_to_delete in divs_to_delete:
342
+ parent = div_to_delete.getparent()
343
+ for element in div_to_delete.iterchildren():
344
+ parent.insert(parent.index(div_to_delete), element)
345
+ parent.remove(div_to_delete)
346
+
347
+ # Add a new div around each div with class "step"
348
+ step_divs = tree.xpath('//div[contains(@class, "step")]')
349
+ for step_div in step_divs:
350
+ container_div = html.Element("div")
351
+ container_div.set("class", "pdfContainer")
352
+ step_div.addprevious(container_div)
353
+ container_div.append(step_div)
354
+
355
+ # Convert the modified tree back to HTML
356
+ html_content = html.tostring(tree, encoding="unicode")
357
+
358
+ # Write the modified HTML back to the file
359
+ with open(html_file_path, "w") as html_file:
360
+ html_file.write(html_content)
361
+
362
+
363
+ def generate_pdf(args):
364
+ """Generates the pdf and returns a list of files used"""
365
+
366
+ source_files = {args.presentation}
367
+ # Parse the template info
368
+ template_info = Template(args.template)
369
+ if args.css:
370
+ presentation_dir = os.path.split(args.presentation)[0]
371
+ target_path = os.path.relpath(args.css, presentation_dir)
372
+ template_info.add_resource(
373
+ args.css, CSS_RESOURCE, target=target_path, extra_info="all"
374
+ )
375
+ source_files.add(args.css)
376
+ if args.js:
377
+ presentation_dir = os.path.split(args.presentation)[0]
378
+ target_path = os.path.relpath(args.js, presentation_dir)
379
+ template_info.add_resource(
380
+ args.js, JS_RESOURCE, target=target_path, extra_info=JS_POSITION_BODY
381
+ )
382
+ source_files.add(args.js)
383
+
384
+ # Make the resulting HTML
385
+ htmldata, dependencies = rst2html(
386
+ args.presentation,
387
+ template_info,
388
+ args.auto_console,
389
+ args.skip_help,
390
+ args.skip_notes,
391
+ args.mathjax,
392
+ args.slide_numbers,
393
+ )
394
+ source_files.update(dependencies)
395
+
396
+ args.targetdir = "tmp"
397
+
398
+ # Write the HTML out
399
+ if not os.path.exists(args.targetdir):
400
+ os.makedirs(args.targetdir)
401
+
402
+ indexHtmlPath = os.path.abspath(os.path.join(args.targetdir, "index.html"))
403
+
404
+ with open(indexHtmlPath, "wb") as outfile:
405
+ outfile.write(htmldata)
406
+
407
+ # Copy supporting files
408
+ source_files.update(template_info.copy_resources(args.targetdir))
409
+
410
+ # Copy files from the source:
411
+ sourcedir = os.path.split(os.path.abspath(args.presentation))[0]
412
+ tree = html.fromstring(htmldata)
413
+ for image in tree.iterdescendants("img"):
414
+ filename = image.attrib["src"]
415
+ source_files.add(copy_resource(filename, sourcedir, args.targetdir))
416
+ for source in tree.iterdescendants("source"):
417
+ filename = source.attrib["src"]
418
+ source_files.add(copy_resource(filename, sourcedir, args.targetdir))
419
+
420
+ # Code for handling iframe sources
421
+ for iframe in tree.iterdescendants("iframe"):
422
+ iframe_src = iframe.attrib.get("src")
423
+ if iframe_src:
424
+ filename = iframe_src.split("/")[-1]
425
+ targetpath = os.path.join(args.targetdir, f"iframe/{filename}")
426
+ source_files.add(
427
+ copy_resource(
428
+ iframe_src,
429
+ sourcedir,
430
+ args.targetdir,
431
+ sourcepath=None,
432
+ targetpath=targetpath,
433
+ )
434
+ )
435
+ iframe.attrib["src"] = f"iframe/{filename}"
436
+
437
+ RE_CSS_URL = re.compile(rb"""url\(['"]?(.*?)['"]?[\)\?\#]""")
438
+
439
+ # Copy any files referenced by url() in the css-files:
440
+ for resource in template_info.resources:
441
+ if resource.resource_type != CSS_RESOURCE:
442
+ continue
443
+ # path in CSS is relative to CSS file; construct source/dest accordingly
444
+ css_base = template_info.template_root if resource.is_in_template else sourcedir
445
+ css_sourcedir = os.path.dirname(os.path.join(css_base, resource.filepath))
446
+ css_targetdir = os.path.dirname(
447
+ os.path.join(args.targetdir, resource.final_path())
448
+ )
449
+ uris = RE_CSS_URL.findall(template_info.read_data(resource))
450
+ uris = [uri.decode() for uri in uris]
451
+ if resource.is_in_template and template_info.builtin_template:
452
+ for filename in uris:
453
+ template_info.add_resource(
454
+ filename, OTHER_RESOURCE, target=css_targetdir, is_in_template=True
455
+ )
456
+ else:
457
+ for filename in uris:
458
+ source_files.add(copy_resource(filename, css_sourcedir, css_targetdir))
459
+
460
+ # ==========
461
+
462
+ prepare_for_pdf(indexHtmlPath)
463
+
464
+ converter.convert(
465
+ f"file:///{indexHtmlPath}",
466
+ args.pdf_output_path,
467
+ install_driver=False,
468
+ print_options={"landscape": True},
469
+ )
470
+
471
+ shutil.rmtree(args.targetdir)
472
+
473
+ return {os.path.abspath(f) for f in source_files if f}