Skip to content

Instantly share code, notes, and snippets.

@53v3n3d4
Last active April 18, 2024 12:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 53v3n3d4/0d2b54a3fd22820906dd77364371e573 to your computer and use it in GitHub Desktop.
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
# 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)
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