Last active
April 18, 2024 12:50
-
-
Save 53v3n3d4/0d2b54a3fd22820906dd77364371e573 to your computer and use it in GitHub Desktop.
Affinity Designer SVG Export exclude xml tag, doc tags and serif:id attributes. Python script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# I needed to clean svgs when testing svg lib in python. | |
# To run in command line | |
# 1. In line 25 change '../icons_test' for your relative path | |
# In this example file is one directory up (icons_test) from where this file is located | |
# 2. If you want to clean only one file | |
# In line 125, change 'file_type_sql.svg' to you svg file name | |
# 3. Select (uncomment) one of the examples at the end of file, clean only one file or all files in | |
# a directory | |
# CleanSVG.clean_svg(file_test, UNUSED_LIST) | |
# CleanSVG.clean_all_svgs(ICONS_TEST_PATH, UNUSED_LIST) | |
# 4. $ python path/to/clean_svg.py | |
import os | |
import re | |
from collections.abc import Set | |
UNUSED_LIST = { | |
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>', | |
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">', | |
' xmlns:serif="http://www.serif.com/"' | |
} | |
# Script dir, replace '../icons_test' with your svg file relative path | |
ICONS_TEST_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../icons_test') | |
class Color: | |
PURPLE = '\x1b[35m' | |
CYAN = '\x1b[36m' | |
RED = '\x1b[91m' | |
YELLOW = '\x1b[93m' | |
END = '\x1b[0m' | |
class CleanSVG: | |
""" | |
Clean unused tags and attributes in svg. | |
Affinity designer program, used to export svgs, produce svgs with unsed tags | |
that needs to be deleted. Error can raise depending on lib used. | |
The tags and attributes below will be deleted: | |
1- <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
2- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
3- Inside svg tag, delete attribute xmlns:serif="http://www.serif.com/" | |
4- Regex clean serif:id="text" attribute | |
There are files that do not have item 4. Example: angular.svg | |
""" | |
def clean_svg(svgfile: str, replace_list: Set): | |
""" | |
Clean unused tags and attributes in svg file, from a list of strings. | |
Parameters: | |
svg (str) -- svg file path. | |
replace_list (Set) -- list of unused strings to be replaced. | |
""" | |
try: | |
basename_svgfile = os.path.basename(svgfile) | |
if svgfile.endswith('.svg'): | |
with open(svgfile, 'r+') as f: | |
clean_file = f.read() | |
# replace string line from unused list | |
for line in replace_list: | |
if line in clean_file: | |
clean_file = clean_file.replace(line, '') | |
print( | |
f'{ Color.CYAN }[!] { basename_svgfile }' | |
f'{ Color.END }: line { Color.YELLOW }{ line } ' | |
f'{ Color.END }found and being deleted.' | |
) | |
else: | |
print( | |
f'{ Color.RED }[!] { basename_svgfile }' | |
f'{ Color.END }: line { Color.YELLOW }{ line } ' | |
f'{ Color.END }not found.' | |
) | |
# Regex to remove all serif:id="<text>". | |
# If left, svg file may not read in lib, also in finder(macOS) | |
# svgs will be flaged with error notice. | |
word = 'serif:id' | |
if word in clean_file: | |
clean_file = re.sub( | |
r'\s+serif:id=".*?"', '', clean_file, flags=re.DOTALL | |
) | |
print( | |
f'{ Color.CYAN }[!] { basename_svgfile }' | |
f'{ Color.END }: attribute { Color.YELLOW }{ word } ' | |
f'{ Color.END }found and being deleted.' | |
) | |
else: | |
print( | |
f'{ Color.RED }[!] { basename_svgfile }' | |
f'{ Color.END }: attribute { Color.YELLOW }{ word } ' | |
f'{ Color.END }not found.' | |
) | |
with open(svgfile, 'w') as f: | |
f.write(clean_file) | |
else: | |
print( | |
f'{ Color.PURPLE }[!] { basename_svgfile }{ Color.END }: ' | |
f'file extension is not svg.' | |
) | |
except FileNotFoundError as f: | |
print('File could not be found.') | |
def clean_all_svgs(foldername: str, replace_list: Set): | |
""" | |
Clean a list of unused tags and attributes from svg files in a directory. | |
Parameters: | |
foldername (str) -- path to directory with svgs files. | |
replace_list (Set) -- list of unused strings to be replaced. | |
""" | |
svgs_in_dir = os.listdir(foldername) | |
for svg in svgs_in_dir: | |
svg = os.path.join(foldername, svg) | |
CleanSVG.clean_svg(svg, replace_list) | |
# print(svg) | |
# print(svgs_in_dir) | |
return svgs_in_dir | |
# Change for svg name file if you use func CleanSVG.clean_svg | |
file_test = os.path.join(ICONS_TEST_PATH, 'file_type_sql.svg') | |
# CleanSVG.clean_svg(file_test, UNUSED_LIST) | |
# print(file_test) | |
# CleanSVG.clean_all_svgs(ICONS_TEST_PATH, UNUSED_LIST) | |
# print(all_svgs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import collections.abc | |
import os | |
# import pytest | |
from pyfakefs.fake_filesystem_unittest import TestCase | |
from clean_svg import CleanSVG | |
unused_list = { | |
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>', | |
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">', | |
' xmlns:serif="http://www.serif.com/"' | |
} | |
class TestCleanSVG(TestCase): | |
@classmethod | |
def setUpClass(cls): | |
cls.setUpClassPyfakefs() | |
cls.fake_fs().create_file('icons/file_type_afdesign.svg', contents='test') | |
cls.fake_fs().create_file('icons/file_type_afphoto.svg', contents='test') | |
cls.fake_fs().create_file('icons/file_type_afpub.svg', contents='test') | |
cls.fake_fs().create_file('icons/file_type_ai.svg', contents='test') | |
cls.fake_fs().create_file('icons/file_type_angular.svg', contents='test') | |
def test_file_exist(self): | |
CleanSVG.clean_svg('icons/file_type_ai.svg', unused_list) | |
self.assertTrue(os.path.exists('icons/file_type_ai.svg')) | |
def test_file_not_found(self): | |
CleanSVG.clean_svg('icons/file_type_babel.svg', unused_list) | |
self.assertFalse(os.path.exists('icons/file_type_babel.svg')) | |
def test_params(self): | |
CleanSVG.clean_svg('icons/file_type_ai.svg', unused_list) | |
self.assertTrue(isinstance('icons/file_type_ai.svg', str)) | |
self.assertTrue(isinstance(unused_list, collections.abc.Set)) | |
self.assertFalse(isinstance('icons/file_type_ai.svg', int)) | |
self.assertFalse(isinstance('icons/file_type_ai.svg', list)) | |
self.assertFalse(isinstance('icons/file_type_ai.svg', bool)) | |
self.assertFalse(isinstance(unused_list, int)) | |
self.assertFalse(isinstance(unused_list, list)) | |
self.assertFalse(isinstance(unused_list, bool)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment