]> git.tdb.fi Git - ttf2png.git/blobdiff - ttf2png.c
Round kerning values to nearest integer rather than down
[ttf2png.git] / ttf2png.c
index 7ef19e14860d9590e8e748dfccde291c0779c1f1..e890e33643084f7784c8d23e280555c425e8fec4 100644 (file)
--- a/ttf2png.c
+++ b/ttf2png.c
@@ -28,18 +28,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 typedef struct sImage
 {
        unsigned w, h;
-       char     *data;
+       unsigned char *data;
 } Image;
 
 typedef struct sGlyph
 {
        unsigned index;
        unsigned code;
-       Image    image;
+       Image image;
        unsigned x, y;
-       int      offset_x;
-       int      offset_y;
-       int      advance;
+       int offset_x;
+       int offset_y;
+       int advance;
 } Glyph;
 
 typedef struct sKerning
@@ -52,21 +52,37 @@ typedef struct sKerning
 typedef struct sFont
 {
        unsigned size;
-       int      ascent;
-       int      descent;
+       int ascent;
+       int descent;
        unsigned n_glyphs;
-       Glyph    *glyphs;
+       Glyph *glyphs;
        unsigned n_kerning;
-       Kerning  *kerning;
-       Image    image;
+       Kerning *kerning;
+       Image image;
 } Font;
 
+typedef struct sRange
+{
+       unsigned first;
+       unsigned last;
+} Range;
+
+typedef int 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 **);
+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 usage();
 void *alloc_image_data(size_t, size_t);
-int init_font(Font *, FT_Face, unsigned, unsigned, int);
-int render_grid(Font *, unsigned, unsigned, unsigned, int);
-int render_packed(Font *);
+int init_font(Font *, FT_Face, const Range *, unsigned, bool);
+int init_glyphs(Font *, FT_Face, const Range *, bool);
+int copy_bitmap(const FT_Bitmap *, Image *);
+int render_grid(Font *, unsigned, unsigned, unsigned, bool, bool);
+int render_packed(Font *, unsigned, unsigned, bool);
 int save_defs(const char *, const Font *);
 int save_png(const char *, const Image *, char);
 
@@ -75,23 +91,26 @@ char verbose = 0;
 int main(int argc, char **argv)
 {
        char *fn;
-       int  begin = 0;
-       int  end = 255;
-       int  size = 10;
-       int  cpl = 0;
-       int  cellw = 0;
-       int  cellh = 0;
-       char autohinter = 0;
-       char seq = 0;
-       char alpha = 0;
-       char invert = 0;
-       char pack = 0;
+       Range *ranges = NULL;
+       unsigned n_ranges = 0;
+       unsigned size = 10;
+       unsigned cpl = 0;
+       unsigned cellw = 0;
+       unsigned cellh = 0;
+       bool autohinter = 0;
+       bool seq = 0;
+       bool alpha = 0;
+       bool invert = 0;
+       bool pack = 0;
+       unsigned margin = 0;
+       unsigned padding = 1;
+       bool npot = 0;
 
        FT_Library freetype;
-       FT_Face    face;
+       FT_Face face;
 
-       int  err;
-       int  i;
+       int err;
+       int i;
 
        char *out_fn = "font.png";
        char *def_fn = NULL;
@@ -104,65 +123,22 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pi")) != -1)
+       while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:f")) != -1)
        {
-               char *ptr;
-               int  temp;
                switch(i)
                {
                case 'r':
-                       if(!strcmp(optarg, "all"))
-                       {
-                               begin = 0;
-                               end = 0x110000;
-                       }
-                       else
-                       {
-                               if(!isdigit(optarg[0]))
-                                       temp = -1;
-                               else
-                               {
-                                       temp = strtol(optarg, &ptr, 0);
-                                       if(ptr[0]!=',' || !isdigit(ptr[1]))
-                                               temp = -1;
-                               }
-                               if(temp<0)
-                               {
-                                       printf("Not a valid range: %s\n", optarg);
-                                       exit(1);
-                               }
-                               else
-                               {
-                                       begin = temp;
-                                       end = strtol(ptr+1, NULL, 0);
-                               }
-                       }
+                       ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
+                       convert_code_point_range('r', &ranges[n_ranges-1]);
                        break;
                case 's':
-                       size = strtol(optarg, NULL, 0);
+                       size = convert_numeric_option('s', 1);
                        break;
                case 'l':
-                       cpl = strtol(optarg, NULL, 0);
+                       cpl = convert_numeric_option('l', 1);
                        break;
                case 'c':
-                       if(!strcmp(optarg, "auto"))
-                       {
-                               cellw = 0;
-                               cellh = 0;
-                       }
-                       else if(!strcmp(optarg, "autorect"))
-                       {
-                               cellw = 0;
-                               cellh = 1;
-                       }
-                       else
-                       {
-                               cellw = strtol(optarg, &ptr, 0);
-                               if(ptr[0]=='x' && isdigit(ptr[1]))
-                                       cellh = strtol(ptr+1, NULL, 0);
-                               else
-                                       cellh = cellw;
-                       }
+                       convert_size('c', &cellw, &cellh);
                        break;
                case 'o':
                        out_fn = optarg;
@@ -192,6 +168,15 @@ int main(int argc, char **argv)
                case 'i':
                        invert = 1;
                        break;
+               case 'm':
+                       margin = convert_numeric_option('m', 0);
+                       break;
+               case 'n':
+                       padding = convert_numeric_option('n', 0);
+                       break;
+               case 'f':
+                       npot = 1;
+                       break;
                }
        }
        if(!strcmp(out_fn, "-"))
@@ -235,15 +220,31 @@ int main(int argc, char **argv)
                return 1;
        }
 
