font metrics and character spacing trouble

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
mr fuzzy

font metrics and character spacing trouble

Post by mr fuzzy »

This is a very esoteric question about character spacing.

I am trying to write a word (a number actually) character by character. I need to do this because I want each character to be colored differently. I am using perlMagick on Ubuntu linux.

I have tried several different methods to get the spacing right. So far the best I have managed is to write the text from right to left, using QueryFontMetrics to determine the right corner of each character.

The result is pretty good, there is a small fixed offset which I don't mind but the spacing between the first and second character (from the left) is always off (too large) by a significant fraction of the character size.

Any help on how to get the correct spacing will be apreciated. Pointers on how to space the characters manually or advice on how to use QueryFontMetrics better.

I have skimmed http://www.microsoft.com/typography/otspec/TTCH01.htm but didn't notice anything on spacing characters in a word.

A code snipit of what I've been trying, it writes outlined red text character by character and the same string all at once in green for comparison:

Code: Select all

use Image::Magick;
use POSIX;

$image        = Image::Magick->new;
$image->Set( size => "200x100" );
$image->read("xc:white");

#Set the center of the string
$x = 100;

$text = "121212";
#get a list of characters
@text = split //, $text;

  ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) =
    $image->QueryFontMetrics(
    pointsize   => 60,
    text        => $text,
    StrokeWidth => 2,
    Stroke      => black
  );

  $line_left    = int( $x - $width / 2 );
  $offset       = 0;
  $offset_text = $text;

  #Draw comparison text below.
  #This text gets the correct spacing.
  $image->Annotate(
    font      => "Helvetica",
    fill        => green,
    pointsize   => 60,
    text        => $text,
    StrokeWidth => 2,
    Stroke      => black,
    align       => left,
    x           => $line_left,
    y           => 95,
  );
  

  #Draw the colored text separately
  #for testing opurposes it's all red
  #Start from the right
  for($i = @text -1; $i >=0; $i--) {
    $char = $text[$i];

    #Get the width.
    #the distance from the start of the line to the right corner of this char
    ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) =
      $image->QueryFontMetrics(
      font        => Helvetica,
      pointsize   => 60,
      text        => $offset_text,
      StrokeWidth => 2,
      );
    $offset = ceil( $width );
    
    $x = $line_left + $offset;

    #Draw the text would usually be different colors for each character
    $image->Annotate(
      font        => Helvetica,
#      fill        => get_color($char),
      fill        => red,
      pointsize   => 60,
      text        => $char,
      StrokeWidth => 2,
      Stroke      => black,
      align       => right,
      x           => $x,
      y           => 50,
    );

    #Strip off the character we just wrote and return for the next
    $offset_text =~ s/.$//;
  }
$image->Write( filename => "numbers.gif", compression => 'None' );
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: font metrics and character spacing trouble

Post by anthony »

Each charact has not only a 'bounding box' or defined drawing space (whcih the actual character drawing could overflow), but it also has a offset for the movement of the 'caret'.

The caret is the 0,0 point to position the character. when drawing a word, you
draw the character then move the caret by the provided offset. At that point you can also optionally add extra justification spacing (to fill a line completely do left and right edges line up).

that is basically it. Nothign fancy. All the fancyness is in ensuring justification spacing bewtten charcaters, between words, and between sentances (larger spacings used in that order) so as to fill lines. Also prehaps to check that the
character drawing bounds do not overflow the end of the line, or page or even the drawn character itself. There are a lot of brain dead font designers out there!

NOTE line spacing is solely defined by the point size, and not by bounding boxes or even the actual drawn height of the character. The Accender/Decender is used to position the base line within the pointsize spaced spacing. Again many fonts are brain dead in this regard.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply