Added preliminary support for adding image based fonts.
authorArnar Mar Hrafnkelsson <addi@cpan.org>
Sun, 30 Mar 2003 12:03:37 +0000 (12:03 +0000)
committerArnar Mar Hrafnkelsson <addi@cpan.org>
Sun, 30 Mar 2003 12:03:37 +0000 (12:03 +0000)
feat.h
lib/Imager/Font.pm
lib/Imager/Font/FreeType2.pm
lib/Imager/Font/Image.pm [new file with mode: 0644]

diff --git a/feat.h b/feat.h
index 5878514..bfcb4c0 100644 (file)
--- a/feat.h
+++ b/feat.h
@@ -30,5 +30,6 @@ static char *i_format_list[]={
   "bmp",
   "tga",
   "rgb",
+  "ifs",
   NULL};
 
index 870d6cf..b21ae81 100644 (file)
@@ -25,6 +25,11 @@ my %drivers =
          module=>'Imager/Font/FreeType2.pm',
          files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt)$',
         },
+   ifs=>{
+         class=>'Imager::Font::Image',
+         module=>'Imager/Font/Image.pm',
+         files=>'.*\.ifs$',
+        },
    w32=>{
          class=>'Imager::Font::Win32',
          module=>'Imager/Font/Win32.pm',
@@ -32,7 +37,7 @@ my %drivers =
   );
 
 # this currently should only contain file based types, don't add w32
-my @priority = qw(t1 tt ft2);
+my @priority = qw(t1 tt ft2 ifs);
 
 # when Imager::Font is loaded, Imager.xs has not been bootstrapped yet
 # this function is called from Imager.pm to finish initialization
@@ -49,25 +54,25 @@ sub __init {
 
 sub new {
   my $class = shift;
-  my $self ={};
-  my ($file,$type,$id);
-  my %hsh=(color=>Imager::Color->new(255,0,0,0),
-          size=>15,
+  my $self = {};
+  my ($file, $type, $id);
+  my %hsh=(color => Imager::Color->new(255,0,0,0),
+          size => 15,
           @_);
 
   bless $self,$class;
 
-  if ($hsh{'file'}) { 
-    $file=$hsh{'file'};
+  if ($hsh{'file'}) {
+    $file = $hsh{'file'};
     if ( $file !~ m/^\// ) {
-      $file='./'.$file;
+      $file = './'.$file;
       if (! -e $file) {
-       $Imager::ERRSTR="Font $file not found";
+       $Imager::ERRSTR = "Font $file not found";
        return();
       }
     }
 
-    $type=$hsh{'type'};
+    $type = $hsh{'type'};
     if (!defined($type) or !$drivers{$type}) {
       for my $drv (@priority) {
         undef $type;
@@ -79,7 +84,7 @@ sub new {
       }
     }
     if (!defined($type)) {
-      $Imager::ERRSTR="Font type not found";
+      $Imager::ERRSTR = "Font type not found";
       return;
     }
   } elsif ($hsh{face}) {
@@ -89,8 +94,8 @@ sub new {
     return;
   }
 
-  if (!$Imager::formats{$type}) { 
-    $Imager::ERRSTR="`$type' not enabled";
+  if (!$Imager::formats{$type}) {
+    $Imager::ERRSTR = "`$type' not enabled";
     return;
   }
 
@@ -148,7 +153,7 @@ sub align {
     Imager->_set_error("Missing required parameter 'string'");
     return;
   }
-  
+
   # image needs to be supplied, but can be supplied as undef
   unless (exists $input{image}) {
     Imager->_set_error("Missing required parameter 'image'");
@@ -156,19 +161,19 @@ sub align {
   }
   my $size = _first($input{size}, $self->{size});
   my $utf8 = _first($input{utf8}, 0);
-  
+
   my $bbox = $self->bounding_box(string=>$text, size=>$size, utf8=>$utf8);
   my $valign = $input{valign};
   $valign = 'baseline'
     unless $valign && $valign =~ /^(?:top|center|bottom|baseline)$/;
-  
+
   my $halign = $input{halign};
   $halign = 'start' 
     unless $halign && $halign =~ /^(?:left|start|center|end|right)$/;
 
   my $x = $input{'x'};
   my $y = $input{'y'};
-  
+
   if ($valign eq 'top') {
     $y += $bbox->ascent;
   }
@@ -273,7 +278,7 @@ sub transform {
     $Imager::ERRSTR = "You need to supply a matrix";
     return;
   }
-  
+
   return $self->_transform(%hsh);
 }
 
index bcf108d..9b1bbb4 100644 (file)
@@ -50,8 +50,8 @@ sub _draw {
              $input{string}, , $input{align}, $input{aa}, $input{vlayout},
              $input{utf8});
   } else {
-    i_ft2_text($self->{id}, $input{image}{IMG}, 
-               $input{'x'}, $input{'y'}, 
+    i_ft2_text($self->{id}, $input{image}{IMG},
+               $input{'x'}, $input{'y'},
                $input{color}, $input{size}, $input{sizew} || 0,
                $input{string}, $input{align}, $input{aa}, $input{vlayout},
                $input{utf8});
diff --git a/lib/Imager/Font/Image.pm b/lib/Imager/Font/Image.pm
new file mode 100644 (file)
index 0000000..19f3920
--- /dev/null
@@ -0,0 +1,167 @@
+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];
+  }
+}