entrusc / Pi-OLED

A Java driver for the popular monochrome SSD1306 128x64 OLED display (over i2c)
Other
22 stars 13 forks source link

Custom fonts #8

Closed gasperinn closed 1 year ago

gasperinn commented 1 year ago

Hi,

I would like to implement some bigger fonts then 5x8 and 4X5 for example something like 16x16. I tried with fonts like those, but no luck. Any tips on how can i generate them or where to find it?

gasperinn commented 1 year ago

Or is there a way how to scale up the existing (5x8, 4x5) ones?

entrusc commented 1 year ago

@gasperinn the current font implementation (the font enum) only supports fonts up to a height of 8, as the columns are stored as bytes:

 void drawChar(OLEDDisplay display, char c, int x, int y, boolean on) {
        if (c > maxChar || c < minChar) {
            c = '?';
        }

        c-= minChar;

        for (int i = 0; i < width; ++i) {
            int line = data[(c * width) + i];

            for (int j = 0; j < height; ++j) {
                if ((line & 0x01) > 0) {
                    display.setPixel(x + i, y + j, on);
                }
                line >>= 1;
            }
        }
    }

But using the display.setPixel() method you should be able to implement any font you like (even the ones you added a linked to), but of course that means some implementation work on your side.

gasperinn commented 1 year ago

Ok, i can see that what you mean. Char "1" is 49 in ascii, which in your fonts translates to (byte) 0x00, (byte) 0x42, (byte) 0x7F, (byte) 0x40, (byte) 0x00. With function drawChar you turn on the pixels from bottom left to upper right pixel on the display where each hex number represents one column.

So in order to implement the fonts provided i have to write the function drawChar16 which will get the char "1" from fonts (which is 0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x03,0x80,0x1F,0x80,0x1F,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x1F,0xF0,0x00,0x00,0x00,0x00,) where every two bites represents one row in 16x16 pixel grid.

Thank you for the help. If i end up with writing some kind of universal function, i will post it here :)

entrusc commented 1 year ago

That's only one way of encoding it. If your font is not broader than 8 pixels, then you could also encode it in rows for example.

Anyways if you end up writing something that other might also use, feel free to open a pull request :)

Happy coding!🎉

gasperinn commented 1 year ago

I ended up modifying Font enum by adding "int type" to the constructor, because the biggest challenge to make a universal function drawChar is because the fonts i look at has to be drawn from top left to bottom right and the one implemented are from bottom left to upper right.

I ended up adding those two fonts 8X12 and 16X16 from here and added the drawing to the function drawChar, so the function now looks like this:

void drawChar(OLEDDisplay display, char c, int x, int y, boolean on) {

        if (c > maxChar || c < minChar) {
            c = '?';
        }

        c-= minChar;

        switch (type){
            case 1:
                //Drawing from bottom left to top right
                for (int i = 0; i < width; ++i) {
                    int line = data[(c * width) + i];

                    for (int j = 0; j < height; ++j) {
                        if ((line & 0x01) > 0) {
                            display.setPixel(x + i, y + j, on);
                        }
                        line >>= 1;
                    }
                }
                break;

            case 2:
                //Drawing from top left to bottom right
                if(width%8 != 0){
                    return;
                }

                int cols = width / 8;
                int row = 0;
                for (int i=0; i < (cols * height); i+=cols) {

                    for(int r=0; r<cols; r++){
                        int thisByte = data[(c * (width / 8 * height)) + i + r];

                        for (int j = 0; j < 8; ++j) {
                            if ((thisByte & 0x80) > 0) {
                                display.setPixel(x + 8*r + j, y + row, on);
                            }
                            thisByte <<= 1;
                        }
                    }

                    row++;
                }
                break;
        }

    }

Thank you for all the help. I did not open a pull request because I don't think my solution (which works for me) is not universal and clean enough to do so :)

entrusc commented 1 year ago

The code doesn't look bad at all. I'm happy you were able to come up with a solution for your problem 😀

I'd also consider adding your code, but the fonts themselves are unfortunately under LGPL and I think that is not compatible with this library's BSD license.

But i will put adding a few more fonts on my list of possible improvements.