• Hello,

    was trying to use fonts included in GT24L24A2Y SPI font chip, these chips are often used in smart watches and fitness trackers to provide fonts in many languages. Basically it is relatively normal SPI flash memory with font data is some format. Th structure of fixed width fonts for this chip is documented here https://github.com/RichardBsolut/GT24L24­A2Y I tried to read is as ordinary SPI flash via W25 module into Graphics.createArrayBuffer and it works and the description of offsets and sizes looks correct and I can see letters when I create buffer in correct format. However the buffer must be created with vertical_byte:true parameter. If I put the data directly into setFontCustom it is not looking good because it does not accept this vertical format.

    Any idea how to load/convert/rotate such font data in memory via some Espruino graphics/bitmap/image magic so I could then pass the buffer directly to setFontCustom ?

    I have attached screenshot how I can load individual letters of https://github.com/RichardBsolut/GT24L24­A2Y#font-clock-4-22x32

    And BTW here is video of example code running on this fittness tracker, it is mostly same as P8 smartwatch code linked previously here. This F07 is ~$14-$16 aliexpress item and can be updated to Espruino without taking apart.


    1 Attachment

    • Capture.PNG
  • ...next thing is a Femto Espruino with plug-able SPI chips like 40+ years ago the PC with 'user'-plug-able io/memory/what-ever cards... ;-)

  • Got it partly solved. I can at least draw it to screen letter by letter. I also mapped the fontchip as ordinary flash via SPIFLASH in board file so it is accesible via Flash module and it can be easily read. Then I found Graphics.asImage which works only when called with asImage("string") (not "object" due to vertical_byte:true ?) and I can draw it via drawImage. so e.g. to draw big digit "3" from the 40x64 font I do it like this:

    var f=require("Flash");
    var fg=Graphics.createArrayBuffer(40,64,1,{v­ertical_byte : true});
    fg.buffer=f.read(320,0x60000000+0x199e0e­+3*322);
    fg.buffer[0]=0;
    g.drawImage(fg.asImage("string"),0,0);
    

    So it works and I can make my own drawString letter by letter. May be even better for large clock numbers.

    Also looks like the first byte of each letter is real letter width so the font is in fact proportional (and I need to zero the data before drawing). Is there way to draw only part of larger image? The width is 40 but letter '1' is only 33 pixels wide. I don't see any way to take/draw only some part of the image both in Graphics.asImage and Graphics.drawImage. Maybe transparency could solve it too but there is no way to provide that either with asImage("string") or drawImage options.

  • Tried to avoid vertical_byte:true in final image to feed it to createCustomFont but it made no difference - still see random garbage. I made following method to convert it to single buffer which is not in vertical format

    function createFont(off,bs,w,h,c){
      var ptr=0x60000000+off;
      var f=require("Flash");
      var totw=w*c; // todo take from letters
      var font=Graphics.createArrayBuffer(totw,h,1­);
      var lg=Graphics.createArrayBuffer(w,h,1,{ver­tical_byte:true});
      var ll=lg.buffer.length;
      var x=0;
      for (var i=0;i<c;i++){
        lg.buffer=f.read(ll,ptr+i*bs);
        lw=lg.buffer[0];lg.buffer[0]=0;
        font.drawImage(lg.asImage("string"),x,0)­;
        x+= w;//(lw>0)?lw:w;
      }
      return font;
    }
    

    and the result is attached, but when creating font from it like this

    g.setFontCustom(ft.asImage("string"),32,­16,32)
    

    or this

    g.setFontCustom(E.toString(ft.buffer),32­,16,32)
    

    it is still not right so the format is still something else.


    1 Attachment

    • Capture.PNG
  • take a look at this online tool

    http://ebfc.mattbrailsford.com/

  • I know about it, not sure how it could help me in this case. I am trying to do it directly on the device on the fly as the data is already there. More helpful is this https://github.com/espruino/Espruino/blo­b/master/scripts/create_custom_font.js but still I didn't get what is correct format from that code.

    The page http://www.espruino.com/Fonts#custom-fon­ts says "You'll need a string containing a column-first, most significant bit first, 1 bit per pixel bitmap" which is still not enough for me to understand. Also when looking at font sources like https://github.com/espruino/Espruino/blo­b/master/libs/graphics/bitmap_font_6x8.c­ it looks like the data is in rows, not columns.

  • I guess I got it, fontchip has data in columns too but second byte is 8 bits from second column (= {vertical_byte:true})while espruino custom font array need all bytes of first column first an then second column starts. So i'll try to swap the bytes around and see.

  • @fanoush, I like our dedication to details... the challenges get you really going!

  • got it working, last catch was lsb to msb conversion (did via table, named M2L in code below)

    function createFont(off,bs,w,h,c,isprop){
      var ptr=0x60000000+off;
      var f=require("Flash");
      var hbytes=h>>3;
      var bmp=new Uint8Array(w*hbytes*c);
      var widths=isprop ? Uint8Array(c) : w;
      var bmpidx=0;
      for (var i=0;i<c;i++){
        var buff=f.read(bs,ptr+i*bs);
        var wprop=w;
        if (isprop){wprop=1+buff[0];widths[i]=wprop­;buff[0]=0;}
        var x,y;bi=0;
        for(y=0;y<hbytes;y++){
          for(x=0;x<wprop;x++)
            bmp[bmpidx+x*hbytes+y]=M2L[buff[bi+x]];
          bi+=w;
        }
        bmpidx+=wprop*hbytes;
        E.kickWatchdog();
      }
      if (isprop){
        return { font: E.toString(Uint8Array(bmp.buffer,0,bmpid­x)), widths: E.toString(widths)};
      }
      return { font: E.toString(bmp), widths: w};
    }
    

    then to set font https://github.com/RichardBsolut/GT24L24­A2Y#font-clock-2-34x48 I use it like

    fnt=createFont(0x19de96,206,34,48,14,tru­e)
    g.setFontCustom(fnt.font,0x30,fnt.widths­,48)
    

    however the code is a bit slow for fonts with more characters so I need to ping the watchdog

    and BTW found out that GT24L24A2Y is otherwise pretty normal 2MB SPI flash that I can write and erase and space over 0x1A3000 is empty so I could perhaps convert those fonts once and write back in better format to load them directly next time

  • Great! Glad you got it sorted! You can do msb:true when creating Graphics which might help you?

    It's possible that you could read the data with vertical_byte:true in one graphics, then blit to another Graphics with msb:true (and maybe rotation?) if you wanted something faster?

  • It could help for lsb to msb conversion but there is at least one other issue: there is no Graphics.createArrayBuffer format that would produce something that Graphics.setFontCustom would consume. Or at least I did not find one. The one with vertical_byte:true is the most similar (=uses columns) and is what the fontchip natively uses too but it is not the same, setFontCustom requires all bytes of first column first, while with vertical_byte:true it is not like that, there second byte contains pixels from second column. while setFontCustom wants in second byte pixels 8-15 of first column. So this is the longest operation here, switching order of same (column pixel) bytes around. So something like vertical_line instead of vertical_byte would be it.

    As for rotation, yes maybe this could do it after all in one extra step, render it from first one with vertical_byte to second one (already done in post #4 - the single bitmap with all letters, this rotates columns into rows) but also setup rotation on destination (so rows are written back to columns in correct order.) Not sure when the rotation is applied - if the bytes are indeed stored rotated or when later reading pixels from it, will check.

    Anyway the biggest issue for me was to understand format of data that Graphics.setFontCustom accepts, the rest is more clear now. There is even arm native library for this fontchip in some github procects (e.g. here or here) so I could use it to get all fonts out of it and with proper encoding. As maybe there are more fonts there than documented at https://github.com/RichardBsolut/GT24L24­A2Y

  • Ahh - I think this is what you need - this code creates the font in Graphics directly: https://github.com/espruino/EspruinoDocs­/blob/master/modules/Font5x7Numeric7Seg.­js

    var gr = Graphics.createArrayBuffer(H,digits.leng­th*W+2,1,{msb:true});
    gr.setRotation(3,1);
    //...
    var font = gr.asImage().buffer;
    var widths = E.toString(widths);
    g.setFontCustom(font, 46, widths, H);
    

    If there's somewhere you think I can improve the docs around setFontCustom let me know though - I know it's not great.

    I guess there's the possibility that something that renders direct from flash could be built into Graphics, or that setFontCustom could have extra options?

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

setFontCustom bitmap format vs vertical_byte:true - GT24L24A2Y fontchip in F07 fitness tracker

Posted by Avatar for fanoush @fanoush

Actions