From: Matthias Kramm Date: Thu, 18 Feb 2010 04:00:58 +0000 (-0800) Subject: added gfxfont_save() to gfxfont.{c,h} X-Git-Tag: version-0-9-1~149 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=4c389168a91bf083e434885fbfd8f51c6dab56fc added gfxfont_save() to gfxfont.{c,h} --- diff --git a/lib/Makefile.in b/lib/Makefile.in index d1c5375..857d928 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -18,7 +18,7 @@ gfxpoly_objects = gfxpoly/active.$(O) gfxpoly/convert.$(O) gfxpoly/poly.$(O) gfx rfxswf_modules = modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c -base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) +base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) ttf.$(O) gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@ rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O) @@ -55,6 +55,8 @@ wav.$(O): wav.c wav.h $(top_builddir)/config.h $(C) wav.c -o $@ xml.$(O): xml.c xml.h bitio.h $(C) xml.c -o $@ +ttf.$(O): ttf.c ttf.h + $(C) ttf.c -o $@ os.$(O): os.c os.h $(top_builddir)/config.h $(C) -DSWFTOOLS_DATADIR=\"$(pkgdatadir)\" os.c -o $@ modules/swfaction.$(O): modules/swfaction.c rfxswf.h diff --git a/lib/devices/swf.c b/lib/devices/swf.c index af5d284..3a9cbd4 100644 --- a/lib/devices/swf.c +++ b/lib/devices/swf.c @@ -2121,6 +2121,8 @@ int swf_setparameter(gfxdevice_t*dev, const char*name, const char*value) i->config_dumpfonts = atoi(value); } else if(!strcmp(name, "animate")) { i->config_animate = atoi(value); + } else if(!strcmp(name, "linknameurl")) { + i->config_linknameurl = atoi(value); } else if(!strcmp(name, "showimages")) { i->config_showimages = atoi(value); } else if(!strcmp(name, "disablelinks")) { diff --git a/lib/gfxfont.c b/lib/gfxfont.c index efe29c3..cc6c62c 100644 --- a/lib/gfxfont.c +++ b/lib/gfxfont.c @@ -25,6 +25,7 @@ #include "gfxdevice.h" #include "gfxtools.h" #include "gfxfont.h" +#include "ttf.h" static int loadfont_scale = 64; static int full_unicode = 1; @@ -491,6 +492,7 @@ gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quali gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality) { fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename); + return 0; } #endif @@ -518,3 +520,104 @@ void gfxfont_free(gfxfont_t*font) free(font); } +ttf_t* gfxfont_to_ttf(gfxfont_t*font) +{ + ttf_t*ttf = ttf_new(); + int num_glyphs = font->num_glyphs; + int offset = 0; + int t; + char has_nondef_glyph = + font->num_glyphs && font->glyphs[0].unicode==-1 && + (!font->glyphs[0].line || !font->glyphs[0].line->next); + + if(!has_nondef_glyph) { + /* insert a new .nondef glyph at the start of the font */ + offset++; + num_glyphs++; + } + ttf->num_glyphs = num_glyphs; + ttf->glyphs = rfx_calloc(num_glyphs*sizeof(ttfglyph_t)); + double scale = 1.0; + int max_unicode = font->max_unicode; + for(t=0;tnum_glyphs;t++) { + gfxglyph_t*src = &font->glyphs[t]; + ttfglyph_t*dest = &ttf->glyphs[t+offset]; + gfxline_t*line = src->line; + int count = 0; + while(line) { + count++; + if(line->type == gfx_splineTo) + count++; + line=line->next; + } + dest->num_points = count; + dest->points = rfx_calloc(count*sizeof(ttfpoint_t)); + count = 0; + while(line) { + if(line->type == gfx_splineTo) { + dest->points[count].x = line->sx*scale; + dest->points[count].y = line->sy*scale; + count++; + } + dest->points[count].x = line->x*scale; + dest->points[count].y = line->y*scale; + dest->points[count].flags |= GLYPH_ON_CURVE; + if(line->type == gfx_moveTo) { + dest->points[count].flags |= GLYPH_CONTOUR_START; + if(count) + dest->points[count-1].flags |= GLYPH_CONTOUR_END; + } + count++; + line=line->next; + } + + /* compute bounding box */ + int s; + if(count) { + dest->xmin = dest->xmax = dest->points[0].x; + dest->ymin = dest->ymax = dest->points[0].y; + for(s=1;spoints[s].x < dest->xmin) + dest->xmin = dest->points[0].x; + if(dest->points[s].y < dest->xmin) + dest->xmin = dest->points[0].y; + if(dest->points[s].x > dest->xmin) + dest->xmax = dest->points[0].x; + if(dest->points[s].y > dest->xmin) + dest->ymax = dest->points[0].y; + } + } + + dest->advance = src->advance*scale; + if(src->unicode > max_unicode) + max_unicode = src->unicode; + } + ttf->unicode_size = max_unicode+1; + ttf->unicode = rfx_calloc(sizeof(unicode_t)*ttf->unicode_size); + for(t=0;tnum_glyphs;t++) { + gfxglyph_t*src = &font->glyphs[t]; + int u = font->glyphs[t].unicode; + if(u>=0) + ttf->unicode[u] = t+offset; + } + int u; + for(u=0;umax_unicode;u++) { + int g = font->unicode2glyph[t]; + if(g>=0) { + ttf->unicode[u] = g; + } + } + ttf->ascent = font->ascent; + ttf->descent = font->descent; + ttf->lineGap = font->ascent + font->descent; + + ttf_create_truetype_tables(ttf); + return ttf; +} + +void gfxfont_save(gfxfont_t*font, const char*filename) +{ + ttf_t*ttf = gfxfont_to_ttf(font); + ttf_save(ttf, filename); +} + diff --git a/lib/gfxfont.h b/lib/gfxfont.h index 695e965..1058db6 100644 --- a/lib/gfxfont.h +++ b/lib/gfxfont.h @@ -33,6 +33,7 @@ extern "C" { /* The quality parameter is given by 1 divided by the zoom factor at which the font still looks good. 1=normal, 0.5=double resolution etc. */ gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality); +void gfxfont_save(gfxfont_t*font, const char*filename); void gfxfont_free(gfxfont_t*font); #ifdef __cplusplus diff --git a/lib/ruby/test.rb b/lib/ruby/test.rb index 1c0418e..dc96d1b 100644 --- a/lib/ruby/test.rb +++ b/lib/ruby/test.rb @@ -1,6 +1,6 @@ require 'gfx' -pdf = GFX::PDF.new('file.pdf') +pdf = GFX::PDF.new('segfault.pdf') class TestRender < GFX::Device def startpage(width,height) diff --git a/lib/ttf.c b/lib/ttf.c index c637f6e..c17b631 100644 --- a/lib/ttf.c +++ b/lib/ttf.c @@ -22,7 +22,6 @@ #include #include #include -#include "bitio.h" #include "log.h" #include "os.h" #include "mem.h" @@ -126,13 +125,13 @@ static void expand(ttf_table_t*w, int newsize) w->memsize = v1>v2?v1:v2; w->data = rfx_realloc(w->data, w->memsize); } -static void writeU8(ttf_table_t*w, unsigned char b) +static inline void writeU8(ttf_table_t*w, unsigned char b) { if(w->memsizelen+1) expand(w, w->len+1); w->data[w->len++] = b; } -static void writeU16(ttf_table_t*w, unsigned short v) +static inline void writeU16(ttf_table_t*w, unsigned short v) { if(w->memsizelen+2) expand(w, w->len+2); @@ -140,7 +139,7 @@ static void writeU16(ttf_table_t*w, unsigned short v) w->data[w->len++] = v; } #define writeS16 writeU16 -static void writeU32(ttf_table_t*w, unsigned long v) +static inline void writeU32(ttf_table_t*w, unsigned long v) { if(w->memsizelen+4) expand(w, w->len+4); @@ -149,7 +148,7 @@ static void writeU32(ttf_table_t*w, unsigned long v) w->data[w->len++] = v>>8; w->data[w->len++] = v; } -static void writeBlock(ttf_table_t*w, void*data, int len) +static inline void writeBlock(ttf_table_t*w, void*data, int len) { if(w->memsizelen+len) expand(w, w->len+len); @@ -258,16 +257,182 @@ static void ttf_table_dump(ttf_table_t*t, const char*prefix) hexdump(t->data, t->len, prefix); } +static table_head_t*head_new(ttf_t*ttf) +{ + table_head_t*head = rfx_calloc(sizeof(table_head_t)); + head->units_per_em = 1024; + int t; + if(ttf->num_glyphs) { + head->xmin = ttf->glyphs[0].xmin; + head->ymin = ttf->glyphs[0].ymin; + head->xmax = ttf->glyphs[0].xmax; + head->ymax = ttf->glyphs[0].ymax; + for(t=1;tnum_glyphs;t++) { + if(ttf->glyphs[0].xmin < head->xmin) head->xmin = ttf->glyphs[0].xmin; + if(ttf->glyphs[0].ymin < head->ymin) head->ymin = ttf->glyphs[0].ymin; + if(ttf->glyphs[0].xmax > head->xmax) head->xmax = ttf->glyphs[0].xmax; + if(ttf->glyphs[0].ymax > head->ymax) head->ymax = ttf->glyphs[0].ymax; + } + } + head->macStyle = 0; + head->lowest_readable_size = 8; // not sure what font renderers actually do with this + head->dir_hint = 0; + return head; +} +static int head_parse(ttf_t*ttf, memreader_t*r) +{ + ttf->head = rfx_calloc(sizeof(table_head_t)); + U32 version = readU32(r); + if(version!=VERSION_1_0) + msg(" Font HEAD has unknown version %08x", version); + U32 revision = readU32(r); + U32 checksum2 = readU32(r); + U32 magic = readU32(r); + if(magic!=0x5f0f3cf5) + msg(" Font HEAD has unknown magic number %08x", magic); + ttf->head->flags = readU16(r); + ttf->head->units_per_em = readU16(r); + readU32(r);readU32(r); //created + readU32(r);readU32(r); //modified + ttf->head->xmin = readU16(r); + ttf->head->ymin = readU16(r); + ttf->head->xmax = readU16(r); + ttf->head->ymax = readU16(r); + ttf->head->macStyle = readU16(r); + ttf->head->lowest_readable_size = readU16(r); //in pixels + ttf->head->dir_hint = readS16(r); + int loc_index = readS16(r); //used in 'loca' table + if(loc_index>1) + msg(" loca index format %d unknown", loc_index); + U16 glyph_data_format = readS16(r); + if(glyph_data_format!=0) + msg(" Font glyph data format unknown: %04x", glyph_data_format); + if(r->pos < r->size) { + msg(" Leftover bytes (%d) in HEAD tag", r->size - r->pos); + } + return loc_index; +} +static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size) +{ + writeU32(w, 0x10000); + writeU32(w, 0x10000); + writeU32(w, 0); //checksum + writeU32(w, 0x5f0f3cf5); //magic + writeU16(w, ttf->head->flags); + writeU16(w, ttf->head->units_per_em); + writeU32(w, 0);writeU32(w, 0); //created + writeU32(w, 0);writeU32(w, 0); //modified + writeU16(w, ttf->head->xmin); + writeU16(w, ttf->head->ymin); + writeU16(w, ttf->head->xmax); + writeU16(w, ttf->head->ymax); + writeU16(w, ttf->head->macStyle); + writeU16(w, ttf->head->lowest_readable_size); + writeS16(w, ttf->head->dir_hint); + writeS16(w, loca_size); //loca index size (32 bit) + writeS16(w, 0); //glyph data format +} +static void head_dump(ttf_t*ttf) +{ + printf("head->flags: %d\n", ttf->head->flags); + printf("head->units_per_em: %d\n", ttf->head->units_per_em); + printf("head->xmin: %d\n", ttf->head->xmin); + printf("head->ymin: %d\n", ttf->head->ymin); + printf("head->xmax: %d\n", ttf->head->xmax); + printf("head->ymax: %d\n", ttf->head->ymax); + printf("head->macStyle: %d\n", ttf->head->macStyle); + printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size); + printf("head->dir_hint: %d\n", ttf->head->dir_hint); +} +static void head_delete(ttf_t*ttf) +{ + if(ttf->head) { + free(ttf->head); + ttf->head=0; + } +} + +static table_os2_t*os2_new(ttf_t*ttf) +{ + table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t)); + if(ttf->num_glyphs) { + int average_width=0; + int t; + for(t=0;tnum_glyphs;t++) { + average_width += (ttf->glyphs[t].advance + ttf->glyphs[t].bearing); + } + os2->xAvgCharWidth = average_width / ttf->num_glyphs; + } + + /* that's what everybody seems to fill in */ + os2->usWeightClass = 400; + os2->usWidthClass = 5; + + if(ttf->head) { + int advance = (ttf->head->xmax - ttf->head->xmin)/2; + int height = (ttf->head->xmax - ttf->head->xmin); + int ymid = height/2; + /* I do believe a sane font rendering engine will actually use + the font advance here- the subscript/superscript position will + not be the same for each glyph */ + os2->ySuperscriptXSize = os2->ySubscriptXSize = (ttf->head->xmax - ttf->head->xmin)/2; + os2->ySuperscriptYSize = os2->ySubscriptYSize = (ttf->head->ymax - ttf->head->ymin)/2; + os2->ySubscriptXOffset = advance; + os2->ySubscriptYOffset = 0; + os2->ySuperscriptXOffset = advance; + os2->ySuperscriptYOffset = (ttf->head->ymax - ttf->head->ymin)/2; + os2->yStrikeoutSize = ttf->head->units_per_em / 10; + os2->yStrikeoutPosition = ymid; + os2->usWinAscent = ttf->head->ymax; + os2->usWinDescent = ttf->head->ymin<0?0:ttf->head->ymin; + os2->sxHeight = ymid; + os2->sCapHeight = height*2/3; + } + os2->panose_Weight = 4; + + /* strictly speaking we'd have to set 92/64 bits in these tables, depending on + what parts of the unicode table is filled. (e.g. bit 90 = tibetan). */ + os2->ulCharRange[0] = 1; + os2->ulCharRange[1] = 0; + os2->ulCharRange[2] = 0; + os2->ulCharRange[3] = 0; + os2->ulCodePageRange1 = 1; + os2->ulCodePageRange2 = 0; + + if(ttf->unicode_size) { + int min,max; + for(min=0;minunicode_size;min++) + if(ttf->unicode[min]) break; + for(max=ttf->unicode_size-1;max>=0;max--) + if(ttf->unicode[max]) break; + if(min<=max) { + os2->fsFirstCharIndex = min; + os2->fsLastCharIndex = max; + } + } + os2->sTypoAscender = ttf->ascent; + os2->sTypoDescender = ttf->descent; + os2->sTypoLineGap = ttf->lineGap; + + os2->usDefaultChar = 0; + os2->usBreakChar = (ttf->unicode_size>0x20 && ttf->unicode[0x20])?0x20:0; + os2->usMaxContext = 0; // we don't use ligatures yet + return os2; +} static table_os2_t*os2_parse(memreader_t*r) { table_os2_t*os2 = rfx_calloc(sizeof(table_os2_t)); U16 version = readU16(r); - if(version!=0 && version!=1 && version!=2) + /* 0 = TrueType 1.5 + 1 = TrueType 1.66 + 2 = OpenType 1.2 + 3 = OpenType 1.4 */ + if(version!=0 && version!=1 && version!=2 && version!=3) msg(" Unknown OS2 version: %04x", version); os2->xAvgCharWidth = readS16(r); os2->usWeightClass = readU16(r); os2->usWidthClass = readU16(r); - os2->fsType = readU16(r); + readU16(r); //fstype os2->ySubscriptXSize = readU16(r); os2->ySubscriptYSize = readU16(r); os2->ySubscriptXOffset = readU16(r); @@ -293,10 +458,7 @@ static table_os2_t*os2_parse(memreader_t*r) os2->ulCharRange[1] = readU32(r); os2->ulCharRange[2] = readU32(r); os2->ulCharRange[3] = readU32(r); - os2->achVendID[0] = readU8(r); - os2->achVendID[1] = readU8(r); - os2->achVendID[2] = readU8(r); - os2->achVendID[3] = readU8(r); + readU32(r); //vendor os2->fsSelection = readU16(r); os2->fsFirstCharIndex = readU16(r); os2->fsLastCharIndex = readU16(r); @@ -314,10 +476,13 @@ static table_os2_t*os2_parse(memreader_t*r) os2->usDefaultChar = readU16(r); os2->usBreakChar = readU16(r); os2->usMaxContext = readU16(r); + + if(r->pos < r->size) { + msg(" Leftover bytes (%d) in OS2 tag", r->size - r->pos); + } return os2; } - -static os2_write(ttf_t*ttf, ttf_table_t*w) +static void os2_write(ttf_t*ttf, ttf_table_t*w) { table_os2_t*os2 = ttf->os2; U16 version=1; @@ -328,7 +493,7 @@ static os2_write(ttf_t*ttf, ttf_table_t*w) writeS16(w, os2->xAvgCharWidth); writeU16(w, os2->usWeightClass); writeU16(w, os2->usWidthClass); - writeU16(w, os2->fsType); + writeU16(w, 0); //fstype writeU16(w, os2->ySubscriptXSize); writeU16(w, os2->ySubscriptYSize); writeU16(w, os2->ySubscriptXOffset); @@ -354,10 +519,7 @@ static os2_write(ttf_t*ttf, ttf_table_t*w) writeU32(w, os2->ulCharRange[1]); writeU32(w, os2->ulCharRange[2]); writeU32(w, os2->ulCharRange[3]); - writeU8(w, os2->achVendID[0]); - writeU8(w, os2->achVendID[1]); - writeU8(w, os2->achVendID[2]); - writeU8(w, os2->achVendID[3]); + writeU32(w, 0x53434244); //vendor writeU16(w, os2->fsSelection); writeU16(w, os2->fsFirstCharIndex); writeU16(w, os2->fsLastCharIndex); @@ -376,21 +538,13 @@ static os2_write(ttf_t*ttf, ttf_table_t*w) writeU16(w, os2->usBreakChar); writeU16(w, os2->usMaxContext); } -static void os2_delete(ttf_t*ttf) -{ - if(ttf->os2) - free(ttf->os2); - ttf->os2=0; -} - -static os2_dump(ttf_t*ttf) +static void os2_dump(ttf_t*ttf) { table_os2_t*os2 = ttf->os2; if(!os2) return; printf("os2->xAvgCharWidth: %d\n", os2->xAvgCharWidth); printf("os2->usWeightClass: %d\n", os2->usWeightClass); printf("os2->usWidthClass: %d\n", os2->usWidthClass); - printf("os2->fsType: %d\n", os2->fsType); printf("os2->ySubscriptXSize: %d\n", os2->ySubscriptXSize); printf("os2->ySubscriptYSize: %d\n", os2->ySubscriptYSize); printf("os2->ySubscriptXOffset: %d\n", os2->ySubscriptXOffset); @@ -416,10 +570,6 @@ static os2_dump(ttf_t*ttf) printf("os2->ulCharRange[1]: %d\n", os2->ulCharRange[1]); printf("os2->ulCharRange[2]: %d\n", os2->ulCharRange[2]); printf("os2->ulCharRange[3]: %d\n", os2->ulCharRange[3]); - printf("os2->achVendID[0]: %d\n", os2->achVendID[0]); - printf("os2->achVendID[1]: %d\n", os2->achVendID[1]); - printf("os2->achVendID[2]: %d\n", os2->achVendID[2]); - printf("os2->achVendID[3]: %d\n", os2->achVendID[3]); printf("os2->fsSelection: %d\n", os2->fsSelection); printf("os2->fsFirstCharIndex: %d\n", os2->fsFirstCharIndex); printf("os2->fsLastCharIndex: %d\n", os2->fsLastCharIndex); @@ -436,80 +586,39 @@ static os2_dump(ttf_t*ttf) printf("os2->usBreakChar: %d\n", os2->usBreakChar); printf("os2->usMaxContext: %d\n", os2->usMaxContext); } - -static int head_parse(ttf_t*ttf, memreader_t*r) +static void os2_delete(ttf_t*ttf) { - ttf->head = rfx_calloc(sizeof(table_head_t)); - U32 version = readU32(r); - if(version!=VERSION_1_0) - msg(" Font HEAD has unknown version %08x", version); - U32 revision = readU32(r); - if(revision!=VERSION_1_0) - msg(" Font HEAD has unknown revision %08x", revision); - U32 checksum2 = readU32(r); - U32 magic = readU32(r); - if(magic!=0x5f0f3cf5) - msg(" Font HEAD has unknown magic number %08x", magic); - ttf->head->flags = readU16(r); - ttf->head->units_per_em = readU16(r); - readU32(r);readU32(r); //created - readU32(r);readU32(r); //modified - ttf->head->xmin = readU16(r); - ttf->head->ymin = readU16(r); - ttf->head->xmax = readU16(r); - ttf->head->ymax = readU16(r); - ttf->head->macStyle = readU16(r); - ttf->head->lowest_readable_size = readU16(r); //in pixels - ttf->head->dir_hint = readS16(r); - int loc_index = readS16(r); //used in 'loca' table - if(loc_index>1) - msg(" loca index format %d unknown", loc_index); - U16 glyph_data_format = readS16(r); - if(glyph_data_format!=0) - msg(" Font glyph data format unknown: %04x", glyph_data_format); - return loc_index; + if(ttf->os2) + free(ttf->os2); + ttf->os2=0; } -static void head_write(ttf_t*ttf, ttf_table_t*w, int loca_size) -{ - writeU32(w, 0x10000); - writeU32(w, 0x10000); - writeU32(w, 0); //checksum - writeU32(w, 0x5f0f3cf5); //magic - writeU16(w, ttf->head->flags); - writeU16(w, ttf->head->units_per_em); - writeU32(w, 0);writeU32(w, 0); //created - writeU32(w, 0);writeU32(w, 0); //modified - writeU16(w, ttf->head->xmin); - writeU16(w, ttf->head->ymin); - writeU16(w, ttf->head->xmax); - writeU16(w, ttf->head->ymax); - writeU16(w, ttf->head->macStyle); - writeU16(w, ttf->head->lowest_readable_size); - writeS16(w, ttf->head->dir_hint); - writeS16(w, loca_size); //loca index size (32 bit) - writeS16(w, 0); //glyph data format -} -static void head_dump(ttf_t*ttf) -{ - printf("head->flags: %d\n", ttf->head->flags); - printf("head->units_per_em: %d\n", ttf->head->units_per_em); - printf("head->xmin: %d\n", ttf->head->xmin); - printf("head->ymin: %d\n", ttf->head->ymin); - printf("head->xmax: %d\n", ttf->head->xmax); - printf("head->ymax: %d\n", ttf->head->ymax); - printf("head->macStyle: %d\n", ttf->head->macStyle); - printf("head->lowest_readable_size: %d\n", ttf->head->lowest_readable_size); - printf("head->dir_hint: %d\n", ttf->head->dir_hint); -} -static void head_delete(ttf_t*ttf) +static table_maxp_t*maxp_new(ttf_t*ttf) { - if(ttf->head) { - free(ttf->head); - ttf->head=0; + table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t)); + int t; + if(ttf->num_glyphs) { + int max = 0; + for(t=0;tnum_glyphs;t++) { + if(ttf->glyphs[t].num_points>max) + max = ttf->glyphs[t].num_points; + int contours = 0; + int s; + for(s=0;sglyphs[t].num_points;s++) { + if(ttf->glyphs[t].points[s].flags&GLYPH_CONTOUR_END) + contours++; + } + if(maxp->maxContours < contours) + maxp->maxContours = contours; + } + maxp->maxPoints = max; + + /* we don't generate composite glyphs yet */ + maxp->maxComponentPoints = 0; + maxp->maxComponentContours = 0; } + return maxp; } - static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r) { U32 version = readU32(r); @@ -517,7 +626,10 @@ static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r) /* according to freetype, older fonts (version<0x10000) apparently only contain the number of glyphs. this is rather rare, though. */ - if(version<0x10000) return 0; + if(version<0x10000 && r->size==6) return 0; + + if(r->size<32) + msg(" Truncated maxp table (version %d)", version); table_maxp_t*maxp = rfx_calloc(sizeof(table_maxp_t)); maxp->maxPoints = readU16(r); @@ -535,10 +647,15 @@ static table_maxp_t* maxp_parse(ttf_t*ttf, memreader_t*r) maxp->maxComponentDepth = readU16(r); return maxp; } - static void maxp_write(ttf_t*ttf, ttf_table_t*w) { table_maxp_t*maxp = ttf->maxp; + if(!maxp) { + /* version 0.5 simplified maxp table */ + writeU32(w, 0x00005000); + writeU16(w, ttf->num_glyphs); + return; + } writeU32(w, 0x10000); //version writeU16(w, ttf->num_glyphs); writeU16(w, maxp->maxPoints); @@ -555,7 +672,6 @@ static void maxp_write(ttf_t*ttf, ttf_table_t*w) writeU16(w, maxp->maxComponentElements); writeU16(w, maxp->maxComponentDepth); } - static void maxp_dump(ttf_t*ttf) { table_maxp_t*maxp = ttf->maxp; @@ -574,7 +690,6 @@ static void maxp_dump(ttf_t*ttf) printf("maxp->maxComponentElements: %d\n", maxp->maxComponentElements); printf("maxp->maxComponentDepth: %d\n", maxp->maxComponentDepth); } - static void maxp_delete(ttf_t*ttf) { if(ttf->maxp) @@ -582,14 +697,33 @@ static void maxp_delete(ttf_t*ttf) ttf->maxp=0; } - +static table_hea_t*hea_new(ttf_t*ttf) +{ + table_hea_t*hea = rfx_calloc(sizeof(table_hea_t)); + if(ttf->num_glyphs) { + int t; + for(t=0;tnum_glyphs;t++) { + if(ttf->glyphs[t].advance > hea->advanceWidthMax) + hea->advanceWidthMax = ttf->glyphs[t].advance; + if(ttf->glyphs[t].xmin < ttf->hea->minLeftSideBearing) + ttf->hea->minLeftSideBearing = ttf->glyphs[t].xmin; + if(ttf->glyphs[t].xmax < ttf->hea->minRightSideBearing) + ttf->hea->minRightSideBearing = ttf->glyphs[t].xmax; + int width = ttf->glyphs[t].xmax - ttf->glyphs[t].xmin; + if(width > hea->xMaxExtent) + hea->xMaxExtent = width; + } + /* TODO: caret */ + } + return hea; +} static int hea_parse(memreader_t*r, ttf_t*ttf) { table_hea_t*hea = ttf->hea = rfx_calloc(sizeof(table_hea_t)); U32 version = readU32(r); - hea->ascent = readS16(r); - hea->descent = readS16(r); - hea->lineGap = readS16(r); + ttf->ascent = readS16(r); + ttf->descent = readS16(r); + ttf->lineGap = readS16(r); hea->advanceWidthMax = readU16(r); hea->minLeftSideBearing = readS16(r); hea->minRightSideBearing = readS16(r); @@ -612,14 +746,13 @@ static int hea_parse(memreader_t*r, ttf_t*ttf) } return num_advances; } - static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances) { table_hea_t*hea = ttf->hea; writeU32(w, 0x00010000); - writeS16(w, hea->ascent); - writeS16(w, hea->descent); - writeS16(w, hea->lineGap); + writeS16(w, ttf->ascent); + writeS16(w, ttf->descent); + writeS16(w, ttf->lineGap); writeU16(w, hea->advanceWidthMax); writeS16(w, hea->minLeftSideBearing); writeS16(w, hea->minRightSideBearing); @@ -638,10 +771,11 @@ static table_hea_t*hea_write(ttf_t*ttf, ttf_table_t*w, int num_advances) static void hea_dump(ttf_t*ttf) { table_hea_t*hea = ttf->hea; + if(!hea) return; const char*dir = ttf->is_vertical?"v":"h"; - printf("%shea->ascent: %d\n", dir, hea->ascent); - printf("%shea->descent: %d\n", dir, hea->descent); - printf("%shea->lineGap: %d\n", dir, hea->lineGap); + printf("%shea->ascent: %d\n", dir, ttf->ascent); + printf("%shea->descent: %d\n", dir, ttf->descent); + printf("%shea->lineGap: %d\n", dir, ttf->lineGap); printf("%shea->advanceWidthMax: %d\n", dir, hea->advanceWidthMax); printf("%shea->minLeftSideBearing: %d\n", dir, hea->minLeftSideBearing); printf("%shea->minRightSideBearing: %d\n", dir, hea->minRightSideBearing); @@ -658,7 +792,7 @@ static void hea_delete(ttf_t*ttf) } } -static void hmtx_parse(memreader_t*r, ttf_t*ttf, int num_advances) +static void mtx_parse(memreader_t*r, ttf_t*ttf, int num_advances) { U16 old_advance = 0; int t; @@ -701,21 +835,30 @@ static int mtx_write(ttf_t*ttf, ttf_table_t*w) } return num_advances; } + static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size) { int t; int num = ttf->num_glyphs+1; U32*locations = rfx_calloc(num*sizeof(U32)); + U32 lastloc = 0; + U32 loc = 0; + char warn_unsorted = 1; if(size) { if(num*4 > r->size) { - msg(" Short 'loca' table (32 bit)"); + msg(" Short 'loca' table (32 bit): %d/%d", r->size/4, num); num=r->size/4; } if(num*4 < r->size) { msg(" Extraneous data (%d bytes) in 'loca' table (32 bit)", r->size-num*4); } for(t=0;t loc && warn_unsorted) { + msg(" Unsorted 'loca' table (32 bit)"); + warn_unsorted=0; + } + lastloc = loc; } } else { if(num*2 > r->size) { @@ -726,7 +869,12 @@ static U32*loca_parse(memreader_t*r, ttf_t*ttf, int size) msg(" Extraneous data (%d bytes) in 'loca' table (16 bit)", r->size-num*2); } for(t=0;t loc && warn_unsorted) { + msg(" Unsorted 'loca' table"); + warn_unsorted=0; + } + lastloc = loc; } } return locations; @@ -754,6 +902,7 @@ static int loca_write(ttf_t*ttf, ttf_table_t*w, U32*locations) return 0; } } + static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int glyphnr) { ttfglyph_t*glyph = &ttf->glyphs[glyphnr]; @@ -863,11 +1012,14 @@ static int parse_simple_glyph(ttf_t*ttf, memreader_t*r, int num_contours, int gl static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca) { int t; - char warn_about_compound_glyphs=1; + char warn_about_compound_glyphs=0; for(t=0;tnum_glyphs;t++) { INIT_READ(r, rr->mem, rr->size, loca[t]); + if(loca[t]==loca[t+1] || loca[t]==r.size) + continue; //empty glyph if(r.pos+10>r.size) { - msg(" Unexpected end of glyph array (or bad loca entry %d/%d)", loca[t], r.size); + msg(" Truncated glyph entry %d/%d (or bad loca entry %d/%d, next loca: %d)", + t, ttf->num_glyphs, loca[t], r.size, loca[t+1]); break; } S16 num_contours = readS16(&r); @@ -887,7 +1039,6 @@ static void glyf_parse(memreader_t*rr, ttf_t*ttf, U32*loca) } } - void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g) { /* endpoints array */ @@ -979,7 +1130,6 @@ void write_simple_glyph(ttf_table_t*w, ttfglyph_t*g) else if(dy) writeS16(w, dy); } } - U32* glyf_write(ttf_t* ttf, ttf_table_t*w) { U32*locations = malloc(sizeof(U32)*(ttf->num_glyphs+1)); @@ -1016,6 +1166,7 @@ U32* glyf_write(ttf_t* ttf, ttf_table_t*w) } void glyf_dump(ttf_t* ttf) { + if(!ttf->glyphs) return; int t; for(t=0;tnum_glyphs;t++) { ttfglyph_t*g = &ttf->glyphs[t]; @@ -1034,7 +1185,6 @@ void glyf_dump(ttf_t* ttf) hexdump(g->code, g->code_size, " "); } } - void glyf_delete(ttf_t* ttf) { if(!ttf->glyphs) @@ -1064,7 +1214,6 @@ static void grow_unicode(ttf_t*ttf, int index) } ttf->unicode_size = size; } - void cmap_parse(memreader_t*r, ttf_t*ttf) { readU16(r); // version (0) @@ -1134,8 +1283,9 @@ void cmap_parse(memreader_t*r, ttf_t*ttf) U16 delta = readU16(&r_delta); U16 range = readU16(&r_range); if(start==0xffff && end==0xffff && delta==1) { - /* this is a common occurence in fonts which explicitly map - "unicode undefined" (0xffff) to "glyph undefined" (0). + /* this is a common (maybe even required) occurence in fonts + which explicitly map "unicode undefined" (0xffff) to + "glyph undefined" (0). We don't want to blow our unicode table up to 65536 just because of this, so ignore this entry. */ @@ -1157,7 +1307,6 @@ void cmap_parse(memreader_t*r, ttf_t*ttf) } } } - static int segment_size(unicode_t*unicode, int pos, int size) { int s; @@ -1177,7 +1326,6 @@ static int segment_size(unicode_t*unicode, int pos, int size) return size-1; return s; } - void cmap_write(ttf_t* ttf, ttf_table_t*w) { writeU16(w, 0); //version @@ -1212,6 +1360,9 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w) pos = s+1; num_segments++; } + + num_segments++; // account for 0xffff mapping + int t; int end_pos = w->len; for(t=0;tlen; for(t=0;tdata[num_segments_pos]=num_segments>>8; - w->data[num_segments_pos+1]=num_segments; + w->data[num_segments_pos]=(num_segments*2)>>8; + w->data[num_segments_pos+1]=(num_segments*2); pos=0; num_segments = 0; @@ -1265,6 +1416,18 @@ void cmap_write(ttf_t* ttf, ttf_table_t*w) num_segments++; pos = end+1; } + + /* write out a mapping from 0xffff to 0- seems to be required + by some libraries (e.g. fonttools) */ + w->data[end_pos++]=0xff; + w->data[end_pos++]=0xff; + w->data[start_pos++]=0xff; + w->data[start_pos++]=0xff; + w->data[delta_pos++]=0; + w->data[delta_pos++]=1; + w->data[range_pos++]=0; + w->data[range_pos++]=0; + w->data[length_pos]=(w->len-20)>>8; w->data[length_pos+1]=w->len-20; } @@ -1321,7 +1484,7 @@ static int ttf_parse_tables(ttf_t*ttf) table = ttf_find_table(ttf, TAG_HMTX); if(table) { INIT_READ(m, table->data, table->len, 0); - hmtx_parse(&m, ttf, num_advances); + mtx_parse(&m, ttf, num_advances); ttf_table_delete(ttf, table); } } else { @@ -1335,7 +1498,7 @@ static int ttf_parse_tables(ttf_t*ttf) table = ttf_find_table(ttf, TAG_VMTX); if(table) { INIT_READ(m, table->data, table->len, 0); - hmtx_parse(&m, ttf, num_advances); + mtx_parse(&m, ttf, num_advances); ttf_table_delete(ttf, table); } } else { @@ -1368,7 +1531,7 @@ static int ttf_parse_tables(ttf_t*ttf) static void ttf_collapse_tables(ttf_t*ttf) { ttf_table_t*table; - + table = ttf_addtable(ttf, TAG_MAXP); maxp_write(ttf, table); maxp_delete(ttf); @@ -1409,7 +1572,13 @@ static void ttf_collapse_tables(ttf_t*ttf) head_delete(ttf); } -ttf_t* load_ttf(void*data, int length) +ttf_t*ttf_new() +{ + ttf_t*ttf = rfx_calloc(sizeof(ttf_t)); + ttf->version = VERSION_1_0; + return ttf; +} +ttf_t* ttf_load(void*data, int length) { INIT_READ(r,data,length, 0); @@ -1475,7 +1644,7 @@ ttf_t* load_ttf(void*data, int length) ttf_table_t*table = ttf_addtable(ttf, tag); table->data = mem; table->len = table->memsize = len; - +#if 0 U32 checksum2 = ttf_table_checksum(table); if(checksum2!=checksum) { msg(" Checksum mismatch in tag %02x%02x%02x%02x %c%c%c%c (%d bytes) %08x!=%08x", @@ -1483,7 +1652,7 @@ ttf_t* load_ttf(void*data, int length) (tag>>24)&0xff, (tag>>16)&0xff, (tag>>8)&0xff, (tag)&0xff, len, checksum2, checksum); } - +#endif } } free(table_data); @@ -1493,7 +1662,17 @@ ttf_t* load_ttf(void*data, int length) return ttf; } - +void ttf_create_truetype_tables(ttf_t*ttf) +{ + if(!ttf->head) + ttf->head = head_new(ttf); + if(!ttf->maxp) + ttf->maxp = maxp_new(ttf); + if(!ttf->hea) + ttf->hea = hea_new(ttf); + if(!ttf->os2) + ttf->os2 = os2_new(ttf); +} ttf_table_t* ttf_write(ttf_t*ttf) { ttf_collapse_tables(ttf); @@ -1562,7 +1741,6 @@ ttf_table_t* ttf_write(ttf_t*ttf) checksum2[3] = checksum>>0; return file; } - void ttf_save(ttf_t*ttf, const char*filename) { ttf_table_t* t = ttf_write(ttf); @@ -1575,7 +1753,6 @@ void ttf_save(ttf_t*ttf, const char*filename) fclose(fi); ttf_table_delete(0, t); } - void ttf_dump(ttf_t*ttf) { msg(" Truetype file version %08x%s", ttf->version, ttf->version == OPENTYPE?" (opentype)":""); @@ -1621,13 +1798,13 @@ int main(int argn, const char*argv[]) filename = argv[1]; //msg(" Loading %s", filename); memfile_t*m = memfile_open(filename); - ttf_t*ttf = load_ttf(m->data, m->len); + ttf_t*ttf = ttf_load(m->data, m->len); if(!ttf) return 1; memfile_close(m); //ttf_dump(ttf); //printf("os2 version: %04x (%d), maxp size: %d\n", // ttf->os2->version, ttf->os2->size, ttf->maxp->size); - ttf_save(ttf, "comic2.ttf"); + ttf_save(ttf, "output.ttf"); ttf_destroy(ttf); return 0; diff --git a/lib/ttf.h b/lib/ttf.h index a5ca523..73bd35c 100644 --- a/lib/ttf.h +++ b/lib/ttf.h @@ -54,7 +54,6 @@ typedef struct _table_os2 { S16 xAvgCharWidth; U16 usWeightClass; U16 usWidthClass; - U16 fsType; U16 ySubscriptXSize; U16 ySubscriptYSize; U16 ySubscriptXOffset; @@ -77,7 +76,6 @@ typedef struct _table_os2 { U8 panose_Midline; U8 panose_XHeight; U32 ulCharRange[4]; - U8 achVendID[4]; U16 fsSelection; U16 fsFirstCharIndex; @@ -103,9 +101,6 @@ typedef struct _table_os2 { typedef struct _table_hea { - S16 ascent; - S16 descent; - S16 lineGap; U16 advanceWidthMax; S16 minLeftSideBearing; S16 minRightSideBearing; @@ -154,6 +149,11 @@ typedef struct _ttf { U16 flags; char is_vertical; + + S16 ascent; + S16 descent; + S16 lineGap; + int num_glyphs; ttfglyph_t*glyphs; @@ -164,7 +164,11 @@ typedef struct _ttf { } ttf_t; -ttf_t*load_ttf(void*data, int length); +ttf_t*ttf_new(); +ttf_t*ttf_load(void*data, int length); ttf_table_t*ttf_addtable(ttf_t*ttf, U32 tag); +void ttf_create_truetype_tables(ttf_t*ttf); +void ttf_dump(ttf_t*ttf); +void ttf_save(ttf_t*ttf, const char*filename); #endif