From: Arnar Mar Hrafnkelsson Date: Sun, 30 Mar 2003 12:03:37 +0000 (+0000) Subject: Added preliminary support for adding image based fonts. X-Git-Tag: Imager-0.48^2~336 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/b4d8a00b33936e084fa4f7f53bde51488e24e221 Added preliminary support for adding image based fonts. --- diff --git a/feat.h b/feat.h index 5878514b..bfcb4c00 100644 --- a/feat.h +++ b/feat.h @@ -30,5 +30,6 @@ static char *i_format_list[]={ "bmp", "tga", "rgb", + "ifs", NULL}; diff --git a/lib/Imager/Font.pm b/lib/Imager/Font.pm index 870d6cfb..b21ae81f 100644 --- a/lib/Imager/Font.pm +++ b/lib/Imager/Font.pm @@ -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); } diff --git a/lib/Imager/Font/FreeType2.pm b/lib/Imager/Font/FreeType2.pm index bcf108dd..9b1bbb47 100644 --- a/lib/Imager/Font/FreeType2.pm +++ b/lib/Imager/Font/FreeType2.pm @@ -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 index 00000000..19f3920f --- /dev/null +++ b/lib/Imager/Font/Image.pm @@ -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() { + 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]; + } +}