background images

Posted on
  • I was wondering if it is possible (on bangje.js) to have a background image.
    E.g. can I create a clock that has a background watchface?
    The closest I could get it do use double buffering.
    Anyone a pointer/suggestion?

    E.g I want to create something like this watchface I have for my Mi Band:
    https://amazfitwatchfaces.com/mi-band-4/­view/2029
    Or a watch like background with the clock hands blitted on top of them.

  • There are some simple examples like the minion clock

    And in fact you can do a full res image - you just write it to Bangle.js's storage, and then blit it direct from flash with g.drawImage(require("Storage").read("myi­mg.img"))

    But there's no easy way to do flicker-free rendering since there's not enough RAM for a full-screen buffer. In your tux example there are areas of solid color, so nothing stops you from just drawing the image on its own and then rendering the clock areas separately.

    There are some options though:

    • Create an offscreen buffer with less bits per pixel. For instance use 2 bits - you can still specify custom colors for each of the 4 colors so could do something pretty interesting:

    b = Graphics.createArrayBuffer(240,240,2,{ms­b:true});
    for (var i=0;i<4;i++) {
      b.setColor(i);
      b.fillRect(10+30*i,10+30*i,100+30*i,100+­30*i);
    }
    var pal = new Uint16Array([
      0x0000,
      0xF800,
      0x001F,
      0xFFFF
    ]);
    g.drawImage({width:240,height:240,bpp:2,­palette:pal,buffer:b.buffer});
    
    • Create a low-res offscreen buffer:

    b = Graphics.createArrayBuffer(120,120,8,{ms­b:true});
    for (var i=0;i<128;i++) {
      b.setColor(i);
      b.fillRect(i,i,30+i,30+i);
    }
    g.drawImage({width:120,height:120,bpp:8,­buffer:b.buffer},0,0,{scale:2});
    
    • Or render in slices, but that could be slow to update. You could probably do pretty well with a combination of the 3 though - for instance 8 bit with a custom palette, also sliced such that you could update the time by changing just a few slices at once.


    I've been considering adding a composeImage function, if you think there's interest? Basically allowing you to render one image on top of another, so you could have a low-bpp Graphics instance with 0 as transparent, rendering on top of a 16 bit 240x240 image rendered direct from flash.

  • I tried to to this

    And in fact you can do a full res image - you just write it to
    Bangle.js's storage, and then blit it direct from flash with
    g.drawImage(require("Storage").read("myi­mg.img"))

    but I am missing the format of the .img file.
    I tried converting my png to a rgb565 image through https://online-converting.com/image/conv­ert2bmp/ but that file was not accepted
    "Uncaught Error: Expecting the first argument to be a valid image"
    Guess this is due to the .bmp header.
    Maybe it would be good to add a mode to http://www.espruino.com/Image+Converter allowing to convert to a .img file.

    Kind regards, Frans.

    PS: I could also not cut&paste my error message from the IDE left panel. Would be a nice enhancement too.

  • I could also not cut&paste my error message from the IDE left panel. Would be a nice enhancement too.

    It should work and is copied to clipboard automatically when you select block and release mouse button (unless it is very large). However it would be also nice if all output from left side could be automatically saved to some log file. Would help a lot with larger blocks that are too large for clipboard. Like e.g. dumping 4MB SPI flash memory via loop of btoa() calls :-)

  • Yes, you just use the image converter, but you'll end up with a reasonably sized file for a 240x240x16 image.

    The easiest way is actually to do it using the IDE. Click on the 3 disc 'storage' icon in the middle of the screen, click 'Upload', choose an image, then it'll be detected and will offer you some options to convert it.

    However it would be also nice if all output from left side could be automatically saved to some log file

    PRs are welcome ;)

  • Yes, you just use the image converter, but you'll end up with a
    reasonably sized file for a 240x240x16 image.

    The easiest way is actually to do it using the IDE. Click on the 3
    disc 'storage' icon in the middle of the screen, click 'Upload',
    choose an image, then it'll be detected and will offer you some
    options to convert it.

    Oh cool, didn't know it would ask for conversion when uploading so I was basically searching for the right image format and how to get to it.

    However it would be also nice if all output from left side could be automatically saved to some log file
    

    PRs are welcome ;)

    Done:
    https://github.com/espruino/Espruino/iss­ues/1813

  • By PR I meant actually a fix for it, rather than just posting a bug report on GitHub :) There's already an issue for it, it just needs someone to actually write some code to fix it.

  • Ah ok, for me PR stands for Problem Report, hence I just submitted a ticket.
    I'm not really versed in web coding, I'm more into embedded programming.

  • Ahh. Yeah, I tend to mean 'Pull Request' - so where someone submits a suggested change to the problem on GitHub :)

  • As we can drawImage() direct from Flash thanks to Storage.read() memory-mapping Flash, then other than performance and (I guess) rewrite cycle wear, is there any reason not to use Storage for storing offscreen buffers?

    For example, if I have a complicated clock-face redraw every minute (hour and minute hand update), I can Storage.write() it, and then drawImage() it every second during that minute and just slap the second hand on quickly.

    ...?

  • Not sure about the wear on the flash, but I would argue that you still would see a flickering clock face every seconds.

    As far as I understand: offscreen buffers are not drawn faster. In your case you would have to redraw the complete watch face every second because the (analog) watch hand moves. So between seconds you would need to redraw the area the hand has crossed to restore the watch face.

    Take a look at @Gordon s image clock
    It is not flickering because it only draws the background once and then for every second updates only a small (rectangular) part of the background where the time is being displayed.

    But I guess you could do something similar for your clock too.

  • At the moment, my beebclock draws the face and the hour and minute hands from scratch to an in-memory image every minute. Then it draws that image to the screen every second and then draws a line for the second hand. The only part that flickers is the second hand, which I think is acceptable. Otherwise, I think the power drain would just be too high, redrawing it all offscreen every second.

    The problem is that the 240x240 buffer is a memory hog even at 1bpp. Fortunately for my watch face I only wanted 1bpp, so I can just about manage to do it in available memory.

    1. The unchanging watch face in Flash
    2. The watch face blitted from (1) with hour/minute hands, updated every minute in Flash
    3. The in-memory offscreen buffer blitted with (2) and second hand added, and blitted to screen every second.

  • Incidentally, @Gordon... any chance of a double-buffered 240 x 240 x 1bpp display mode? That, combined with the suggested composeImage() function using Flash-backed images would allow for some very neat tricks. Colour is overrated. :)

    (It'd preclude widgets, I guess... unless support was added for monochrome widgets somehow)

  • I've actually added some big speed improvements in recent Bangle.js builds, so you can create a 1bpp offscreen buffer and then drawImage it and it should be almost as fast as a special display mode (while still being backwards compatible and working with widgets).

    For instance check out the T-Rex game now.

  • I'd say avoid writing an image that changes to flash - that could be really bad for the flash, and is going to be pretty slow. In terms of power usage, the screen uses about 10x more power than the CPU does when it's flat out, so I wouldn't worry about doing too much computation!

    Also, you won't see any flicker if you overwrite the whole screen, as long as you do it with the same stuff :)

  • Also, you won't see any flicker if you overwrite the whole screen, as long as you do it with the same stuff

    Right........ :)

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

background images

Posted by Avatar for FransM @FransM

Actions