Skip to content

Commit

Permalink
- the Win32 font driver bounding_box() method now puts accuarate values
Browse files Browse the repository at this point in the history
  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.
  • Loading branch information
Tony Cook committed May 2, 2005
1 parent 9ab6338 commit a6d9b73
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 22 deletions.
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -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.

=================================================================

Expand Down
1 change: 0 additions & 1 deletion Imager.xs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion lib/Imager/Font.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions t/t30t1font.t
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
4 changes: 2 additions & 2 deletions t/t35ttfont.t
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
30 changes: 28 additions & 2 deletions t/t37w32font.t
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#!perl -w
use strict;
use lib 't';
use Test::More tests => 18;
use Test::More tests => 32;
BEGIN { use_ok(Imager => ':all') }
++$|;

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';
Expand Down Expand Up @@ -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");
}

}
4 changes: 2 additions & 2 deletions t/t38ft2font.t
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
58 changes: 46 additions & 12 deletions win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -68,28 +69,48 @@ 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);
ReleaseDC(NULL, dc);
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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand All @@ -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;

Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit a6d9b73

Please sign in to comment.