Bangle.js screenshots

Posted on
  • We finally have a way of doing screenshots! I'm interested to see what you think, but if you paste this code into the IDE:

    function screenshot(draw) {
      var _g = g;
      Bluetooth.print("data:image/bmp;base64,");
      var l = 26/*header length*/ + 240*3;
      var data = E.toString([66,77,l&255,l>>8, // 0
                    0,0,0,0,0,0,      // 4
                    26,0,0,0,         // 10
                    12,0,0,0,240,0,240,0,1,0,24,0]); // 14
    
      var b = Graphics.createArrayBuffer(240,1,24);
      g = Graphics.createCallback(240,240,16,{
          setPixel:function(x,y,c) { b.setPixel(x,y-yo,((c&0xF800)<<8) | ((c&0x7E0)<<5) | ((c&0x1F)<<3)); },
          fillRect:function(x1,y1,x2,y2,c) { b.setColor(((c&0xF800)<<8) | ((c&0x7E0)<<5) | ((c&0x1F)<<3)).fillRect(x1,y1-yo,x2,y2-yo); }
        });
      g.flip = function(){};
      var t = getTime(), t2=t;
      for (var yo=239;yo>=0;yo--) {
        g.setClipRect(0,yo,239,yo);
        b.clear();
        t2 += getTime()-t;setTime(t);
        draw();
        var n = 0;
        while (data.length%3) data += String.fromCharCode(b.buffer[n++]);
        Bluetooth.print(btoa(data));
        data = E.toString(b.buffer).substr(n);
      }
      setTime(t2);
      Bluetooth.println(btoa(data));
      g = _g;
    }
    

    And then, assuming your app has a function called draw that redraws the entire screen, you call screenshot(draw) in the IDE, you should get a screenshot.

    It's very slow - you're looking at multiple minutes per screen because it's having to re-render the image for every line of pixels.

    Still, it is a way of getting screenshots out of Bangle.js!

  • Nice, and using setTime is a nice touch.
    Why can't it use getPixel to get a "real" screenshot?

  • Why can't it use getPixel

    The LCD in the Bangle is write-only, with no offscreen buffer (there's not enough RAM).

    It's a shame, because otherwise it would have been trivial to get screenshots!

  • actually the st7789 has read functionality, at least with SPI it worked for me some time ago on P8 watch, when checking datasheet (e.g. https://www.crystalfontz.com/controllers/Sitronix/ST7789V/ ) there are timing diagrams of both write and read operations also for the 8bit mode - page 52. Can be tricky and may not be worth it for getPixel due to speed (or maybe yes) but for making screenshot it could be used. Or is there some unidirectional level shifter/buffer between nrf52 gpio and lcd so that those 8 data pins cannot be switched from output to input temporarily?

    EDIT: oh maybe the RDX pin is not available. The diagram shows while writing you toggle WRX pin (which may be the the pin_sck in BANGLEJS.py)but there is also separate RDX pin to allow reading and that one may not be connected :-(

  • st7789 has read functionality ... oh maybe the RDX pin is not available.

    Sadly I think that is the case :( Every IO on the nRF52 chip is accounted for at https://www.espruino.com/Bangle.js+Technical

    I guess it could be on the IO expander, but I can guarantee that the original firmware didn't use any other IOs

    I'd love to be proven wrong though, so if you do find a way to make it work let us know!

  • Hi, on a follow up, here's the script for the bangle.js2 with adjustments to the dimensions:

        function screenshot(draw) {
          var _g = g;
          Bluetooth.print("data:image/bmp;base64,");
          var l = 26/*header length*/ + 176*3;
          var data = E.toString([66,77,l&255,l>>8, // 0
                        0,0,0,0,0,0,      // 4
                        26,0,0,0,         // 10
                        12,0,0,0,176,0,176,0,1,0,24,0]); // 14
          var b = Graphics.createArrayBuffer(176,1,24);
          g = Graphics.createCallback(176,176,16,{
              setPixel:function(x,y,c) { b.setPixel(x,y-yo,((c&0xF800)<<8) | ((c&0x7E0)<<5) | ((c&0x1F)<<3)); },
              fillRect:function(x1,y1,x2,y2,c) { b.setColor(((c&0xF800)<<8) | ((c&0x7E0)<<5) | ((c&0x1F)<<3)).fillRect(x1,y1-yo,x2,y2-yo); }
            });
          g.flip = function(){};
          var t = getTime(), t2=t;
          for (var yo=175;yo>=0;yo--) {
            g.setClipRect(0,yo,175,yo);
            b.clear();
            t2 += getTime()-t;setTime(t);
            draw();
            var n = 0;
            while (data.length%3) data += String.fromCharCode(b.buffer[n++]);
            Bluetooth.print(btoa(data));
            data = E.toString(b.buffer).substr(n);
          }
          setTime(t2);
          Bluetooth.println(btoa(data));
          g = _g;
        }
    
    
  • Hi @diego - on Bangle 2 you just type g.dump(); in the left hand side of the IDE and it does a screenshot really quickly, its built in. Sorry to bring that news :)

  • Well, ain't that something? And so much faster! Somehow I missed that, thanks!

  • Would be great to have that available as a button on the Web IDE to make it more visible for users.

  • I agree, or maybe using the keyword screenshot on the documentation, a search for bangle/espruino + screenshot could only find this forum post.

  • I'll add a heading called 'screenshots' to the Bangle.js 2 page - that should then go into the keywords when people search

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

Bangle.js screenshots

Posted by Avatar for Gordon @Gordon

Actions