Program to create fonts, animations... bitmaps... etc WIP

:o Been spending a lot of time on a program that allows bitmaps, fonts and even animated gif images to be loaded, touched up and turned into MCU images.

It can take less than a minute to churn out a new font or to tweak an animated gif into the format you need.

The end result can be saved as a binary file that has a very simple format or as code that can be inserted directly into a sketch or project.

The code produced is a single "blob" with a header that describes where various offsets are. This enables the resource to sit in memory as a single variable or if read from SD etc means only the small header needs to be loaded and the rest as needed.

At the moment only 1 BPP has been coded until I sort out the other formats. (Other formats are simple but I want to also support palette color).

I have a DIB library that allows all the resources built to be displayed on about anything as images are rendered onto a virtual screen/bitmap and then the device does what it needs to render it.

Have used the animations, fonts and bitmaps on max7219 arrays, nokia5110, 13xx OLED, 1289 LCD and other various hardware with no problems.

Fonts can have > 256 characters and fully support unicode. The sizes can either be fixed which means each glyph will be the same dimension regardless of contents or variable where each glyph takes up the minimal amount of room.

In a variable length font "W" would take up a lot more room than... ".", "-", "=", etc.

The header information will tell you if optional bytes proceed the glyph data. This may include the glyph dimensions (using either 1 or 2 bytes per dimension) and whether the glyph has a "hotspot" which is optional.

As we know memory for images on embedded devices is prime real estate so I've been trying to make it so working with color images is as efficient as possible without complex compression.

All images in the program are 32 bit with alpha however these can be converted to the format you need in the last step before coding or saving. You may have a 24 bit image and after converting to 8 bit with a palette it looks just as good but uses 1/4 of the space.

I've had a lot of success in dithering and creating optimal color palettes which will allow for 4 and 8 bit palette colors with or without a single index for 100% transparent color.

The demo below is old and only shows a font being made.
Old demo of creating a font and some code

Example code produced for a small font with just a few numbers :-

#ifndef _VAL32
#define _VAL32(x)((x) >> 24) & 0xFF, ((x) >> 16) & 0xFF, ((x) >> 8) & 0xFF, ((x)) & 0xFF
#define _VAL16(x) ((x) >> 8) & 0xFF, ((x)) & 0xFF
#define _VAL8(x) ((x) & 0xFF)
#End If

 // 14 characters, 5*9 pixels

BYTE font1[302] = 
{
   _VAL32(0xFEEDBEEF), // File identifier
   _VAL16(301), // File version
   _VAL8(1), // Mode - FONT
   _VAL8(1), // Bits per pixel - 1
   _VAL8(0x01), // Frame minx, maxx, miny, maxy 1 byte, no hotspots
   _VAL16(14), // Number of frames
   _VAL16(5), // Maximum pixel width
   _VAL16(9), // Maximum height - this is used as the font height if a font
   _VAL16(0), // Number of palette entries... 0 if no palette
   _VAL16(0), // Palette entry size... 0=no palette, 1=rgb565 2=rgb24
   _VAL16(182), // Data length in bytes
   _VAL16(36), // Offset of offsets
   _VAL16(92), // Offset of char table (0 if not font)
   _VAL16(0), // Offset of palette (0 if no palette)

// data offsets
 _VAL32(120), _VAL32(133), _VAL32(146), _VAL32(159), _VAL32(172), _VAL32(185), _VAL32(198),
 _VAL32(211), _VAL32(224), _VAL32(237), _VAL32(250), _VAL32(263), _VAL32(276), _VAL32(289),

// font character table
 _VAL16(32), _VAL16(43), _VAL16(45), _VAL16(46), _VAL16(48), _VAL16(49), _VAL16(50), _VAL16(51),
 _VAL16(52), _VAL16(53), _VAL16(54), _VAL16(55), _VAL16(56), _VAL16(57),

// frame 0, character 32 " "
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  0,0,0,0,0,0,0,0,0,
// frame 1, character 43 "+"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  0,0,0,32,32,248,32,32,0,
// frame 2, character 45 "-"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  0,0,0,0,0,192,0,0,0,
// frame 3, character 46 "."
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  0,0,0,0,0,0,0,0,128,
// frame 4, character 48 "0"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,136,136,136,136,112,
// frame 5, character 49 "1"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  32,224,32,32,32,32,32,32,32,
// frame 6, character 50 "2"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,8,8,16,32,64,128,248,
// frame 7, character 51 "3"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,8,8,48,8,8,136,112,
// frame 8, character 52 "4"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  16,48,48,80,80,144,248,16,16,
// frame 9, character 53 "5"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  248,128,128,240,136,8,8,136,112,
// frame 10, character 54 "6"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,128,128,240,136,136,136,112,
// frame 11, character 55 "7"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  248,8,16,16,32,32,64,64,64,
// frame 12, character 56 "8"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,112,136,136,136,112,
// frame 13, character 57 "9"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,120,8,8,136,112
};

