/* (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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #undef SIZEOF_LONG #include #include FT_GLYPH_H #define MAX_SIZE_COUNT 256 #define MAX_ROW_WIDTH 2047 D_DEBUG_DOMAIN( mkdgiff, "mkdgiff", "DirectFB Glyph Image File Format Tool" ); static DirectFBPixelFormatNames( format_names ); static const char *filename; static int face_index; static DFBSurfacePixelFormat format = DSPF_A8; static int size_count; static int face_sizes[MAX_SIZE_COUNT]; /**********************************************************************************************************************/ 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 A8)\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 DFBBoolean parse_sizes( const char *arg ) { int i = 0; int size = 0; for (i=0; arg[i]; i++) { switch (arg[i]) { case '0' ... '9': if (size_count == MAX_SIZE_COUNT) { fprintf (stderr, "\nMaximum number of sizes (%d) exceeded!\n\n", MAX_SIZE_COUNT ); return DFB_FALSE; } size = size * 10 + arg[i] - '0'; break; case ',': if (size) { face_sizes[size_count++] = size; size = 0; } break; default: fprintf (stderr, "\nInvalid character used in sizes argument!\n\n" ); return DFB_FALSE; } } if (size) face_sizes[size_count++] = size; return DFB_TRUE; } static DFBBoolean parse_command_line( int argc, char *argv[] ) { int n; for (n = 1; n < argc; n++) { const char *arg = argv[n]; if (strcmp (arg, "-h") == 0 || strcmp (arg, "--help") == 0) { print_usage (argv[0]); return DFB_FALSE; } if (strcmp (arg, "-v") == 0 || strcmp (arg, "--version") == 0) { fprintf (stderr, "mkdgiff version %s\n", DIRECTFB_VERSION); return DFB_FALSE; } if (strcmp (arg, "-f") == 0 || strcmp (arg, "--format") == 0) { if (++n == argc) { print_usage (argv[0]); return DFB_FALSE; } if (!parse_format( argv[n], &format )) return DFB_FALSE; continue; } if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sizes") == 0) { if (++n == argc) { print_usage (argv[0]); return DFB_FALSE; } if (!parse_sizes( argv[n] )) return DFB_FALSE; continue; } if (filename || access( arg, R_OK )) { print_usage (argv[0]); return DFB_FALSE; } filename = arg; } if (!filename) { print_usage (argv[0]); return DFB_FALSE; } return DFB_TRUE; } /**********************************************************************************************************************/ static void write_glyph( DGIFFGlyphInfo *glyph, FT_GlyphSlot slot, void *dst, int pitch ) { int y; u8 *src = slot->bitmap.buffer; D_DEBUG_AT( mkdgiff, "%s( %p, %p, %p, %d ) <- width %d\n", __FUNCTION__, glyph, slot, dst, pitch, glyph->width ); for (y=0; y < glyph->height; y++) { int i, j, n; u8 *dst8 = dst; u16 *dst16 = dst; u32 *dst32 = dst; switch (slot->bitmap.pixel_mode) { case ft_pixel_mode_grays: switch (format) { case DSPF_ARGB: if (0){//FIXME thiz->surface_caps & DSCAPS_PREMULTIPLIED) { for (i=0; iwidth; i++) dst32[i] = ((src[i] << 24) | (src[i] << 16) | (src[i] << 8) | src[i]); } else for (i=0; iwidth; i++) dst32[i] = (src[i] << 24) | 0xFFFFFF; break; case DSPF_AiRGB: for (i=0; iwidth; i++) dst32[i] = ((src[i] ^ 0xFF) << 24) | 0xFFFFFF; break; case DSPF_ARGB4444: for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0xFFF; break; case DSPF_ARGB2554: for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0x3FFF; break; case DSPF_ARGB1555: for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0x7FFF; break; case DSPF_A8: direct_memcpy( dst, src, glyph->width ); break; case DSPF_A4: for (i=0, j=0; iwidth; i+=2, j++) dst8[j] = (src[i] & 0xF0) | (src[i+1] >> 4); break; case DSPF_A1: for (i=0, j=0; i < glyph->width; ++j) { register u8 p = 0; for (n=0; n<8 && iwidth; ++i, ++n) p |= (src[i] & 0x80) >> n; dst8[j] = p; } break; default: break; } break; case ft_pixel_mode_mono: switch (format) { case DSPF_ARGB: for (i=0; iwidth; i++) dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0xFF : 0x00) << 24) | 0xFFFFFF; break; case DSPF_AiRGB: for (i=0; iwidth; i++) dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x00 : 0xFF) << 24) | 0xFFFFFF; break; case DSPF_ARGB4444: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0xF : 0x0) << 12) | 0xFFF; break; case DSPF_ARGB2554: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x3 : 0x0) << 14) | 0x3FFF; break; case DSPF_ARGB1555: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x1 : 0x0) << 15) | 0x7FFF; break; case DSPF_A8: for (i=0; iwidth; i++) dst8[i] = (src[i>>3] & (1<<(7-(i%8)))) ? 0xFF : 0x00; break; case DSPF_A4: for (i=0, j=0; iwidth; i+=2, j++) dst8[j] = ((src[i>>3] & (1<<(7-(i%8)))) ? 0xF0 : 0x00) | ((src[(i+1)>>3] & (1<<(7-((i+1)%8)))) ? 0x0F : 0x00); break; case DSPF_A1: direct_memcpy( dst, src, DFB_BYTES_PER_LINE(DSPF_A1, glyph->width) ); break; default: break; } break; default: break; } src += slot->bitmap.pitch; dst += pitch; } } static int do_face( FT_Face face, int size ) { int i, ret; int align = DFB_PIXELFORMAT_ALIGNMENT( 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; FT_ULong code; FT_UInt index; DGIFFFaceHeader header; DGIFFGlyphInfo *glyphs; DGIFFGlyphRow *rows; void **row_data; D_DEBUG_AT( mkdgiff, "%s( %p, %d ) <- %ld glyphs\n", __FUNCTION__, face, size, face->num_glyphs ); /* Clear to not leak any data into file. */ memset( &header, 0, sizeof(header) ); /* Set the desired size. */ ret = FT_Set_Char_Size( face, 0, size << 6, 0, 0 ); if (ret) { D_ERROR( "Could not set pixel size to %d!\n", size ); return ret; } /* Allocate glyph info array. */ glyphs = D_CALLOC( face->num_glyphs, sizeof(DGIFFGlyphInfo) ); rows = D_CALLOC( face->num_glyphs, sizeof(DGIFFGlyphRow) ); /* WORST case :) */ row_data = D_CALLOC( face->num_glyphs, sizeof(void*) ); /* WORST case :) */ for (code = FT_Get_First_Char( face, &index ); index; code = FT_Get_Next_Char( face, code, &index )) { FT_GlyphSlot slot; DGIFFGlyphInfo *glyph = &glyphs[num_glyphs]; DGIFFGlyphRow *row = &rows[num_rows - 1]; D_DEBUG_AT( mkdgiff, " -> code %3lu - index %3u\n", code, index ); if (num_glyphs == face->num_glyphs) { D_ERROR( "Actual number of characters is bigger than number of glyphs!\n" ); break; } ret = FT_Load_Glyph( face, index, FT_LOAD_RENDER ); if (ret) { D_ERROR( "Could not render glyph for character index %d!\n", index ); goto out; } slot = face->glyph; glyph->unicode = code; glyph->width = slot->bitmap.width; glyph->height = slot->bitmap.rows; glyph->left = slot->bitmap_left; glyph->top = (face->size->metrics.ascender >> 6) - slot->bitmap_top; glyph->advance = slot->advance.x >> 6; num_glyphs++; if (row->width > 0 && row->width + glyph->width > MAX_ROW_WIDTH) { num_rows++; row++; } row->width += (glyph->width + align) & ~align; if (row->height < glyph->height) row->height = glyph->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( 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 reloading character 0x%x (%d)\n", glyph->unicode, i ); ret = FT_Load_Char( face, glyph->unicode, FT_LOAD_RENDER ); if (ret) { D_ERROR( "Could not render glyph for unicode character 0x%x!\n", glyph->unicode ); goto out; } 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, face->glyph, row_data[row_index] + DFB_BYTES_PER_LINE( 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 = size; header.ascender = face->size->metrics.ascender >> 6; header.descender = face->size->metrics.descender >> 6; header.height = header.ascender - header.descender + 1; header.max_advance = face->size->metrics.max_advance >> 6; header.pixelformat = format; header.num_glyphs = num_glyphs; header.num_rows = num_rows; 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 ); } out: for (i=0; idebug = true; direct_config->debugmem = true; /* Parse the command line. */ if (!parse_command_line( argc, argv )) return -1; if (!size_count) { fprintf( stderr, "\n\nUsing default sizes 8, 10, 12, 16, 22, 32\n" ); size_count = 6; face_sizes[0] = 8; face_sizes[1] = 10; face_sizes[2] = 12; face_sizes[3] = 16; face_sizes[4] = 22; face_sizes[5] = 32; } header.num_faces = size_count; ret = FT_Init_FreeType( &library ); if (ret) { D_ERROR( "Initialization of the FreeType2 library failed!\n" ); goto out; } ret = FT_New_Face( library, filename, face_index, &face ); if (ret) { if (ret == FT_Err_Unknown_File_Format) D_ERROR( "Unsupported font format in file `%s'!\n", filename ); else D_ERROR( "Failed loading face %d from font file `%s'!\n", face_index, filename ); goto out; } ret = FT_Select_Charmap( face, ft_encoding_unicode ); if (ret) { D_ERROR( "Couldn't select Unicode encoding, falling back to Latin1.\n" ); ret = FT_Select_Charmap( face, ft_encoding_latin_1 ); if (ret) D_ERROR( "Couldn't even select Latin1 encoding!\n" ); } fwrite( &header, sizeof(header), 1, stdout ); for (i=0; i