📄 gdttf.c
字号:
static intglyphTest ( void *element, void *key ){ glyph_t *a=(glyph_t *)element; glyphkey_t *b=(glyphkey_t *)key; return (a->character == b->character && a->hinting == b->hinting && a->gray_render == b->gray_render);}static void *glyphFetch ( char **error, void *key ){ glyph_t *a; glyphkey_t *b=(glyphkey_t *)key; short glyph_code; int flags, err; int crect[8], xmin, xmax, ymin, ymax; double cos_a, sin_a; a = (glyph_t *)pemalloc(sizeof(glyph_t), 1); a->character = b->character; a->hinting = b->hinting; a->gray_render = b->gray_render; a->oldx = a->oldy = 0; /* create glyph container */ if ((TT_New_Glyph(b->font->face, &a->glyph))) { *error = "Could not create glyph container"; pefree(a, 1); return NULL; } flags = TTLOAD_SCALE_GLYPH; if (a->hinting && b->font->angle == 0.0) { flags |= TTLOAD_HINT_GLYPH; } if (b->font->have_char_map_Unicode) { glyph_code = TT_Char_Index(b->font->char_map_Unicode, a->character); } else if (a->character < 161 && b->font->have_char_map_Roman) { glyph_code = TT_Char_Index(b->font->char_map_Roman, a->character); } else if ( b->font->have_char_map_Big5) { glyph_code = TT_Char_Index(b->font->char_map_Big5, a->character); } if ((err=TT_Load_Glyph(b->font->instance, a->glyph, glyph_code, flags))) { *error = "TT_Load_Glyph problem"; pefree(a, 1); return NULL; } TT_Get_Glyph_Metrics(a->glyph, &a->metrics); if (b->font->angle != 0.0) { TT_Get_Glyph_Outline(a->glyph, &a->outline); TT_Transform_Outline(&a->outline, &b->font->matrix); } /* calculate bitmap size */ xmin = a->metrics.bbox.xMin -64; ymin = a->metrics.bbox.yMin -64; xmax = a->metrics.bbox.xMax +64; ymax = a->metrics.bbox.yMax +64; cos_a = b->font->cos_a; sin_a = b->font->sin_a; crect[0] = (int)(xmin * cos_a - ymin * sin_a); crect[1] = (int)(xmin * sin_a + ymin * cos_a); crect[2] = (int)(xmax * cos_a - ymin * sin_a); crect[3] = (int)(xmax * sin_a + ymin * cos_a); crect[4] = (int)(xmax * cos_a - ymax * sin_a); crect[5] = (int)(xmax * sin_a + ymax * cos_a); crect[6] = (int)(xmin * cos_a - ymax * sin_a); crect[7] = (int)(xmin * sin_a + ymax * cos_a); a->xmin = MIN(MIN(crect[0], crect[2]), MIN(crect[4], crect[6])); a->xmax = MAX(MAX(crect[0], crect[2]), MAX(crect[4], crect[6])); a->ymin = MIN(MIN(crect[1], crect[3]), MIN(crect[5], crect[7])); a->ymax = MAX(MAX(crect[1], crect[3]), MAX(crect[5], crect[7])); /* allocate bitmap large enough for character */ a->Bit.rows = (a->ymax - a->ymin + 32 + 64) / 64; a->Bit.width = (a->xmax - a->xmin + 32 + 64) / 64; a->Bit.flow = TT_Flow_Up; if (a->gray_render) { a->Bit.cols = a->Bit.width; /* 1 byte per pixel */ } else { a->Bit.cols = (a->Bit.width + 7) / 8; /* 1 bit per pixel */ } a->Bit.cols = (a->Bit.cols + 3) & ~3; /* pad to 32 bits */ a->Bit.size = a->Bit.rows * a->Bit.cols; /* # of bytes in buffer */ a->Bit.bitmap = NULL; a->bitmapCache = gdCacheCreate( BITMAPCACHESIZE, bitmapTest, bitmapFetch, bitmapRelease); return (void *)a;}static voidglyphRelease( void *element ){ glyph_t *a=(glyph_t *)element; gdCacheDelete(a->bitmapCache); TT_Done_Glyph( a->glyph ); pefree ((char *)element, 1);}/********************************************************************//* bitmap cache functions */static intbitmapTest ( void *element, void *key ){ bitmap_t *a=(bitmap_t *)element; bitmapkey_t *b=(bitmapkey_t *)key; if (a->xoffset == b->xoffset && a->yoffset == b->yoffset) { b->glyph->Bit.bitmap = a->bitmap; return TRUE; } return FALSE;}static void *bitmapFetch ( char **error, void *key ){ bitmap_t *a; bitmapkey_t *b=(bitmapkey_t *)key; a = (bitmap_t *)pemalloc(sizeof(bitmap_t), 1); a->xoffset = b->xoffset; a->yoffset = b->yoffset; b->glyph->Bit.bitmap = a->bitmap = (char *)pemalloc(b->glyph->Bit.size, 1); memset(a->bitmap, 0, b->glyph->Bit.size); /* render glyph */ if (b->glyph->gray_render) { TT_Get_Glyph_Pixmap(b->glyph->glyph, &b->glyph->Bit, a->xoffset, a->yoffset); } else { TT_Get_Glyph_Bitmap(b->glyph->glyph, &b->glyph->Bit, a->xoffset, a->yoffset); } return (void *)a;}static voidbitmapRelease( void *element ){ bitmap_t *a=(bitmap_t *)element; pefree (a->bitmap, 1); pefree ((char *)element, 1);}/********************************************************************//* tweencolor cache functions */static inttweenColorTest (void *element, void *key){ tweencolor_t *a=(tweencolor_t *)element; tweencolorkey_t *b=(tweencolorkey_t *)key; return (a->pixel == b->pixel && a->bgcolor == b->bgcolor && a->fgcolor == b->fgcolor && a->im == b->im);} static void *tweenColorFetch (char **error, void *key){ tweencolor_t *a; tweencolorkey_t *b=(tweencolorkey_t *)key; int pixel, npixel, bg, fg; gdImagePtr im; a = (tweencolor_t *)pemalloc(sizeof(tweencolor_t), 1); pixel = a->pixel = b->pixel; bg = a->bgcolor = b->bgcolor; fg = a->fgcolor = b->fgcolor; im = b->im; /* if fg is specified by a negative color idx, then don't antialias */ if (fg <0) { a->tweencolor = -fg; } else { npixel = NUMCOLORS - pixel; a->tweencolor = gdImageColorResolve(im, (pixel * im->red [fg] + npixel * im->red [bg]) / NUMCOLORS, (pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS, (pixel * im->blue [fg] + npixel * im->blue [bg]) / NUMCOLORS); } *error = NULL; return (void *)a;} static voidtweenColorRelease(void *element){ pefree((char *)element, 1);} /********************************************************************//* gdttfchar - render one character onto a gd image */static int OneTime=0;static gdCache_head_t *tweenColorCache;char *gdttfchar(gdImage *im, int fg, font_t *font, int x, int y, /* string start pos in pixels */ TT_F26Dot6 x1, TT_F26Dot6 y1, /* char start offset (*64) from x,y */ TT_F26Dot6 *advance, TT_BBox **bbox, char **next){ int pc, ch, len; int row, col; int x2, y2; /* char start pos in pixels */ int x3, y3; /* current pixel pos */ unsigned char *pixel; glyph_t *glyph; glyphkey_t glyphkey; bitmapkey_t bitmapkey; tweencolor_t *tweencolor; tweencolorkey_t tweencolorkey; /****** set up tweenColorCache on first call ************/ if (! OneTime) { tweenColorCache = gdCacheCreate(TWEENCOLORCACHESIZE, tweenColorTest, tweenColorFetch, tweenColorRelease); OneTime++; } /**************/ if (font->have_char_map_Unicode) { /* use UTF-8 mapping from ASCII */ len = gdTcl_UtfToUniChar(*next, &ch); *next += len; } else { /* * Big 5 mapping: * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref: * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs */ ch = (**next) & 255; /* don't extend sign */ (*next)++; if (ch >= 161 /* first code of JIS-8 pair */ && **next) { /* don't advance past '\0' */ ch = (ch * 256) + **next; (*next)++; } } glyphkey.character = ch; glyphkey.hinting = 1; /* if fg is specified by a negative color idx, then don't antialias */ glyphkey.gray_render = ((font->ptsize < MINANTIALIASPTSIZE) || (fg <0))?FALSE:TRUE; glyphkey.font = font; glyph = (glyph_t *)gdCacheGet(font->glyphCache, &glyphkey); if (! glyph) return font->glyphCache->error; *bbox = &glyph->metrics.bbox; *advance = glyph->metrics.advance; /* if null *im, or invalid color, then assume user just wants brect */ if (!im || fg > 255 || fg < -255) return (char *)NULL; /* render (via cache) a bitmap for the current fractional offset */ bitmapkey.xoffset = ((x1+32) & 63) - 32 - ((glyph->xmin+32) & -64); bitmapkey.yoffset = ((y1+32) & 63) - 32 - ((glyph->ymin+32) & -64); bitmapkey.glyph = glyph; gdCacheGet(glyph->bitmapCache, &bitmapkey); /* copy to gif, mapping colors */ x2 = x + (((glyph->xmin+32) & -64) + ((x1+32) & -64)) / 64; y2 = y - (((glyph->ymin+32) & -64) + ((y1+32) & -64)) / 64; tweencolorkey.fgcolor = fg; tweencolorkey.im = im; for (row = 0; row < glyph->Bit.rows; row++) { if (glyph->gray_render) pc = row * glyph->Bit.cols; else pc = row * glyph->Bit.cols * 8; y3 = y2 - row; if (y3 >= im->sy || y3 < 0) continue; for (col = 0; col < glyph->Bit.width; col++, pc++) { if (glyph->gray_render) { tweencolorkey.pixel = *((unsigned char *)(glyph->Bit.bitmap) + pc); } else { tweencolorkey.pixel = (((*((unsigned char *)(glyph->Bit.bitmap) + pc/8)) <<(pc%8))&128)?4:0; } /* if not background */ if (tweencolorkey.pixel > 0) { x3 = x2 + col; if (x3 >= im->sx || x3 < 0) continue;#if HAVE_LIBGD20 if (im->trueColor) { pixel = &im->tpixels[y3][x3]; } else#endif {#if HAVE_LIBGD13 pixel = &im->pixels[y3][x3];#else pixel = &im->pixels[x3][y3];#endif } tweencolorkey.bgcolor = *pixel; tweencolor = (tweencolor_t *)gdCacheGet( tweenColorCache, &tweencolorkey); *pixel = tweencolor->tweencolor; } } } return (char *)NULL;}/********************************************************************//* gdttf - render a utf8 string onto a gd image */char *gdttf(gdImage *im, int *brect, int fg, char *fontname, double ptsize, double angle, int x, int y, char *str){ TT_F26Dot6 ur_x=0, ur_y=0, ll_x=0, ll_y=0; TT_F26Dot6 advance_x, advance_y, advance, x1, y1; TT_BBox *bbox; double sin_a, cos_a; int i=0, ch; font_t *font; fontkey_t fontkey; char *error, *next; /****** initialize font engine on first call ************/ static gdCache_head_t *fontCache; static TT_Engine engine; if (! fontCache) { if (TT_Init_FreeType(&engine)) { return "Failure to initialize font engine"; } fontCache = gdCacheCreate( FONTCACHESIZE, fontTest, fontFetch, fontRelease); } /**************/ /* get the font (via font cache) */ fontkey.fontname = fontname; fontkey.ptsize = ptsize; fontkey.angle = angle; fontkey.engine = &engine; font = (font_t *)gdCacheGet(fontCache, &fontkey); if (! font) { return fontCache->error; } sin_a = font->sin_a; cos_a = font->cos_a; advance_x = advance_y = 0; next=str; while (*next) { ch = *next; /* carriage returns */ if (ch == '\r') { advance_x = 0; next++; continue; } /* newlines */ if (ch == '\n') { advance_y -= (TT_F26Dot6)(font->imetrics.y_ppem * LINESPACE * 64); advance_y = (advance_y-32) & -64; /* round to next pixel row */ next++; continue; } x1 = (TT_F26Dot6)(advance_x * cos_a - advance_y * sin_a); y1 = (TT_F26Dot6)(advance_x * sin_a + advance_y * cos_a); if ((error=gdttfchar(im, fg, font, x, y, x1, y1, &advance, &bbox, &next))) return error; if (! i++) { /* if first character, init BB corner values */ ll_x = bbox->xMin; ll_y = bbox->yMin; ur_x = bbox->xMax; ur_y = bbox->yMax; } else { if (! advance_x) ll_x = MIN(bbox->xMin, ll_x); ll_y = MIN(advance_y + bbox->yMin, ll_y); ur_x = MAX(advance_x + bbox->xMax, ur_x); if (! advance_y) ur_y = MAX(bbox->yMax, ur_y); } advance_x += advance; } /* rotate bounding rectangle */ brect[0] = (int)(ll_x * cos_a - ll_y * sin_a); brect[1] = (int)(ll_x * sin_a + ll_y * cos_a); brect[2] = (int)(ur_x * cos_a - ll_y * sin_a); brect[3] = (int)(ur_x * sin_a + ll_y * cos_a); brect[4] = (int)(ur_x * cos_a - ur_y * sin_a); brect[5] = (int)(ur_x * sin_a + ur_y * cos_a); brect[6] = (int)(ll_x * cos_a - ur_y * sin_a); brect[7] = (int)(ll_x * sin_a + ur_y * cos_a); /* scale, round and offset brect */ i = 0; while (i<8) { brect[i] = x + (brect[i] + 32) / 64; i++; brect[i] = y - (brect[i] + 32) / 64; i++; } return (char *)NULL;} #endif /* HAVE_LIBTTF *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -