reactos/rosapps/applications/devutils/bootvid_font_generator/bootvid_font_generator.c
Hermès Bélusca-Maïto 4219c4eed0 [BOOTVID_FONT_GEN]
Improve the bootvid font generator of Colin (see r70507) in many ways:
- Allow the user to specify the font name (optional), and optionally a font size and x- and y-offset so that (s)he doesn't have to recompile the generator each time (s)he wants to test a new font.
- The default settings (in case the user doesn't specify all or part of the font definition) are those of Windows' bootvid font (i.e. "Lucida Console", font size 10, x_offset = y_offset = 0).
- Create only once the DC and the font handle (to be used for all the generated characters) instead of each time a character is being generated. I still keep the recreation of the HBITMAP for each character (I don't know if we can also improve there by creating it once and zeroing it out before generating each character).

svn path=/trunk/; revision=70512
2016-01-07 00:29:41 +00:00

195 lines
5.3 KiB
C

/*
* PROJECT: ReactOS BootVid Font Generator Utility
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
* PURPOSE: Generates the FontData array for the bootdata.c file of bootvid.sys
* COPYRIGHT: Copyright 2016 Colin Finck <colin@reactos.org>
*/
#include <stdio.h>
#include <conio.h>
#include <windows.h>
/*
* Enable this #define if you want to dump the generated character on screen
*/
// #define DUMP_CHAR_ON_SCREEN
// Windows original Blue Screen font is "Lucida Console" at FONT_SIZE 10 with no offsets.
#define FONT_NAME_DEF "Lucida Console" // "DejaVu Sans Mono" // "Anonymous Pro"
#define FONT_SIZE_DEF 10
#define X_OFFSET_DEF 0 // 0 // 1
#define Y_OFFSET_DEF 0
#define HEIGHT 13 // Must be == BOOTCHAR_HEIGHT (see reactos/drivers/base/bootvid/precomp.h)
#define WIDTH 8 // 8 bits == 1 byte
#ifdef DUMP_CHAR_ON_SCREEN
/**
* Sketch the character on the console screen using ASCII characters.
* Allows you to easily check if the font fits properly into the 8x13 box.
*/
static void DumpCharacterOnScreen(DWORD BmpBits[])
{
int i, j;
for (i = 0; i < HEIGHT; i++)
{
for (j = WIDTH; --j >= 0;)
{
if (BmpBits[i] >> j & 0x1)
putchar(' ');
else
putchar('#');
}
putchar('\n');
}
}
#else
/**
* Dump the FontData for the bootvid/i386/bootdata.c array.
*/
static void DumpCharacterFontData(DWORD BmpBits[])
{
static int iBegin = 0;
int i;
fprintf(stdout, " ");
for (i = 0; i < HEIGHT; i++)
fprintf(stdout, "0x%02lX, ", BmpBits[i]);
fprintf(stdout, " // %d\n", iBegin);
iBegin += HEIGHT;
}
#endif
/**
* Use GDI APIs to load a monospace font and plot a single character into a bitmap.
*/
static BOOL PlotCharacter(HDC hDC, HFONT hFont, INT XOffset, INT YOffset, CHAR Character, DWORD BmpBits[])
{
BOOL bReturnValue = FALSE;
HBITMAP hOldBmp;
HFONT hOldFont;
HBITMAP hBmp = NULL;
BYTE BmpInfo[sizeof(BITMAPINFO) + sizeof(RGBQUAD)];
PBITMAPINFO pBmpInfo = (PBITMAPINFO)&BmpInfo;
hBmp = CreateCompatibleBitmap(hDC, WIDTH, HEIGHT);
if (!hBmp)
{
fprintf(stderr, "CreateCompatibleBitmap failed with error %lu!\n", GetLastError());
goto Cleanup;
}
hOldBmp = SelectObject(hDC, hBmp);
hOldFont = SelectObject(hDC, hFont);
SetBkColor(hDC, RGB(0, 0, 0));
SetTextColor(hDC, RGB(255, 255, 255));
TextOutA(hDC, XOffset, YOffset, &Character, 1);
/*
* Use enough memory for BITMAPINFO and one additional color in the color table.
* BITMAPINFO already contains a color table entry for a single color and
* GetDIBits needs space for two colors (black and white).
*/
ZeroMemory(&BmpInfo, sizeof(BmpInfo));
pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmpInfo->bmiHeader.biHeight = -HEIGHT;
pBmpInfo->bmiHeader.biWidth = WIDTH;
pBmpInfo->bmiHeader.biBitCount = 1;
pBmpInfo->bmiHeader.biPlanes = 1;
bReturnValue = TRUE;
if (!GetDIBits(hDC, hBmp, 0, HEIGHT, BmpBits, pBmpInfo, 0))
{
fprintf(stderr, "GetDIBits failed with error %lu!\n", GetLastError());
bReturnValue = FALSE;
}
SelectObject(hDC, hOldBmp);
SelectObject(hDC, hOldFont);
Cleanup:
if (hBmp)
DeleteObject(hBmp);
return bReturnValue;
}
static void DumpFont(LPSTR FontName, INT FontSize, INT XOffset, INT YOffset)
{
int iHeight;
HDC hDC = NULL;
HFONT hFont = NULL;
DWORD BmpBits[HEIGHT];
USHORT c;
hDC = CreateCompatibleDC(NULL);
if (!hDC)
{
fprintf(stderr, "CreateCompatibleDC failed with error %lu!\n", GetLastError());
goto Cleanup;
}
iHeight = -MulDiv(FontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
hFont = CreateFontA(iHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
ANSI_CHARSET, 0, 0, NONANTIALIASED_QUALITY,
FIXED_PITCH, FontName);
if (!hFont)
{
fprintf(stderr, "CreateFont failed with error %lu!\n", GetLastError());
goto Cleanup;
}
for (c = 0; c < 256; c++)
{
PlotCharacter(hDC, hFont, XOffset, YOffset, (CHAR)c, BmpBits);
#ifdef DUMP_CHAR_ON_SCREEN
DumpCharacterOnScreen(BmpBits);
fprintf(stdout, "\nPress any key to continue...\n");
_getch();
system("cls");
#else
DumpCharacterFontData(BmpBits);
#endif
}
Cleanup:
if (hFont)
DeleteObject(hFont);
if (hDC)
DeleteDC(hDC);
}
int main(int argc, char** argv)
{
/* Validate the arguments */
if (argc > 5 || (argc >= 2 && strncmp(argv[1], "/?", 2) == 0))
{
fprintf(stdout,
"Usage: %s \"font name\" [font size] [X-offset] [Y-offset]\n"
"Default font name is: \"%s\"\n"
"Default font size is: %i\n"
"Default X-offset is: %i\n"
"Default Y-offset is: %i\n",
argv[0],
FONT_NAME_DEF, FONT_SIZE_DEF, X_OFFSET_DEF, Y_OFFSET_DEF);
return -1;
}
DumpFont((argc <= 1) ? FONT_NAME_DEF : argv[1],
(argc <= 2) ? FONT_SIZE_DEF : atoi(argv[2]),
(argc <= 3) ? X_OFFSET_DEF : atoi(argv[3]),
(argc <= 4) ? Y_OFFSET_DEF : atoi(argv[4]));
return 0;
}