fr en

Extraire toutes les images encodées en base64 d'un SVG

Posted on 2017-02-13 in Trucs et astuces

Récemment, j'ai eu besoin d'intégrer un SVG dans un template Aurelia. Malheureusement, il contenait beaucoup d'images et elles étaient toutes incluses au format base64. Cela rendait le fichier quasiment inutilisable avec de gros pâtés qui empêchent de voir le code utile et d'ajouter les attributs « Aurelia » (comme if.bind). Heureusement, Python (3) est là !

Le script ci-dessous prend comme paramètre le chemin vers un fichier SVG et va extraire toutes les images encodées en base64 dans le dossier courrant. Le SVG utilisant ces images extraites est sauvegardé dans le dossier courrant avec le nom svg-without-images.svg.

 1 import sys
 2 
 3 from base64 import b64decode
 4 from lxml import etree
 5 
 6 
 7 # On définit les espaces de nom XML (namespace) qui vont nous permettre de faire des requêtes dans le SVG.
 8 NS = {
 9     'svg': 'http://www.w3.org/2000/svg',
10     'xlink': 'http://www.w3.org/1999/xlink',
11 }
12 
13 
14 def print_help():
15     print('./extract-images-svg.py SVG_FILE')
16     print('This will extract the images included in b64 in the SVG.')
17 
18 
19 def extract_images_svg(file_name):
20     # On ouvre le fichier source et on le parse.
21     with open(file_name) as svg_file:
22         svg = etree.parse(svg_file)
23 
24     # On utilise xpath pour trouver toutes les images contenues dans le fichier.
25     images = svg.xpath('.//svg:image', namespaces=NS)
26     for index, img in enumerate(images):
27         # On récupère le contenu de l'image.
28         content = img.get('{http://www.w3.org/1999/xlink}href')
29         # On regarde si l'image est au format base64. Si oui, on extrait le contenu.
30         if content.startswith('data:image/'):
31             # On extrait l'image et ses méta-données (seul le format nous intéresse ici).
32             meta, img_b64 = content.split(';base64,')
33             _, img_format = meta.split('/')
34             # On extrait l'image dans le format utilisé avant l'encodage en base64.
35             img_file_name = 'img-{index}.{format}'.format(index=index, format=img_format)
36             # On remplace le lien vers l'image extraite.
37             img.set('{http://www.w3.org/1999/xlink}href', img_file_name)
38             # On sauvegarde le fichier.
39             with open(img_file_name, 'wb') as img_file:
40                 img_file.write(b64decode(img_b64))
41 
42     # On sauvegarde notre nouveau SVG.
43     with open('svg-without-images.svg', 'w') as svg_file:
44         svg_content = etree.tostring(svg)\
45                 .decode('utf-8')\
46                 .replace('>', '>')
47         svg_file.write(svg_content)
48 
49 
50 if __name__ == "__main__":
51     if len(sys.argv) != 2:
52         print_help()
53         sys.exit(0)
54 
55     extract_images_svg(sys.argv[1])