GD is an open source code library for the dynamic creation of images by programmers. GD is written in C, and “wrappers” are available for Perl, PHP and other languages. GD creates PNG, JPEG and GIF images, among other formats. GD is commonly used to generate charts, graphics, thumbnails, and most anything else, on the fly. While not restricted to use on the web, the most common applications of GD involve web site development.
See the GD website for more informations.
FS#54 — wobbly text when rotated
Opened by Neil Turner (onlyfamily) - Friday, 09 March 2007, 00:19 GMT+2
Last edited by Pierre Joye (Pierre) - Friday, 09 March 2007, 01:48 GMT+2
|
DetailsWhen trying to render text at an angle the kerning and baseline are not uniform. I made the changes to gdft.c from version 2.0.33 of GD. The solution was to perform the glyph transformations in the order that the FreeType website recommends: translate then rotate. here is the diff: -bash-3.00$ diff ../gd-2.0.33/gdft.c.orig ../gd-2.0.33/gdft.c 945,947d944 < /* set rotation transform */ < FT_Set_Transform (face, &matrix, NULL); < 1286a1284,1293 > //translate > FT_Vector tmpPen; > tmpPen.x = penf.x * hdpi / (METRIC_RES); > tmpPen.y = -penf.y * vdpi / (METRIC_RES); > FT_Glyph_Transform(image, 0, &tmpPen); > //rotate > FT_Vector start; > start.x = 0; > start.y = 0; > FT_Glyph_Transform(image, &matrix, &start); 1303,1305c1310,1315 < gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap, < x + (penf.x * cos_a + penf.y * sin_a)*hdpi/(METRIC_RES*64) + bm->left, < y - (penf.x * sin_a - penf.y * cos_a)*vdpi/(METRIC_RES*64) - bm->top); --- > gdft_draw_bitmap (tc_cache, > im, > fg, > bm->bitmap, > x + bm->left, > y - bm->top); |
Hi,
I'm not sure to see the baseline problem. Is it possible to provide a sample app to show your problem? Ideally with two images, with or without your patch.
Can you attach a unified diff against 2.0.34? (cvs diff -up using GD_2_0, or diff -up against 2.0.34 release). You can attach the images and patches.
'fontwheeltest' shows the visual issues: see attached images.
The kerning is obvious everywhere but the baseline issue is harder to see. Look at the "e" in the first "Hello" above horizontal. It drops a little bit.
I have never done unified diff before; I hope this is what you are asking for??
-bash-3.00$ diff -up gd-2.0.34/gdft.c gd-2.0.33/gdft.c --- gd-2.0.34/gdft.c 2007-03-08 13:37:48.000000000 -0800 +++ gd-2.0.33/gdft.c 2007-03-07 14:52:01.000000000 -0800 @@ -439,10 +439,6 @@ fontFetch (char **error, void *key) *error = NULL; a = (font_t *) gdMalloc (sizeof (font_t)); - if (!a) { - return NULL; - } - a->fontlist = strdup (b->fontlist); a->flags = b->flags; a->library = b->library; @@ -542,14 +538,10 @@ tweenColorFetch (char **error, void *key gdImagePtr im; a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t)); - if (!a) { - return NULL; - } - pixel = a->pixel = b->pixel; bg = a->bgcolor = b->bgcolor; fg = a->fgcolor = b->fgcolor; - im = a->im = b->im; + im = b->im; /* if fg is specified by a negative color idx, then don't antialias */ if (fg < 0) @@ -826,9 +818,6 @@ BGD_DECLARE(int) gdFontCacheSetup (void) return -1; } fontCache = gdCacheCreate (FONTCACHESIZE, fontTest, fontFetch, fontRelease); - if (!fontCache) { - return -2; - } return 0; } @@ -843,7 +832,7 @@ BGD_DECLARE(char *) gdImageStringFTEx (g FT_Matrix matrix; FT_Vector penf, oldpenf, delta, total_min = {0,0}, total_max = {0,0}, glyph_min, glyph_max; FT_Face face; - FT_CharMap charmap = NULL; + FT_CharMap charmap; FT_Glyph image; FT_GlyphSlot slot; FT_Error err; @@ -916,12 +905,6 @@ BGD_DECLARE(char *) gdImageStringFTEx (g face = font->face; /* shortcut */ slot = face->glyph; /* shortcut */ - if (brect) - { - total_min.x = total_min.y = 0; - total_max.x = total_max.y = 0; - } - /* * Added hdpi and vdpi to support images at non-screen resolutions, i.e. 300 dpi TIFF, * or 100h x 50v dpi FAX format. 2.0.23. @@ -959,9 +942,6 @@ BGD_DECLARE(char *) gdImageStringFTEx (g matrix.xy = -matrix.yx; matrix.yy = matrix.xx; - /* set rotation transform */ - FT_Set_Transform (face, &matrix, NULL); - FT_New_Size (face, &platform_independent); FT_Activate_Size (platform_independent); if (FT_Set_Char_Size (face, 0, (FT_F26Dot6)(ptsize*64), METRIC_RES, METRIC_RES)) @@ -1004,14 +984,6 @@ BGD_DECLARE(char *) gdImageStringFTEx (g break; } } - else if (encoding == gdFTEX_Adobe_Custom) - { - if (charmap->encoding == FT_ENCODING_ADOBE_CUSTOM) - { - encodingfound++; - break; - } - } else if (encoding == gdFTEX_Big5) { /* renamed sometime after freetype-2.1.4 */ @@ -1186,7 +1158,7 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d { ch = c & 0xFF; /* don't extend sign */ } - if (*next) next++; + next++; } break; case gdFTEX_Big5: @@ -1207,12 +1179,6 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d } } break; - - case gdFTEX_Adobe_Custom: - default: - ch &= 0xFF; - next++; - break; } /* Convert character code to glyph index */ @@ -1238,19 +1204,13 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d /* make sure we have enough allocation for two numbers so we don't have to recheck for the terminating number */ if (! xshow_alloc) { - xshow_alloc = 100; - strex->xshow = gdMalloc(xshow_alloc); - if (!strex->xshow) { - return 0; - } - xshow_pos = 0; + xshow_alloc = 100; + strex->xshow = malloc(xshow_alloc); + xshow_pos = 0; } else if (xshow_pos + 20 > xshow_alloc) { xshow_alloc += 100; - strex->xshow = gdRealloc(strex->xshow, xshow_alloc); - if (!strex->xshow) { - return 0; - } + strex->xshow = realloc(strex->xshow, xshow_alloc); } xshow_pos += sprintf(strex->xshow + xshow_pos, "%g ", (double)(penf.x - oldpenf.x) * hdpi / (64 * METRIC_RES)); @@ -1321,6 +1281,16 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d /* load and transform glyph image */ FT_Get_Glyph (slot, &image); + //translate + FT_Vector tmpPen; + tmpPen.x = penf.x * hdpi / (METRIC_RES); + tmpPen.y = -penf.y * vdpi / (METRIC_RES); + FT_Glyph_Transform(image, 0, &tmpPen); + //rotate + FT_Vector start; + start.x = 0; + start.y = 0; + FT_Glyph_Transform(image, &matrix, &start); if (image->format != ft_glyph_format_bitmap) { @@ -1337,9 +1307,12 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d bm = (FT_BitmapGlyph) image; /* position rounded down to nearest pixel at current dpi (the estimate was rounded up to next 1/METRIC_RES, so this should fit) */ - gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap, - x + (penf.x * cos_a + penf.y * sin_a)*hdpi/(METRIC_RES*64) + bm->left, - y - (penf.x * sin_a - penf.y * cos_a)*vdpi/(METRIC_RES*64) - bm->top); + gdft_draw_bitmap (tc_cache, + im, + fg, + bm->bitmap, + x + bm->left, + y - bm->top); FT_Done_Glyph (image); } @@ -1358,9 +1331,11 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d } if (brect) - { /* only if need brect */ - double scalex = (double)hdpi / (64 * METRIC_RES); - double scaley = (double)vdpi / (64 * METRIC_RES); + { /* only if need brect */ + double dpix, dpiy; + + dpix = 64 * METRIC_RES / hdpi; + dpiy = 64 * METRIC_RES / vdpi; /* increase by 1 pixel to allow for rounding */ total_min.x -= METRIC_RES; @@ -1369,14 +1344,14 @@ fprintf(stderr,"dpi=%d,%d metric_res=%d total_max.y += METRIC_RES; /* rotate bounding rectangle, scale and round to int pixels, and translate */ - brect[0] = x + (total_min.x * cos_a + total_max.y * sin_a)*scalex; - brect[1] = y - (total_min.x * sin_a - total_max.y * cos_a)*scaley; - brect[2] = x + (total_max.x * cos_a + total_max.y * sin_a)*scalex; - brect[3] = y - (total_max.x * sin_a - total_max.y * cos_a)*scaley; - brect[4] = x + (total_max.x * cos_a + total_min.y * sin_a)*scalex; - brect[5] = y - (total_max.x * sin_a - total_min.y * cos_a)*scaley; - brect[6] = x + (total_min.x * cos_a + total_min.y * sin_a)*scalex; - brect[7] = y - (total_min.x * sin_a - total_min.y * cos_a)*scaley; + brect[0] = x + (total_min.x * cos_a + total_max.y * sin_a)/dpix; + brect[1] = y - (total_min.x * sin_a - total_max.y * cos_a)/dpiy; + brect[2] = x + (total_max.x * cos_a + total_max.y * sin_a)/dpix; + brect[3] = y - (total_max.x * sin_a - total_max.y * cos_a)/dpiy; + brect[4] = x + (total_max.x * cos_a + total_min.y * sin_a)/dpix; + brect[5] = y - (total_max.x * sin_a - total_min.y * cos_a)/dpiy; + brect[6] = x + (total_min.x * cos_a + total_min.y * sin_a)/dpix; + brect[7] = y - (total_min.x * sin_a - total_min.y * cos_a)/dpiy; } FT_Done_Size (platform_independent); -bash-3.00$Thanks for the updated details! I see the problem now. Have you reproduced it with 2.0.34 as well (I can try myself later as well)?
About the patch, fetch gd 2.0.34 or from cvs (see http://www.libgd.org/Downloads for the anonymous access). Then using diff:
diff -up gd-2.0.34/gdft.c gd-2.0.33/gdft.c > bug00054.patch
or cvs after you have modified the file: cvs diff -up gdft.c > bug00054.patch
and attach the bug00054.patch to this report. As you can see, your patch reverts some of the bug fixes I introduced in 2.0.34. If you can update it against 2.0.34 or CVS, it will help me to test it as soon as possible.
okay i did the diff command above and attached the result.
I haven't reproduced it in 2.0.34, but in just briefly looking at the code... the same problem is there: the order of transforms is the same as .33
Ok, we fixed a bit the kerning, so the difference may have been reduced.
About the patch, I'm sorry to ask again but you need to apply your modification to 2.0.34 or cvs and then run the diff command. A diff between a modified 2.0.33 and 2.0.34 will revert all changes between 2.0.33 and 2.0.34, it is not really desired :) There is a lot of changes and fixes (rounding problem, cache fixed, etc.) in this file.
Okay I just quickly added my changes to .34
Attached is the unified patch and 2 images.
Sorry, it is still between 2.0.33 and 2.0.34, the patch reverts all changes done for 2.0.34. Please attach your modified _2.0.34_ gdft.c version, easier.
One thing I can already see, you have to put the declaration at the top of the function or right a bracket. For example after if (render) (line 1313 in 2.0.34). Many compilers do not support this kind of declarations.
By the way, the fix will make it in 2.1.0.
I am pretty sure that the diff patch was 2.0.34 last time (there were a couple other white space changes that may have made my modifications look more bulky than they really were), but I have attached the modified 2.0.34 gdft.c file. I moved the 2 new FT_Vector declarations to the top of the function.
Thanks! I attached the patch against current CVS.
Doh, I got confused too... Now it is the real patch, take #2. :)
patch applied in head