Continuando la riflessione di cui al post precedente, in cui abbiamo visto come recuperare le istruzioni fondamentali per la realizzazione di spostamenti sulla canvas (istruzione M in SVG), realizzazione di linee (istruzione L) e curve (istruzione C), siamo in grado di iniziare a tradurre le istruzioni SVG in Tkinter. Dobbiamo considerare pero' che, mentre in SVG possiamo tracciare il percorso <path> d=' nell'ambito della stessa istruzione, in Tkinter abbiamo delle primitive per la creazione di curve o figure che devono essere realizzate separatamente. Per avere un criterio unificatore, possiamo considerare l'attributo generico 'tag' dei widget, già visto in precedenza, che ci permetterà di usare più oggetti canvas simultaneamente, come fossero un solo oggetto.
E' necessario, prima di andare avanti, chiarire due aspetti. Uno riguarda la differenza tra le istruzioni SVG M, L, C e le corrispondenti minuscole. Le prime indicano riferimenti assoluti, le seconde riferimenti relativi. Nel primo caso vengono indicate le coordinate esatte, nel secondo gli spostamenti.
Altro chiarimento che vi devo riguarda il metodo usato nel post precedente per estrarre le informazioni dal path; la ricerca fatta con l'uso delle espressioni regolari avviene in tutta la stringa, prescindendo dall'ordine.
Pertanto la ricostruzione del tracciato è sicuramente affetta da errori, se non si tiene conto del punto corretto di inizio tracciato della nuova linea o curva.
Ciò detto, riprendiamo a lavorare sul file di estrazione, apportando le correzioni necessarie al codice.
#|/usr/bin/env python import re class SVG2Tk: import xml.etree.ElementTree as ET def __init__(self, file_s, file_out): self.file_s = open(file_s, 'r') self.file_out= open(file_out,'w') tree = SVG2Tk.ET.parse(file_s) root = tree.getroot() self.xmlrecur(root) self.file_out.close() file_in = open(file_out) self.tk_out = open('tk_out.txt','w') try: width=file_in.next() height=file_in.next() self.tk_out.write('width %sheight %s' % (width, height)) except Exception: print Exception while True: try: id_ = file_in.next() style = file_in.next() d = file_in.next() self.tk_out.write('id,' + id_) while len(d)>0: pattern1 = r'([M]{1}[\s]*[-\d]*[\.]?[\d]*[\,\s]?[-\d]*[\.]?[\d]*[\s]*)' matchObj = re.match(pattern1, d) if matchObj: string = matchObj.group() d=d.replace(string, "") s_string = re.split(r'[;\s]*',string) string = ','.join(s_string[:-1]) self.tk_out.write(string+'\n') pattern2 = r'([L]{1}[\s]*[-\d]*[\.]?[\d]*[\,\s]{1}[-\d]*[\.]?[\d]*[\s]*)' matchOb2 = re.match(pattern2, d) if matchOb2: string = matchOb2.group() d=d.replace(string, "") s_string = re.split(r'[;\s]*',string) string = ','.join(s_string[:-1]) self.tk_out.write(string+'\n') pattern3 = r'([C]{1}[\s]*)(([-\d]*[\.]?[\d]*[\,\s]{1}[-\d]*[\.]?[\d]*[\s]*){3})' matchOb3 = re.match(pattern3, d) if matchOb3: string = matchOb3.group() d=d.replace(string, "") s_string = re.split(r'[;\s]*',string) string = ','.join(s_string[:-1]) self.tk_out.write(string+'\n') pattern4 = r'([z]{1}[\s]*)' matchOb4 = re.match(pattern4, d) if matchOb4: string = matchOb4.group() d=d.replace(string, "") s_string = re.split(r'[;\s]*',string) string = ','.join(s_string[:-1]) self.tk_out.write(string+'\n') except Exception: print Exception self.tk_out.close() break def xmlrecur(self,x): for i in x: if set(['id','style','d']).issubset(i.attrib): self.file_out.write(i.attrib['id']) self.file_out.write('\n') self.file_out.write(i.attrib['style']) self.file_out.write('\n') self.file_out.write(i.attrib['d']) self.file_out.write('\n') elif set(['width','height']).issubset(i.attrib): self.file_out.write(i.attrib['width']) self.file_out.write('\n') self.file_out.write(i.attrib['height']) self.file_out.write('\n') else: self.xmlrecur(i) if __name__ == '__main__': app = SVG2Tk('EU-Italy.svg','out_xml.txt')
Le correzioni maggiori apportate al codice del post precedente riguardano:
- L'uso del solo metodo 'match' delle regular expression, perchè in questo particolare contesto vogliamo che la stringa corrispondente all'attributo 'd' sia consumata man mano che si trova la corrispondenza tra il modello e la prima parte della stringa. Ogni volta che si verifica l'abbinamento, la parte iniziale corrispondente della stringa viene cancellata e la procedura viene iterata fino a consumare tutta la stringa.
- Il file SVG sorgente usa solo i codici path M C e L maiuscoli e z minuscolo, per cui la ricerca della lettera iniziale si limita a queste consonanti. Per inciso la lettera z rappresenta il codice di chiusura della poligonale sul punto iniziale.
- In questa fase, e sempre in modo temporaneo, creiamo un nuovo file di appoggio, denominato tk_out.txt, in cui scriviamo le stringhe risultanti dalla rilettura del file out_file.txt che viene generato all'inizio. Le stringhe contengono elementi separati da ';' per maggiore agio nella successiva suddivisione. Tutto questo, bene inteso, fino alla stesura finale del codice.
Ci stiamo progressivamente avvicinando al momento della traduzione. Portate pazienza ancora un po'