From: Tony Cook Date: Mon, 2 May 2005 14:37:48 +0000 (+0000) Subject: - the Win32 font driver bounding_box() method now puts accuarate values X-Git-Tag: Imager-0.48^2~162 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/a6d9b73704e6b26e5888b966aa53a46a865b82b8?ds=sidebyside - the Win32 font driver bounding_box() method now puts accuarate values in the ascent and descent values, previous that were set to the font ascent/descent rather than the values specific to the string. - supplying align=>0 to the win32 font driver string() function now aligns in the same way as the other drivers. --- diff --git a/Changes b/Changes index 7ce98d5c..a2383187 100644 --- a/Changes +++ b/Changes @@ -1079,6 +1079,11 @@ Revision history for Perl extension Imager. - the FT1.x driver now supports the align parameter correctly. Tests were added to each driver to check correct handling of the align parameter. +- the Win32 font driver bounding_box() method now puts accuarate values + in the ascent and descent values, previous that were set to the + font ascent/descent rather than the values specific to the string. +- supplying align=>0 to the win32 font driver string() function + now aligns in the same way as the other drivers. ================================================================= diff --git a/Imager.xs b/Imager.xs index 8e8d8739..b1597a7f 100644 --- a/Imager.xs +++ b/Imager.xs @@ -3970,7 +3970,6 @@ i_tags_get_string(im, what_sv) char const *name = NULL; int code; char buffer[200]; - int result; PPCODE: if (SvIOK(what_sv)) { code = SvIV(what_sv); diff --git a/lib/Imager/Font.pm b/lib/Imager/Font.pm index dfc2bbc3..c806a25c 100644 --- a/lib/Imager/Font.pm +++ b/lib/Imager/Font.pm @@ -535,7 +535,12 @@ The start point for rendering the text. See the align parameter. =item align If non-zero the point supplied in (x,y) will be on the base-line, if -zero then (x,y) will be at the top-left of the first character. +zero then (x,y) will be at the top-left of the string. + +ie. if drawing the string "yA" and align is 0 the point (x,y) will +aligned with the top of the A. If align is 1 (the default) it will be +aligned with the baseline of the font, typically bottom of the A, +depending on the font used. =item channel diff --git a/t/t30t1font.t b/t/t30t1font.t index 2a978846..385128bc 100644 --- a/t/t30t1font.t +++ b/t/t30t1font.t @@ -243,8 +243,8 @@ SKIP: $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], - [ x=>75, text=>"A", cp=>1 ], - [ x=>110, text=>"y", cp=>1 ]) { + [ x=>75, text=>"A", channel=>1 ], + [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); diff --git a/t/t35ttfont.t b/t/t35ttfont.t index 9c06d546..fba92435 100644 --- a/t/t35ttfont.t +++ b/t/t35ttfont.t @@ -211,8 +211,8 @@ SKIP: $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], - [ x=>75, text=>"A", cp=>1 ], - [ x=>110, text=>"y", cp=>1 ]) { + [ x=>75, text=>"A", channel=>1 ], + [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); diff --git a/t/t37w32font.t b/t/t37w32font.t index 49fb2647..bbbafaff 100644 --- a/t/t37w32font.t +++ b/t/t37w32font.t @@ -1,7 +1,7 @@ #!perl -w use strict; use lib 't'; -use Test::More tests => 18; +use Test::More tests => 32; BEGIN { use_ok(Imager => ':all') } ++$|; @@ -9,7 +9,7 @@ init_log("testout/t37w32font.log",1); SKIP: { - i_has_format('w32') or skip("no MS Windows", 17); + i_has_format('w32') or skip("no MS Windows", 31); print "# has w32\n"; my $fontname=$ENV{'TTFONTTEST'} || 'Times New Roman Bold'; @@ -104,4 +104,30 @@ SKIP: "display smaller than advance"); } + SKIP: + { print "# alignment tests\n"; + my $font = Imager::Font->new(face=>"Arial"); + ok($font, "loaded Arial OO") + or skip("could not load font:".Imager->errstr, 4); + my $im = Imager->new(xsize=>140, ysize=>150); + my %common = + ( + font=>$font, + size=>40, + aa=>1, + ); + $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue'); + $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue'); + $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); + for my $args ([ x=>5, text=>"A", color=>"white" ], + [ x=>40, text=>"y", color=>"white" ], + [ x=>75, text=>"A", channel=>1 ], + [ x=>110, text=>"y", channel=>1 ]) { + ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); + ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); + ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); + } + ok($im->write(file=>'testout/t37align.ppm'), "save align image"); + } + } diff --git a/t/t38ft2font.t b/t/t38ft2font.t index 7c5580f2..062303a5 100644 --- a/t/t38ft2font.t +++ b/t/t38ft2font.t @@ -390,8 +390,8 @@ SKIP: $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue'); for my $args ([ x=>5, text=>"A", color=>"white" ], [ x=>40, text=>"y", color=>"white" ], - [ x=>75, text=>"A", cp=>1 ], - [ x=>110, text=>"y", cp=>1 ]) { + [ x=>75, text=>"A", channel=>1 ], + [ x=>110, text=>"y", channel=>1 ]) { ok($im->string(%common, @$args, 'y'=>40), "A no alignment"); ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1"); ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0"); diff --git a/win32.c b/win32.c index 61a4e651..1a3ed5cd 100644 --- a/win32.c +++ b/win32.c @@ -51,6 +51,7 @@ int i_wf_bbox(char *face, int size, char *text, int length, int *bbox) { GLYPHMETRICS gm; int i; MAT2 mat; + int ascent, descent, max_ascent = -size, min_descent = size; mm_log((1, "i_wf_bbox(face %s, size %d, text %p, length %d, bbox %p)\n", face, size, text, length, bbox)); @@ -68,6 +69,28 @@ int i_wf_bbox(char *face, int size, char *text, int length, int *bbox) { } } + for (i = 0; i < length; ++i) { + unsigned char c = text[i]; + unsigned char cp = c > '~' ? '.' : c < ' ' ? '.' : c; + + memset(&mat, 0, sizeof(mat)); + mat.eM11.value = 1; + mat.eM22.value = 1; + if (GetGlyphOutline(dc, c, GGO_METRICS, &gm, 0, NULL, &mat) != GDI_ERROR) { + mm_log((2, " glyph '%c' (%02x): bbx (%u,%u) org (%d,%d) inc(%d,%d)\n", + cp, c, gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, + gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY)); + + ascent = gm.gmptGlyphOrigin.y; + descent = ascent - gm.gmBlackBoxY; + if (ascent > max_ascent) max_ascent = ascent; + if (descent < min_descent) min_descent = descent; + } + else { + mm_log((1, " glyph '%c' (%02x): error %d\n", cp, c, GetLastError())); + } + } + if (!GetTextExtentPoint32(dc, text, length, &sz) || !GetTextMetrics(dc, &tm)) { SelectObject(dc, oldFont); @@ -75,21 +98,19 @@ int i_wf_bbox(char *face, int size, char *text, int length, int *bbox) { DeleteObject(font); return 0; } - /* if there's a way to get a characters ascent/descent reliably, I can't - see it. GetGlyphOutline() seems to return the same size for - all characters. - */ - bbox[BBOX_GLOBAL_DESCENT] = bbox[BBOX_DESCENT] = tm.tmDescent; + bbox[BBOX_GLOBAL_DESCENT] = tm.tmDescent; + bbox[BBOX_DESCENT] = min_descent == size ? tm.tmDescent : min_descent; bbox[BBOX_POS_WIDTH] = sz.cx; bbox[BBOX_ADVANCE_WIDTH] = sz.cx; - bbox[BBOX_GLOBAL_ASCENT] = bbox[BBOX_ASCENT] = tm.tmAscent; + bbox[BBOX_GLOBAL_ASCENT] = tm.tmAscent; + bbox[BBOX_ASCENT] = max_ascent == -size ? tm.tmAscent : max_ascent; if (length && GetCharABCWidths(dc, text[0], text[0], &first) && GetCharABCWidths(dc, text[length-1], text[length-1], &last)) { mm_log((1, "first: %d A: %d B: %d C: %d\n", text[0], first.abcA, first.abcB, first.abcC)); - mm_log((1, "first: %d A: %d B: %d C: %d\n", text[length-1], + mm_log((1, "last: %d A: %d B: %d C: %d\n", text[length-1], last.abcA, last.abcB, last.abcC)); bbox[BBOX_NEG_WIDTH] = first.abcA; bbox[BBOX_RIGHT_BEARING] = last.abcC; @@ -137,8 +158,15 @@ i_wf_text(char *face, i_img *im, int tx, int ty, i_color *cl, int size, line_width = sz.cx * 3; line_width = (line_width + 3) / 4 * 4; top = ty; - if (align) + if (align) { top -= tm.tmAscent; + } + else { + int bbox[BOUNDING_BOX_COUNT]; + + i_wf_bbox(face, size, text, len, bbox); + top -= tm.tmAscent - bbox[BBOX_ASCENT]; + } for (y = 0; y < sz.cy; ++y) { for (x = 0; x < sz.cx; ++x) { @@ -147,7 +175,7 @@ i_wf_text(char *face, i_img *im, int tx, int ty, i_color *cl, int size, i_gpix(im, tx+x, top+sz.cy-y-1, &pel); for (ch = 0; ch < im->channels; ++ch) { pel.channel[ch] = - ((255-scale) * pel.channel[ch] + scale*cl->channel[ch]) / 255.0; + ((255-scale) * pel.channel[ch] + scale*cl->channel[ch]) / 255; } i_ppix(im, tx+x, top+sz.cy-y-1, &pel); } @@ -174,7 +202,6 @@ i_wf_cp(char *face, i_img *im, int tx, int ty, int channel, int size, SIZE sz; int line_width; int x, y; - int ch; TEXTMETRIC tm; int top; @@ -185,8 +212,15 @@ i_wf_cp(char *face, i_img *im, int tx, int ty, int channel, int size, line_width = sz.cx * 3; line_width = (line_width + 3) / 4 * 4; top = ty; - if (align) + if (align) { top -= tm.tmAscent; + } + else { + int bbox[BOUNDING_BOX_COUNT]; + + i_wf_bbox(face, size, text, len, bbox); + top -= tm.tmAscent - bbox[BBOX_ASCENT]; + } for (y = 0; y < sz.cy; ++y) { for (x = 0; x < sz.cx; ++x) { @@ -298,7 +332,7 @@ static LPVOID render_text(char *face, int size, char *text, int length, int aa, bmih->biBitCount = 24; bmih->biCompression = BI_RGB; bmih->biSizeImage = 0; - bmih->biXPelsPerMeter = 72 / 2.54 * 100; + bmih->biXPelsPerMeter = (LONG)(72 / 2.54 * 100); bmih->biYPelsPerMeter = bmih->biXPelsPerMeter; bmih->biClrUsed = 0; bmih->biClrImportant = 0;