mirror of
https://github.com/mamedev/mame.git
synced 2024-11-16 07:48:32 +01:00
Converted png2bcd tool to python [Andrew Gardner]
This commit is contained in:
parent
739811854e
commit
fb5c151082
6 changed files with 3116 additions and 455 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,3 +15,4 @@
|
|||
src/regtests/chdman/temp
|
||||
src/regtests/jedutil/output
|
||||
/sta
|
||||
*.pyc
|
||||
|
|
4
makefile
4
makefile
|
@ -991,9 +991,9 @@ $(OBJ)/%.lh: $(SRC)/%.lay $(SRC)/build/file2str.py
|
|||
@echo Converting $<...
|
||||
@$(PYTHON) $(SRC)/build/file2str.py $< $@ layout_$(basename $(notdir $<))
|
||||
|
||||
$(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC_TARGET) $(SRC)/build/file2str.py
|
||||
$(OBJ)/%.fh: $(SRC)/%.png $(SRC)/build/png2bdc.py $(SRC)/build/file2str.py
|
||||
@echo Converting $<...
|
||||
@$(PNG2BDC) $< $(OBJ)/temp.bdc
|
||||
@$(PYTHON) $(SRC)/build/png2bdc.py $< $(OBJ)/temp.bdc
|
||||
@$(PYTHON) $(SRC)/build/file2str.py $(OBJ)/temp.bdc $@ font_$(basename $(notdir $<)) UINT8
|
||||
|
||||
$(DRIVLISTOBJ): $(DRIVLISTSRC)
|
||||
|
|
|
@ -21,13 +21,11 @@ OBJDIRS += \
|
|||
MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE)
|
||||
MAKEMAK_TARGET = $(BUILDOUT)/makemak$(BUILD_EXE)
|
||||
MAKELIST_TARGET = $(BUILDOUT)/makelist$(BUILD_EXE)
|
||||
PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE)
|
||||
VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE)
|
||||
|
||||
MAKEDEP = $(MAKEDEP_TARGET)
|
||||
MAKEMAK = $(MAKEMAK_TARGET)
|
||||
MAKELIST = $(MAKELIST_TARGET)
|
||||
PNG2BDC = $(PNG2BDC_TARGET)
|
||||
VERINFO = $(VERINFO_TARGET)
|
||||
|
||||
ifneq ($(TERM),cygwin)
|
||||
|
@ -35,7 +33,6 @@ ifeq ($(OS),Windows_NT)
|
|||
MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET))
|
||||
MAKEMAK = $(subst /,\,$(MAKEMAK_TARGET))
|
||||
MAKELIST = $(subst /,\,$(MAKELIST_TARGET))
|
||||
PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET))
|
||||
VERINFO = $(subst /,\,$(VERINFO_TARGET))
|
||||
endif
|
||||
endif
|
||||
|
@ -45,7 +42,6 @@ BUILD += \
|
|||
$(MAKEDEP_TARGET) \
|
||||
$(MAKEMAK_TARGET) \
|
||||
$(MAKELIST_TARGET) \
|
||||
$(PNG2BDC_TARGET) \
|
||||
$(VERINFO_TARGET) \
|
||||
|
||||
|
||||
|
@ -106,26 +102,6 @@ $(MAKELIST_TARGET): $(MAKELISTOBJS) $(LIBOCORE) $(ZLIB)
|
|||
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
# png2bdc
|
||||
#-------------------------------------------------
|
||||
|
||||
PNG2BDCOBJS = \
|
||||
$(BUILDOBJ)/png2bdc.o \
|
||||
$(OBJ)/lib/util/astring.o \
|
||||
$(OBJ)/lib/util/corefile.o \
|
||||
$(OBJ)/lib/util/corealloc.o \
|
||||
$(OBJ)/lib/util/bitmap.o \
|
||||
$(OBJ)/lib/util/png.o \
|
||||
$(OBJ)/lib/util/palette.o \
|
||||
$(OBJ)/lib/util/unicode.o \
|
||||
|
||||
$(PNG2BDC_TARGET): $(PNG2BDCOBJS) $(LIBOCORE) $(ZLIB)
|
||||
@echo Linking $@...
|
||||
$(LD) $(LDFLAGS) $^ $(BASELIBS) -o $@
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
# verinfo
|
||||
#-------------------------------------------------
|
||||
|
@ -147,9 +123,6 @@ $(MAKEDEP_TARGET):
|
|||
$(MAKELIST_TARGET):
|
||||
@echo $@ should be built natively. Nothing to do.
|
||||
|
||||
$(PNG2BDC_TARGET):
|
||||
@echo $@ should be built natively. Nothing to do.
|
||||
|
||||
$(VERINFO_TARGET):
|
||||
@echo $@ should be built natively. Nothing to do.
|
||||
|
||||
|
|
2752
src/build/png.py
Normal file
2752
src/build/png.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,426 +0,0 @@
|
|||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
|
||||
png2bdc.c
|
||||
|
||||
Super-simple PNG to BDC file generator
|
||||
|
||||
****************************************************************************
|
||||
|
||||
Format of PNG data:
|
||||
|
||||
Multiple rows of characters. A black pixel means "on". All other colors
|
||||
mean "off". Each row looks like this:
|
||||
|
||||
* 8888 *** *
|
||||
* 4444 * * **
|
||||
* 2222 * * *
|
||||
* 1111 * * *
|
||||
* * * *
|
||||
** *** ***
|
||||
*
|
||||
*
|
||||
|
||||
****** ****
|
||||
|
||||
The column of pixels on the left-hand side (column 0) indicates the
|
||||
character cell height. This column must be present on each row and
|
||||
the height must be consistent for each row.
|
||||
|
||||
Protruding one pixel into column 1 is the baseline indicator. There
|
||||
should only be one row with a pixel in column 1 for each line, and
|
||||
that pixel row index should be consistent for each row.
|
||||
|
||||
In columns 2-5 are a 4-hex-digit starting character index number. This
|
||||
is encoded as binary value. Each column is 4 pixels tall and represents
|
||||
one binary digit. The character index number is the unicode character
|
||||
number of the first character encoded in this row; subsequent
|
||||
characters in the row are at increasing character indices.
|
||||
|
||||
Starting in column 6 and beyond are the actual character bitmaps.
|
||||
Below them, in the second row after the last row of the character,
|
||||
is a solid line that indicates the width of the character, and also
|
||||
where the character bitmap begins and ends.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <new>
|
||||
#include "png.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS & DEFINES
|
||||
//**************************************************************************
|
||||
|
||||
#define CACHED_CHAR_SIZE 12
|
||||
#define CACHED_HEADER_SIZE 16
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// a render_font contains information about a single character in a font
|
||||
struct render_font_char
|
||||
{
|
||||
render_font_char() : width(0), xoffs(0), yoffs(0), bmwidth(0), bmheight(0) { }
|
||||
|
||||
INT32 width; // width from this character to the next
|
||||
INT32 xoffs, yoffs; // X and Y offset from baseline to top,left of bitmap
|
||||
INT32 bmwidth, bmheight; // width and height of bitmap
|
||||
bitmap_argb32 * bitmap; // pointer to the bitmap containing the raw data
|
||||
};
|
||||
|
||||
|
||||
// a render_font contains information about a font
|
||||
struct render_font
|
||||
{
|
||||
render_font() : height(0), yoffs(0) { }
|
||||
|
||||
int height; // height of the font, from ascent to descent
|
||||
int yoffs; // y offset from baseline to descent
|
||||
render_font_char chars[65536]; // array of characters
|
||||
};
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INLINE FUNCTIONS
|
||||
//**************************************************************************
|
||||
|
||||
inline int pixel_is_set(bitmap_argb32 &bitmap, int y, int x)
|
||||
{
|
||||
return (bitmap.pix32(y, x) & 0xffffff) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MAIN
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// write_data - write data to the given file and
|
||||
// throw an exception if an error occurs
|
||||
//-------------------------------------------------
|
||||
|
||||
static void write_data(core_file &file, UINT8 *base, UINT8 *end)
|
||||
{
|
||||
UINT32 bytes_written = core_fwrite(&file, base, end - base);
|
||||
if (bytes_written != end - base)
|
||||
{
|
||||
fprintf(stderr, "Error writing to destination file\n");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// render_font_save_cached - write the cached
|
||||
// data out to the file
|
||||
//-------------------------------------------------
|
||||
|
||||
static bool render_font_save_cached(render_font &font, const char *filename, UINT32 hash)
|
||||
{
|
||||
// attempt to open the file
|
||||
core_file *file;
|
||||
file_error filerr = core_fopen(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
|
||||
if (filerr != FILERR_NONE)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
// determine the number of characters
|
||||
int numchars = 0;
|
||||
for (int chnum = 0; chnum < 65536; chnum++)
|
||||
if (font.chars[chnum].width > 0)
|
||||
numchars++;
|
||||
|
||||
// write the header
|
||||
dynamic_buffer tempbuffer(65536);
|
||||
UINT8 *dest = &tempbuffer[0];
|
||||
*dest++ = 'f';
|
||||
*dest++ = 'o';
|
||||
*dest++ = 'n';
|
||||
*dest++ = 't';
|
||||
*dest++ = hash >> 24;
|
||||
*dest++ = hash >> 16;
|
||||
*dest++ = hash >> 8;
|
||||
*dest++ = hash & 0xff;
|
||||
*dest++ = font.height >> 8;
|
||||
*dest++ = font.height & 0xff;
|
||||
*dest++ = font.yoffs >> 8;
|
||||
*dest++ = font.yoffs & 0xff;
|
||||
*dest++ = numchars >> 24;
|
||||
*dest++ = numchars >> 16;
|
||||
*dest++ = numchars >> 8;
|
||||
*dest++ = numchars & 0xff;
|
||||
write_data(*file, tempbuffer, dest);
|
||||
|
||||
// write the empty table to the beginning of the file
|
||||
dynamic_buffer chartable(numchars * CACHED_CHAR_SIZE + 1, 0);
|
||||
write_data(*file, &chartable[0], &chartable[numchars * CACHED_CHAR_SIZE]);
|
||||
|
||||
// loop over all characters
|
||||
int tableindex = 0;
|
||||
for (int chnum = 0; chnum < 65536; chnum++)
|
||||
{
|
||||
render_font_char &ch = font.chars[chnum];
|
||||
if (ch.width > 0)
|
||||
{
|
||||
// write out a bit-compressed bitmap if we have one
|
||||
if (ch.bitmap != NULL)
|
||||
{
|
||||
// write the data to the tempbuffer
|
||||
dest = tempbuffer;
|
||||
UINT8 accum = 0;
|
||||
UINT8 accbit = 7;
|
||||
|
||||
// bit-encode the character data
|
||||
for (int y = 0; y < ch.bmheight; y++)
|
||||
{
|
||||
int desty = y + font.height + font.yoffs - ch.yoffs - ch.bmheight;
|
||||
const UINT32 *src = (desty >= 0 && desty < font.height) ? &ch.bitmap->pix32(desty) : NULL;
|
||||
for (int x = 0; x < ch.bmwidth; x++)
|
||||
{
|
||||
if (src != NULL && src[x] != 0)
|
||||
accum |= 1 << accbit;
|
||||
if (accbit-- == 0)
|
||||
{
|
||||
*dest++ = accum;
|
||||
accum = 0;
|
||||
accbit = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flush any extra
|
||||
if (accbit != 7)
|
||||
*dest++ = accum;
|
||||
|
||||
// write the data
|
||||
write_data(*file, tempbuffer, dest);
|
||||
|
||||
// free the bitmap and texture
|
||||
global_free(ch.bitmap);
|
||||
ch.bitmap = NULL;
|
||||
}
|
||||
|
||||
// compute the table entry
|
||||
dest = &chartable[tableindex++ * CACHED_CHAR_SIZE];
|
||||
*dest++ = chnum >> 8;
|
||||
*dest++ = chnum & 0xff;
|
||||
*dest++ = ch.width >> 8;
|
||||
*dest++ = ch.width & 0xff;
|
||||
*dest++ = ch.xoffs >> 8;
|
||||
*dest++ = ch.xoffs & 0xff;
|
||||
*dest++ = ch.yoffs >> 8;
|
||||
*dest++ = ch.yoffs & 0xff;
|
||||
*dest++ = ch.bmwidth >> 8;
|
||||
*dest++ = ch.bmwidth & 0xff;
|
||||
*dest++ = ch.bmheight >> 8;
|
||||
*dest++ = ch.bmheight & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// seek back to the beginning and rewrite the table
|
||||
core_fseek(file, CACHED_HEADER_SIZE, SEEK_SET);
|
||||
write_data(*file, &chartable[0], &chartable[numchars * CACHED_CHAR_SIZE]);
|
||||
|
||||
// all done
|
||||
core_fclose(file);
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
core_fclose(file);
|
||||
osd_rmfile(filename);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// bitmap_to_chars - convert a bitmap to
|
||||
// characters in the given font
|
||||
//-------------------------------------------------
|
||||
|
||||
static bool bitmap_to_chars(bitmap_argb32 &bitmap, render_font &font)
|
||||
{
|
||||
// loop over rows
|
||||
int rowstart = 0;
|
||||
while (rowstart < bitmap.height())
|
||||
{
|
||||
// find the top of the row
|
||||
for ( ; rowstart < bitmap.height(); rowstart++)
|
||||
if (pixel_is_set(bitmap, rowstart, 0))
|
||||
break;
|
||||
if (rowstart >= bitmap.height())
|
||||
break;
|
||||
|
||||
// find the bottom of the row
|
||||
int rowend;
|
||||
for (rowend = rowstart + 1; rowend < bitmap.height(); rowend++)
|
||||
if (!pixel_is_set(bitmap, rowend, 0))
|
||||
{
|
||||
rowend--;
|
||||
break;
|
||||
}
|
||||
|
||||
// find the baseline
|
||||
int baseline;
|
||||
for (baseline = rowstart; baseline <= rowend; baseline++)
|
||||
if (pixel_is_set(bitmap, baseline, 1))
|
||||
break;
|
||||
if (baseline > rowend)
|
||||
{
|
||||
fprintf(stderr, "No baseline found between rows %d-%d\n", rowstart, rowend);
|
||||
break;
|
||||
}
|
||||
|
||||
// set or confirm the height
|
||||
if (font.height == 0)
|
||||
{
|
||||
font.height = rowend - rowstart + 1;
|
||||
font.yoffs = baseline - rowend;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (font.height != rowend - rowstart + 1)
|
||||
{
|
||||
fprintf(stderr, "Inconsistent font height at rows %d-%d\n", rowstart, rowend);
|
||||
break;
|
||||
}
|
||||
if (font.yoffs != baseline - rowend)
|
||||
{
|
||||
fprintf(stderr, "Inconsistent baseline at rows %d-%d\n", rowstart, rowend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// decode the starting character
|
||||
int chstart = 0;
|
||||
for (int x = 0; x < 4; x++)
|
||||
for (int y = 0; y < 4; y++)
|
||||
chstart = (chstart << 1) | pixel_is_set(bitmap, rowstart + y, 2 + x);
|
||||
|
||||
// print info
|
||||
// printf("Row %d-%d, baseline %d, character start %X\n", rowstart, rowend, baseline, chstart);
|
||||
|
||||
// scan the column to find characters
|
||||
int colstart = 0;
|
||||
while (colstart < bitmap.width())
|
||||
{
|
||||
render_font_char &ch = font.chars[chstart];
|
||||
|
||||
// find the start of the character
|
||||
for ( ; colstart < bitmap.width(); colstart++)
|
||||
if (pixel_is_set(bitmap, rowend + 2, colstart))
|
||||
break;
|
||||
if (colstart >= bitmap.width())
|
||||
break;
|
||||
|
||||
// find the end of the character
|
||||
int colend;
|
||||
for (colend = colstart + 1; colend < bitmap.width(); colend++)
|
||||
if (!pixel_is_set(bitmap, rowend + 2, colend))
|
||||
{
|
||||
colend--;
|
||||
break;
|
||||
}
|
||||
|
||||
// skip char which code is already registered
|
||||
if (ch.width <= 0)
|
||||
{
|
||||
// print info
|
||||
// printf(" Character %X - width = %d\n", chstart, colend - colstart + 1);
|
||||
|
||||
// allocate a bitmap
|
||||
ch.bitmap = global_alloc(bitmap_argb32(colend - colstart + 1, font.height));
|
||||
|
||||
// plot the character
|
||||
for (int y = rowstart; y <= rowend; y++)
|
||||
for (int x = colstart; x <= colend; x++)
|
||||
ch.bitmap->pix32(y - rowstart, x - colstart) = pixel_is_set(bitmap, y, x) ? 0xffffffff : 0x00000000;
|
||||
|
||||
// set the character parameters
|
||||
ch.width = colend - colstart + 1;
|
||||
ch.xoffs = 0;
|
||||
ch.yoffs = font.yoffs;
|
||||
ch.bmwidth = ch.bitmap->width();
|
||||
ch.bmheight = ch.bitmap->height();
|
||||
}
|
||||
|
||||
// next character
|
||||
chstart++;
|
||||
colstart = colend + 1;
|
||||
}
|
||||
|
||||
// next row
|
||||
rowstart = rowend + 1;
|
||||
}
|
||||
|
||||
// return non-zero (TRUE) if we errored
|
||||
return (rowstart < bitmap.height());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// main - main entry point
|
||||
//-------------------------------------------------
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// validate arguments
|
||||
if (argc < 3)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n%s <input.png> [<input2.png> [...]] <output.bdc>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
const char *bdcname = argv[argc - 1];
|
||||
|
||||
// iterate over input files
|
||||
static render_font font;
|
||||
bool error = false;
|
||||
for (int curarg = 1; curarg < argc - 1; curarg++)
|
||||
{
|
||||
// load the png file
|
||||
const char *pngname = argv[curarg];
|
||||
core_file *file;
|
||||
file_error filerr = core_fopen(pngname, OPEN_FLAG_READ, &file);
|
||||
if (filerr != FILERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error %d attempting to open PNG file\n", filerr);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
bitmap_argb32 bitmap;
|
||||
png_error pngerr = png_read_bitmap(file, bitmap);
|
||||
core_fclose(file);
|
||||
if (pngerr != PNGERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error %d reading PNG file\n", pngerr);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// parse the PNG into characters
|
||||
error = bitmap_to_chars(bitmap, font);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
// write out the resulting font
|
||||
if (!error)
|
||||
error = render_font_save_cached(font, bdcname, 0);
|
||||
|
||||
// cleanup after ourselves
|
||||
return error ? 1 : 0;
|
||||
}
|
361
src/build/png2bdc.py
Normal file
361
src/build/png2bdc.py
Normal file
|
@ -0,0 +1,361 @@
|
|||
#!/usr/bin/env python
|
||||
##
|
||||
## license:BSD-3-Clause
|
||||
## copyright-holders:Aaron Giles, Andrew Gardner
|
||||
## ****************************************************************************
|
||||
##
|
||||
## png2bdc.c
|
||||
##
|
||||
## Super-simple PNG to BDC file generator
|
||||
##
|
||||
## ****************************************************************************
|
||||
##
|
||||
## Format of PNG data:
|
||||
##
|
||||
## Multiple rows of characters. A black pixel means "on". All other colors
|
||||
## mean "off". Each row looks like this:
|
||||
##
|
||||
## * 8888 *** *
|
||||
## * 4444 * * **
|
||||
## * 2222 * * *
|
||||
## * 1111 * * *
|
||||
## * * * *
|
||||
## ** *** ***
|
||||
## *
|
||||
## *
|
||||
##
|
||||
## ****** ****
|
||||
##
|
||||
## The column of pixels on the left-hand side (column 0) indicates the
|
||||
## character cell height. This column must be present on each row and
|
||||
## the height must be consistent for each row.
|
||||
##
|
||||
## Protruding one pixel into column 1 is the baseline indicator. There
|
||||
## should only be one row with a pixel in column 1 for each line, and
|
||||
## that pixel row index should be consistent for each row.
|
||||
##
|
||||
## In columns 2-5 are a 4-hex-digit starting character index number. This
|
||||
## is encoded as binary value. Each column is 4 pixels tall and represents
|
||||
## one binary digit. The character index number is the unicode character
|
||||
## number of the first character encoded in this row; subsequent
|
||||
## characters in the row are at increasing character indices.
|
||||
##
|
||||
## Starting in column 6 and beyond are the actual character bitmaps.
|
||||
## Below them, in the second row after the last row of the character,
|
||||
## is a solid line that indicates the width of the character, and also
|
||||
## where the character bitmap begins and ends.
|
||||
##
|
||||
## ***************************************************************************
|
||||
|
||||
##
|
||||
## Python note:
|
||||
## This is a near-literal translation of the original C++ code. As such there
|
||||
## are some very non-pythonic things done throughout. The conversion was done
|
||||
## this way so as to insure compatibility as much as possible given the small
|
||||
## number of test cases.
|
||||
##
|
||||
|
||||
import os
|
||||
import png
|
||||
import sys
|
||||
|
||||
|
||||
########################################
|
||||
## Helper classes
|
||||
########################################
|
||||
class RenderFontChar:
|
||||
"""
|
||||
Contains information about a single character in a font.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
"""
|
||||
self.width = 0 # width from this character to the next
|
||||
self.xOffs = 0 # X offset from baseline to top,left of bitmap
|
||||
self.yOffs = 0 # Y offset from baseline to top,left of bitmap
|
||||
self.bmWidth = 0 # width of bitmap
|
||||
self.bmHeight = 0 # height of bitmap
|
||||
self.bitmap = None # pointer to the bitmap containing the raw data
|
||||
|
||||
|
||||
class RenderFont:
|
||||
"""
|
||||
Contains information about a font
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.height = 0 # height of the font, from ascent to descent
|
||||
self.yOffs = 0 # y offset from baseline to descent
|
||||
self.chars = list() # array of characters
|
||||
for i in range(0, 65536):
|
||||
self.chars.append(RenderFontChar())
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
## Helper functions
|
||||
########################################
|
||||
def pixelIsSet(value):
|
||||
return (value & 0xffffff) == 0
|
||||
|
||||
|
||||
def renderFontSaveCached(font, filename, hash32):
|
||||
"""
|
||||
"""
|
||||
fp = open(filename, "wb")
|
||||
if not fp:
|
||||
return 1
|
||||
|
||||
# Write the header
|
||||
numChars = 0
|
||||
for c in font.chars:
|
||||
if c.width > 0:
|
||||
numChars += 1
|
||||
|
||||
CACHED_CHAR_SIZE = 12
|
||||
CACHED_HEADER_SIZE = 16
|
||||
|
||||
try:
|
||||
fp.write('f')
|
||||
fp.write('o')
|
||||
fp.write('n')
|
||||
fp.write('t')
|
||||
fp.write(bytearray([hash32 >> 24 & 0xff]))
|
||||
fp.write(bytearray([hash32 >> 16 & 0xff]))
|
||||
fp.write(bytearray([hash32 >> 8 & 0xff]))
|
||||
fp.write(bytearray([hash32 >> 0 & 0xff]))
|
||||
fp.write(bytearray([font.height >> 8 & 0xff]))
|
||||
fp.write(bytearray([font.height >> 0 & 0xff]))
|
||||
fp.write(bytearray([font.yOffs >> 8 & 0xff]))
|
||||
fp.write(bytearray([font.yOffs >> 0 & 0xff]))
|
||||
fp.write(bytearray([numChars >> 24 & 0xff]))
|
||||
fp.write(bytearray([numChars >> 16 & 0xff]))
|
||||
fp.write(bytearray([numChars >> 8 & 0xff]))
|
||||
fp.write(bytearray([numChars >> 0 & 0xff]))
|
||||
|
||||
# Write a blank table at first (?)
|
||||
charTable = [0]*(numChars * CACHED_CHAR_SIZE)
|
||||
fp.write(bytearray(charTable))
|
||||
|
||||
# Loop over all characters
|
||||
tableIndex = 0
|
||||
|
||||
for i in range(len(font.chars)):
|
||||
c = font.chars[i]
|
||||
if c.width == 0:
|
||||
continue
|
||||
|
||||
if c.bitmap:
|
||||
dBuffer = list()
|
||||
accum = 0
|
||||
accbit = 7
|
||||
|
||||
# Bit-encode the character data
|
||||
for y in range(0, c.bmHeight):
|
||||
src = None
|
||||
desty = y + font.height + font.yOffs - c.yOffs - c.bmHeight
|
||||
if desty >= 0 and desty < font.height:
|
||||
src = c.bitmap[desty]
|
||||
for x in range(0, c.bmWidth):
|
||||
if src is not None and src[x] != 0:
|
||||
accum |= 1 << accbit
|
||||
accbit -= 1
|
||||
if accbit+1 == 0:
|
||||
dBuffer.append(accum)
|
||||
accum = 0
|
||||
accbit = 7
|
||||
|
||||
# Flush any extra
|
||||
if accbit != 7:
|
||||
dBuffer.append(accum)
|
||||
|
||||
# Write the data
|
||||
fp.write(bytearray(dBuffer))
|
||||
|
||||
destIndex = tableIndex * CACHED_CHAR_SIZE
|
||||
charTable[destIndex + 0] = i >> 8 & 0xff
|
||||
charTable[destIndex + 1] = i >> 0 & 0xff
|
||||
charTable[destIndex + 2] = c.width >> 8 & 0xff
|
||||
charTable[destIndex + 3] = c.width >> 0 & 0xff
|
||||
charTable[destIndex + 4] = c.xOffs >> 8 & 0xff
|
||||
charTable[destIndex + 5] = c.xOffs >> 0 & 0xff
|
||||
charTable[destIndex + 6] = c.yOffs >> 8 & 0xff
|
||||
charTable[destIndex + 7] = c.yOffs >> 0 & 0xff
|
||||
charTable[destIndex + 8] = c.bmWidth >> 8 & 0xff
|
||||
charTable[destIndex + 9] = c.bmWidth >> 0 & 0xff
|
||||
charTable[destIndex + 10] = c.bmHeight >> 8 & 0xff
|
||||
charTable[destIndex + 11] = c.bmHeight >> 0 & 0xff
|
||||
tableIndex += 1
|
||||
|
||||
# Seek back to the beginning and rewrite the table
|
||||
fp.seek(CACHED_HEADER_SIZE, 0)
|
||||
fp.write(bytearray(charTable))
|
||||
|
||||
fp.close()
|
||||
return 0
|
||||
|
||||
except:
|
||||
return 1
|
||||
|
||||
|
||||
def bitmapToChars(pngObject, font):
|
||||
"""
|
||||
Convert a bitmap to characters in the given font
|
||||
"""
|
||||
# Just cache the bitmap into a list of lists since random access is paramount
|
||||
bitmap = list()
|
||||
width = pngObject.asRGBA8()[0]
|
||||
height = pngObject.asRGBA8()[1]
|
||||
rowGenerator = pngObject.asRGBA8()[2]
|
||||
for row in rowGenerator:
|
||||
cRow = list()
|
||||
irpd = iter(row)
|
||||
for r,g,b,a in zip(irpd, irpd, irpd, irpd):
|
||||
cRow.append(a << 24 | r << 16 | g << 8 | b)
|
||||
bitmap.append(cRow)
|
||||
|
||||
rowStart = 0
|
||||
while rowStart < height:
|
||||
# Find the top of the row
|
||||
for i in range(rowStart, height):
|
||||
if pixelIsSet(bitmap[rowStart][0]):
|
||||
break
|
||||
rowStart += 1
|
||||
if rowStart >= height:
|
||||
break
|
||||
|
||||
# Find the bottom of the row
|
||||
rowEnd = rowStart + 1
|
||||
for i in range(rowEnd, height):
|
||||
if not pixelIsSet(bitmap[rowEnd][0]):
|
||||
rowEnd -= 1
|
||||
break
|
||||
rowEnd += 1
|
||||
|
||||
# Find the baseline
|
||||
baseline = rowStart
|
||||
for i in range(rowStart, rowEnd+1):
|
||||
if pixelIsSet(bitmap[baseline][1]):
|
||||
break
|
||||
baseline += 1
|
||||
if baseline > rowEnd:
|
||||
sys.stderr.write("No baseline found between rows %d-%d\n" % (rowStart, rowEnd))
|
||||
break
|
||||
|
||||
# Set or confirm the height
|
||||
if font.height == 0:
|
||||
font.height = rowEnd - rowStart + 1
|
||||
font.yOffs = baseline - rowEnd
|
||||
else:
|
||||
if font.height != (rowEnd - rowStart + 1):
|
||||
sys.stderr.write("Inconsistent font height at rows %d-%d\n" % (rowStart, rowEnd))
|
||||
break
|
||||
if font.yOffs != (baseline - rowEnd):
|
||||
sys.stderr.write("Inconsistent baseline at rows %d-%d\n" % (rowStart, rowEnd))
|
||||
break
|
||||
|
||||
# decode the starting character
|
||||
chStart = 0
|
||||
for x in range(0, 4):
|
||||
for y in range(0, 4):
|
||||
chStart = (chStart << 1) | pixelIsSet(bitmap[rowStart+y][2+x])
|
||||
|
||||
# Print debug info
|
||||
# print("Row %d-%d, baseline %d, character start %X" % (rowStart, rowEnd, baseline, chStart))
|
||||
|
||||
# scan the column to find characters
|
||||
colStart = 0
|
||||
while (colStart < width):
|
||||
ch = RenderFontChar()
|
||||
|
||||
# Find the start of the character
|
||||
for i in range(colStart, width):
|
||||
if pixelIsSet(bitmap[rowEnd+2][colStart]):
|
||||
break
|
||||
colStart += 1
|
||||
if colStart >= width:
|
||||
break
|
||||
|
||||
# Find the end of the character
|
||||
colEnd = colStart + 1
|
||||
for i in range(colEnd, width):
|
||||
if not pixelIsSet(bitmap[rowEnd+2][colEnd]):
|
||||
colEnd -= 1
|
||||
break
|
||||
colEnd += 1
|
||||
|
||||
# Skip char which code is already registered
|
||||
if ch.width <= 0:
|
||||
# Print debug info
|
||||
# print " Character %X - width = %d" % (chStart, colEnd - colStart + 1)
|
||||
|
||||
# Plot the character
|
||||
ch.bitmap = list()
|
||||
for y in range(rowStart, rowEnd+1):
|
||||
ch.bitmap.append(list())
|
||||
for x in range(colStart, colEnd+1):
|
||||
if pixelIsSet(bitmap[y][x]):
|
||||
ch.bitmap[-1].append(0xffffffff)
|
||||
else:
|
||||
ch.bitmap[-1].append(0x00000000)
|
||||
|
||||
# Set the character parameters
|
||||
ch.width = colEnd - colStart + 1
|
||||
ch.xOffs = 0
|
||||
ch.yOffs = font.yOffs
|
||||
ch.bmWidth = len(ch.bitmap[0])
|
||||
ch.bmHeight = len(ch.bitmap)
|
||||
|
||||
# Insert the character into the list
|
||||
font.chars[chStart] = ch
|
||||
|
||||
# Next character
|
||||
chStart += 1
|
||||
colStart = colEnd + 1
|
||||
|
||||
# Next row
|
||||
rowStart = rowEnd + 1
|
||||
|
||||
# Return non-zero if we errored
|
||||
return (rowStart < height)
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
## Main
|
||||
########################################
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
sys.stderr.write("Usage:\n%s <input.png> [<input2.png> [...]] <output.bdc>\n" % sys.argv[0])
|
||||
return 1
|
||||
bdcName = sys.argv[-1]
|
||||
|
||||
font = RenderFont()
|
||||
for i in range(1, len(sys.argv)-1):
|
||||
filename = sys.argv[i]
|
||||
if not os.path.exists(filename):
|
||||
sys.stderr.write("Error attempting to open PNG file.\n")
|
||||
return 1
|
||||
|
||||
pngObject = png.Reader(filename)
|
||||
try:
|
||||
pngObject.validate_signature()
|
||||
except:
|
||||
sys.stderr.write("Error reading PNG file.\n")
|
||||
return 1
|
||||
|
||||
error = bitmapToChars(pngObject, font)
|
||||
if error:
|
||||
return 1
|
||||
|
||||
error = renderFontSaveCached(font, bdcName, 0)
|
||||
return error
|
||||
|
||||
|
||||
|
||||
########################################
|
||||
## Program entry point
|
||||
########################################
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
Loading…
Reference in a new issue