Creating graphics to display - how to get at the colour codes?

I know this is a strange request, but presumably others have had to do it at some time.

I want to draw some graphics on a 320x240 TFT screen (via ESP32-S3 board) - which i can do fine, given the x, y, and colour code.

So How do I easily go about drawing a graphic - then extracting the colour code I need at each position?

I can do it on a piece of graph paper - manually - but has anyone got a tool or bit of code that will read and output these coordinates form a .bmp, gif or jpg?

Not sure I understand that question, because normally these sorts of displays are write only.

So you can't read back what you have written. The only way would be to make a note of each pixel's colour as you write it in an array.

Or if your display writes a whole buffer at once you can extract this from this buffer before or after you write it to the display.

Is it what you want - to draw a .bmp file to the TFT screen? If so - most of graphics libraries has a method for it.

For example, for AdafruitGFx library the method called drawBitmap()

1 Like

Sorry - probably not that clear. I want to create graphics - but first need to draw them out using Paint, PShop etc, - then need the x, y, colour to use in the code to draw them onto the screen. Can do manually - the long winded way but hoped there may be a utility that opened a graphic file - and output me a set of coordinates and colour to use

No I can do the drawing to the screen - I want to design some graphics, then get the list of x,y,colour to use in the code to do the drawing on the screen.

sure, there are a dozen such utilites...
http://www.rinkydinkelectronics.com/t_imageconverter565.php

Surely, from Paint, PShop, or whatever you just save as a graphic file, and then your graphics library will display that file - as @b707 said.

EDIT

Or are you looking for a GUI designer?

How are you going to use this list of coordinates in your code? Manually type it into a sketch? Nobody does that.
There are two main ways - either you directly read the graphic file from the SD card or internal storage and display it on the screen, or you convert the graphics into an array of points, which is again saved in the file and used during compilation.
For the second way look at the link I gave in the post above

1 Like

b707 - Thank you so much - yes that link is exactly what I need. I'm new to embedded coding - and so far have been manually entering coordinates and using drawPixel commands. Using an ESP-S3-BOX-Lite so no card reader - so need to get the coordinates in there somehow.

This is great Thank You.

On ESP32 you can use internal flash as a filesystem. Google LiitleFS

The arduino libraries I'm using won't display files - need to be Drawn with the Draw commands.

Thanks b707 - I'll certainly look at that.

Hi @PhilMonfie,

not sure if I understand you correctly ... But if you are looking for a way to create graphics and read coordinates as well as color information you might have a look at inkscape:

https://inkscape.org/

It's a free vector graphics designer. To get a list of x,y, colour you may work as follows:

  • Download and start inkscape on your computer
  • Open the document properties
  • Use format "mm"
  • Change width to 320
  • Change height to 240
  • Make sure that the picture rulers show "mm" raster
  • Create your picture using the vector tools
  • Save as SVG
  • Open the SVG with a text editor (e.g. notepad++)

Here a simple example:

In the SVG file you'll find

  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <rect
       style="fill:#00ff00;stroke-width:0.354184"
       id="rect1"
       width="100"
       height="100"
       x="20"
       y="20" />
    <rect
       style="fill:#0000ff;stroke-width:0.433788"
       id="rect1-2"
       width="150"
       height="100"
       x="150"
       y="20" />
    <circle
       style="fill:#ff0000;stroke-width:0.343797"
       id="path4"
       cx="140.00002"
       cy="190"
       r="40" />
  </g>

