The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Imager::Font::Image;
use strict;
use Imager::Color;
use File::Basename;
use File::Spec;

use vars qw(@ISA %REQUIRED_FIELDS);
@ISA = qw(Imager::Font);

sub NWIDTH   () { 0 }
sub PWIDTH   () { 2 }
sub GDESCENT () { 1 }
sub GASCENT  () { 3 }
sub DESCENT  () { 4 }
sub ASCENT   () { 5 }


%REQUIRED_FIELDS = (
	Image_spec     => 1,
	Font_size      => 1,
	Global_ascent  => 1,
	Global_descent => 1,);

# Required fields
# Fontmetrics:
# Font global data:
#   image name
#   font size
#   max glyph height
#   max glyph width
#
# The per character data is:
#   left edge   (inclusive)
#   right edge  (exclusive)
#   top edge    (inclusive)
#   bottom edge (exclusive)
#   left adjustment
#   forward shift
#   baseline adjustment (from top)
#
# The left adjustment is the starting
# offset into the glyph, the forward shift
# is the actual forward movement of the
# imaginary cursor.

# To calculate the size of a string use:
#  sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last

# example font spec file:

# IAGRFONT
# # This is an imager font definition file.  This is a comment
# Image_spec = foo.png
# Font_size  = 12
# Global_ascent = 10
# Global_descent = -2
# # Per character data
# FM_65 = 20 40 30 50 3 15
# # Code for 'A' left edge = 20, right = 40, top = 30, bottom 50, leading = 3, forward = 15.
# The left adjustment is the starting
# offset into the glyph, the forward shift
# is the actual forward movement of the
# imaginary cursor.

# To calculate the size of a string use:
#  sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last



sub parse_fontspec_file {
  my ($self, $file) = @_;
  local *FH;
  return unless open(FH, "<$file");

  my %req = %REQUIRED_FIELDS;

  while(<FH>) {
    next if m/^\#/;
    if (m/^\s*?(\S+?)\s*=\s*(.+?)\s*$/) {
      # Check for a required field:
      my $char = $1;
      my $metric = $2;
      if ($req{$char}) {
	$self->{$char} = $metric;
	delete $req{$1};
      } else {
	next unless $char =~ s/^FM_(\d+)$/$1/;
	next unless $metric =~ m/(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/;
	$self->{fm}->{$char} = [$1, $2, $3, $4, $5, $6];
      }
    }
  }
  close(FH);
  return $self;
}



sub new {
  my $self = bless {}, shift;
  my %opts = (color=>Imager::Color->new(255, 0, 0, 0), @_);

  unless ($opts{file}) {
    $Imager::ERRSTR = "No font file specified";
    return;
  }
  unless ($self->parse_fontspec_file($opts{file})) {
    $Imager::ERRSTR = "Font file $opts{file} not found or bad";
    return;
  }

  my $img = Imager->new();
  my $img_filename = File::Spec->catfile( dirname($opts{'file'}),
					  $self->{Image_spec} );

  unless ($img->open(%opts, file=>$img_filename)) {
    $Imager::ERRSTR = "Font IMAGE file $img_filename not found or bad: ".
      $img->errstr();
    return;
  }

  $self->{image} = $img;
  $self->{size} = $self->{Font_size};
  return $self;
}

sub get_glyph_data {
  my ($self, $glyph_code) = @_;
  return unless exists $self->{fm}->{$glyph_code};
  return @{$self->{fm}->{$glyph_code}};
}

# copy_glyph
#
# $x, $y is left, baseline for glyphs.
#

sub copy_glyph {
  my ($self, $glyph_code, $target_img, $x, $y) = @_;

  my @gdata = $self->get_glyph_data($glyph_code) or return;

  $target_img->rubthrough(src=>$self->{image},
			  tx => $x + $gdata[4],
			  ty => $y -  $self->{Global_ascent},,
			  src_minx => $gdata[0],
			  src_maxx => $gdata[1],
			  src_miny => $gdata[2],
			  src_maxy => $gdata[3]);
}

sub _draw {
  my ($self, %opts) = @_;

  my $x = $opts{'x'};
  my $y = $opts{'y'};

  my @glyphs = unpack("C*", $opts{string});
  my $img = $opts{image};

  my $glyph;
  for $glyph (@glyphs) {
    my @gmetrics = $self->get_glyph_data($glyph) or next;
    $self->copy_glyph($glyph, $img, $x, $y);
    $x += $gmetrics[5];
  }
}