:o Was a small error in the example code above. Clearly it's not variable length as a change I made last night had a small typo.

The code below is correct. Notice the number of bytes for each character IS variable now.

#ifndef _VAL32
#define _VAL32(x)((x) >> 24) & 0xFF, ((x) >> 16) & 0xFF, ((x) >> 8) & 0xFF, ((x)) & 0xFF
#define _VAL16(x) ((x) >> 8) & 0xFF, ((x)) & 0xFF
#define _VAL8(x) ((x) & 0xFF)
#End If

 // 17 characters, 5*11 pixels

BYTE font1[332] = 
{
   _VAL32(0xFEEDBEEF), // File identifier
   _VAL16(301), // File version
   _VAL8(1), // Mode - FONT
   _VAL8(1), // Bits per pixel - 1
   _VAL8(0x01), // Frame minx, maxx, miny, maxy 1 byte, no hotspots
   _VAL16(17), // Number of frames
   _VAL16(5), // Maximum pixel width
   _VAL16(11), // Maximum height - this is used as the font height if a font
   _VAL16(0), // Number of palette entries... 0 if no palette
   _VAL16(0), // Palette entry size... 0=no palette, 1=rgb565 2=rgb24
   _VAL16(194), // Data length in bytes
   _VAL16(36), // Offset of offsets
   _VAL16(104), // Offset of char table (0 if not font)
   _VAL16(0), // Offset of palette (0 if no palette)

// data offsets
 _VAL32(138), _VAL32(143), _VAL32(158), _VAL32(173), _VAL32(182), _VAL32(187), _VAL32(192),
 _VAL32(205), _VAL32(218), _VAL32(231), _VAL32(244), _VAL32(257), _VAL32(270), _VAL32(283),
 _VAL32(296), _VAL32(309), _VAL32(322),

// font character table
 _VAL16(32), _VAL16(40), _VAL16(41), _VAL16(43), _VAL16(45), _VAL16(46), _VAL16(48), _VAL16(49),
 _VAL16(50), _VAL16(51), _VAL16(52), _VAL16(53), _VAL16(54), _VAL16(55), _VAL16(56), _VAL16(57),
 _VAL16(101),

// frame 0, character 32 " "
  0,0,0,0, // BYTE minx, maxx, miny, maxy
  0,
// frame 1, character 40 "("
  0,1,0,10, // BYTE minx, maxx, miny, maxy
  64,128,128,128,128,128,128,128,128,128,64,
// frame 2, character 41 ")"
  0,1,0,10, // BYTE minx, maxx, miny, maxy
  128,64,64,64,64,64,64,64,64,64,128,
// frame 3, character 43 "+"
  0,4,3,7, // BYTE minx, maxx, miny, maxy
  32,32,248,32,32,
// frame 4, character 45 "-"
  0,1,5,5, // BYTE minx, maxx, miny, maxy
  192,
// frame 5, character 46 "."
  0,0,8,8, // BYTE minx, maxx, miny, maxy
  128,
// frame 6, character 48 "0"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,136,136,136,136,112,
// frame 7, character 49 "1"
  0,2,0,8, // BYTE minx, maxx, miny, maxy
  32,224,32,32,32,32,32,32,32,
// frame 8, character 50 "2"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,8,8,16,32,64,128,248,
// frame 9, character 51 "3"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,8,8,48,8,8,136,112,
// frame 10, character 52 "4"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  16,48,48,80,80,144,248,16,16,
// frame 11, character 53 "5"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  248,128,128,240,136,8,8,136,112,
// frame 12, character 54 "6"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,128,128,240,136,136,136,112,
// frame 13, character 55 "7"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  248,8,16,16,32,32,64,64,64,
// frame 14, character 56 "8"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,112,136,136,136,112,
// frame 15, character 57 "9"
  0,4,0,8, // BYTE minx, maxx, miny, maxy
  112,136,136,136,120,8,8,136,112,
// frame 16, character 101 "e"
  0,4,3,8, // BYTE minx, maxx, miny, maxy
  112,136,248,128,136,112
};

Nice work but is there any code or at least a binary available somewhere or are you just flaunting here? :wink:

Btw. can you output images to 16bit 565 format with dithering? And can you specify a range of characters, like if I only want characters '0'-'5' rather than all numbers?

