From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/tools/mkdgifft.cpp | 1043 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1043 insertions(+) create mode 100755 Source/DirectFB/tools/mkdgifft.cpp (limited to 'Source/DirectFB/tools/mkdgifft.cpp') diff --git a/Source/DirectFB/tools/mkdgifft.cpp b/Source/DirectFB/tools/mkdgifft.cpp new file mode 100755 index 0000000..4937558 --- /dev/null +++ b/Source/DirectFB/tools/mkdgifft.cpp @@ -0,0 +1,1043 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This file is subject to the terms and conditions of the MIT License: + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#define DIRECT_ENABLE_DEBUG + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +} + +#include +#include +#include +#include + + +#define MAX_ROW_WIDTH 2047 + +D_DEBUG_DOMAIN( mkdgiff, "mkdgiff", "DirectFB Glyph Image File Format Tool" ); + +/**********************************************************************************************************************/ + +static DirectFBPixelFormatNames( format_names ); +static DirectFBSurfaceBlittingFlagsNames( m_bflags ); + +static const char *filename; +static DFBSurfacePixelFormat m_format = DSPF_ARGB; + +/**********************************************************************************************************************/ + +static void +print_usage (const char *prg_name) +{ + int i = 0; + + fprintf (stderr, "\nDirectFB Glyph Image File Format Tool (version %s)\n\n", DIRECTFB_VERSION); + fprintf (stderr, "Usage: %s [options]\n\n", prg_name); + fprintf (stderr, "Options:\n"); + fprintf (stderr, " -f, --format Choose the pixel format (default ARGB)\n"); + fprintf (stderr, " -s, --sizes [,s2...] Choose sizes to generate glyph images for\n"); + fprintf (stderr, " -h, --help Show this help message\n"); + fprintf (stderr, " -v, --version Print version information\n"); + fprintf (stderr, "\n"); + + fprintf (stderr, "Known pixel formats with alpha:\n"); + + while (format_names[i].format != DSPF_UNKNOWN) { + DFBSurfacePixelFormat format = format_names[i].format; + + if (DFB_PIXELFORMAT_HAS_ALPHA(format)) { + fprintf (stderr, " %-10s %2d bits, %d bytes", + format_names[i].name, DFB_BITS_PER_PIXEL(format), + DFB_BYTES_PER_PIXEL(format)); + + if (DFB_PIXELFORMAT_IS_INDEXED(format)) + fprintf (stderr, " INDEXED"); + + if (DFB_PLANAR_PIXELFORMAT(format)) { + int planes = DFB_PLANE_MULTIPLY(format, 1000); + + fprintf (stderr, " PLANAR (x%d.%03d)", + planes / 1000, planes % 1000); + } + + fprintf (stderr, "\n"); + } + + ++i; + } + fprintf (stderr, "\n"); +} + +static DFBBoolean +parse_format( const char *arg, DFBSurfacePixelFormat *ret_format ) +{ + int i = 0; + + while (format_names[i].format != DSPF_UNKNOWN) { + if (!strcasecmp( arg, format_names[i].name )) { + *ret_format = format_names[i].format; + return DFB_TRUE; + } + + ++i; + } + + fprintf (stderr, "\nInvalid format specified!\n\n" ); + + return DFB_FALSE; +} + +static void +parse_flags( const char *arg, DFBSurfaceBlittingFlags *ret_flags ) +{ + int i; + + *ret_flags = DSBLIT_NOFX; + + for (i=0; i list; + typedef std::vector vector; +}; + +class Face : public Entity +{ +public: + Face() + : + Entity(), + size( 0 ), + height( 0 ), + ascender( 0 ), + descender( 0 ), + maxadvance( 0 ), + blittingflags( DSBLIT_NOFX ) + { + } + + + virtual Type GetType() const { return ENTITY_FACE; } + + + virtual void Dump() const; + + virtual void SetProperty( const std::string &name, const std::string &value ); + + + unsigned int size; + unsigned int height; + int ascender; + int descender; + int maxadvance; + DFBSurfaceBlittingFlags blittingflags; +}; + +class Glyph : public Entity +{ +public: + Glyph() + : + Entity(), + unicode( 0 ), + left( 0 ), + top( 0 ), + advance( 0 ) + { + } + + + virtual Type GetType() const { return ENTITY_GLYPH; } + + + virtual void Dump() const; + + virtual void SetProperty( const std::string &name, const std::string &value ); + + + unsigned int unicode; + int left; + int top; + int advance; + std::string file; +}; + +/**********************************************************************************************************************/ + +void +Entity::Dump() const +{ + direct_log_printf( NULL, "\n" ); + direct_log_printf( NULL, "Entity (TYPE %d)\n", GetType() ); + direct_log_printf( NULL, " Buffer at %p [%zu]\n", buf, length ); +} + +void +Face::Dump() const +{ + Entity::Dump(); + + direct_log_printf( NULL, " Size %u\n", size ); + direct_log_printf( NULL, " Height %u\n", height ); + direct_log_printf( NULL, " Ascender %d\n", ascender ); + direct_log_printf( NULL, " Descender %d\n", descender ); + direct_log_printf( NULL, " MaxAdvance %d\n", maxadvance ); + direct_log_printf( NULL, " BlittingFlags 0x%08x\n", blittingflags ); +} + +void +Glyph::Dump() const +{ + Entity::Dump(); + + direct_log_printf( NULL, " Unicode 0x%04x\n", unicode ); + direct_log_printf( NULL, " Left %d\n", left ); + direct_log_printf( NULL, " Top %d\n", top ); + direct_log_printf( NULL, " Advance %d\n", advance ); + direct_log_printf( NULL, " File '%s'\n", file.c_str() ); +} + +/**********************************************************************************************************************/ + +void +Entity::SetProperty( const std::string &name, + const std::string &value ) +{ +} + +void +Face::SetProperty( const std::string &name, + const std::string &value ) +{ + if (name == "size") { + sscanf( value.c_str(), "%u", &size ); + return; + } + + if (name == "height") { + sscanf( value.c_str(), "%u", &height ); + return; + } + + if (name == "ascender") { + sscanf( value.c_str(), "%d", &ascender ); + return; + } + + if (name == "descender") { + sscanf( value.c_str(), "%d", &descender ); + return; + } + + if (name == "maxadvance") { + sscanf( value.c_str(), "%d", &maxadvance ); + return; + } + + if (name == "blittingflags") { + parse_flags( value.c_str(), &blittingflags ); + return; + } +} + +void +Glyph::SetProperty( const std::string &name, + const std::string &value ) +{ + if (name == "unicode") { + sscanf( value.c_str(), "%x", &unicode ); + return; + } + + if (name == "left") { + sscanf( value.c_str(), "%d", &left ); + return; + } + + if (name == "top") { + sscanf( value.c_str(), "%d", &top ); + return; + } + + if (name == "advance") { + sscanf( value.c_str(), "%d", &advance ); + return; + } + + if (name == "file") { + file = value; + return; + } +} + +/**********************************************************************************************************************/ + +static void +get_entities( const char *buf, + size_t length, + Entity::vector &out_vector ) +{ + size_t i; + unsigned int level = 0; + bool quote = false; + + std::string name; + std::map names; + + Entity *entity = NULL; + + D_DEBUG_AT( mkdgiff, "%s( buf %p, length %zu )\n", __func__, buf, length ); + + for (i=0; i '%c' <-\n", level*2, "", level, buf[i] ); + + if (quote) { + switch (buf[i]) { + case '"': + quote = false; + break; + + default: + name += buf[i]; + } + } + else { + switch (buf[i]) { + case '"': + quote = true; + break; + + case '-': + case '_': + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + name += buf[i]; + break; + + default: + if (!name.empty()) { + D_DEBUG_AT( mkdgiff, "%*s=-> name = '%s'\n", level*2, "", name.c_str() ); + + if (!names[level].empty()) { + switch (level) { + case 1: + D_DEBUG_AT( mkdgiff, "%*s#### setting property '%s' = '%s'\n", + level*2, "", names[level].c_str(), name.c_str() ); + + D_ASSERT( entity != NULL ); + + entity->SetProperty( names[level], name ); + break; + + default: + break; + } + + name = ""; + } + + names[level] = name; + name = ""; + } + + switch (buf[i]) { + case '{': + case '}': + switch (buf[i]) { + case '{': + switch (level) { + case 0: + if (names[level] == "face") { + D_ASSERT( entity == NULL ); + + entity = new Face(); + + entity->buf = &buf[i + 1]; + + D_DEBUG_AT( mkdgiff, "%*s#### open entity %p (Face)\n", level*2, "", entity ); + } + if (names[level] == "glyph") { + D_ASSERT( entity == NULL ); + + entity = new Glyph(); + + entity->buf = &buf[i + 1]; + + D_DEBUG_AT( mkdgiff, "%*s#### open entity %p (Glyph)\n", level*2, "", entity ); + } + break; + + default: + break; + } + + names[level] = ""; + + level++; + break; + + case '}': + D_ASSERT( names[level].empty() ); + + level--; + + switch (level) { + case 0: + D_DEBUG_AT( mkdgiff, "%*s#### close entity %p\n", level*2, "", entity ); + + D_ASSERT( entity != NULL ); + + entity->length = &buf[i-1] - entity->buf; + + out_vector.push_back( entity ); + + entity = NULL; + break; + + case 1: + break; + + default: + break; + } + break; + } + + D_DEBUG_AT( mkdgiff, "%*s=-> level => %u\n", level*2, "", level ); + break; + + case ' ': + case '\t': + case '\n': + case '\r': + break; + + default: + break; + } + break; + } + } + } +} + +/**********************************************************************************************************************/ + +static DFBResult +load_image (const char *filename, + DFBSurfaceDescription *desc) +{ + DFBSurfacePixelFormat dest_format; + DFBSurfacePixelFormat src_format; + FILE *fp; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + unsigned char *data = NULL; + int type; + char header[8]; + int bytes, pitch; + + dest_format = (desc->flags & DSDESC_PIXELFORMAT) ? desc->pixelformat : DSPF_UNKNOWN; + + desc->flags = DSDESC_NONE; + desc->preallocated[0].data = NULL; + + if (!(fp = fopen (filename, "rb"))) { + fprintf (stderr, "Failed to open file '%s': %s.\n", + filename, strerror (errno)); + goto cleanup; + } + + bytes = fread (header, 1, sizeof(header), fp); + if (png_sig_cmp ((unsigned char*) header, 0, bytes)) { + fprintf (stderr, "File '%s' doesn't seem to be a PNG image file.\n", + filename); + goto cleanup; + } + + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (!png_ptr) + goto cleanup; + + if (setjmp (png_ptr->jmpbuf)) { + if (desc->preallocated[0].data) { + free (desc->preallocated[0].data); + desc->preallocated[0].data = NULL; + } + + /* data might have been clobbered, + set it to NULL and leak instead of crashing */ + data = NULL; + + goto cleanup; + } + + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + goto cleanup; + + png_init_io (png_ptr, fp); + png_set_sig_bytes (png_ptr, bytes); + + png_read_info (png_ptr, info_ptr); + + png_get_IHDR (png_ptr, info_ptr, + &width, &height, &bytes, &type, NULL, NULL, NULL); + + if (bytes == 16) + png_set_strip_16 (png_ptr); + +#ifdef WORDS_BIGENDIAN + png_set_swap_alpha (png_ptr); +#else + png_set_bgr (png_ptr); +#endif + + src_format = (type & PNG_COLOR_MASK_ALPHA) ? DSPF_ARGB : DSPF_RGB32; + switch (type) { + case PNG_COLOR_TYPE_GRAY: + if (dest_format == DSPF_A8) { + src_format = DSPF_A8; + break; + } + /* fallthru */ + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_set_gray_to_rgb (png_ptr); +// if (rgbformat) +// dest_format = rgbformat; + break; + + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb (png_ptr); + /* fallthru */ + case PNG_COLOR_TYPE_RGB: +// if (rgbformat) +// dest_format = rgbformat; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (dest_format == DSPF_RGB24) { + png_set_strip_alpha (png_ptr); + src_format = DSPF_RGB24; + } + break; + } + + switch (src_format) { + case DSPF_RGB32: + png_set_filler (png_ptr, 0xFF, +#ifdef WORDS_BIGENDIAN + PNG_FILLER_BEFORE +#else + PNG_FILLER_AFTER +#endif + ); + break; + case DSPF_ARGB: + case DSPF_A8: + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png_ptr); + break; + default: + break; + } + + pitch = (DFB_BYTES_PER_LINE( src_format, width ) + 7) & ~7; + + data = (unsigned char*) malloc (height * pitch); + if (!data) { + fprintf (stderr, "Failed to allocate %ld bytes.\n", height * pitch); + goto cleanup; + } + + { + unsigned int i; + png_bytep bptrs[height]; + + for (i = 0; i < height; i++) + bptrs[i] = data + i * pitch; + + png_read_image (png_ptr, bptrs); + } + + if (!dest_format) + dest_format = src_format; + + if (DFB_BYTES_PER_PIXEL(src_format) != DFB_BYTES_PER_PIXEL(dest_format)) { + unsigned char *s, *d, *dest; + int d_pitch, h; + + D_ASSERT( DFB_BYTES_PER_PIXEL(src_format) == 4 ); + + d_pitch = (DFB_BYTES_PER_LINE(dest_format, width) + 7) & ~7; + + dest = (unsigned char*) malloc (height * d_pitch); + if (!dest) { + fprintf (stderr, "Failed to allocate %ld bytes.\n", + height * d_pitch); + goto cleanup; + } + + h = height; + switch (dest_format) { + case DSPF_RGB16: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_rgb16 ((u32 *) s, (u16 *) d, width); + break; + case DSPF_ARGB1555: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_argb1555 ((u32 *) s, (u16 *) d, width); + break; + case DSPF_ARGB2554: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_argb2554 ((u32 *) s, (u16 *) d, width); + break; + case DSPF_ARGB4444: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_argb4444 ((u32 *) s, (u16 *) d, width); + break; + case DSPF_RGB332: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_rgb332 ((u32 *) s, (u8 *) d, width); + break; + case DSPF_A8: + for (s = data, d = dest; h; h--, s += pitch, d += d_pitch) + dfb_argb_to_a8 ((u32 *) s, (u8 *) d, width); + break; + default: + fprintf (stderr, + "Sorry, unsupported format conversion.\n"); + goto cleanup; + } + + free (data); + data = dest; + pitch = d_pitch; + } + + desc->flags = (DFBSurfaceDescriptionFlags)(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | + DSDESC_PREALLOCATED); + desc->width = width; + desc->height = height; + desc->pixelformat = dest_format; + desc->preallocated[0].pitch = pitch; + desc->preallocated[0].data = data; + + data = NULL; + + cleanup: + if (fp) + fclose (fp); + + if (png_ptr) + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + + if (data) + free (data); + + return ((desc->flags) ? DFB_OK : DFB_FAILURE); +} + +/**********************************************************************************************************************/ + +static void +write_glyph( DGIFFGlyphInfo *glyph, const DFBSurfaceDescription &desc, void *dst, int pitch ) +{ + D_DEBUG_AT( mkdgiff, "%s( %p, %p, %d ) <- size %ux%u\n", + __FUNCTION__, glyph, dst, pitch, desc.width, desc.height ); + + switch (m_format) { + case DSPF_ARGB: + dfb_convert_to_argb( desc.pixelformat, desc.preallocated[0].data, desc.preallocated[0].pitch, + desc.height, (u32*) dst, pitch, desc.width, desc.height ); + break; + + default: + D_UNIMPLEMENTED(); + break; + } +} + +static int +do_face( const Face *face ) +{ + int i, ret; + int align = DFB_PIXELFORMAT_ALIGNMENT( m_format ); + int num_glyphs = 0; + int num_rows = 1; + int row_index = 0; + int row_offset = 0; + int next_face = sizeof(DGIFFFaceHeader); + int total_height = 0; + + Entity::vector glyph_vector; + unsigned int glyph_count = 0; + + DGIFFFaceHeader header; + DGIFFGlyphInfo *glyphs; + DGIFFGlyphRow *rows; + void **row_data; + + DFBSurfaceDescription *descs; + + D_DEBUG_AT( mkdgiff, "%s( %p )\n", __FUNCTION__, face ); + + get_entities( face->buf, face->length, glyph_vector ); + + glyph_count = glyph_vector.size(); + + + /* Clear to not leak any data into file. */ + memset( &header, 0, sizeof(header) ); + + + /* Allocate glyph info array. */ + glyphs = (DGIFFGlyphInfo*) D_CALLOC( glyph_count, sizeof(DGIFFGlyphInfo) ); + rows = (DGIFFGlyphRow*) D_CALLOC( glyph_count, sizeof(DGIFFGlyphRow) ); /* WORST case :) */ + row_data = (void**) D_CALLOC( glyph_count, sizeof(void*) ); /* WORST case :) */ + descs = (DFBSurfaceDescription*) D_CALLOC( glyph_count, sizeof(DFBSurfaceDescription) ); /* WORST case :) */ + + for (Entity::vector::const_iterator iter = glyph_vector.begin(); iter != glyph_vector.end(); iter++) { + const Glyph *glyph = dynamic_cast( *iter ); + + glyph->Dump(); + + + DGIFFGlyphInfo *info = &glyphs[num_glyphs]; + DGIFFGlyphRow *row = &rows[num_rows - 1]; + + D_DEBUG_AT( mkdgiff, " -> code %3u\n", glyph->unicode ); + + ret = load_image( glyph->file.c_str(), &descs[num_glyphs] ); + if (ret) + continue; + + info->unicode = glyph->unicode; + + info->width = descs[num_glyphs].width; + info->height = descs[num_glyphs].height; + + info->left = glyph->left; + info->top = glyph->top; + info->advance = glyph->advance; + + num_glyphs++; + + if (row->width > 0 && row->width + info->width > MAX_ROW_WIDTH) { + num_rows++; + row++; + } + + row->width += (info->width + align) & ~align; + + if (row->height < info->height) + row->height = info->height; + } + + for (i=0; i row %d, width %d, height %d\n", i, row->width, row->height ); + + total_height += row->height; + + row->pitch = (DFB_BYTES_PER_LINE( m_format, row->width ) + 7) & ~7; + + row_data[i] = D_CALLOC( row->height, row->pitch ); + + next_face += row->height * row->pitch; + } + + D_DEBUG_AT( mkdgiff, " -> %d glyphs, %d rows, total height %d\n", num_glyphs, num_rows, total_height ); + + next_face += num_glyphs * sizeof(DGIFFGlyphInfo); + next_face += num_rows * sizeof(DGIFFGlyphRow); + + for (i=0; i writing character 0x%x (%d)\n", glyph->unicode, i ); + + if (row_offset > 0 && row_offset + glyph->width > MAX_ROW_WIDTH) { + row_index++; + row_offset = 0; + } + + + D_DEBUG_AT( mkdgiff, " -> row offset %d\n", row_offset ); + + write_glyph( glyph, descs[i], + (char*) row_data[row_index] + DFB_BYTES_PER_LINE( m_format, row_offset ), + rows[row_index].pitch ); + + glyph->row = row_index; + glyph->offset = row_offset; + + row_offset += (glyph->width + align) & ~align; + } + + D_ASSERT( row_index == num_rows - 1 ); + + header.next_face = next_face; + header.size = face->size; + + header.ascender = face->ascender; + header.descender = face->descender; + header.height = face->height; + + header.max_advance = face->maxadvance; + + header.pixelformat = m_format; + + header.num_glyphs = num_glyphs; + header.num_rows = num_rows; + + header.blittingflags = face->blittingflags; + + D_DEBUG_AT( mkdgiff, " -> ascender %d, descender %d\n", header.ascender, header.descender ); + D_DEBUG_AT( mkdgiff, " -> height %d, max advance %d\n", header.height, header.max_advance ); + + fwrite( &header, sizeof(header), 1, stdout ); + + fwrite( glyphs, sizeof(*glyphs), num_glyphs, stdout ); + + for (i=0; ipitch, row->height, stdout ); + } + + for (i=0; idebug = true; + direct_config->debugmem = true; + + /* Parse the command line. */ + if (!parse_command_line( argc, argv )) + return -1; + + + /* Open the file. */ + fd = open( filename, O_RDONLY ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Font/DGIFF: Failure during open() of '%s'!\n", filename ); + return ret; + } + + /* Query file size etc. */ + if (fstat( fd, &stat ) < 0) { + ret = errno2result( errno ); + D_PERROR( "Font/DGIFF: Failure during fstat() of '%s'!\n", filename ); + goto out; + } + + /* Memory map the file. */ + ptr = mmap( NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if (ptr == MAP_FAILED) { + ret = errno2result( errno ); + D_PERROR( "Font/DGIFF: Failure during mmap() of '%s'!\n", filename ); + goto out; + } + + + get_entities( (const char*) ptr, stat.st_size, faces ); + + header.num_faces = faces.size(); + + + + fwrite( &header, sizeof(header), 1, stdout ); + + for (Entity::vector::const_iterator iter = faces.begin(); iter != faces.end(); iter++) { + const Face *face = dynamic_cast( *iter ); + + face->Dump(); + + ret = do_face( face ); + if (ret) + goto out; + } + + +out: + if (ptr != MAP_FAILED) + munmap( ptr, stat.st_size ); + + close( fd ); + + direct_print_memleaks(); + + direct_shutdown(); + + return ret; +} + -- cgit