Use Images and Fonts on System without File System

Build source for incore images and fonts, and load them for your MiniGUI apps.

Table of Contents

Overview

We often need to embed raw data of images and/or fonts into the final executable of a MiniGUI app, for example:

  • The operating system does not provide support for file system.

  • You need to protect your digital intellectual properties such as icons.

For such purpose, MiniGUI provides a set of APIs and tools to embed arbitrary data into the final executable.

Note that, in MiniGUI terms, we often call the embedded data as incore data, incore resource, or inner resource.

For a complete sample, please refer to:

https://github.com/VincentWei/mg-samples/tree/master/incore-data

Tools for Generating Incore Data

We provide tools in mg-tools to generate source files for your incore data:

  • bin2c: a general tool for converting a binary file to a C source file. This tool generates a unsigned char array for your program.

  • vbf2c: this tool generates a VBFINFO struct from a MiniGUI VBF font file for your program.

  • upf2c: this tool generates a UPFINFO struct from a MiniGUI UPF font file for your program. It also generates an external function to return the pointer to the struct instead of exporting a global symbol of the struct name.

To generate an incore source file for a UPF file, you can call upf2c:

 $ upf2c res/unifont_160_50.upf unifont_160_50

This command generates a source file named unifont_160_50.c:

/*
** In-core UPF file for upf_unifont_160_50.
**
** This file is created by 'upf2c'
** Please do not modify it manually.
**
*/
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>

#ifdef _MGFONT_UPF

typedef struct
{
    Uint8       width;
    Uint8       height;
    Sint8       ascent;
    Sint8       descent;
    Uint8       max_width;
    Uint8       underline_pos;
    Uint8       underline_width;
    Sint8       leading;
    Uint8       mono_bitmap;
    Uint8       reserved[3];
    const void* root_dir;
    Uint32      file_size;
} UPFINFO;

static const unsigned char font_data[] = {
   ...
};

static const UPFINFO upf_unifont_160_50 = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0},
    font_data, sizeof (font_data)
};

const void* get_incore_font_data_upf_unifont_160_50 (void)
{
    return &upf_unifont_160_50;
}
#endif /* _MGFONT_UPF */

To generate the source file for incore images or RBF fonts, you can use bin2c:

$ bin2c -o png_pics.inc res/*.png

This command generates a large C source file which defines some unsigned char arrays for the PNG files in res/ subdirectory, one array for each file:

static const unsigned char _png__mguxdemo_10_data[] = {
    ...
};

static const unsigned char _png__mguxdemo_11_data[] = {
    ...
};

The variable name for one file is consisted of the file name and the _png__ prefix and _data suffix.

APIs for Managing Incore Data

For fonts and images, MiniGUI provides basic APIs to load them from incore data:

DEVFONT* GUIAPI LoadDevFontFromIncoreData (const char *devfont_name,
        const void *data);
void GUIAPI DestroyDynamicDevFont (DEVFONT **devfont);

int GUIAPI LoadBitmapFromMem (HDC hdc, PBITMAP pBitmap,
                const void* mem, int size, const char* ext);
void GUIAPI UnloadBitmap (PBITMAP pBitmap);

For fonts, you should load an incore font before using it, generally before creating any main window, and destroy the font before exiting MiniGUI:

#define FONTNAME_UNIFONT_160_50     "upf-unifont-rrncnn-16-16-UTF-8"
static DEVFONT* devfont_unifont_160_50;

...
    // Load incore font to create a devfont object
    if ((devfont_unifont_160_50 = LoadDevFontFromIncoreData(
            FONTNAME_UNIFONT_160_50,
            get_incore_font_data_upf_unifont_160_50())) == NULL) {
        _ERR_PRINTF("Failed to load incore UPF font.\n");
        exit (1);
    }

    // use the devfont by creating a logfont object
    logfont = CreateLogFontByName("upf-unifont-rrncnn-16-16-UTF-8");
...

    // Destroy devfont object of the incore font
    DestroyDynamicDevFont(&devfont_unifont_160_50);

For incore images, you can use the basic functions (LoadBitmapFromMem and UnloadBitmap) to load and destroy the BITMAP object. Or you can use the MiniGUI resource manager to manage the objects using the reference count mechanism.

By using the MiniGUI resource manager, you can use the original file name to load a resource from incore resource. If there is an incore resource for a specific file name, the resource manager will load it from the incore resource, otherwise it will try to load it from the file. On the other hand, the resource manager will maintain a reference count for every loaded resource, and really release the object only if the reference count reaches 0. In this way, you can avoid some bugs about object life cycle.

The following sample uses the resource manager to maintain the incore images:

#include "png_pics.inc"

static INNER_RES incore_pngs [] = {
    { 0, _png__mguxdemo_1_data,  sizeof(_png__mguxdemo_1_data),
            "res/mguxdemo-1.png" },
    { 0, _png__mguxdemo_2_data,  sizeof(_png__mguxdemo_2_data),
            "res/mguxdemo-2.png" },
    { 0, _png__mguxdemo_3_data,  sizeof(_png__mguxdemo_3_data),
            "res/mguxdemo-3.png" },
    { 0, _png__mguxdemo_4_data,  sizeof(_png__mguxdemo_4_data),
            "res/mguxdemo-4.png" },
    { 0, _png__mguxdemo_5_data,  sizeof(_png__mguxdemo_5_data),
            "res/mguxdemo-5.png" },
    { 0, _png__mguxdemo_6_data,  sizeof(_png__mguxdemo_6_data),
            "res/mguxdemo-6.png" },
    { 0, _png__mguxdemo_7_data,  sizeof(_png__mguxdemo_7_data),
            "res/mguxdemo-7.png" },
    { 0, _png__mguxdemo_8_data,  sizeof(_png__mguxdemo_8_data),
            "res/mguxdemo-8.png" },
    { 0, _png__mguxdemo_9_data,  sizeof(_png__mguxdemo_9_data),
            "res/mguxdemo-9.png" },
    { 0, _png__mguxdemo_10_data, sizeof(_png__mguxdemo_10_data),
            "res/mguxdemo-10.png" },
    { 0, _png__mguxdemo_11_data, sizeof(_png__mguxdemo_11_data),
            "res/mguxdemo-11.png" },
    { 0, _png__mguxdemo_12_data, sizeof(_png__mguxdemo_12_data),
            "res/mguxdemo-12.png" },
    { 0, _png__mguxdemo_13_data, sizeof(_png__mguxdemo_13_data),
            "res/mguxdemo-13.png" },
};

...

    // add the incore resource to MiniGUI resource manager
    for (i = 0; i < TABLESIZE(incore_pngs); i++) {
        incore_pngs[i].key = Str2Key(incore_pngs[i].additional);
        incore_pngs[i].additional = "png";
    }

    if (AddInnerRes(incore_pngs, TABLESIZE(incore_pngs), FALSE)
            != RES_RET_OK) {
        _ERR_PRINTF("Failed to add incore PNG files.\n");
        exit (1);
    }

...

    // load BITMAP object by using the file name
    bmp = LoadBitmapFromRes(hdc, "res/mguxdemo-11.png");
    if (bmp == NULL) {
        _ERR_PRINTF("Failed to loaded png picture: %s\n", png_file_name);
        return;
    }

    // use the BITMAP object
    ...


    // Release resource
    ReleaseRes(Str2Key("res/mguxdemo-11.png"));

...

    // release the resource eventually
    for (i = 0; i < TABLESIZE(incore_pngs); i++) {
        ReleaseRes(incore_pngs[i].key);
    }

Restrictions

Note that, currently, MiniGUI does not support incore TrueType fonts.

Last updated