MarekB:
Nice work but is there any code or at least a binary available somewhere or are you just flaunting here? :wink:

Btw. can you output images to 16bit 565 format with dithering? And can you specify a range of characters, like if I only want characters '0'-'5' rather than all numbers?

I'll try to make a binary available soon. It's in VB.Net with some stuff in VC.Net (ie stuff that needs speed)

I'm working on the "other formats" atm.

It will be able to output 565 16 bit or 8 bit with palette dithered. If you have a color image with only 16 distinct colors then it can produce a 4 bit image with the palette. Which should use up a lot less space than an 8, 16 or 24 bit image.

The palette routine supports either "oct-tree" or the "Xiaolin Wu" algorithm. The second will optionally dither. In testing so far... the results have been very good with very little visual difference between the converted images.

When making a font the dialog has a lot of options. Can pick a standard 32-127 ASCII, 32-255 extended ASCII, or with the custom settings pick from several blocks of characters and/or add your own. In the latest version I added Greek upper and lower as options for if scientific symbols need to be used.

It's very easy to have a font with say just numbers 0,1,2,3,4,5. If you want just specific characters... type them in. It will automatically get rid of duplicates and order them.

If you needed a font for a logo with say... "Arduino" then you can make a font with just those specific characters.

:o Progress would be faster except I implemented an undo feature ~ 1 week ago that I'm still fine tuning.

I use to hate it myself when I did something and ruined the project because there was no simple undo.

Some operations effect just the current frame... but some will effect all (ie. remove a column or row, changing format)

Moved the navigator from a listview to a datagridview last night and it's heaps better. Will be able to support copy and paste of frames easily now.

Really nice job!

Do you know if there are any libs, like the adafruit for instance, that allows an 8 bit (256 color) bitmap to be drawn on the TFT, directly from memory, instead of the sd card?

Something similar from the DrawBitmap(...) function, but for 4 bit, 8 bit bmps?

Rimbaldo:
Really nice job!

Do you know if there are any libs, like the adafruit for instance, that allows an 8 bit (256 color) bitmap to be drawn on the TFT, directly from memory, instead of the sd card?

Something similar from the DrawBitmap(...) function, but for 4 bit, 8 bit bmps?

Off the top of my head I don't know of any... which is why I have attempted to at least provide an easy way to define them.

I have made major changes and improvements to my program and it's basically unrecognisable from the 1st "version".

It will support exactly what you have queried!

I can load an animated gif with many frames and then convert it to 16 or 256 color indexed color. The actual colors are stored as a palette already in 565 format if desired. It can also optionally "reserve" index 0 for "transparent".

The main aim of the format is to (1) support directly embedding any type of image (2) Making it so streaming larger ones can be done easily and efficiently (3) Keeping the format as simple as possible.

Uncompressing a PNG or animated gif or even decoding a BMP because of the way it's stored upside down is a pain.

Basically the format is the same for fonts and bitmaps. Can have 1 or many... makes no difference.

Font have a char lookup table so a utf8 char can be mapped to a specific frame number.

At the moment I'm adding a bit of "fluff" so the end code and/or saved binary format can target little or big endian.

My Mega2650 quite happily loads an animated GIF 320*240 4 and 8 bit -> TFT 565.

The main guts is the mono 1 bit functionality for fonts that can be used for... MAX7219, Nokia5110 or any device that needs 1 bit fonts/bitmaps. There use to be a 256 frame limit... but now it's only really restricted by memory. I have no problems making an animated gif 320240 with 154 frames or a 814 font with > 300 characters.

In theory... given the simple file format you could write your own specific bitmap routines quite easily.

I intend to give sample code out and people can basically use it as they see fit. If you only want to stream 1 BPP images then no use lumping people with some bloated package that uses up all their memory.

Ideally I would like to be able to target the program to Windows XP and above but MS has made that hard. In the long term I may create an XP compatible version and use a lower .NET version.

:o Another function I put in was the ability to create colored fonts specific for the 565 screens that are around. I had (past tense) a routine that got a regular font and created a nixie tube font that IMO looked quite good for a 1st cut. However I sort of misplaced the code for that when making major changes as it was "temp experimental" code.

I'll get some screen shots out tonight :o

:o Interface has been split a bit to have 2 tool windows to control selecting frames and navigator.

It has some tools that work well now with a few different brushes for “basic editing”.

Newest screen shots

Spent a lot of time cleaning up code and improving some slow areas. (One example was 7+ seconds to save 10MB animated gif that was reduced to ~ 1 second)

New version also allows frames to be deleted, copied and inserted.

Bitmaps will be numbers from 0 starting at first frame… fonts will be in character order.

