]> git.tdb.fi Git - ttf2png.git/blobdiff - ttf2png.c
Bump version to 2.0
[ttf2png.git] / ttf2png.c
index 6543a8d8a009b2de12f898c6effcb964707012b1..76c2e0d96d7330fa530fe00d842b42eca40573e7 100644 (file)
--- a/ttf2png.c
+++ b/ttf2png.c
@@ -1,6 +1,6 @@
 /*
 ttf2png - True Type Font to PNG converter
-Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions
+Copyright (c) 2004-2021 Mikko Rasa, Mikkosoft Productions
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ typedef struct sImage
 {
        unsigned w, h;
        unsigned char *data;
+       unsigned border;
 } Image;
 
 typedef struct sGlyph
@@ -44,8 +45,8 @@ typedef struct sGlyph
 
 typedef struct sKerning
 {
-       unsigned left_code;
-       unsigned right_code;
+       Glyph *left_glyph;
+       Glyph *right_glyph;
        int distance;
 } Kerning;
 
@@ -67,17 +68,17 @@ typedef struct sRange
        unsigned last;
 } Range;
 
-typedef int bool;
+typedef unsigned char bool;
 
 void usage(void);
 int convert_numeric_option(char, int);
 void convert_code_point_range(char, Range *);
-unsigned str_to_code_point(const char *, char **);
+int str_to_code_point(const char *, char **);
 void convert_size(char, unsigned *, unsigned *);
 void sort_and_compact_ranges(Range *, unsigned *);
 int range_cmp(const void *, const void *);
 unsigned round_to_pot(unsigned);
-void *alloc_image_data(size_t, size_t);
+int init_image(Image *, size_t, size_t);
 int init_font(Font *, FT_Face, const Range *, unsigned, bool, unsigned, unsigned);
 int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned, unsigned);
 int copy_bitmap(const FT_Bitmap *, Image *);
@@ -288,8 +289,8 @@ int main(int argc, char **argv)
 
 void usage(void)
 {
-       printf("ttf2png 1.1 - True Type Font to PNG converter\n"
-               "Copyright (c) 2004-2018  Mikko Rasa, Mikkosoft Productions\n"
+       printf("ttf2png 2.0 - True Type Font to PNG converter\n"
+               "Copyright (c) 2004-2021  Mikko Rasa, Mikkosoft Productions\n"
                "Distributed under the GNU General Public License\n\n");
 
        printf("Usage: ttf2png [options] <TTF file>\n\n");
@@ -308,8 +309,9 @@ void usage(void)
                "  -p  Pack the glyphs tightly instead of in a grid\n"
                "  -m  Margin around image edges (packed mode only) [0]\n"
                "  -n  Padding between glyphs (packed mode only) [1]\n"
-               "  -g  Allow non-power-of-two result\n"
-               "  -f  Create a distance field texture\n"
+               "  -g  Allow non-power-of-two result\n");
+       printf("  -f  Create a distance field texture\n"
+               "  -b  Specify distance field border zone width\n"
                "  -d  File name for writing glyph definitions\n"
                "  -h  Print this message\n");
 }
@@ -342,11 +344,11 @@ void convert_code_point_range(char opt, Range *range)
        }
 
        value = str_to_code_point(optarg, &ptr);
-       if(value>0 && *ptr==',')
+       if(value>=0 && *ptr==',')
        {
                range->first = value;
                value = str_to_code_point(ptr+1, &ptr);
-               if(value>0 && !*ptr)
+               if(value>=(int)range->first && !*ptr)
                {
                        range->last = value;
                        return;
@@ -357,7 +359,7 @@ void convert_code_point_range(char opt, Range *range)
        exit(1);
 }
 
-unsigned str_to_code_point(const char *nptr, char **endptr)
+int str_to_code_point(const char *nptr, char **endptr)
 {
        if(nptr[0]=='U' && nptr[1]=='+')
                return strtoul(nptr+2, endptr, 16);
@@ -372,9 +374,9 @@ unsigned str_to_code_point(const char *nptr, char **endptr)
 
                for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
                        if((nptr[bytes]&0xC0)!=0x80)
-                               return 0;
+                               return -1;
                if(bytes<2)
-                       return 0;
+                       return -1;
 
                code = nptr[0]&(0x3F>>bytes);
                for(i=1; i<bytes; ++i)
@@ -487,28 +489,33 @@ unsigned round_to_pot(unsigned n)
        return n+1;
 }
 
-void *alloc_image_data(size_t a, size_t b)
+int init_image(Image *image, size_t w, size_t h)
 {
-       void *ptr;
+       size_t s;
+
+       image->w = w;
+       image->h = h;
+       image->data = NULL;
+       image->border = 0;
+
+       if(!image->w || !image->h)
+               return 0;
 
-       /* Carry out the multiplication manually so we can check for overflow. */
-       while(b>1)
+       s = w*h;
+       if(s/h!=w)
        {
-               size_t c = a;
-               a *= 2;
-               if(b&1)
-                       a += c;
-               if(a<c)
-               {
-                       fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
-                       return NULL;
-               }
-               b /= 2;
+               fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
+               return -1;
+       }
+
+       image->data = malloc(s);
+       if(!image->data)
+       {
+               fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
+               return -1;
        }
-       ptr = malloc(a);
-       if(!ptr)
-               fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
-       return ptr;
+
+       return 0;
 }
 
 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border)
@@ -556,8 +563,8 @@ int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges,
                                }
 
                                kern = &font->kerning[font->n_kerning++];
-                               kern->left_code = font->glyphs[i].code;
-                               kern->right_code = font->glyphs[j].code;
+                               kern->left_glyph = &font->glyphs[i];
+                               kern->right_glyph = &font->glyphs[j];
                                kern->distance = (kerning.x/scale+32)/64;
                        }
                }
