Preamble
Let machine do the dirty work. To continue what I started in last post, I tried to see if it is possible to parse the SVG file and generate arduino sketch code out of it. The answer is yes. There is a wonderful post and a SVG Optimiser which helps me greatly for this project.
Parse the SVG file with the powerful lxml to generate an element tree
1 2 3 4 5 |
from lxml import etree import re tree = etree.parse(open(svg_file.svg)) |
Parsing out the Vector parameters needed for your GUI.
The rest is to loop through element tree to search tags (line, text, rect or polygon etc ) and their attributes and properties needed for GUI construction. Following is an example for rectangle. Elements.get is your friend. RegEX will be needed also to extract some of the them.
1 2 3 4 5 6 |
for element in tree.iter(): if element.tag.split("}")[1] == 'rect': #remove namespace prefix from the element print(element.tag) #will generate sth like x=float(element.get('x') |
Arduion sketch code can be generated as following.
I writes the setup and loop code in two different files, and combined them later. Of course you needed to modify them based on your Arduion Graphic library. Following is to draw the rectangle.
1 2 3 4 5 6 7 8 9 10 11 12 |
#generate code for TFT display f_setup.write("tft.drawRect("+element.get("x")+","+element.get("y")+","+ element.get("width")+","+element.get("height")+","+RBG24to16(element.get("stroke"))+ ")"+";") f_setup.write(" //"+element.tag.split("}")[1]+" --> "+'"'+element.get("id")+'"'+" with color "+element.get("stroke")+"\n") if 'id' in element.attrib else f_setup.write(" //rect -->"+' "'+" no-id"+'"'+" with color "+element.get("stroke") + "\n") #generate the code for touch screen ymin=str(int(float(element.get("y")))+4) ymax=str(int(float(element.get("y"))+float(element.get("height")))-4) xmin=str(int(float(element.get("x"))+4)) xmax=str(int((float(element.get("x"))+float(element.get("width"))))-4) f_loop.write("if (p.y >"+ymin+" && p.y < "+ymax+" && p.x > "+xmin+" && p.x < "+xmax+")"+"{"+"\n"+"\t//put code here\n") f_loop.write("\tSerial.println("+'"'+"You have pressed "+element.tag.split("}")[1]+" --> "+ element.get("id") +" with color "+element.get("stroke")+'"'+");\n") if 'id' in element.attrib else f_loop.write("\tSerial.println("+'"'+"You have pressed "+"rect -->" +" no-id"+" with color "+element.get("stroke") +'"'+ ");\n") |
and, fill the rectangle if needed. You can also adding padding between the border and inner filling border. There is no discrimination between stroke and fill in most Arduion graphic library.
1 2 3 4 5 6 7 8 |
if ('fill' in element.attrib) and not (element.get("fill")=="none"): #for filled Rect f_setup.write("tft.fillRect("+str(float(element.get("x"))+gap)+","+str(float(element.get("y"))+gap)+","+ str(round((float(element.get("width"))-gap*2),1))+","+str(round((float(element.get("height"))-gap*2),1))+"," +rx+","+RBG24to16(element.get("fill"))+ ")"+";\n") #round to remove excessive decimal place when width and height are caculated. f_loop.write("\ttft.fillRect("+str(float(element.get("x"))+gap)+","+str(float(element.get("y"))+gap)+","+ str(float(element.get("width"))-gap*2)+","+str(round((float(element.get("height"))-gap*2),1))+"," +rx+"," + RBG24to16('#ffffff')+ ")"+";\n") f_loop.write("\tdelay(500)"+";\n") f_loop.write("\ttft.fillRect("+str(float(element.get("x"))+gap)+","+str(float(element.get("y"))+gap)+","+ str(float(element.get("width"))-gap*2)+","+str(float(element.get("height"))-gap*2)+"," +rx+","+RBG24to16(element.get('fill'))+ ")"+";\n") f_loop.write("\t}" +"\n") |
A few tricks needed for the rough corners.
-
Color code convertion Arduino only takes 16 bits RGB565, not 24bit RGB888 provided by SVG. Following function takes care of it.
1234567891011def RBG24to16(value):""" convert from RBG888 24 bit to RGB565 16 bittake in the red, green and blue values (0-255) as 8 bit values and then combineand shift them to make them a 16 bit hex value in 565 format. """value = value.lstrip('#')lv = len(value)rgb = tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))hex = "0x%0.4X" % ((int(rgb[0] / 255 * 31) << 11) | (int(rgb[1] / 255 * 63) << 5) | (int(rgb[2] / 255 * 31)))return hex - There is no round Rectangle in Adobe Illustrator, what I did to to add a roundRect id tag, and add a rounded corner by adding a rx.
- Polygon is tough to handle. You only need to deal with triangle anyway, which is not bad. Remember us polygon tool, NOT star tool though.
-
Text properties is wrapped in matrix, use RegEx.
123456789matrix=element.get("transform")list = ((re.search("\(([^)]+)\)" ,element.get("transform"))).group(1)).split() #split the numbers between () based on spacex=list[4]x=str(round(float(x),0))y=list[5]y=str(round((float(y)-10),0)) #move 10 pixel up in arduinofontsize = str(float(element.get("font-size"))/6)
Let machine do the dirty work.
The SVG file:
and, Arduino code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
/*---------------Beginning of code for SETUP in Arduino Sketch------------------*/ tft.drawCircle(160,120,75,0x0000); tft.fillCircle(160,120,73.0,0xC180); tft.drawRect(141,161,41,14,0x07E0); //rect --> " no-id" with color #00FF00 tft.drawLine(146,138,154,147, 0x0000);//line --> noid with color #000000 tft.drawLine(154,147,162,138, 0x0000);//line --> noid with color #000000 tft.drawLine(162,138,169,147, 0x0000);//line --> noid with color #000000 tft.drawLine(169,147,178,138, 0x0000);//line --> noid with color #000000 tft.drawLine(178,138,186,147, 0x0000);//line --> noid with color #000000 tft.drawLine(146,138,136,147, 0x0000);//line --> noid with color #000000 tft.drawTriangle(172, 120, 190, 89, 207, 120,0x07E0); //polygon --> no-id with color #00FF00 tft.fillTriangle(174.0, 118.0, 190.0, 91.0, 205.0, 118.0, 0x0018); tft.drawTriangle(113, 121, 132, 88, 151, 121,0x0000); //polygon --> no-id with color #000000 tft.fillTriangle(115.0, 119.0, 132.0, 90.0, 149.0, 119.0, 0xF800); tft.drawTriangle(174, 17, 158, 45, 141, 17,0xC000); //polygon --> no-id with color #CC0000 tft.fillTriangle(172.0, 19.0, 158.0, 43.0, 143.0, 19.0, 0xFFE0); /*-------------------End of code for SETUP in Arduino Sketch------------------*/ /*----------------Beginning of code for LOOP in Arduino Sketch------------------*/ if (p.y >66 && p.y < 173 && p.x > 106 && p.x < 213){ //put code here Serial.println("You have pressed circle --> no-id with color #000000"); tft.fillCircle(160,120,73.0,0xC180); delay(500); tft.fillCircle(160,120,73.0,0xFFFF); } if (p.y >165 && p.y < 171 && p.x > 145 && p.x < 178){ //put code here Serial.println("You have pressed rect --> no-id with color #00FF00"); } if (p.y >89.0 && p.y < 120.0 && p.x > 172.0 && p.x < 207.0){ //put code here Serial.println("You have pressed polygan --> no-id with color #00FF00"); tft.fillTriangle(174.0, 118.0, 190.0, 91.0, 205.0, 118.0, 0xFFFF); delay(500); tft.fillTriangle(174.0, 118.0, 190.0, 91.0, 205.0, 118.0, 0x0018); } if (p.y >88.0 && p.y < 121.0 && p.x > 113.0 && p.x < 151.0){ //put code here Serial.println("You have pressed polygan --> no-id with color #000000"); tft.fillTriangle(115.0, 119.0, 132.0, 90.0, 149.0, 119.0, 0xFFFF); delay(500); tft.fillTriangle(115.0, 119.0, 132.0, 90.0, 149.0, 119.0, 0xF800); } if (p.y >17.0 && p.y < 45.0 && p.x > 141.0 && p.x < 174.0){ //put code here Serial.println("You have pressed polygan --> no-id with color #CC0000"); tft.fillTriangle(172.0, 19.0, 158.0, 43.0, 143.0, 19.0, 0xFFFF); delay(500); tft.fillTriangle(172.0, 19.0, 158.0, 43.0, 143.0, 19.0, 0xFFE0); } /*--------------------End of code for LOOP in Arduino Sketch------------------*/ |
Another Example with Menus
Postamble
In the last a few posts, I have covered what I call “The 3 Musketeers” for Arduino TFT GUI designed: the Adafruit Graphic Libarary, SVG Vector Design with Adobe Illustrator or Inkscape and Bitmap images from either C-array or from SD Cards. It is possible to design any GUI with these 3 friends in your hands. There is another GUI library which I like a lot, but I am having trouble fixing it.
NOV
About the Author:
Beyond 8 hours - Computer, Sports, Family...