]> git.imager.perl.org - imager.git/commitdiff
- the Win32 font driver bounding_box() method now puts accuarate values
authorTony Cook <tony@develop=help.com>
Mon, 2 May 2005 14:37:48 +0000 (14:37 +0000)
committerTony Cook <tony@develop=help.com>
Mon, 2 May 2005 14:37:48 +0000 (14:37 +0000)
  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.

Changes
Imager.xs
lib/Imager/Font.pm
t/t30t1font.t
t/t35ttfont.t
t/t37w32font.t
t/t38ft2font.t
win32.c

diff --git a/Changes b/Changes
index 7ce98d5cf7c5ba453f3aaf54c5b4d1f48bbc3fe1..a2383187904f8c6ea8bc6344f7893fe6772afe2e 100644 (file)
--- 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.
 
 =================================================================
 
index 8e8d87399075f949bfbcfeaf215ae1bcd6ebdc8c..b1597a7f83248ff9759d8797b68c53dfc97f8765 100644 (file)
--- 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);
index dfc2bbc370598893f049589b5f8262042d1de7ab..c806a25cfc983b2e9e3a75edccb6de2c40539023 100644 (file)
@@ -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
 
index 2a9788464ba41824be31e02760f8d153c743e3dd..385128bc74d600018b0f0c6410fc5d03e71eb369 100644 (file)
@@ -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");
index 9c06d54633d93cae894d1c8783712931631504ce..fba92435091e989a6fb16192ccb6286227d4c426 100644 (file)
@@ -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");
index 49fb264788732505b9b193680cf7d13a62cd0bf7..bbbafaff4e5622e5900baa0288b236e5a2841f55 100644 (file)
@@ -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");
+  }
+
 }
index 7c5580f2acf2d1e5d9daf7f3c7aa49b3162a0825..062303a5436a2d97baa773192b477aaedfd8ff96 100644 (file)
@@ -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 61a4e6511c1251a117efb29caaf03c01a33bbc9f..1a3ed5cd859dfac342b8aba10d25e1cb0cb799f9 100644 (file)
--- 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;