-
Notifications
You must be signed in to change notification settings - Fork 60
/
data-uri-to-svg.py
executable file
·75 lines (57 loc) · 2.02 KB
/
data-uri-to-svg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python
"""
Replace data: URIs for SVGs in CSS files with URIs pointing to the extracted
SVG file.
This allows us to avoid adding the data: scheme to our Content Security Policy,
because it is insecure.
See https://github.com/fedora-infra/noggin/issues/333
If you update the CSS file, you need to run this script on it again.
"""
import argparse
import os
import re
from urllib.parse import unquote
DATA_URI_RE = re.compile(r"url\(\"data:image/svg\+xml,([^\"]+)\"\)")
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("css_file", metavar="css-file", nargs="+")
args = parser.parse_args()
return args
class Replacer:
def __init__(self, filename):
self.filename = filename
self.directory = os.path.dirname(filename)
self.svgs = []
self.replacements = 0
@property
def target_filename(self):
return os.path.splitext(self.filename)[0] + ".nodata.css"
def _get_svg(self, match):
svg = match.group(1)
try:
svg_index = self.svgs.index(svg)
except ValueError:
svg_index = len(self.svgs)
self.svgs.append(svg)
with open(os.path.join(self.directory, f"{svg_index}.svg"), "w") as svg_file:
svg_file.write(unquote(svg))
self.replacements += 1
return f"url(\"{svg_index}.svg\")"
def run(self):
with open(self.filename) as css_file:
with open(self.target_filename, "w") as new_css_file:
new_css_file.write(
"/* This file has been generated by data-uri-to-svg.py */\n\n"
)
for line in css_file:
new_css_file.write(DATA_URI_RE.sub(self._get_svg, line))
print(
f"Replaced {self.replacements} data URIs with {len(self.svgs)} "
f"SVG files in {self.target_filename}."
)
def main():
args = parse_args()
for css_file in args.css_file:
Replacer(css_file).run()
if __name__ == "__main__":
main()