+       if(!n_ranges)
+       {
+               ranges = malloc(sizeof(Range));
+               ranges[0].first = 0;
+               ranges[0].last = 255;
+               n_ranges = 1;
+       }
+       else
+               sort_and_compact_ranges(ranges, &n_ranges);
+
        font.size = size;
-       err = init_font(&font, face, begin, end, autohinter);
+       err = init_font(&font, face, ranges, n_ranges, autohinter);
        if(err)
                return 1;
 
+       if(!font.n_glyphs)
+       {
+               fprintf(stderr, "No glyphs found in the requested range\n");
+               return 1;
+       }
+
        if(pack)
-               err = render_packed(&font);
+               err = render_packed(&font, margin, padding, npot);
        else
-               err = render_grid(&font, cellw, cellh, cpl, seq);
+               err = render_grid(&font, cellw, cellh, cpl, seq, npot);
        if(err)
                return 1;
 
@@ -264,6 +265,7 @@ int main(int argc, char **argv)
        free(font.glyphs);
        free(font.kerning);
        free(font.image.data);
+       free(ranges);
 
        FT_Done_Face(face);
        FT_Done_FreeType(freetype);
@@ -271,42 +273,206 @@ int main(int argc, char **argv)
        return 0;
 }
 
-unsigned round_to_pot(unsigned n)
-{
-       n -= 1;
-       n |= n>>1;
-       n |= n>>2;
-       n |= n>>4;
-       n |= n>>8;
-       n |= n>>16;
-
-       return n+1;
-}
-
-void usage()
+void usage(void)
 {
-       printf("ttf2png - True Type Font to PNG converter\n"
-               "Copyright (c) 2004-2008  Mikko Rasa, Mikkosoft Productions\n"
+       printf("ttf2png 1.1 - True Type Font to PNG converter\n"
+               "Copyright (c) 2004-2018  Mikko Rasa, Mikkosoft Productions\n"
                "Distributed under the GNU General Public License\n\n");
 
        printf("Usage: ttf2png [options] <TTF file>\n\n");
 
        printf("Accepted options (default values in [brackets])\n"
-               "  -r  Range of characters to convert [0,255]\n"
+               "  -r  Range of code points to convert [0,255]\n"
                "  -s  Font size to use, in pixels [10]\n"
-               "  -l  Number of characters to put in one line [auto]\n"
-               "  -c  Character cell size, in pixels [auto]\n"
+               "  -l  Number of glyphs to put in one line [auto]\n"
+               "  -c  Glyph cell size, in pixels (grid mode only) [auto]\n"
                "  -o  Output file name (or - for stdout) [font.png]\n");
        printf("  -a  Force autohinter\n"
                "  -t  Render glyphs to alpha channel\n"
                "  -i  Invert colors of the glyphs\n"
                "  -v  Increase the level of verbosity\n"
-               "  -e  Use cells in sequence, without gaps\n"
+               "  -e  Use cells in sequence, without gaps (grid mode only)\n"
                "  -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"
+               "  -f  Allow non-power-of-two result\n"
                "  -d  File name for writing glyph definitions\n"
                "  -h  Print this message\n");
 }
 
+int convert_numeric_option(char opt, int min_value)
+{
+       int value;
+       char *ptr;
+
+       value = strtol(optarg, &ptr, 0);
+       if(value<min_value || *ptr)
+       {
+               printf("Invalid option argument in -%c %s\n", opt, optarg);
+               exit(1);
+       }
+
+       return value;
+}
+
+void convert_code_point_range(char opt, Range *range)
+{
+       int value;
+       char *ptr;
+
+       if(!strcmp(optarg, "all"))
+       {
+               range->first = 0;
+               range->last = 0x10FFFF;
+               return;
+       }
+
+       value = str_to_code_point(optarg, &ptr);
+       if(value>0 && *ptr==',')
+       {
+               range->first = value;
+               value = str_to_code_point(ptr+1, &ptr);
+               if(value>0 && !*ptr)
+               {
+                       range->last = value;
+                       return;
+               }
+       }
+
+       printf("Invalid option argument in -%c %s\n", opt, optarg);
+       exit(1);
+}
+
+unsigned str_to_code_point(const char *nptr, char **endptr)
+{
+       if(nptr[0]=='U' && nptr[1]=='+')
+               return strtoul(nptr+2, endptr, 16);
+       else if(nptr[0]&0x80)
+       {
+               unsigned bytes;
+               unsigned code;
+               unsigned i;
+
+               if(endptr)
+                       *endptr = (char *)nptr;
+
+               for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
+                       if((nptr[bytes]&0xC0)!=0x80)
+                               return 0;
+               if(bytes<2)
+                       return 0;
+
+               code = nptr[0]&(0x3F>>bytes);
+               for(i=1; i<bytes; ++i)
+                       code = (code<<6)|(nptr[i]&0x3F);
+
+               if(endptr)
+                       *endptr = (char *)nptr+bytes;
+
+               return code;
+       }
+       else if(isdigit(nptr[0]))
+               return strtoul(nptr, endptr, 0);
+       else
+       {
+               if(endptr)
+                       *endptr = (char *)nptr+1;
+               return *nptr;
+       }
+}
+
+void convert_size(char opt, unsigned *width, unsigned *height)
+{
+       int value;
+       char *ptr;
+
+       if(!strcmp(optarg, "auto"))
+       {
+               *width = 0;
+               *height = 0;
+               return;
+       }
+       else if(!strcmp(optarg, "autorect"))
+       {
+               *width = 0;
+               *height = 1;
+               return;
+       }
+
+       value = strtol(optarg, &ptr, 0);
+       if(value>0)
+       {
+               *width = value;
+               if(*ptr=='x')
+               {
+                       value = strtol(ptr+1, &ptr, 0);
+                       if(value>0 && !*ptr)
+                       {
+                               *height = value;
+                               return;
+                       }
+               }
+               else if(!*ptr)
+               {
+                       *height = *width;
+                       return;
+               }
+       }
+
+       printf("Invalid option argument in -%c %s\n", opt, optarg);
+       exit(1);
+}
+
+void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
+{
+       unsigned i, j;
+
+       if(!*n_ranges)
+               return;
+
+       qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
+       for(i=0, j=1; j<*n_ranges; ++j)
+       {
+               if(ranges[i].last+1>=ranges[j].first)
+               {
+                       if(ranges[j].last>ranges[i].last)
+                               ranges[i].last = ranges[j].last;
+               }
+               else
+               {
+                       ++i;
+                       if(i!=j)
+                               ranges[i] = ranges[j];
+               }
+       }
+
+       *n_ranges = i+1;
+}
+
+int range_cmp(const void *p1, const void *p2)
+{
+       const Range *r1 = (const Range *)p1;
+       const Range *r2 = (const Range *)p2;
+       if(r1->first!=r2->first)
+               return (r1->first<r2->first ? -1 : 1);
+       else if(r1->last!=r2->last)
+               return (r1->last<r2->last ? -1 : 1);
+       else
+               return 0;
+}
+
+unsigned round_to_pot(unsigned n)
+{
+       n -= 1;
+       n |= n>>1;
+       n |= n>>2;
+       n |= n>>4;
+       n |= n>>8;
+       n |= n>>16;
+
+       return n+1;
+}
+
 void *alloc_image_data(size_t a, size_t b)
 {
        void *ptr;
@@ -320,24 +486,24 @@ void *alloc_image_data(size_t a, size_t b)
                        a += c;
                if(a<c)
                {
-                       fprintf(stderr, "Cannot allocate %d kbytes of memory for image\n", c/1024*b);
+                       fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
                        return NULL;
                }
                b /= 2;
        }
        ptr = malloc(a);
        if(!ptr)
-               fprintf(stderr, "Cannot allocate %d kbytes of memory for image\n", a/1024*b);
+               fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
        return ptr;
 }
 
