Coverage for src/svglib/__init__.py: 28%
47 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-06-16 15:14 +0200
« prev ^ index » next coverage.py v7.10.6, created at 2026-06-16 15:14 +0200
1"""A tool for converting SVG to PDF.
3This module provides a high-level function for converting SVG files to PDF format
4using the ReportLab graphics library. It also serves as the main entry point for
5the svglib package.
7The module includes:
8- svg2pdf(): Convert SVG files to PDF programmatically.
9- main(): Command-line interface for SVG to PDF conversion.
10- Automatic file path handling and output generation.
11"""
13import argparse
14import sys
15import textwrap
16from datetime import datetime
17from importlib.metadata import PackageNotFoundError, version
18from os.path import basename, dirname, exists, splitext
19from typing import Optional
21from reportlab.graphics import renderPDF
23from svglib import svglib
25try:
26 __version__ = version("svglib")
27except PackageNotFoundError:
28 __version__ = "unknown"
31def svg2pdf(path: str, outputPat: Optional[str] = None) -> None:
32 """Convert an SVG file to PDF format.
34 High-level function that loads an SVG file, converts it to a ReportLab drawing,
35 and saves it as a PDF file. Supports both .svg and .svgz (compressed SVG) files.
37 Args:
38 path: Path to the input SVG file (.svg or .svgz extension).
39 outputPat: Optional output path pattern. Supports placeholders:
40 - %(dirname)s: Directory of input file
41 - %(basename)s: Full filename with extension
42 - %(base)s: Filename without extension
43 - %(ext)s: File extension
44 - %(now)s: Current datetime object
45 - %(format)s: Output format (always "pdf")
46 Also supports {name} format strings.
48 Returns:
49 None. The PDF file is written to disk.
51 Raises:
52 FileNotFoundError: If the input SVG file does not exist.
53 Exception: If SVG parsing or PDF generation fails.
54 OSError: If the output directory is not writable.
56 Examples:
57 Basic conversion:
58 >>> svg2pdf("input.svg") # Creates "input.pdf"
60 Custom output location:
61 >>> svg2pdf("input.svg", "output.pdf")
63 Using placeholders:
64 >>> svg2pdf("path/file.svg", "%(dirname)s/converted/%(base)s.pdf")
65 # Creates "path/converted/file.pdf"
67 Timestamped output:
68 >>> svg2pdf("file.svg", "backup/%(now.year)s-%(now.month)s-%(base)s.pdf")
70 Note:
71 The function will overwrite existing PDF files without warning.
72 For compressed SVG files (.svgz), the file is automatically decompressed.
73 """
75 # derive output filename from output pattern
76 file_info = {
77 "dirname": dirname(path) or ".",
78 "basename": basename(path),
79 "base": basename(splitext(path)[0]),
80 "ext": splitext(path)[1],
81 "now": datetime.now(),
82 "format": "pdf",
83 }
84 out_pattern = outputPat or "%(dirname)s/%(base)s.%(format)s"
85 # allow classic %%(name)s notation
86 out_path = out_pattern % file_info
87 # allow also newer {name} notation
88 out_path = out_path.format(**file_info)
90 # generate a drawing from the SVG file
91 try:
92 drawing = svglib.svg2rlg(path)
93 except:
94 print("Rendering failed.")
95 raise
97 # save converted file
98 if drawing:
99 renderPDF.drawToFile(drawing, out_path, showBoundary=0)
102# command-line usage stuff
103def main() -> None:
104 """Main entry point for the CLI."""
105 ext = "pdf"
106 ext_caps = ext.upper()
107 format_args = dict(
108 prog=basename(sys.argv[0]),
109 version=__version__,
110 ts_pattern="{{dirname}}/out-"
111 "{{now.hour}}-{{now.minute}}-{{now.second}}-"
112 "%(base)s",
113 ext=ext,
114 ext_caps=ext_caps,
115 )
116 format_args["ts_pattern"] += ".%s" % format_args["ext"]
117 desc = "{prog} v. {version}\n".format(**format_args)
118 desc += "A converter from SVG to {} (via ReportLab Graphics)\n".format(ext_caps)
119 epilog = textwrap.dedent(
120 """\
121 examples:
122 # convert path/file.svg to path/file.{ext}
123 {prog} path/file.svg
125 # convert file1.svg to file1.{ext} and file2.svgz to file2.{ext}
126 {prog} file1.svg file2.svgz
128 # convert file.svg to out.{ext}
129 {prog} -o out.{ext} file.svg
131 # convert all SVG files in path/ to PDF files with names like:
132 # path/file1.svg -> file1.{ext}
133 {prog} -o "%(base)s.{ext}" path/file*.svg
135 # like before but with timestamp in the PDF files:
136 # path/file1.svg -> path/out-12-58-36-file1.{ext}
137 {prog} -o {ts_pattern} path/file*.svg
139 issues/pull requests:
140 https://github.com/deeplook/svglib
141 """.format(**format_args)
142 )
143 p = argparse.ArgumentParser(
144 description=desc,
145 epilog=epilog,
146 formatter_class=argparse.RawDescriptionHelpFormatter,
147 )
149 p.add_argument(
150 "-v", "--version", help="Print version number and exit.", action="store_true"
151 )
153 p.add_argument(
154 "-o",
155 "--output",
156 metavar="PATH_PAT",
157 help="Set output path (incl. the placeholders: dirname, basename,"
158 "base, ext, now) in both, %%(name)s and {name} notations.",
159 )
161 p.add_argument(
162 "input",
163 metavar="PATH",
164 nargs="*",
165 help="Input SVG file path with extension .svg or .svgz.",
166 )
168 args = p.parse_args()
170 if args.version:
171 print(__version__)
172 sys.exit()
174 if not args.input:
175 p.print_usage()
176 sys.exit()
178 paths = [a for a in args.input if exists(a)]
179 for path in paths:
180 svg2pdf(path, outputPat=args.output)