📄 gdft.c
字号:
return (a->pixel == b->pixel && a->bgcolor == b->bgcolor && a->fgcolor == b->fgcolor && a->im == b->im);}/* * Computes a color in im's color table that is part way between * the background and foreground colors proportional to the gray * pixel value in the range 0-NUMCOLORS. The fg and bg colors must already * be in the color table. */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 *) gdMalloc (sizeof (tweencolor_t)); 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; if (im->trueColor) { /* 2.0.1: use gdImageSetPixel to do the alpha blending work, or to just store the alpha level. All we have to do here is incorporate our knowledge of the percentage of this pixel that is really "lit" by pushing the alpha value up toward transparency in edge regions. */ a->tweencolor = gdTrueColorAlpha ( gdTrueColorGetRed (fg), gdTrueColorGetGreen (fg), gdTrueColorGetBlue (fg), gdAlphaMax - (gdTrueColorGetAlpha (fg) * pixel / NUMCOLORS)); } else { 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); } } return (void *) a;}static voidtweenColorRelease (void *element){ gdFree ((char *) element);}/* draw_bitmap - transfers glyph bitmap to GD image *//* static */ char *gdft_draw_bitmap (gdImage * im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y){ unsigned char *pixel; int *tpixel; int x, y, row, col, pc; tweencolor_t *tc_elem; tweencolorkey_t tc_key; /* initialize tweenColorCache on first call */ static gdCache_head_t *tc_cache; if (!tc_cache) { tc_cache = gdCacheCreate (TWEENCOLORCACHESIZE, tweenColorTest, tweenColorFetch, tweenColorRelease); } /* copy to image, mapping colors */ tc_key.fgcolor = fg; tc_key.im = im; for (row = 0; row < bitmap.rows; row++) { pc = row * bitmap.pitch; y = pen_y + row; /* clip if out of bounds */ if (y >= im->sy || y < 0) continue; for (col = 0; col < bitmap.width; col++, pc++) { if (bitmap.pixel_mode == ft_pixel_mode_grays) { /* * Round to NUMCOLORS levels of antialiasing for * index color images since only 256 colors are * available. */ tc_key.pixel = ((bitmap.buffer[pc] * NUMCOLORS) + bitmap.num_grays / 2) / (bitmap.num_grays - 1); } else if (bitmap.pixel_mode == ft_pixel_mode_mono) { tc_key.pixel = ((bitmap.buffer[pc / 8] << (pc % 8)) & 128) ? NUMCOLORS : 0; } else { return "Unsupported ft_pixel_mode"; } if (tc_key.pixel > 0) { /* if not background */ x = pen_x + col; /* clip if out of bounds */ if (x >= im->sx || x < 0) continue; /* get pixel location in gd buffer */ if (im->trueColor) { tpixel = &im->tpixels[y][x]; } else { pixel = &im->pixels[y][x]; } if (tc_key.pixel == NUMCOLORS) { /* use fg color directly */ if (im->trueColor) { *tpixel = fg; } else { *pixel = fg; } } else { /* find antialised color */ if (im->trueColor) { tc_key.bgcolor = *tpixel; } else { tc_key.bgcolor = *pixel; } tc_elem = (tweencolor_t *) gdCacheGet ( tc_cache, &tc_key); if (im->trueColor) { *tpixel = tc_elem->tweencolor; } else { *pixel = tc_elem->tweencolor; } } } } } return (char *) NULL;}extern int any2eucjp (char *, char *, unsigned int);/********************************************************************//* gdImageStringFT - render a utf8 string onto a gd image */char *gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist, double ptsize, double angle, int x, int y, char *string){ FT_BBox bbox, glyph_bbox; FT_Matrix matrix; FT_Vector pen, delta, penf; FT_Face face; FT_Glyph image; FT_GlyphSlot slot; FT_Error err; FT_Bool use_kerning; FT_UInt glyph_index, previous; double sin_a = sin (angle); double cos_a = cos (angle); int len, i = 0, ch; int x1 = 0, y1 = 0; font_t *font; fontkey_t fontkey; char *next; char *tmpstr = 0; int render = (im && (im->trueColor || (fg <= 255 && fg >= -255))); FT_BitmapGlyph bm;/***** initialize font library and font cache on first call ******/ static gdCache_head_t *fontCache; static FT_Library library; if (!fontCache) { if (FT_Init_FreeType (&library)) { return "Failure to initialize font library"; } fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, fontFetch, fontRelease); }/*****/ /* get the font (via font cache) */ fontkey.fontlist = fontlist; fontkey.library = &library; font = (font_t *) gdCacheGet (fontCache, &fontkey); if (!font) { return fontCache->error; } face = font->face; /* shortcut */ slot = face->glyph; /* shortcut */ if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64), GD_RESOLUTION, GD_RESOLUTION)) { return "Could not set character size"; } matrix.xx = (FT_Fixed) (cos_a * (1 << 16)); matrix.yx = (FT_Fixed) (sin_a * (1 << 16)); matrix.xy = -matrix.yx; matrix.yy = matrix.xx; penf.x = penf.y = 0; /* running position of non-rotated string */ pen.x = pen.y = 0; /* running position of rotated string */ bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0; use_kerning = FT_HAS_KERNING (face); previous = 0;#ifndef JISX0208 if (font->have_char_map_sjis) {#endif if (tmpstr = (char *) gdMalloc (BUFSIZ)) { any2eucjp (tmpstr, string, BUFSIZ); next = tmpstr; } else { next = string; }#ifndef JISX0208 } else { next = string; }#endif while (*next) { ch = *next; /* carriage returns */ if (ch == '\r') { penf.x = 0; x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64; y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64; pen.x = pen.y = 0; previous = 0; /* clear kerning flag */ next++; continue; } /* newlines */ if (ch == '\n') { penf.y -= face->size->metrics.height * LINESPACE; penf.y = (penf.y - 32) & -64; /* round to next pixel row */ x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64; y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64; pen.x = pen.y = 0; previous = 0; /* clear kerning flag */ next++; continue; } if (font->have_char_map_unicode) { /* use UTF-8 mapping from ASCII */ len = gdTcl_UtfToUniChar (next, &ch); next += len; } else if (font->have_char_map_sjis) { unsigned char c; int jiscode; c = *next; if (0xA1 <= c && c <= 0xFE) { next++; jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F); ch = (jiscode >> 8) & 0xFF; jiscode &= 0xFF; if (ch & 1) jiscode += 0x40 - 0x21; else jiscode += 0x9E - 0x21; if (jiscode >= 0x7F) jiscode++; ch = (ch - 0x21) / 2 + 0x81; if (ch >= 0xA0) ch += 0x40; ch = (ch << 8) + jiscode; } else { ch = c & 0xFF; /* don't extend sign */ } next++; } 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) & 0xFF; /* don't extend sign */ next++; if (ch >= 161 /* first code of JIS-8 pair */ && *next) { /* don't advance past '\0' */ /* TBB: Fix from Kwok Wah On: & 255 needed */ ch = (ch * 256) + ((*next) & 255); next++; } } /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index (face, ch); /* retrieve kerning distance and move pen position */ if (use_kerning && previous && glyph_index) { FT_Get_Kerning (face, previous, glyph_index, ft_kerning_default, &delta); pen.x += delta.x; } /* load glyph image into the slot (erase previous one) */ err = FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); if (err) return "Problem loading glyph"; /* transform glyph image */ FT_Get_Glyph (slot, &image); if (brect) { /* only if need brect */ FT_Glyph_Get_CBox (image, ft_glyph_bbox_gridfit, &glyph_bbox); if (!i) { /* if first character, init BB corner values */ bbox.xMin = bbox.yMin = (1 << 30) - 1; bbox.xMax = bbox.yMax = -bbox.xMin; } glyph_bbox.xMin += penf.x; glyph_bbox.yMin += penf.y; glyph_bbox.xMax += penf.x; glyph_bbox.yMax += penf.y; if (bbox.xMin > glyph_bbox.xMin) bbox.xMin = glyph_bbox.xMin; if (bbox.yMin > glyph_bbox.yMin) bbox.yMin = glyph_bbox.yMin; if (bbox.xMax < glyph_bbox.xMax) bbox.xMax = glyph_bbox.xMax; if (bbox.yMax < glyph_bbox.yMax) bbox.yMax = glyph_bbox.yMax; i++; } /* transform glyph image */ FT_Glyph_Transform (image, &matrix, 0); if (render) { if (image->format != ft_glyph_format_bitmap) { err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1); if (err) return "Problem rendering glyph"; } /* now, draw to our target surface */ bm = (FT_BitmapGlyph) image; gdft_draw_bitmap (im, fg, bm->bitmap, x + x1 + ((pen.x + 31) >> 6) + bm->left, y - y1 + ((pen.y + 31) >> 6) - bm->top); } /* record current glyph index for kerning */ previous = glyph_index; /* increment pen position */ pen.x += image->advance.x >> 10; pen.y -= image->advance.y >> 10; penf.x += slot->metrics.horiAdvance; FT_Done_Glyph (image); } if (brect) { /* only if need brect */ /* For perfect rounding, must get sin(a + pi/4) and sin(a - pi/4). */ double d1 = sin (angle + 0.78539816339744830962); double d2 = sin (angle - 0.78539816339744830962); /* rotate bounding rectangle */ brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a); brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a); brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a); brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a); brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a); brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a); brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a); brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a); /* scale, round and offset brect */ brect[0] = x + gdroundupdown (brect[0], d2 > 0); brect[1] = y - gdroundupdown (brect[1], d1 < 0); brect[2] = x + gdroundupdown (brect[2], d1 > 0); brect[3] = y - gdroundupdown (brect[3], d2 > 0); brect[4] = x + gdroundupdown (brect[4], d2 < 0); brect[5] = y - gdroundupdown (brect[5], d1 > 0); brect[6] = x + gdroundupdown (brect[6], d1 < 0); brect[7] = y - gdroundupdown (brect[7], d2 < 0); } if (tmpstr) gdFree (tmpstr); return (char *) NULL;}intgdroundupdown (FT_F26Dot6 v1, int updown){ return (!updown) ? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6) : (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);}#endif /* HAVE_LIBFREETYPE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -