Empty SVG groups grow up the exported files

Discussions about the development of the TechDraw workbench
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
flachyjoe
Veteran
Posts: 1891
Joined: Sat Mar 31, 2012 12:00 pm
Location: Limoges, France

Empty SVG groups grow up the exported files

Post by flachyjoe »

Hi,
I notice some SVG files produced by TechDraw have many empty groups : a <g> item without any geometry inside.
ie.

Code: Select all

[...]
     stroke-linejoin="bevel"
     id="g111675">
    <g
       fill="none"
       stroke="#000000"
       stroke-opacity="1"
       stroke-width="1"
       stroke-linecap="square"
       stroke-linejoin="bevel"
       transform="matrix(1,0,0,1,0,0)"
       font-family=".SF NS Text"
       font-size="45.8611"
       font-weight="400"
       font-style="normal"
       id="g75837" />
    <g
       fill="none"
[...]
Such dust can be cleaned with this search RegExp in a text editor :

Code: Select all

<g[^<>]*/>
- Flachy Joe -
Image
User avatar
wandererfan
Veteran
Posts: 6317
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Empty SVG groups grow up the exported files

Post by wandererfan »

flachyjoe wrote: Mon May 07, 2018 2:01 pm I notice some SVG files produced by TechDraw have many empty groups : a <g> item without any geometry inside.
Not sure we can do much about this. The file is created automagically by the QtSvg module.
ulrich1a
Veteran
Posts: 1957
Joined: Sun Jul 07, 2013 12:08 pm

Re: Empty SVG groups grow up the exported files

Post by ulrich1a »

The program scour does a good job in optimizing the size of a SVG-file: https://github.com/scour-project/scour

What could be done in FreeCAD, is to open the file and do some cleaning and save the cleaned file automatically.
The other option is to write a SVG-exporter.

Ulrich
User avatar
flachyjoe
Veteran
Posts: 1891
Joined: Sat Mar 31, 2012 12:00 pm
Location: Limoges, France

Re: Empty SVG groups grow up the exported files

Post by flachyjoe »

Hi,
I spent a few time to write a cleaner witch remove empty groups and concatenate identical adjacent ones.
When edit with Inkscape for example, we got one group per view. It's really useful.
A improvement will concatenate non-adjacent similar groups.

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  clean_fc_svg.py
#  
#  Copyright 2019 Florian Foinant <ffw_at_2f2v.fr>
#  
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#  
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.

def main(args):
	if len(args)!=3 :
		print "Clean a FreeCAD exported SVG file"
		print "Usage : python clean_fc_svg.py input.svg output.svg"
		return 1
	
	input_svg = open(args[1],'r').read()
	
	import re
	#remove empty groups
	input_svg = re.sub('<g[^<>]*/>\n ','',input_svg)
	
	#parse the xml
	import lxml.etree as ET
	ET.register_namespace("svg", "http://www.w3.org/2000/svg")
	parser = ET.XMLParser(remove_blank_text=True)
	
	root = ET.fromstring(input_svg, parser)
	tree = ET.ElementTree(root)

	#concatenate identical adjacent groups
	last_grp = None
	parent_grp = None
	for grp in root.iter('{http://www.w3.org/2000/svg}g') :
		if len(grp) == 1 :
			if not last_grp is None and cmp(grp.attrib,last_grp.attrib)==0 :
				last_grp.append(grp[0])
				if parent_grp is not None :
					parent_grp.remove(grp)
			else :
				last_grp = grp
		else :
			parent_grp = grp

	#Save the cleaned XML
	tree.write(args[2], encoding='utf8', xml_declaration=True, pretty_print=True)
	return 0

if __name__ == '__main__':
	import sys
	sys.exit(main(sys.argv))
- Flachy Joe -
Image
User avatar
flachyjoe
Veteran
Posts: 1891
Joined: Sat Mar 31, 2012 12:00 pm
Location: Limoges, France

Re: Empty SVG groups grow up the exported files

Post by flachyjoe »

Updated with the announced improvement :

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  clean_fc_svg.py
#  
#  Copyright 2019 Florian Foinant <ffw_at_2f2v.fr>
#  
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#  
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#  
def main(args):
	if len(args)!=3 :
		print "Clean a FreeCAD exported SVG file"
		print "Usage : python clean_fc_svg.py input.svg output.svg"
		return 1

	try :
		input_svg = open(args[1],'r').read()
	except IOError :
		print "No such file:", args[1]
		return 1

	#parse the xml
	import lxml.etree as ET
	ET.register_namespace("svg", "http://www.w3.org/2000/svg")
	parser = ET.XMLParser(remove_blank_text=True)

	root = ET.fromstring(input_svg, parser)
	
	grps = [g for g in root.iter('{http://www.w3.org/2000/svg}g')]
	print 'Start : %i groups' % len(grps)

	#concatenate identical groups and remove empty ones
	parent_grp = root
	empty_count=0
	identic_count=0
	for grp in grps :
		if len(grp) == 0 :
			parent_grp.remove(grp)
			empty_count += 1
		elif len(grp) == 1 :
			for known in grps :
				if grp != known :
					if cmp(grp.attrib,known.attrib)==0 :
						known.append(grp[0])
						parent_grp.remove(grp)
						identic_count += 1
						break
				else :
					break
		else :
			parent_grp = grp
	
	print 'End : %i groups' % len([g for g in root.iter('{http://www.w3.org/2000/svg}g')]), ', %i empty and %i identical removed' % (empty_count, identic_count)

	#Save the cleaned XML
	tree = ET.ElementTree(root)
	tree.write(args[2], encoding='utf8', xml_declaration=True, pretty_print=True)
	return 0

if __name__ == '__main__':
	import sys
	sys.exit(main(sys.argv))

With my test file :

Code: Select all

flachy@joe:~/EnCours/tests FC$ python clean_fc_svg.py test.svg clean.svg
Start : 1136 groups
End : 27 groups , 674 empty and 435 identical removed
- Flachy Joe -
Image
Post Reply