Fonts and bitmaps can have an optional HOTSPOT. If not used then no extra bytes will be used up and the default will be 0,0 (ie upper left hand corner).

Wondering about the colored fonts. How many bits per pixel is it?

MarekB:
Wondering about the colored fonts. How many bits per pixel is it?

Initially was going to be 4 bit… but given work done on palettes and 16 bit conversion I’d aim at 32 bit then people can scale down however they see fit.

:o Almost got to the stage where a first cut can be put somewhere.

The work done with palette modes has worked a lot better than I envisioned and the optional dithering has also worked very well.

As you are aware... rendering a 24 bit image -> 16 bit sometimes has noticeable color banding. I'm happy to report in these cases dithering seems to eliminate most of this.

The program has been developed on a Windows 10 machine and I spent the last day creating a setup.exe and trying to get it running it on a Windows 7 machine. Got it working this morning on the Windows 7 machine... so it should work on Windows 7 -> 10 and MAYBE XP.

I will try and get a downloadable version happening soon and people can experiment or have a look. I still need to make some basic tutorials, a bit more testing and most important document the end format so people can integrate the images into their own projects.

Hoek:
Initially was going to be 4 bit... but given work done on palettes and 16 bit conversion I'd aim at 32 bit then people can scale down however they see fit.

Ok, what I am basically interested in is if I'll be able to generate antialiased fonts. Basically instead of 1bit per pixel you'd have 4 or 8 bits per pixel defining transparency (I guess 4bits would be enough).

MarekB:
Ok, what I am basically interested in is if I'll be able to generate antialiased fonts. Basically instead of 1bit per pixel you'd have 4 or 8 bits per pixel defining transparency (I guess 4bits would be enough).

Yes... it is quite possible to create the antialiased fonts with a hard coded background color.

This is one area I intend to expand as people with color displays are wanting access to some color fonts.

4 bit palette color is quite a good compromise IMO between number of colors and size required, and with the font characters only taking up the minimal room per character you can end up with a decent color font that is very viable to use.

The code that produces the fonts has a "rendering hint" where 1 produces a grid fit and the other is antialiased so I implemented this to produce 2 types of font.

:o OK... made some changes and basically if the font is not 1 BPP it becomes 32 BPP with aliasing.

I added a pixel processing option to "Flatten Alpha" against a particular background color which then lets you save the font to any format with the aliasing. (ie. 4 bit palette, 256 palette or RGB565)

Would you not be able to produce a 4bit transparent font (without flattening alpha)?
I would like to have a font where only the level of transparency is stored and which does not include any kind of color information. That way you have a font which you can render with any color on any color background. With 4bits per pixel, 0 would be a fully transparent pixel and 15 a fully opaque pixel (or vice versa, does not matter). When the font is rendered, one can do a simple linear blend between the background color and the font color based on the transparency. To speed things up, those 16 blends of color could be precomputed so blending is not calculated for every pixel.

It’s basically the same. I always order the palette colors darkest to lightest so still end up with what is effectively a scale 0 - 15 where 0 is 100% transparent and 15 is 100% opaque. (Had to do this as when the code is created it has to search for the exact color 1000’s of times and having a binary search in a 256 color palette made a HUGE difference in speed).

So I create a font with 32 BPP and it seems when MS antialaise the fonts they use a scale of 0-15 for shading which is convenient.

I then use flatten alpha and then convert to palette color so each pixel only uses 4 bits.

In theory, on the rendering side you are free to do anything with the 0-15 value of each pixel. Use the palette to render if you want… or as you want to do… blend with your background that may or may not be complex.

The main problem in the past has been getting font data → format you can use in a consistent manner.

The palette color for each of the 16 values can be looked at and from that an alpha 0-255 value can be calculated easily.

If you want a copy of the setup.exe PM me with your Email and I can send it… it’s ~ 1MB and requires .Net 4.0 or better and Windows 7 onwards (maybe XP???) Get in (assuming it installs - only tested on daughters W7 machine) and experiment, make sure click off option that produces 1 BPP font. Then use “Pixel factory” to “Flatten alpha” … in your case make sure the background color option is on black. The image now can be put through “Palette Factory” where it will create a 0-15 palette that can be saved, loaded and rendered.

This current version is a rewrite of my original that now saves the entire “blob” as a single stream of BYTE. I just need some small bits of demo code to show how to render any frame at any particular X, Y position.

The only “real” difference between a font and bitmap is that a font contains a char lookup table. Basically it maps a known character to a frame number. The 1st one is ALWAYS “SPACE” as it’s special. Other than that the font table can have anything.