/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package feuille.drawing.svg; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import feuille.drawing.adf.LayerContent; /** * * @author The Wingate 2940 */ public class XmlVectorHandler { /* Structure à lire : * <?xml version="1.0" standalone="no"?> * <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> * <svg width="centimètres" height="centimètres" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> * <title>TITRE</title> * <desc>DESCRIPTION</desc> * <rect x="1" y="1" width="398" height="398" fill="none" stroke="blue" /> * <path d="M 100 100 L 300 100 L 200 300 z" fill="red" stroke="blue" stroke-width="3" /> * </svg> */ VectorHandler vh; public XmlVectorHandler(String path) throws ParserConfigurationException, SAXException, IOException{ SAXParserFactory fabrique = SAXParserFactory.newInstance(); SAXParser parseur = fabrique.newSAXParser(); File fichier = new File(path); //Crée un fichier de lecture temporaire (sans entête) : FileInputStream fis = new FileInputStream(fichier); BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF-8")); String newline; File file = new File(fichier.getParentFile(),"temp.svg"); FileOutputStream fos = new FileOutputStream(file); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8")); PrintWriter pw = new PrintWriter(bw); while((newline=br.readLine())!=null){ if(newline.contains("?xml")==false && newline.contains("!DOCTYPE")==false && newline.contains(".dtd")==false){ pw.println(newline); pw.flush(); } } pw.close(); bw.close(); fos.close(); br.close(); fis.close(); //--------------------------------------------------- vh = new VectorHandler(); parseur.parse(file, vh); file.delete(); } public VectorObject getVectorObject(){ return vh.getVectorObject(); } public class VectorHandler extends DefaultHandler{ //résultats de notre parsing private VectorObject vro; private LayerContent lc; private String currentPath, currentColor; //flags nous indiquant la position du parseur private boolean inDrawing, inLayer, inTranslate, inRect; //buffer nous permettant de récupérer les données private StringBuffer buffer; public VectorHandler(){ super(); } public VectorObject getVectorObject(){ return vro; } //détection d'ouverture de balise @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{ if(qName.equals("svg")){ vro = new VectorObject(); inDrawing = true; }else{ buffer = new StringBuffer(); if(qName.equals("path")){ lc = new LayerContent(); currentPath = attributes.getValue("d"); //d="PATH" currentColor = attributes.getValue("fill"); //fill="COLOR" inLayer = true; }{ //erreur, on peut lever une exception // throw new SAXException("Balise "+qName+" inconnue."); } } } //détection fin de balise @Override public void endElement(String uri, String localName, String qName) throws SAXException{ if(qName.equals("svg")){ inDrawing = false; }else{ if(qName.equals("path")){ lc.setName(""); lc.fromHTMLColor("0000FF");//currentColor lc.setAssCommands(SVGtoASS(currentPath)); vro.addLayer(lc); buffer = null; inLayer = false; }else{ //erreur, on peut lever une exception // throw new SAXException("Balise "+qName+" inconnue."); } } } //détection de caractères @Override public void characters(char[] ch,int start, int length) throws SAXException{ String lecture = new String(ch,start,length); if(buffer != null) { buffer.append(lecture); } } //début du parsing @Override public void startDocument() throws SAXException { // System.out.println("Début du parsing"); } //fin du parsing @Override public void endDocument() throws SAXException { // System.out.println("Fin du parsing"); // System.out.println("Resultats du parsing"); // for(ParticleObject p : lpo){ // System.out.println(p); // } } //====================================================================== // Retraitement des données //====================================================================== private String SVGtoASS(String SVGpath){ String assCommands = SVGpath; // String assCommands = SVGpath.toLowerCase(); // if(assCommands.contains("h")){ // assCommands = assCommands.replaceAll("h", "l"); // } // if(assCommands.contains("v")){ // assCommands = assCommands.replaceAll("v", "l"); // } // if(assCommands.contains("c")){ // assCommands = assCommands.replaceAll("c", "b"); // } // if(assCommands.contains("z")){ // assCommands = assCommands.replaceAll("z", "c"); // } //Remplace deux espaces par un espace while(assCommands.contains(" ")){ assCommands = assCommands.replaceAll(" ", " "); } //Remplace les chiffres à virgule par des entiers while(assCommands.contains(".")){ String start = assCommands.substring(0, assCommands.indexOf(".")); int next1, next2; String end = ""; try{ next1 = assCommands.indexOf(" ", assCommands.indexOf(".")); next2 = assCommands.indexOf(",", assCommands.indexOf(".")); int next = next1<next2 ? next1 : next2; if(next1 == -1){ next = next2; } if(next2 == -1){ next = next1; } end = assCommands.substring(next); }catch (IndexOutOfBoundsException ex){ } assCommands = start + end; } //Remplace les virgules des coordonnées par des espaces if(assCommands.contains(",")){ assCommands = assCommands.replaceAll(",", " "); } List<String> SVGTags = getCleanSVGTags(assCommands); String verylast = "", first, second, last, close, newCommands = ""; for(String tag : SVGTags){ //Parser pour le MoveTo en absolu if(tag.contains("M")){ Pattern p = Pattern.compile("M?\\s?(-*\\d+\\s+-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ newCommands = newCommands.isEmpty() ? "m " + m.group(1) : newCommands + " m " + m.group(1); verylast = m.group(1); //Point } } //Parser pour le MoveTo en relatif if(tag.contains("m")){ Pattern p = Pattern.compile("m?\\s?(-*\\d+\\s+-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int x = getX(verylast), y = getY(verylast), xa = getX(m.group(1)), ya = getY(m.group(1)); newCommands = newCommands + " m " + (x+xa) + " " + (y+ya); verylast = (x+xa) + " " + (y+ya); //Point } } //Parser pour le LineTo en absolu if(tag.contains("L")){ Pattern p = Pattern.compile("L?\\s?(-*\\d+\\s+-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ newCommands = newCommands + " l " + m.group(1); verylast = m.group(1); //Point } } //Parser pour le LineTo en relatif if(tag.contains("l")){ Pattern p = Pattern.compile("l?\\s?(-*\\d+\\s+-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int x = getX(verylast), y = getY(verylast), xa = getX(m.group(1)), ya = getY(m.group(1)); newCommands = newCommands + " l " + (x+xa) + " " + (y+ya); verylast = (x+xa) + " " + (y+ya); //Point } } //Parser pour le Horizontal LineTo en absolu if(tag.contains("H")){ Pattern p = Pattern.compile("H?\\s?(-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int y = getY(verylast), xa = Integer.parseInt(m.group(1)), ya = y; newCommands = newCommands + " l " + xa + " " + ya; verylast = xa + " " + ya; //Point } } //Parser pour le Horizontal LineTo en relatif if(tag.contains("h")){ Pattern p = Pattern.compile("h?\\s?(-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int x = getX(verylast), y = getY(verylast), xa = Integer.parseInt(m.group(1)), ya = y; newCommands = newCommands + " l " + (x+xa) + " " + ya; verylast = (x+xa) + " " + ya; //Point } } //Parser pour le Vertical LineTo en absolu if(tag.contains("V")){ Pattern p = Pattern.compile("V?\\s?(-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int x = getX(verylast), xa = x, ya = Integer.parseInt(m.group(1)); newCommands = newCommands + " l " + xa + " " + ya; verylast = xa + " " + ya; //Point } } //Parser pour le Vertical LineTo en relatif if(tag.contains("v")){ Pattern p = Pattern.compile("v?\\s?(-*\\d+)"); Matcher m = p.matcher(tag); if(m.find()){ int x = getX(verylast), y = getY(verylast), xa = x, ya = Integer.parseInt(m.group(1)); newCommands = newCommands + " l " + xa + " " + (y+ya); verylast = xa + " " + (y+ya); //Point } } //Parser pour le CurveTo en absolu if(tag.contains("C")){ Pattern p = Pattern.compile("C?\\s?(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s*(z*Z*)"); Matcher m = p.matcher(tag); int count = 0; while(m.find()){ first = m.group(1); //Control point 1 si b ou point si l second = m.group(2); //Control point 2 si b ou rien si l last = m.group(3); //Point si b ou rien si l close = m.group(4); //Close si b ou rien si l if(verylast.equalsIgnoreCase(first) && second.equalsIgnoreCase(last)){ newCommands = newCommands + " l " + last; }else{ newCommands = newCommands + " b " + first + " " + second + " " + last; if(close.isEmpty()==false){ newCommands = newCommands + " c"; } } verylast = last; count += 1; } if(count>1 && newCommands.contains("b")){//Transformation en BSpline for(int i=0; i<count; i++){ int index = newCommands.lastIndexOf("b"); if (i==count-1){ newCommands = newCommands.substring(0, index) + "s" + newCommands.substring(index+1); }else{ newCommands = newCommands.substring(0, index) + "" + newCommands.substring(index+1); } } } } //Parser pour le CurveTo en relatif if(tag.contains("c")){ Pattern p = Pattern.compile("c?\\s?(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s*(z*Z*)"); Matcher m = p.matcher(tag); int count = 0; while(m.find()){ int x = getX(verylast), y = getY(verylast); int xa = getX(m.group(1))+x, ya = getY(m.group(1))+y; //Control point 1 int xb = getX(m.group(2))+xa, yb = getY(m.group(2))+ya; //Control point 2 int xc = getX(m.group(3))+xb, yc = getY(m.group(3))+yb; //Last close = m.group(4); //Close si b ou rien si l if(verylast.equalsIgnoreCase(xa + " " + ya) && (xb + " " + yb).equalsIgnoreCase((xc + " " + yc))){ newCommands = newCommands + " l " + xc + " " + yc; }else{ newCommands = newCommands + " b " + xa + " " + ya + " " + xb + " " + yb + " " + xc + " " + yc; if(close.isEmpty()==false){ newCommands = newCommands + " c"; } } verylast = xc + " " + yc; count += 1; } if(count>1 && newCommands.contains("b")){//Transformation en BSpline for(int i=0; i<count; i++){ int index = newCommands.lastIndexOf("b"); if (i==count-1){ newCommands = newCommands.substring(0, index) + "s" + newCommands.substring(index+1); }else{ newCommands = newCommands.substring(0, index) + "" + newCommands.substring(index+1); } } } } } assCommands = newCommands; //Vérifie et remplace les longues chaines de commandes par des courtes // List<String> tags = getCleanTags(assCommands); // String verylast = "", first, second, last, close, newCommands = ""; // for(String tag : tags){ // if(tag.contains("m")){ // Pattern p = Pattern.compile("m?\\s?(-*\\d+\\s+-*\\d+)"); // Matcher m = p.matcher(tag); // if(m.find()){ // verylast = m.group(1); //Point // newCommands = newCommands.isEmpty() ? m.group(0) : newCommands + " " + m.group(0); // } // } // if(tag.contains("l")){ // Pattern p = Pattern.compile("l?\\s?(-*\\d+\\s+-*\\d+)"); // Matcher m = p.matcher(tag); // if(m.find()){ // verylast = m.group(1); //Point // newCommands = newCommands + " " + m.group(0); // } // } // if(tag.contains("b")){ // Pattern p = Pattern.compile("b?\\s?(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s+(-*\\d+\\s+-*\\d+)\\s?(c?)"); // Matcher m = p.matcher(tag); // while(m.find()){ // first = m.group(1); //Control point 1 si b ou point si l // second = m.group(2); //Control point 2 si b ou rien si l // last = m.group(3); //Point si b ou rien si l // close = m.group(4); //Close si b ou rien si l // // if(verylast.equalsIgnoreCase(first) && second.equalsIgnoreCase(last)){ // newCommands = newCommands + " l " + last; // }else{ // newCommands = newCommands + " b " + first + " " + second + " " + last; // if(close.isEmpty()==false){ // newCommands = newCommands + " c"; // } // } // verylast = last; // } // } // } // assCommands = newCommands; return assCommands; } private List<String> getCleanTags(String assCommands){ //Crée un schéma (commande) List<String> sList = new ArrayList<String>(); String lastWords = assCommands; while(lastWords.indexOf("b")!=-1 | lastWords.indexOf("l")!=-1 | lastWords.indexOf("m")!=-1){ int[] ta = new int[3]; ta[0] = lastWords.indexOf("b"); ta[1] = lastWords.indexOf("l"); ta[2] = lastWords.indexOf("m"); int m = getSmaller(ta, true); if(m!=1){ int[] tb = new int[3]; tb[0] = lastWords.indexOf("b", m+1); tb[1] = lastWords.indexOf("l", m+1); tb[2] = lastWords.indexOf("m", m+1); int n = getSmaller(tb, true); if(n!=-1){ sList.add(lastWords.substring(m, n)); lastWords = lastWords.substring(n); }else{ sList.add(lastWords.substring(m)); lastWords = ""; } } } return sList; } private List<String> getCleanSVGTags(String assCommands){ //Crée un schéma (commande) List<String> sList = new ArrayList<String>(); String lastWords = assCommands; while(lastWords.indexOf("M")!=-1 | lastWords.indexOf("m")!=-1 | lastWords.indexOf("L")!=-1 | lastWords.indexOf("l")!=-1 | lastWords.indexOf("H")!=-1 | lastWords.indexOf("h")!=-1 | lastWords.indexOf("V")!=-1 | lastWords.indexOf("v")!=-1 | lastWords.indexOf("C")!=-1 | lastWords.indexOf("c")!=-1){ int[] ta = new int[16]; ta[0] = lastWords.indexOf("M"); ta[1] = lastWords.indexOf("m"); ta[2] = lastWords.indexOf("L"); ta[3] = lastWords.indexOf("l"); ta[4] = lastWords.indexOf("H"); ta[5] = lastWords.indexOf("h"); ta[6] = lastWords.indexOf("V"); ta[7] = lastWords.indexOf("v"); ta[8] = lastWords.indexOf("C"); ta[9] = lastWords.indexOf("c"); ta[10] = lastWords.indexOf("S"); ta[11] = lastWords.indexOf("s"); ta[12] = lastWords.indexOf("Q"); ta[13] = lastWords.indexOf("q"); ta[14] = lastWords.indexOf("T"); ta[15] = lastWords.indexOf("t"); int m = getSmaller(ta, true); if(m!=1){ int[] tb = new int[16]; tb[0] = lastWords.indexOf("M", m+1); tb[1] = lastWords.indexOf("m", m+1); tb[2] = lastWords.indexOf("L", m+1); tb[3] = lastWords.indexOf("l", m+1); tb[4] = lastWords.indexOf("H", m+1); tb[5] = lastWords.indexOf("h", m+1); tb[6] = lastWords.indexOf("V", m+1); tb[7] = lastWords.indexOf("v", m+1); tb[8] = lastWords.indexOf("C", m+1); tb[9] = lastWords.indexOf("c", m+1); tb[10] = lastWords.indexOf("S", m+1); tb[11] = lastWords.indexOf("s", m+1); tb[12] = lastWords.indexOf("Q", m+1); tb[13] = lastWords.indexOf("q", m+1); tb[14] = lastWords.indexOf("T", m+1); tb[15] = lastWords.indexOf("t", m+1); int n = getSmaller(tb, true); if(n!=-1){ sList.add(lastWords.substring(m, n)); lastWords = lastWords.substring(n); }else{ sList.add(lastWords.substring(m)); lastWords = ""; } } } return sList; } private int getSmaller(int[] table, boolean positive){ //On crée une list pour pouvoir les trier List<Integer> li = new ArrayList<Integer>(); for(int i = 0; i<table.length; i++){ li.add(table[i]); } //On effectue le tri Collections.sort(li, new Comparator() { @Override public int compare(Object o1, Object o2) { return ((Comparable) o1).compareTo(o2); } }); //On renvoie si possible une valeur positive if(positive==true){ for(int i : li){ if(i>=0){ return i; } } } //Ou alors on renvoie la première valeur return li.get(0); } private int getX(String coordinates){ String[] table = coordinates.split(" "); return Integer.parseInt(table[0]); } private int getY(String coordinates){ String[] table = coordinates.split(" "); return Integer.parseInt(table[1]); } } }