Easy to read:

  • rectangle color Green (RGB -> #00ff00), upper left corner ( 20, 20), width and height (100,100)
  • rectangle color Blue (RGB -> #0000ff), upper left corner (150, 20), width and height (150,100)
  • circle color Red (RGB -> #ff0000), center x,y (140,190), radius (40)

If you are familiar with Freepascal/Lazarus or Python or the like you could even write a little program that might parse the SVG and convert it to the corresponding Arduino C++ drawing statements ... :wink:

But there are plenty which will - why not use one?

https://javl.github.io/image2cpp/

1 Like

ec2021 - thanks that's a useful way of doing some of the images - thanks very much

@xfpd - that's brilliant - just what I need - just a shame it's only mono and not using colour codes, but I can use it for most of the job.

Thanks very much

@awneil If you could suggest one that will work with the ESP32-S3-Box-Lite then I'll definitely look at using it. Preferably with some sample code. I am relatively new to embedded coding, and been trawling forums for days asking for such a thing - but found.nothing

Just for the fun of it:

This Python script reads SVGs created with inkscape (only tested with a few ... :wink: ) and creates C++ statements that can be copied into Arduino sketches. It uses the function tft.color565() to convert from 24 Bit (888) to the 16 Bit (565) color format of the ILI9341 display.

#!/usr/bin/python3

from xml.dom import minidom

svg_file = 'inkscape.svg'
doc = minidom.parse(svg_file)


def isFilled(line):
    if 'fill:none' in line:
        return False
    else:
        return True

def getFillColor(line):
    line = line.upper()
    red   = '(0x'+line[6:8]
    green = ',0x'+line[8:10]
    blue  = ',0x'+line[10:12]+')' 
    return 'tft.color565'+red+green+blue

def getStrokeColor(line):
    p = line.find('stroke:')+8
    line = line.upper()
    red   = '(0x'+line[p:p+2]
    green = ',0x'+line[p+2:p+4]
    blue  = ',0x'+line[p+4:p+6]+')' 
    return 'tft.color565'+red+green+blue


def roundCoord(coord):
    return round(float(coord))

rects = doc.getElementsByTagName('rect')
for rect in rects:
    x = roundCoord(rect.attributes['x'].value)
    y = roundCoord(rect.attributes['y'].value)
    w = roundCoord(rect.attributes['width'].value)
    h = roundCoord(rect.attributes['height'].value)
    c = rect.attributes['style'].value
    if isFilled(c):
        cl = getFillColor(c)
        print('tft.fillRect(',x,',',y,',',w,',',h,',',cl,');')
    else:
        cl = getStrokeColor(c)
        print('tft.drawRect(',x,',',y,',',w,',',h,',',cl,');')

circles = doc.getElementsByTagName('circle')
for circle in circles:
    cx = roundCoord(circle.attributes['cx'].value)
    cy = roundCoord(circle.attributes['cy'].value)
    r =  roundCoord(circle.attributes['r'].value)
    c =  circle.attributes['style'].value
    if isFilled(c):
        cl = getFillColor(c)
        print('tft.fillCircle(',cx,',',cy,',',r,',',cl,');')
    else:
        cl = getStrokeColor(c)
        print('tft.drawCircle(',cx,',',cy,',',r,',',cl,');')
        
doc.unlink()

I prepared also a small demo on Wokwi that contains an example file and explanation how to use it. As the extension ".svg" is not allowed I used ".txt" instead for the vector drawing.

See https://wokwi.com/projects/378850204953865217

The sketch (not very impressive by itself):

/*

  Forum: https://forum.arduino.cc/t/creating-graphics-to-display-how-to-get-at-the-colour-codes/1179354
  Wokwi: https://wokwi.com/projects/378850204953865217

*/

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
  tft.begin();
  tft.fillScreen(ILI9341_WHITE);
  tft.setRotation(1);
  drawGraphics();
}


void loop(void) {
}

void drawGraphics() {
  // Output of the Python Script to be copied here
  tft.fillRect( 20, 20, 100, 100, tft.color565(0x00, 0xFF, 0x00) );
  tft.fillRect( 150, 20, 150, 100, tft.color565(0x00, 0x00, 0xFF) );
  tft.fillRect( 20, 120, 280, 5, tft.color565(0xD4, 0xAA, 0x00) );
  tft.drawRect( 60, 75, 175, 110, tft.color565(0xE1, 0x00, 0x00) );
  tft.fillCircle( 140, 190, 40, tft.color565(0xFF, 0x00, 0x00) );
}

Just as a proof of concept, not comprehensive but it is possible to extend the conversion e.g. for line drawings.

Good luck!

P.S.: Just an addition to the Python script. As Adafruit_GFX does not support ellipses but those my be a part of the SVG I added ellipses and substitute them by RoundRect which is not the same but at least shows something "similar" :wink:

Python Script
#!/usr/bin/python3

from xml.dom import minidom

svg_file = 'inkscape2.svg'
doc = minidom.parse(svg_file)


def isFilled(line):
    if 'fill:none' in line:
        return False
    else:
        return True

def getFillColor(line):
    line = line.upper()
    red   = '(0x'+line[6:8]
    green = ',0x'+line[8:10]
    blue  = ',0x'+line[10:12]+')' 
    return 'tft.color565'+red+green+blue

def getStrokeColor(line):
    p = line.find('stroke:')+8
    line = line.upper()
    red   = '(0x'+line[p:p+2]
    green = ',0x'+line[p+2:p+4]
    blue  = ',0x'+line[p+4:p+6]+')' 
    return 'tft.color565'+red+green+blue


def roundCoord(coord):
    return round(float(coord))

rects = doc.getElementsByTagName('rect')
for rect in rects:
    x = roundCoord(rect.attributes['x'].value)
    y = roundCoord(rect.attributes['y'].value)
    w = roundCoord(rect.attributes['width'].value)
    h = roundCoord(rect.attributes['height'].value)
    c = rect.attributes['style'].value
    if isFilled(c):
        cl = getFillColor(c)
        print('tft.fillRect(',x,',',y,',',w,',',h,',',cl,');')
    else:
        cl = getStrokeColor(c)
        print('tft.drawRect(',x,',',y,',',w,',',h,',',cl,');')

circles = doc.getElementsByTagName('circle')
for circle in circles:
    cx = roundCoord(circle.attributes['cx'].value)
    cy = roundCoord(circle.attributes['cy'].value)
    r =  roundCoord(circle.attributes['r'].value)
    c =  circle.attributes['style'].value
    if isFilled(c):
        cl = getFillColor(c)
        print('tft.fillCircle(',cx,',',cy,',',r,',',cl,');')
    else:
        cl = getStrokeColor(c)
        print('tft.drawCircle(',cx,',',cy,',',r,',',cl,');')
        

ellipses = doc.getElementsByTagName('ellipse')
for ellipse in ellipses:
    cx = roundCoord(ellipse.attributes['cx'].value)
    cy = roundCoord(ellipse.attributes['cy'].value)
    rx =  roundCoord(ellipse.attributes['rx'].value)
    ry =  roundCoord(ellipse.attributes['ry'].value)
    c =  ellipse.attributes['style'].value
    if isFilled(c):
        cl = getFillColor(c)
        print('tft.fillRoundRect(',cx-rx,',',cy-ry,',',2*rx,',',2*ry,',',abs(rx-ry),',',cl,');')
    else:
        cl = getStrokeColor(c)
        print('tft.drawRoundRect(',cx-rx,',',cy-ry,',',2*rx,',',2*ry,',',abs(rx-ry),',',cl,');')


doc.unlink()

Search "bmp file format" for tips on writing an application to deconstruct a BMP.
The BMP Wiki.
Reading and writing BMP images.