X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=ttf2png.c;h=0a66de26cc72f2c09772743db26f6eb7696cd5da;hb=a815ebe3941e2157639365806e9186e49ee944b5;hp=a634b2b9def92998add21bd3e7ecfebf077db243;hpb=c7b77aeb1a478f53c47d2aa08e7cc7728aa0898b;p=ttf2png.git diff --git a/ttf2png.c b/ttf2png.c index a634b2b..0a66de2 100644 --- a/ttf2png.c +++ b/ttf2png.c @@ -78,10 +78,11 @@ 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, const Range *, unsigned, bool, unsigned); -int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned); +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 *); -void propagate_distance(unsigned short *, int); +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); @@ -108,6 +109,7 @@ int main(int argc, char **argv) unsigned padding = 1; bool npot = 0; unsigned distfield = 0; + unsigned border = 0; FT_Library freetype; FT_Face face; @@ -126,7 +128,7 @@ int main(int argc, char **argv) return 1; } - while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:")) != -1) + while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:b:")) != -1) { switch(i) { @@ -183,6 +185,9 @@ int main(int argc, char **argv) case 'f': distfield = convert_numeric_option('f', 1); break; + case 'b': + border = convert_numeric_option('b', 1); + break; } } if(!strcmp(out_fn, "-")) @@ -219,7 +224,15 @@ int main(int argc, char **argv) printf("Glyphs: %ld\n", face->num_glyphs); } - err = FT_Set_Pixel_Sizes(face, 0, (distfield ? size*distfield : size)); + font.size = size; + if(distfield) + { + if(!border) + border = sqrti(font.size); + size *= distfield; + } + + err = FT_Set_Pixel_Sizes(face, 0, size); if(err) { fprintf(stderr, "Couldn't set size\n"); @@ -236,8 +249,7 @@ int main(int argc, char **argv) else sort_and_compact_ranges(ranges, &n_ranges); - font.size = size; - err = init_font(&font, face, ranges, n_ranges, autohinter, distfield); + err = init_font(&font, face, ranges, n_ranges, autohinter, distfield, border); if(err) return 1; @@ -504,7 +516,7 @@ void *alloc_image_data(size_t a, size_t b) return ptr; } -int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield) +int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border) { unsigned i, j; unsigned size = 0; @@ -522,7 +534,7 @@ int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, font->n_glyphs = 0; font->glyphs = NULL; for(i=0; i=1) @@ -561,7 +573,7 @@ int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, return 0; } -int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield) +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; @@ -628,11 +640,9 @@ int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, u start from the bottom. */ if(distfield) { - unsigned margin = 3; - - glyph->offset_x -= margin; - glyph->offset_y -= margin; - create_distance_field(bmp, &glyph->image, distfield, margin); + glyph->offset_x -= border; + glyph->offset_y -= border; + create_distance_field(bmp, &glyph->image, distfield, border); } else { @@ -691,23 +701,55 @@ int copy_bitmap(const FT_Bitmap *bmp, Image *image) return 0; } -void propagate_distance(unsigned short *pixel, int offset) +unsigned sqrti(unsigned num) { - unsigned short *neighbor = pixel+offset; - if((*neighbor^*pixel)&0x8000) - *neighbor = (*neighbor&0x8000)+1; - else if((*neighbor&0x7FFF)>(*pixel&0x7FFF)) - *neighbor = *pixel+2; + 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(dwidth || !bmp->rows) { @@ -720,66 +762,28 @@ int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, un if(copy_bitmap(bmp, &base_image)) return -1; - map_w = base_image.w+2*margin*scale+scale-1; - map_w -= map_w%scale; - map_h = base_image.h+2*margin*scale+scale-1; - map_h -= map_h%scale; - distance_map = (unsigned short *)malloc(map_w*map_h*sizeof(unsigned short)); - if(!distance_map) - { - fprintf(stderr, "Cannot allocate %d bytes of memory for distance map\n", map_w*map_h); - free(base_image.data); - return -1; - } - - image->w = map_w/scale; - image->h = map_h/scale; + 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); - free(distance_map); return -1; } - for(x=0; x0; --x) - propagate_distance(distance_map+x+y*map_w, -1); - } - - for(x=0; x0; --y) - propagate_distance(distance_map+x+y*map_w, -map_w); - } - - offset = scale/2*(map_w+1); for(y=0; yh; ++y) for(x=0; xw; ++x) { - unsigned short pixel = distance_map[offset+(x+y*map_w)*scale]; - unsigned short dist = (pixel&0x7FFF)*0x7F/(margin*scale*2+1); - if(dist>0x7F) - dist = 0x7F; - if(pixel&0x8000) - image->data[x+y*image->w] = 0x80+dist; - else - image->data[x+y*image->w] = 0x7F-dist; + 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(distance_map); free(base_image.data); return 0; @@ -919,18 +923,18 @@ int render_packed(Font *font, unsigned margin, unsigned padding, bool npot) area = a; } - /* Find an image size that's no higher than wide, allowing for some - imperfections in the packing. */ + /* Find an image size that's approximately square. */ for(font->image.w=1;; font->image.w<<=1) { if(font->image.w<=margin*2) continue; - font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2; + font->image.h = area/(font->image.w-margin*2)+margin*2; if(font->image.h<=font->image.w) break; } - if(!npot) - 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