- 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.
=================================================================
char const *name = NULL;
int code;
char buffer[200];
- int result;
PPCODE:
if (SvIOK(what_sv)) {
code = SvIV(what_sv);
=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
$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");
$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");
#!perl -w
use strict;
use lib 't';
-use Test::More tests => 18;
+use Test::More tests => 32;
BEGIN { use_ok(Imager => ':all') }
++$|;
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';
"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");
+ }
+
}
$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");
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));
}
}
+ 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);
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;
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) {
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);
}
SIZE sz;
int line_width;
int x, y;
- int ch;
TEXTMETRIC tm;
int top;
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) {
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;