diff options
author | Mark Plomer <mail@mark-plomer.de> | 2016-04-03 11:52:59 +0200 |
---|---|---|
committer | Mark Plomer <mail@mark-plomer.de> | 2016-04-03 12:11:26 +0200 |
commit | f5f94d9c089cb670e9c119fff4102af1ffc7fbe5 (patch) | |
tree | bee5ea5bc7992aba6c3657f3a4fef67165c97baa /ext/gd/libgd | |
parent | 9f25f736ed50a2dc94aeff4f289c1a5e26fc6a40 (diff) | |
download | php-git-f5f94d9c089cb670e9c119fff4102af1ffc7fbe5.tar.gz |
fix left-shifted/misaligned bounding-box + wrong kerning in imagettfbbox/imageftbbox
- load glyph with FT_LOAD_IGNORE_TRANSFORM for bbox as final bbox is rotated at once later (fixes "double-rotation" per glyph for calculating bbox)
- reload the rotated glyph for painting after that (only if angle != 0)
- rotate the original bbox at 0,0 and do not throw away xMin/yMin (drawing-rotation is also based at "origin" point - including the bearingX, see http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html#section-3) - this fixes the "left-shift"-problem also when angle = 0
- removed "xb/yb" and use "x/y" directly for offsetting brect (no need for adding "x1/y1" and substracting "yd" later)
- removed therefore unused "yd" helper var which seems tried to fix parts of the original problems
- initialize x/y with 0 instead of -1 in php_imagettftext_common() to make image*text() and image*bbox() results identical (there was a -1px shift in image*bbox() before)
- fixed gdroundupdown() for negative numbers (-256 / 64 gives -5 instead of -4 before)
- rotate kerning-delta by given angle (fixes completely wrong kerning and therefore wrong bounding box if angle != 0)
- changed 3 tests and added a new one to test for the new (better) coordinates
Diffstat (limited to 'ext/gd/libgd')
-rw-r--r-- | ext/gd/libgd/gdft.c | 127 |
1 files changed, 66 insertions, 61 deletions
diff --git a/ext/gd/libgd/gdft.c b/ext/gd/libgd/gdft.c index 763efcf68c..b74c4938ea 100644 --- a/ext/gd/libgd/gdft.c +++ b/ext/gd/libgd/gdft.c @@ -748,9 +748,9 @@ static char * gdft_draw_bitmap (gdCache_head_t *tc_cache, gdImage * im, int fg, } static int -gdroundupdown (FT_F26Dot6 v1, int updown) +gdroundupdown (FT_F26Dot6 v1, int roundup) { - return (!updown) ? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6) : (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6); + return (!roundup) ? v1 >> 6 : (v1 + 63) >> 6; } void gdFontCacheShutdown() @@ -820,8 +820,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi double cos_a = cos (angle); int len, i = 0, ch; int x1 = 0, y1 = 0; - int xb = x, yb = y; - int yd = 0; font_t *font; fontkey_t fontkey; char *next; @@ -982,9 +980,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi penf.y = (penf.y - 32) & -64; /* round to next pixel row */ x1 = (int)(- penf.y * sin_a + 32) / 64; y1 = (int)(- penf.y * cos_a + 32) / 64; - xb = x + x1; - yb = y + y1; - yd = 0; pen.x = pen.y = 0; previous = 0; /* clear kerning flag */ continue; @@ -1074,31 +1069,32 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi /* 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; + pen.x += (int)(delta.x * cos_a); + pen.y -= (int)(delta.x * sin_a); penf.x += delta.x; } - /* load glyph image into the slot (erase previous one) */ - if (FT_Load_Glyph(face, glyph_index, render_mode)) { - if (tmpstr) { - gdFree(tmpstr); + if (brect) { /* only if need brect */ + /* load glyph image into the slot (erase previous one) */ + if (FT_Load_Glyph(face, glyph_index, render_mode | FT_LOAD_IGNORE_TRANSFORM)) { + if (tmpstr) { + gdFree(tmpstr); + } + gdCacheDelete(tc_cache); + gdMutexUnlock(gdFontCacheMutex); + return "Problem loading glyph"; } - gdCacheDelete(tc_cache); - gdMutexUnlock(gdFontCacheMutex); - return "Problem loading glyph"; - } - /* transform glyph image */ - if (FT_Get_Glyph(slot, &image)) { - if (tmpstr) { - gdFree(tmpstr); + /* transform glyph image */ + if (FT_Get_Glyph(slot, &image)) { + if (tmpstr) { + gdFree(tmpstr); + } + gdCacheDelete(tc_cache); + gdMutexUnlock(gdFontCacheMutex); + return "Problem loading glyph"; } - gdCacheDelete(tc_cache); - gdMutexUnlock(gdFontCacheMutex); - return "Problem loading glyph"; - } - if (brect) { /* only if need brect */ FT_Glyph_Get_CBox(image, ft_glyph_bbox_gridfit, &glyph_bbox); glyph_bbox.xMin += penf.x; glyph_bbox.yMin += penf.y; @@ -1108,17 +1104,11 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi glyph_bbox.xMax += slot->metrics.horiAdvance; } if (!i) { /* if first character, init BB corner values */ - yd = slot->metrics.height - slot->metrics.horiBearingY; bbox.xMin = glyph_bbox.xMin; bbox.yMin = glyph_bbox.yMin; bbox.xMax = glyph_bbox.xMax; bbox.yMax = glyph_bbox.yMax; } else { - FT_Pos desc; - - if ( (desc = (slot->metrics.height - slot->metrics.horiBearingY)) > yd) { - yd = desc; - } if (bbox.xMin > glyph_bbox.xMin) { bbox.xMin = glyph_bbox.xMin; } @@ -1135,7 +1125,35 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi i++; } + /* increment (unrotated) pen position */ + penf.x += slot->metrics.horiAdvance; + if (render) { + if (!brect || angle != 0) { + /* reload the rotated glyph (for bbox we needed FT_LOAD_IGNORE_TRANSFORM - bbox is rotated later) */ + FT_Done_Glyph(image); + + /* load glyph image into the slot (erase previous one) */ + if (FT_Load_Glyph(face, glyph_index, render_mode)) { + if (tmpstr) { + gdFree(tmpstr); + } + gdCacheDelete(tc_cache); + gdMutexUnlock(gdFontCacheMutex); + return "Problem loading glyph"; + } + + /* transform glyph image */ + if (FT_Get_Glyph(slot, &image)) { + if (tmpstr) { + gdFree(tmpstr); + } + gdCacheDelete(tc_cache); + gdMutexUnlock(gdFontCacheMutex); + return "Problem loading glyph"; + } + } + if (image->format != ft_glyph_format_bitmap && FT_Glyph_To_Bitmap(&image, ft_render_mode_normal, 0, 1)) { FT_Done_Glyph(image); if (tmpstr) { @@ -1158,8 +1176,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi pen.x += image->advance.x >> 10; pen.y -= image->advance.y >> 10; - penf.x += slot->metrics.horiAdvance; - FT_Done_Glyph(image); } @@ -1168,36 +1184,25 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi double d1 = sin (angle + 0.78539816339744830962); double d2 = sin (angle - 0.78539816339744830962); - /* make the center of rotation at (0, 0) */ - FT_BBox normbox; - - normbox.xMin = 0; - normbox.yMin = 0; - normbox.xMax = bbox.xMax - bbox.xMin; - normbox.yMax = bbox.yMax - bbox.yMin; - - brect[0] = brect[2] = brect[4] = brect[6] = (int) (yd * sin_a); - brect[1] = brect[3] = brect[5] = brect[7] = (int)(- yd * cos_a); - - /* rotate bounding rectangle */ - brect[0] += (int) (normbox.xMin * cos_a - normbox.yMin * sin_a); - brect[1] += (int) (normbox.xMin * sin_a + normbox.yMin * cos_a); - brect[2] += (int) (normbox.xMax * cos_a - normbox.yMin * sin_a); - brect[3] += (int) (normbox.xMax * sin_a + normbox.yMin * cos_a); - brect[4] += (int) (normbox.xMax * cos_a - normbox.yMax * sin_a); - brect[5] += (int) (normbox.xMax * sin_a + normbox.yMax * cos_a); - brect[6] += (int) (normbox.xMin * cos_a - normbox.yMax * sin_a); - brect[7] += (int) (normbox.xMin * sin_a + normbox.yMax * cos_a); + /* rotate bounding rectangle (at 0, 0) */ + 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] = xb + gdroundupdown(brect[0], d2 > 0); - brect[1] = yb - gdroundupdown(brect[1], d1 < 0); - brect[2] = xb + gdroundupdown(brect[2], d1 > 0); - brect[3] = yb - gdroundupdown(brect[3], d2 > 0); - brect[4] = xb + gdroundupdown(brect[4], d2 < 0); - brect[5] = yb - gdroundupdown(brect[5], d1 > 0); - brect[6] = xb + gdroundupdown(brect[6], d1 < 0); - brect[7] = yb - gdroundupdown(brect[7], d2 < 0); + 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) { |