@@ -655,20 +662,10 @@ int copy_bitmap(const FT_Bitmap *bmp, Image *image)
        unsigned char *src;
        unsigned char *dst;
 
-       image->w = bmp->width;
-       image->h = bmp->rows;
+       if(init_image(image, bmp->width, bmp->rows))
+               return -1;
        if(!image->w || !image->h)
-       {
-               image->data = NULL;
                return 0;
-       }
-
-       image->data = (unsigned char *)malloc(image->w*image->h);
-       if(!image->data)
-       {
-               fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
-               return -1;
-       }
 
        if(bmp->pitch<0)
                src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
@@ -746,27 +743,15 @@ int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, un
        unsigned x, y;
        Image base_image;
 
-       if(!bmp->width || !bmp->rows)
-       {
-               image->w = 0;
-               image->h = 0;
-               image->data = NULL;
+       if(init_image(image, (bmp->width+scale-1)/scale+2*margin, (bmp->rows+scale-1)/scale+2*margin))
+               return -1;
+       if(!image->w || !image->h)
                return 0;
-       }
 
        if(copy_bitmap(bmp, &base_image))
                return -1;
 
-       image->w = (base_image.w-1)/scale+2*margin+1;
-       image->h = (base_image.h-1)/scale+2*margin+1;
-       image->data = (unsigned char *)malloc(image->w*image->h);
-       if(!image->data)
-       {
-               fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
-               free(base_image.data);
-               return -1;
-       }
-
+       image->border = margin;
        for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
        {
                int bx = (x-margin)*scale+scale/2;
@@ -788,7 +773,7 @@ int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool s
 {
        unsigned i;
        int top = 0, bot = 0;
-       unsigned first, last;
+       unsigned first, n_cells;
        unsigned maxw = 0, maxh = 0;
 
        /* Find extremes of the glyph images. */
@@ -844,18 +829,15 @@ int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool s
        }
 
        first = font->glyphs[0].code;
-       if(!seq)
-               first -= first%cpl;
-       last = font->glyphs[font->n_glyphs-1].code;
-
-       font->image.w = cpl*cellw;
        if(seq)
-               font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
+               n_cells = font->n_glyphs;
        else
-               font->image.h = (last-first+cpl)/cpl*cellh;
+       {
+               first -= first%cpl;
+               n_cells = font->glyphs[font->n_glyphs-1].code+1-first;
+       }
 
-       font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
-       if(!font->image.data)
+       if(init_image(&font->image, cpl*cellw, (n_cells+cpl-1)/cpl*cellh))
                return -1;
        memset(font->image.data, 0, font->image.w*font->image.h);
 
@@ -897,7 +879,7 @@ int render_packed(Font *font, unsigned margin, unsigned padding)
 {
        unsigned i;
        size_t area = 0;
-       char *used_glyphs;
+       bool *used_glyphs;
        unsigned *used_pixels;
        unsigned cx = margin, cy;
        unsigned used_h = 0;
@@ -931,13 +913,12 @@ int render_packed(Font *font, unsigned margin, unsigned padding)
        glyphs.  Since glyphs are rectangular and the image is filled starting from
        the top, it's enough to track the number of used pixels at the top of each
        column. */
-       font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
-       if(!font->image.data)
+       if(init_image(&font->image, font->image.w, font->image.h))
                return -1;
        memset(font->image.data, 0, font->image.w*font->image.h);
        used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
        memset(used_pixels, 0, font->image.w*sizeof(unsigned));
-       used_glyphs = (char *)malloc(font->n_glyphs);
+       used_glyphs = (bool *)malloc(font->n_glyphs);
        memset(used_glyphs, 0, font->n_glyphs);
 
        for(cy=margin; cy+margin<font->image.h;)
@@ -1044,19 +1025,38 @@ int save_defs(const char *fn, const Font *font)
        fprintf(out, "# Image/font info:\n");
        fprintf(out, "# width height size ascent descent\n");
        fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
+
+       fprintf(out, "\n# Code point mapping:\n");
+       fprintf(out, "# code index\n");
+       for(i=0; i<font->n_glyphs; ++i)
+       {
+               const Glyph *g = &font->glyphs[i];
+               fprintf(out, "code %u %u\n", g->code, g->index);
+       }
+
+       fprintf(out, "\n# Metrics info:\n");
+       fprintf(out, "# index width height offset_x offset_y advance\n");
+       for(i=0; i<font->n_glyphs; ++i)
+       {
+               const Glyph *g = &font->glyphs[i];
+               int b = g->image.border;
+               fprintf(out, "metrics %u %u %u %d %d %d\n", g->index, g->image.w-2*b, g->image.h-2*b, g->offset_x+b, g->offset_y+b, g->advance);
+       }
+
        fprintf(out, "\n# Glyph info:\n");
-       fprintf(out, "# code x y width height offset_x offset_y advance\n");
+       fprintf(out, "# index x y width height border\n");
        for(i=0; i<font->n_glyphs; ++i)
        {
                const Glyph *g = &font->glyphs[i];
-               fprintf(out, "glyph %u %u %u %u %u %d %d %d\n", g->code, g->x, g->y, g->image.w, g->image.h, g->offset_x, g->offset_y, g->advance);
+               fprintf(out, "glyph %u %u %u %u %u %u\n", g->index, g->x, g->y, g->image.w, g->image.h, g->image.border);
        }
+
        fprintf(out, "\n# Kerning info:\n");
        fprintf(out, "# left right distance\n");
        for(i=0; i<font->n_kerning; ++i)
        {
                const Kerning *k = &font->kerning[i];
-               fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
+               fprintf(out, "kern %u %u %d\n", k->left_glyph->index, k->right_glyph->index, k->distance);
        }
 
        fclose(out);