Bem, acontece que trabalhar com XML em python é bem fácil. O código a seguir recursivamente (para lidar com grupos aninhados) é executado sobre o arquivo. Um hash de cada caminho (alguns dos caminhos são bem longos) é armazenado, a menos que o hash seja uma duplicata, caso em que o nó é marcado para exclusão. Exclusão real acontece antes de voltar para o pai, uma vez que parece quebrar a iteração sobre os filhos, se feito na mosca. A exclusão de objetos preenchidos com branco também está lá.
import xml.etree.ElementTree as ET
import hashlib as hash
def iter_groups(group):
global hashlist
global count
rem=[]
for child in group:
if child.tag==rtag+'g' :#we have a group
iter_groups(child)
else:
if child.tag==rtag+'path':
h=hash.md5(str(child.attrib)).hexdigest()
print h
if h in hashlist:
rem.append(child)
print "removing ",child.tag, "in",group.tag,group.attrib," -- duplicate"
count+=1
else:
try:
print child.attrib['fill']
except KeyError:
print 'no fill'
#no fill attribute
else:
if ("rgb(255,255,255)") in child.attrib['fill']:
rem.append(child)
print "removing ",child.tag, "in",group.tag,group.attrib," -- white"
else:
hashlist.append(h)
for r in rem: group.remove(r)
#main#
hashlist=[]
count=0
tree = ET.parse('imgtest.svg')
root = tree.getroot()
rtag= root.tag.split('}')[0]+'}'
iter_groups(root)
tree.write('imgtest_out.svg',encoding="us-ascii", xml_declaration=True, default_namespace="", method="xml")
Problemas:
- Por algum motivo, todas as tags na saída são prefixadas com "ns0:" - localizar e substituir as correções que
- Você pode ficar com muitos grupos vazios e ids não referenciados - executando vasculhando o arquivo depois (com
--enable-id-stripping
) é uma boa ideia.
Resultados: arquivo inicial: 20,030KB após este código: 8,555KB após a lavagem: 4.545KB isso é praticamente viável no inkscape.
Existem ainda algumas duplicatas visuais produzidas por código marginalmente diferente e ainda alguns grupos funcionalmente vazios.
Editar o código acima tinha vários bugs, não apenas que ele não removesse os objetos brancos. Eu também hackeei algo para lidar com grupos vazios e grupos contendo apenas 1 elemento. É feio, mas aqui está mesmo assim.
import xml.etree.cElementTree as ET
import hashlib as hash
import copy
def get_attr(obj,attr):
try:
return obj.attrib[attr]
except KeyError:
return None
else:
return None
def iter_groups(group):
global hashlist
global count
rem=[]
for child in group:
if child.tag==rtag+'g' :#we have a group
iter_groups(child)
else:
if child.tag==rtag+'path':
h=hash.md5(str(child.attrib)).hexdigest()
print h
if h in hashlist:
rem.append(child)
print "removing ",child.tag, "in",group.tag,group.attrib," -- duplicate"
count+=1
else:
if get_attr(child,'fill')!=None:
if ("rgb(255,255,255)") in child.attrib['fill']:
print "removing ",get_attr(child,'id'), "in",group.tag,group.attrib," -- white"
rem.append(child)
else:
hashlist.append(h)
for r in rem:
print "about to remove",r.attrib
group.remove(r)
rem=[]
for child in group:
if child.tag==rtag+'g' :#we have a group
if len(child.findall('*'))==0:
print "removing ",child.tag, "in",group.tag,group.attrib," -- empty"
rem.append(child)
for r in rem: group.remove(r)
def ungroup_singles(group):
global count
for child in group:
#print child.tag,rtag
if child.tag==rtag+'g' :#we have a group
print "len(group",get_attr(child,'id'),")",len(child)
if len(child)>1:
ungroup_singles(child)
else :
if len(child)==1:
if (len(child[0])>=1)or(child[0].tag<>rtag+'g'):
print "about to promote",child[0].tag,get_attr(child[0],'id'),get_attr(child[0],'class')
print len(child[0])
moveelem=copy.deepcopy(child[0])
group.append(moveelem)
group.remove(child)
count+=1
else:
print "about to remove",child[0].tag,get_attr(child[0],'id'),get_attr(child[0],'class')
child.remove(child[0])
count+=1
else:#i.e. len(child)==0
print "about to remove",child.tag,get_attr(child,'id'),get_attr(child,'class')
group.remove(child)
count+=1
#else:
# if gl==1:#and not clipped?
#moveelem= ET.copy.deepcopy(child)
#main#
hashlist=[]
count=0
ET.register_namespace("","http://www.w3.org/2000/svg")
tree = ET.parse('imgtest_l.svg')
root = tree.getroot()
rtag= root.tag.split('}')[0]+'}'
iter_groups(root)
print "A", count," elements removed"
lcount=1
while True:
count=0
ungroup_singles(root)
print lcount,":",count," empty groups removed / single elements promoted from groups"
lcount+=1
if count==0 or lcount>10:
break
tree.write('imgtest_out.svg',encoding="us-ascii", xml_declaration=True, default_namespace="", method="xml")