Rewriting OzOLED and adding a few extra functions, I tried to double an 8x8 font to a 16x16 font.
On a 0.96" display, the double font is a nice to have feature.
Adding a double font bitmap for just the numbers requires 32 x 10 = 320 bytes plus at least a punctuation,
in total 352 bytes.
Just doubling the bitmap has the disadvantage of a ragged loook.
The advantage is that the doubling can be applied to all ascii characters plus
upper range up to the value 255 using just a few more memory bytes.
I have looked for an existing way to improve the displayed font, but have not found any solution.
So I decided to give the following a try:
One way to soften the look could be to add a bit, converting sharp corners to staircases.
An example:
Original Result
## ##
## ###
## ###
## ##
Using a simple forward looking function comparing three positions at a time does
an imperfect job, soften some of the edges and distorting the image slightly.
Dumping the bitmap using a cmd line program, it is easy to show the results
just doubling bits, a teoretical result, and the actual result.
Extra bits added are shown as 0.
Origianal Times Two Optimal x2 Resulting x2
...#.... ......##........ ......##........ ......##........
..####.. ......##........ ......##........ .....0##........ <
.#.#.... ....########.... ....########.... ....########....
..###... ....########.... ...0########.... ...0########.... <
...#.#.. ..##..##........ ..##..##........ ..##..##........
.####... ..##..##........ ..##..##0....... ..##.0##........ <
...#.... ....######...... ...0######...... ....######......
........ ....######...... ....######0..... ....######...... <
......##..##.... .....0##..##.... ......##..##....
......##..##.... ......##..##.... .....0##.0##.... <
..########...... ..########0..... ..########......
..########...... ..########...... ..########...... <
......##........ ......##....... .....0##........
......##........ ......##........ ......##........ <
................ ................ ................
................ ................ ................ <
^ ^ ^ ^ ^ ^ ^ ^
The < and ^ shows where bits can be added using the forward looking function.
Overall the result is a little bit easier on the eyes, but is it worth the trouble and
extra memory usage?
Or to put it in another way:
Is there a way to do a better job not using a lot of memory?
The code is an extract from my MiniOled library which can be found here:
https://github.com/cbpdk/MiniOled
uint8_t MiniOled::doubleHalfByte(uint8_t c) {
uint8_t t = 4;
uint8_t b = 8;
c = c& 0x0f;
//Shift 4 lower bits and double them
for(char i=3; i >=0; i--) {
if((c & b) == b ) {
c |= b << t;
c |= b << (t-1);
if(i > 0)
c &= ~b; //clear bit
}
b >>=1;
t--;
}
return c;
}
uint8_t MiniOled::adjustPattern(uint8_t item1, uint8_t item2) {
uint8_t currBit = 3; //bit 1,2
uint8_t nextBit = 0x0c; //bit 3,4
uint8_t prevBit = 0; //Empty
//Ignore first and last bits as either previous or next bits are out of range.
for(char i = 0; i < 4; i++) {
//Second bits compare to first bits next pair
if(i<3 && (item1 & currBit) != currBit &&
(item2 & currBit) == currBit &&
(item1 & nextBit) == nextBit) {
item1 |= currBit << 1; // add one bit, second already set
} else if(i >0 && (item1 & currBit) != currBit &&
(item1 & prevBit) == prevBit &&
(item2 & currBit) == currBit ) {
item1 |= currBit >> 1; // add one bit, second already set
}
currBit <<= 2;
nextBit <<= 2;
prevBit = currBit >> 2;
}
return item1;
}
void MiniOled::printStringx2adv(const char *string, uint8_t X, uint8_t Y, uint8_t numChar) {
if( X > 13 || Y > 7)
return;
setCursor(X, Y);
uint8_t tmpY = Y;
uint8_t count = 0;
uint8_t dc;
uint8_t halfx2[FONT_WIDTH]; //Holds one half of the height
do {
count = 0;
//Send one full length row at a time.
beginData();
while (string[count] && count < numChar) {
//Get all columns for half one character.
for (char i = 0; i < FONT_WIDTH; i++) {
uint8_t c = (uint8_t)string[count];
#ifdef CUSTOM_RANGE
//Above ascii, try remap
if( c > 127 )
c = mapChar(c);
#endif
if (c < FONT_START || c >= FONT_END ) { //ASCII plus above
dc = 0; //Unrecognized, print a space
} else {
c -= 32;
dc = pgm_read_byte(&BasicFont[c][i]);
if( Y - tmpY == 1)
dc >>= 4; //Second run, use upper half byte
halfx2[i] = doubleHalfByte(dc);
}
}
//Assumes FONT_WIDTH is the width of a normal character on the display.
for (char j = 0; j < FONT_WIDTH; j++) {
dc= halfx2[j];
sendDataByte(dc);
dc = adjustPattern(dc, (j < FONT_WIDTH-1) ? halfx2[j+1]:0);
sendDataByte(dc);
}
count++;
}
Wire.endTransmission();
Y += 1;
setCursor(X, Y); //Next row
} while( Y - tmpY < 2);
if(tmpY +2 < MO_MAX_ROWS-1)
tmpY +=2;
setCursor(X, tmpY);
}
The code is not optimised, making it easier to follow.
Attached is a photo showing the difference on a 0.96" display.