-int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autohinter)
+int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter)
 {
        unsigned i, j;
        unsigned size = 0;
 
-       font->ascent = (face->size->metrics.ascender+63)>>6;
-       font->descent = (face->size->metrics.descender+63)>>6;
+       font->ascent = (face->size->metrics.ascender+63)/64;
+       font->descent = (face->size->metrics.descender-63)/64;
 
        if(verbose>=1)
        {
@@ -347,13 +513,57 @@ int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autoh
 
        font->n_glyphs = 0;
        font->glyphs = NULL;
-       for(i=first; i<=last; ++i)
+       for(i=0; i<n_ranges; ++i)
+               if(init_glyphs(font, face, &ranges[i], autohinter))
+                       return -1;
+
+       if(verbose>=1)
+               printf("Loaded %u glyphs\n", font->n_glyphs);
+
+       font->n_kerning = 0;
+       font->kerning = NULL;
+       for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
+               if(j!=i)
+               {
+                       FT_Vector kerning;
+                       FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
+
+                       /* FreeType documentation says that vertical kerning is practically
+                       never used, so we ignore it. */
+                       if(kerning.x)
+                       {
+                               Kerning *kern;
+
+                               if(font->n_kerning>=size)
+                               {
+                                       size += 16;
+                                       font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
+                               }
+
+                               kern = &font->kerning[font->n_kerning++];
+                               kern->left_code = font->glyphs[i].code;
+                               kern->right_code = font->glyphs[j].code;
+                               kern->distance = (kerning.x+32)/64;
+                       }
+               }
+
+       if(verbose>=1)
+               printf("Loaded %d kerning pairs\n", font->n_kerning);
+
+       return 0;
+}
+
+int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter)
+{
+       unsigned i, j;
+       unsigned size = font->n_glyphs;
+
+       for(i=range->first; i<=range->last; ++i)
        {
-               unsigned  n;
+               unsigned n;
                FT_Bitmap *bmp = &face->glyph->bitmap;
-               int       x, y;
-               int       flags = 0;
-               Glyph     *glyph;
+               int flags = 0;
+               Glyph *glyph;
 
                n = FT_Get_Char_Index(face, i);
                if(!n)
@@ -365,11 +575,29 @@ int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autoh
                FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
 
                if(verbose>=2)
-                       printf("  Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
+               {
+                       printf("  Code point U+%04X", i);
+                       if(i>=0x20 && i<0x7F)
+                               printf(" (%c)", i);
+                       else if(i>=0xA0 && i<=0x10FFFF)
+                       {
+                               char utf8[5];
+                               unsigned bytes;
+
+                               for(bytes=2; i>>(1+bytes*5); ++bytes) ;
+                               for(j=0; j<bytes; ++j)
+                                       utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
+                               utf8[0] |= 0xF0<<(4-bytes);
+                               utf8[j] = 0;
 
-               if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
+                               printf(" (%s)", utf8);
+                       }
+                       printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
+               }
+
+               if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
                {
-                       fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
+                       fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
                        continue;
                }
 
@@ -382,74 +610,71 @@ int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autoh
                glyph = &font->glyphs[font->n_glyphs++];
                glyph->index = n;
                glyph->code = i;
-               glyph->image.w = bmp->width;
-               glyph->image.h = bmp->rows;
-               glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
-               if(!glyph->image.data)
-               {
-                       fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
-                       return -1;
-               }
                glyph->offset_x = face->glyph->bitmap_left;
                glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
                glyph->advance = (int)(face->glyph->advance.x+32)/64;
 
                /* Copy the glyph image since FreeType uses a global buffer, which would
                be overwritten by the next glyph.  Negative pitch means the scanlines
-               start from the bottom */
-               if(bmp->pitch<0)
-               {
-                       for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
-                               glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
-               }
-               else
-               {
-                       for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
-                               glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
-               }
+               start from the bottom. */
+               if(copy_bitmap(bmp, &glyph->image))
+                       return -1;
        }
 
-       if(verbose>=1)
-               printf("Loaded %u glyphs\n", font->n_glyphs);
+       return 0;
+}
 
-       size = 0;
-       font->n_kerning = 0;
-       font->kerning = NULL;
-       for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
-               if(j!=i)
-               {
-                       FT_Vector kerning;
-                       FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
+int copy_bitmap(const FT_Bitmap *bmp, Image *image)
+{
+       unsigned x, y;
+       unsigned char *src;
+       unsigned char *dst;
 
-                       /* FreeType documentation says that vertical kerning is practically
-                       never used, so we ignore it. */
-                       if(kerning.x)
-                       {
-                               Kerning *kern;
+       image->w = bmp->width;
+       image->h = bmp->rows;
+       if(!image->w || !image->h)
+       {
+               image->data = NULL;
+               return 0;
+       }
 
-                               if(font->n_kerning>=size)
-                               {
-                                       size += 16;
-                                       font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
-                               }
+       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;
+       }
 
-                               kern = &font->kerning[font->n_kerning++];
-                               kern->left_code = font->glyphs[i].code;
-                               kern->right_code = font->glyphs[j].code;
-                               kern->distance = kerning.x/64;
-                       }
+       if(bmp->pitch<0)
+               src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
+       else
+               src = bmp->buffer;
+       dst = image->data;
+
+       for(y=0; y<bmp->rows; ++y)
+       {
+               if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
+               {
+                       for(x=0; x<bmp->width; ++x)
+                               dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
+               }
+               else
+               {
+                       for(x=0; x<bmp->width; ++x)
+                               dst[x] = src[x];
                }
 
-       if(verbose>=1)
-               printf("Loaded %d kerning pairs\n", font->n_kerning);
+               src += bmp->pitch;
+               dst += image->w;
+       }
 
        return 0;
 }
 
-int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int seq)
+int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
 {
        unsigned i;
-       int      top = 0, bot = 0;
+       int top = 0, bot = 0;
        unsigned first, last;
        unsigned maxw = 0, maxh = 0;
 
@@ -510,17 +735,24 @@ int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int se
                first -= first%cpl;
        last = font->glyphs[font->n_glyphs-1].code;
 
-       font->image.w = round_to_pot(cpl*cellw);
-       font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
+       font->image.w = cpl*cellw;
+       if(!npot)
+               font->image.w = round_to_pot(font->image.w);
+       if(seq)
+               font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
+       else
+               font->image.h = (last-first+cpl)/cpl*cellh;
+       if(!npot)
+               font->image.h = round_to_pot(font->image.h);
 
-       font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
+       font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
        if(!font->image.data)
                return -1;
        memset(font->image.data, 255, font->image.w*font->image.h);
 
        for(i=0; i<font->n_glyphs; ++i)
        {
-               Glyph    *glyph;
+               Glyph *glyph;
                unsigned ci, cx, cy;
                unsigned x, y;
 
@@ -552,19 +784,19 @@ int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int se
        return 0;
 }
 
-int render_packed(Font *font)
+int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
 {
        unsigned i;
-       size_t   area = 0;
-       char     *used_glyphs;
+       size_t area = 0;
+       char *used_glyphs;
        unsigned *used_pixels;
-       unsigned cx = 0, cy;
+       unsigned cx = margin, cy;
        unsigned used_h = 0;
 
        /* Compute the total area occupied by glyphs and padding. */
        for(i=0; i<font->n_glyphs; ++i)
        {
-               size_t a = area+(font->glyphs[i].image.w+1)*(font->glyphs[i].image.h+1);
+               size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
                if(a<area)
                {
                        fprintf(stderr, "Overflow in counting total glyph area\n");
@@ -577,17 +809,20 @@ int render_packed(Font *font)
        imperfections in the packing. */
        for(font->image.w=1;; font->image.w<<=1)
        {
-               font->image.h = (area*5/4)/font->image.w;
+               if(font->image.w<=margin*2)
+                       continue;
+               font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
                if(font->image.h<=font->image.w)
                        break;
        }
-       font->image.h = round_to_pot(font->image.h);
+       if(!npot)
+               font->image.h = round_to_pot(font->image.h);
 
        /* Allocate arrays for storing the image and keeping track of used pixels and
        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 = (char *)alloc_image_data(font->image.w, font->image.h);
+       font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
        if(!font->image.data)
                return -1;
        memset(font->image.data, 255, font->image.w*font->image.h);
@@ -596,29 +831,29 @@ int render_packed(Font *font)
        used_glyphs = (char *)malloc(font->n_glyphs);
        memset(used_glyphs, 0, font->n_glyphs);
 
-       for(cy=0; cy<font->image.h;)
+       for(cy=margin; cy+margin<font->image.h;)
        {
                unsigned w;
                unsigned x, y;
-               Glyph    *glyph = NULL;
+               Glyph *glyph = NULL;
                unsigned best_score = 0;
                unsigned target_h = 0;
 
-               /* Find the leftmost free pixel on this row.    Also record the lowest extent of glyphs
-               to the left of the free position. */
-               for(; (cx<font->image.w && used_pixels[cx]>cy); ++cx)
-                       if(used_pixels[cx]-cy-1>target_h)
-                               target_h = used_pixels[cx]-cy-1;
+               /* Find the leftmost free pixel on this row.  Also record the lowest
+               extent of glyphs to the left of the free position. */
+               for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
+                       if(used_pixels[cx]-cy-padding>target_h)
+                               target_h = used_pixels[cx]-cy-padding;
 
-               if(cx>=font->image.w)
+               if(cx+margin>=font->image.w)
                {
-                       cx = 0;
+                       cx = margin;
                        ++cy;
                        continue;
                }
 
                /* Count the free pixel at this position. */
-               for(w=0; (cx+w<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
+               for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
 
                /* Find a suitable glyph to put here. */
                for(i=0; i<font->n_glyphs; ++i)
@@ -633,7 +868,7 @@ int render_packed(Font *font)
                                /* Prefer glyphs that would reach exactly as low as the ones left
                                of here.  This aims to create a straight edge at the bottom for
                                lining up further glyphs. */
-                               score = g->image.h+1;
+                               score = g->image.h+padding;
                                if(g->image.h==target_h)
                                        score *= g->image.w;
                                else
@@ -663,21 +898,23 @@ int render_packed(Font *font)
                                continue;
                        font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
                }
-               for(x=0; x<glyph->image.w+2; ++x)
+               for(x=0; x<glyph->image.w+2*padding; ++x)
                {
-                       if(cx+x<1 || cx+x>font->image.w)
+                       if(cx+x<padding || cx+x>=font->image.w+padding)
                                continue;
-                       if(used_pixels[cx+x-1]<cy+glyph->image.h+1)
-                               used_pixels[cx+x-1] = cy+glyph->image.h+1;
+                       if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
+                               used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
                }
 
-               if(cy+glyph->image.h>used_h)
-                       used_h = cy+glyph->image.h;
+               if(cy+glyph->image.h+margin>used_h)
+                       used_h = cy+glyph->image.h+margin;
        }
 
        /* Trim the image to the actually used size, in case the original estimate
        was too pessimistic. */
-       font->image.h = round_to_pot(used_h);
+       font->image.h = used_h;
+       if(!npot)
+               font->image.h = round_to_pot(font->image.h);
 
        free(used_glyphs);
        free(used_pixels);
@@ -687,7 +924,7 @@ int render_packed(Font *font)
 
 int save_defs(const char *fn, const Font *font)
 {
-       FILE     *out;
+       FILE *out;
        unsigned i;
 
        out = fopen(fn, "w");
@@ -722,13 +959,13 @@ int save_defs(const char *fn, const Font *font)
 
 int save_png(const char *fn, const Image *image, char alpha)
 {
-       FILE       *out;
+       FILE *out;
        png_struct *pngs;
-       png_info   *pngi;
-       png_byte   **rows;
-       unsigned   i;
-       png_byte   *data2;
-       int        color;
+       png_info *pngi;
+       png_byte **rows;
+       unsigned i;
+       png_byte *data2 = 0;
+       int color;
 
        if(!strcmp(fn, "-"))
                out = stdout;