X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=ttf2png.c;h=0a66de26cc72f2c09772743db26f6eb7696cd5da;hb=a815ebe3941e2157639365806e9186e49ee944b5;hp=e25434945e41fa44d906ebfd1c5babc431b791a3;hpb=4e23e9715dbd92cc53c085e465c4df2e704df3c1;p=ttf2png.git diff --git a/ttf2png.c b/ttf2png.c index e254349..0a66de2 100644 --- 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,40 @@ 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; -void usage(); +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 *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, unsigned, unsigned); +int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned, unsigned); +int copy_bitmap(const FT_Bitmap *, Image *); +unsigned sqrti(unsigned); +unsigned find_distance_to_edge(const Image *, int, int, unsigned); +int create_distance_field(const FT_Bitmap *, Image *, unsigned, unsigned); +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 +94,28 @@ 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; + unsigned distfield = 0; + unsigned border = 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 +128,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:gf:b:")) != -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 +173,21 @@ 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 'g': + npot = 1; + break; + case 'f': + distfield = convert_numeric_option('f', 1); + break; + case 'b': + border = convert_numeric_option('b', 1); + break; } } if(!strcmp(out_fn, "-")) @@ -228,6 +224,14 @@ int main(int argc, char **argv) printf("Glyphs: %ld\n", face->num_glyphs); } + font.size = size; + if(distfield) + { + if(!border) + border = sqrti(font.size); + size *= distfield; + } + err = FT_Set_Pixel_Sizes(face, 0, size); if(err) { @@ -235,24 +239,39 @@ int main(int argc, char **argv) return 1; } - font.size = size; - err = init_font(&font, face, begin, end, autohinter); + 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); + + err = init_font(&font, face, ranges, n_ranges, autohinter, distfield, border); 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; - if(invert) + if(invert || distfield) { for(i=0; (unsigned)i\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" + " -g Allow non-power-of-two result\n" + " -f Create a distance field texture\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(valuefirst = 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; i0) + { + *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->firstfirst ? -1 : 1); + else if(r1->last!=r2->last) + return (r1->lastlast ? -1 : 1); + else + return 0; +} + unsigned round_to_pot(unsigned n) { n -= 1; @@ -320,24 +505,25 @@ void *alloc_image_data(size_t a, size_t b) a += c; if(a0 ? distfield : 1); - font->ascent = (face->size->metrics.ascender+63)>>6; - font->descent = (face->size->metrics.descender+63)>>6; + font->ascent = (face->size->metrics.ascender/scale+63)/64; + font->descent = (face->size->metrics.descender/scale-63)/64; if(verbose>=1) { @@ -347,13 +533,58 @@ 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=1) + printf("Loaded %u glyphs\n", font->n_glyphs); + + font->n_kerning = 0; + font->kerning = NULL; + for(i=0; in_glyphs; ++i) for(j=0; jn_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/scale+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 distfield, unsigned border) +{ + unsigned i, j; + unsigned size = font->n_glyphs; + int scale = (distfield>0 ? distfield : 1); + + 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) @@ -362,14 +593,32 @@ int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autoh if(autohinter) flags |= FT_LOAD_FORCE_AUTOHINT; FT_Load_Glyph(face, n, flags); - FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : 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-1)*6))&0x3F); + utf8[0] |= 0xF0<<(4-bytes); + utf8[j] = 0; + + printf(" (%s)", utf8); + } + printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale); + } - if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY) + 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 +631,168 @@ 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; + glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale; + glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale; + glyph->advance = (int)(face->glyph->advance.x/scale+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) + if(distfield) { - for(y=0; yrows; ++y) for(x=0; xwidth; ++x) - glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch]; + glyph->offset_x -= border; + glyph->offset_y -= border; + create_distance_field(bmp, &glyph->image, distfield, border); } else { - for(y=0; yrows; ++y) for(x=0; xwidth; ++x) - glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch]; + 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; in_glyphs; ++i) for(j=0; jn_glyphs; ++j) - if(j!=i) +int copy_bitmap(const FT_Bitmap *bmp, Image *image) +{ + unsigned x, y; + unsigned char *src; + unsigned char *dst; + + image->w = bmp->width; + image->h = bmp->rows; + 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; + else + src = bmp->buffer; + dst = image->data; + + for(y=0; yrows; ++y) + { + if(bmp->pixel_mode==FT_PIXEL_MODE_MONO) { - FT_Vector kerning; - FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning); + for(x=0; xwidth; ++x) + dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00); + } + else + { + for(x=0; xwidth; ++x) + dst[x] = src[x]; + } - /* FreeType documentation says that vertical kerning is practically - never used, so we ignore it. */ - if(kerning.x) - { - Kerning *kern; + src += bmp->pitch; + dst += image->w; + } - if(font->n_kerning>=size) - { - size += 16; - font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning)); - } + return 0; +} - 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; +unsigned sqrti(unsigned num) +{ + unsigned result = (num>0xFFFF ? 0xFFFF : 0x100); + while(result && result*result>=result+num) + result -= (result*result+result-num)/(result*2); + + return result; +} + +unsigned find_distance_to_edge(const Image *image, int origin_x, int origin_y, unsigned range) +{ + unsigned i, j; + int x, y; + unsigned char origin_pixel = 0; + unsigned closest = range*range; + + if(origin_x>=0 && (unsigned)origin_xw && origin_y>=0 && (unsigned)origin_yh) + origin_pixel = image->data[origin_x+origin_y*image->w]; + + x = origin_x-1; + y = origin_y-1; + for(i=1; (i=0 && (unsigned)xw && y>=0 && (unsigned)yh) + pixel = image->data[x+y*image->w]; + + if((pixel^origin_pixel)&0x80) + { + unsigned d = 2*i*i + k*k - 2*k*i; + if(d=1) - printf("Loaded %d kerning pairs\n", font->n_kerning); + return sqrti(closest*0x3F01)/range; +} + +int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin) +{ + unsigned x, y; + Image base_image; + + if(!bmp->width || !bmp->rows) + { + image->w = 0; + image->h = 0; + image->data = NULL; + 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; + } + + for(y=0; yh; ++y) for(x=0; xw; ++x) + { + int bx = (x-margin)*scale+scale/2; + int by = (y-margin)*scale+scale/2; + unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale); + if(bx>=0 && (unsigned)bx=0 && (unsigned)bydata[x+y*image->w] = pixel; + } + + free(base_image.data); 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 +853,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; in_glyphs; ++i) { - Glyph *glyph; + Glyph *glyph; unsigned ci, cx, cy; unsigned x, y; @@ -552,19 +902,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; in_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(aimage.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/(font->image.w-margin*2)+margin*2; if(font->image.h<=font->image.w) break; } - font->image.h = round_to_pot(font->image.h); + + /* Add some extra space to accommodate packing imperfections. */ + font->image.h = font->image.h*3/2; /* 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 +949,29 @@ int render_packed(Font *font) used_glyphs = (char *)malloc(font->n_glyphs); memset(used_glyphs, 0, font->n_glyphs); - for(cy=0; cyimage.h;) + for(cy=margin; cy+marginimage.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(; (cximage.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+marginimage.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+wimage.w && used_pixels[cx+w]<=cy); ++w) ; + for(w=0; (cx+w+marginimage.w && used_pixels[cx+w]<=cy); ++w) ; /* Find a suitable glyph to put here. */ for(i=0; in_glyphs; ++i) @@ -633,7 +986,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 +1016,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; ximage.w+2; ++x) + for(x=0; ximage.w+2*padding; ++x) { - if(cx+x<1 || cx+x>font->image.w) + if(cx+x=font->image.w+padding) continue; - if(used_pixels[cx+x-1]image.h+1) - used_pixels[cx+x-1] = cy+glyph->image.h+1; + if(used_pixels[cx+x-padding]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 +1042,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 +1077,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;