Page 2 of 4

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Tue Jun 21, 2016 5:46 am
by Peter.Kenyon
well I guessed that it was a typo on the backing field, the ability to replace the function with a simple assignment is a powerful tool ?, (adults only coding)
@platforma : similar in backlight I believe
ps got the ghi n18 up and running, had to configure the spi correctly and init is different (as you point out)

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Tue Jun 21, 2016 11:32 am
by platforma
Thanks for pointing out the bug! Now fixed. Also looking into the suggested font techniques.

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 7:25 am
by Peter.Kenyon
wrt fonts one technique I found quite useful is to store bitmap images of antialiased fonts on the sd card,.
This presupposes you know the background color and foreground color, but there is plenty of room for lucida green 24 say and Helvetica alice blue 12, and nowadays most displays should be uncluttered on a neutral background (black)
The file contains all the glyphs and on init you rip thro and build up a seek table for the character.
To display a character just seek to the offset, set the window to the cx and cy and then blit the rgb565 chars.
here is a snippet...

Code: Select all

def draw_image(f,x,y):
    print("need to read the header and then blit to the screen")
    print(f, x, y)

# static helper to store/cache the fonts
class Fonts:

    _segoe14 = None
    _segoe16 = None
    _segoe24 = None
    _segoe36 = None

    @staticmethod
    def Segoe14():
        if Fonts._segoe14 is None:
            Fonts._segoe14 = Font('segoe-14.gff')
        return Fonts._segoe14

    @staticmethod
    def Segoe16():
        if Fonts._segoe16 is None:
            Fonts._segoe16 = Font('segoe-16.gff')
        return Fonts._segoe16

    @staticmethod
    def Segoe24():
        if Fonts._segoe24 is None:
            Fonts._segoe24 = Font('segoe-24.gff')
        return Fonts._segoe24

    @staticmethod
    def Segoe36():
        if Fonts._segoe36 is None:
            Fonts._segoe36 = Font('segoe-36.gff')
        return Fonts._segoe36

    @staticmethod
    def Load():
        # preload fonts we want to avoid delays - can take some time
        Fonts.Segoe14()
        Fonts.Segoe16()
        Fonts.Segoe24()
        Fonts.Segoe36()


class Font(object):

    def __init__(self, filename):
        # save the filename for multiple use
        self._filename = filename
        # open read glpyh info and close
        with open(filename, 'rb') as f:
            # generate lookup table - takes a little while
            self.table = {}
            index = 0
            for c in range(32, 127):
                r = f.seek(index)
                header = f.read(4)
                w = header[0]*256 + header[1]
                h = header[2]*256 + header[3]
                self.table[chr(c)] = (w,h,index)
                index += 6 + w * h * 2
        # save some meta data about this font
        self.emwidth, self.font_height = self.measure('M')
        self.line_height = self.font_height + 1  ## ??
        self.f = None

    def open(self):
        self.f = open(self._filename, 'rb')
        return self

    def release(self):
        if self.f:
            self.f.close()
            #del self.f
            self.f = None

    def __enter__(self):
        return self.open()

    def __exit__(self, type, value, traceback):
        self.release()

    def draw_text(self, x, y, text, align='left'):
        # check self.f is not None
        if not self.f:
            raise ValueError('draw_text not called in an open context')
        if align == 'center':
            w, h = self.measure(text)
            x -= w // 2
        elif align == 'right':
            w, h = self.measure(text)
            x -= w
        elif align != 'left':
            raise ValueError("align should be 'left', 'center' or 'right'")
        for c in text:
            w, h, index = self.table[c]
            self.f.seek(index)
            r = draw_image(self.f, x, y)
            x += w
        pass

    # doesnt require the file to be open to do this
    def measure(self, text):
        width, height = 0, 0
        for c in text:
            w, h, index = self.table[c]
            width += w
            height = max(height, h)
        return width, height

    def __del__(self):
        self.release()


Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 7:35 am
by deshipu
It's actually not that hard to blend an ant-ialiased font with an RGB pixel value, treating the original greymap as the alpha channel, and using any foreground color you want.

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 7:51 am
by Peter.Kenyon
I'm guessing that you could store a glyph table with byte values representing weight ie 255 is full on and 0 is transparent.
Then you could use a run time algortithm to blend into the background display, but sounds quite tricky and would need a backing buffer or are you suggesting something completely different

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 8:21 am
by deshipu
No, that's precisely what I meant by "alpha channel".

Sure, you either need a frame buffer, or a way to retrieve the pixels from the display itself (e.g. MISO wire connected) to be able to do blending -- after all, you need to know what pixels are there somehow. But you can also fall back to assuming a background color, and then you basically get the same thing you initially suggested.

As for being tricky, I'm not sure it's really that complex. I mean, Bresenham's line drawing algorithm is trickier, but everyone do it anyways.

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 8:34 am
by Peter.Kenyon
for efficiency I guess the glyph table would only need to be 2 or 4 bits per pixel,
Is it really as simple as : new pixel = ((1-weight) * old) + (weight*color) ??
Sounds like a challenge ;-)
Bresenham's line drawing algorithm is straightforward BUT not if you want to ant alias the jaggies

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Wed Jun 22, 2016 9:27 am
by deshipu
Peter.Kenyon wrote: Is it really as simple as : new pixel = ((1-weight) * old) + (weight*color)?
It can even be simpler, depending on the exact result desired:

Code: Select all

new pixel = min(limit, old + weight * color)
(yes, won't work for dark too well)

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Thu Jun 23, 2016 4:09 pm
by pythoncoder
Peter.Kenyon wrote:wrt fonts one technique I found quite useful is to store bitmap images of antialiased fonts on the sd card...
There is a potential performance issue here: performing a file random access for every character can be slow. I've used this approach for driving ePaper displays where the device is inherently slow, but found it to be a problem with faster displays. Hence my suggestion of writing a utility to convert a font to Python source (a bytes object plus a minimal amount of extra code such as font metrics) which can then be frozen as bytecode. In my testing this is provides performance with minimal ram usage.

Re: (WIP) Sitronix ST7735 TFT Display

Posted: Fri Jun 24, 2016 7:10 am
by Peter.Kenyon
good point, but not seen any problems yet, but only updating a few things now and again, not a scrolling console window or anything.