SVG::GD - SVG::GD documentation


SVG-GD documentation Contained in the SVG-GD distribution.

Index


Code Index:

Name: SVG::GD

Top

Version 0.20

Top

Author: Ronan Oger

Top

Abstract

Top

Provide (as seamless as possible) an SVG wrapper to the GD API in order to provide SVG output of images generate with the Perl GD module

Synopsis

Top

	use GD;
	use SVG::GD;
	$im = new GD::Image(100,50);

	# allocate black -- this will be our background
	$black = $im->colorAllocate(0, 0, 0);

	# allocate white
	$white = $im->colorAllocate(255, 255, 255);

	# allocate red
	$red = $im->colorAllocate(255, 0, 0);

	# allocate blue
	$blue = $im->colorAllocate(0,0,255);

	#Inscribe an ellipse in the image
	$im->arc(50, 25, 98, 48, 0, 360, $white);

	# Flood-fill the ellipse. Fill color is red, and will replace the
	# black interior of the ellipse
	$im->fill(50, 21, $red);

	binmode STDOUT;

	# print the image to stdout
	print $im->png;

gdTinyFont

returns SVG::GD::Font::Tiny

gdSmallFont

returns SVG::GD::Font::Small();

gdMediumBoldFont

returns SVG::GD::Font::Bold();

gdLargeFont

Returns SVG::GD::Font::Large()

gdGiantFont

Returns SVG::GD::Font::Giant()

gdBrushed

Does nothing at this time

getSVGstyle($font)

retrieve the style in SVG format for predefined fomts

setPixel

set a pixel to a colour Because SVG does not understand pixels, this method has to be faked. We know from the image size what is meant by a pixel, so we create a rectangle of size 1x1 and give it a colour

colorAllocate

Allocate the colour to a variable (red,green,blue)

colorResolve ($red,$green,$blue)

for an rbg tripplet, either returns the index for the colour or generates a new index for that colour

colorsTotal

return the number of allocated colors

colorExact

check for the existance of an exact color

colorClosest

returns the closest colour to the RGB triplet being submitted

line

Draw a line between 2 points

filledRectangle

Draw a filled rectangle.

rectangle

Draw a rectangle.

arc

Draw an arc. Only supports closed arcs at present. Note that we will ultimately need to differenciate between an arc and a circle.

SVG::GD::Image::filledPolygon

Draw a polygon defined by ab SVG::GD::Polygon object

polygon

Draw an empty polygon

string methods

Top

string

write a text string

char

write a character

charUp

write a character upwards

rgb

Return the red,green,blue array for an allocated colour

svg

replace the gif writing request with an svg writing request

png

Return the binary image in PNG format

jpg

Return the binary image in JPEG format

gif

Return the binary image in GIF format Note that some versions of SVG::GD do not support this method


SVG-GD documentation Contained in the SVG-GD distribution.
package SVG::GD;

$VERSION = '0.20';

no  strict 'refs';

use SVG;
use Exporter;
use warnings;


BEGIN {
	#first, let's re-map the GD::Image methods to somewhere else safe.
	#nb we will also have to do this with the GD::Font methods
#	*SVG::HGD::Image::new = \&GD::Image::new;
#	*SVG::HGD::gdSmallFont =\&GD::gdSmallFont;
#	*SVG::HGD::gdLargeFont =\&GD::gdLargeFont;
#	*SVG::HGD::gdMediumBoldFont =\&GD::gdMediumBoldFont;
#	*SVG::HGD::gdTinyFont =\&GD::gdTinyFont;
#	*SVG::HGD::gdGiantFont =\&GD::gdGiantFont;
#	*SVG::HGD::Image::_make_filehandle =\&GD::Image::_make_filehandle;
#	*SVG::HGD::Image::new =\&GD::Image::new;
#	*SVG::HGD::Image::newTrueColor =\&GD::Image::newTrueColor;
#	*SVG::HGD::Image::newPalette =\&GD::Image::newPalette;
#	*SVG::HGD::Image::newFromPng =\&GD::Image::newFromPng;
#	*SVG::HGD::Image::newFromJpeg =\&GD::Image::newFromJpeg;
#	*SVG::HGD::Image::newFromXbm =\&GD::Image::newFromXbm;
#	*SVG::HGD::Image::newFromGd =\&GD::Image::newFromGd;
#	*SVG::HGD::Image::newFromGd2 =\&GD::Image::newFromGd2;
#	*SVG::HGD::Image::newFromGd2Part =\&GD::Image::newFromGd2Part;
#	*SVG::HGD::Image::ellipse =\&GD::Image::ellipse;
#	*SVG::HGD::Image::clone =\&GD::Image::clone;
#	*SVG::HGD::Polygon::new =\&GD::Polygon::new;
#	*SVG::HGD::Polygon::DESTROY =\&GD::Polygon::DESTROY;
#	*SVG::HGD::Polygon::addPt =\&GD::Polygon::addPt;
#	*SVG::HGD::Polygon::getPt =\&GD::Polygon::getPt;
#	*SVG::HGD::Polygon::setPt =\&GD::Polygon::setPt;
#	*SVG::HGD::Polygon::length =\&GD::Polygon::length;
#	*SVG::HGD::Polygon::vertices =\&GD::Polygon::vertices;
#	*SVG::HGD::Polygon::bounds =\&GD::Polygon::bounds;
#	*SVG::HGD::Polygon::deletePt =\&GD::Polygon::deletePt;
#	*SVG::HGD::Polygon::offset =\&GD::Polygon::offset;
#	*SVG::HGD::Polygon::map =\&GD::Polygon::map;
#	*SVG::HGD::Image::polygon =\&GD::Image::polygon;
#	*SVG::HGD::Polygon::toPt =\&GD::Polygon::toPt;
#	*SVG::HGD::Polygon::transform =\&GD::Polygon::transform;
#	*SVG::HGD::Polygon::scale =\&GD::Polygon::scale;

	*GD::Font:: = *SVG::GD::Font::;
	*GD::Image:: = *SVG::GD::Image::;
}	

use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS/;

our $tinyfontsize='5';
our $smallfontsize='7';
our $mediumfontsize='10';
our $largefontsize='12';
our $giantfontsize='16';
our $font = {};
our $fontindex = 0;

@ISA = qw/Exporter/;

@EXPORT = qw/
	gdBrushed
    gdDashSize
	gdMaxColors
	gdStyled
	gdStyledBrushed
	gdTiled
	gdTransparent
	gdSmallFont
	gdMediumBoldFont
	gdLargeFont
	gdGiantFont /;

@EXPORT_OK = qw/
    GD_CMP_IMAGE
	GD_CMP_NUM_COLORS
	GD_CMP_COLOR
	GD_CMP_SIZE_X
	GD_CMP_SIZE_Y
	GD_CMP_TRANSPARENT
	GD_CMP_BACKGROUND
	GD_CMP_INTERLACE
	GD_CMP_TRUECOLOR /;

%EXPORT_TAGS = ('cmp'  => [	qw/
		GD_CMP_IMAGE
		GD_CMP_NUM_COLORS
		GD_CMP_COLOR
		GD_CMP_SIZE_X
		GD_CMP_SIZE_Y
		GD_CMP_TRANSPARENT
		GD_CMP_BACKGROUND
		GD_CMP_INTERLACE
		GD_CMP_TRUECOLOR / ]
);

#font control


sub SVG::GD::gdTinyFont {
	return SVG::GD::Font::Tiny();
}

#font control


sub SVG::GD::gdSmallFont {
	return SVG::GD::Font::Small();
}

#font control
sub SVG::GD::gdMediumBoldFont {
	return SVG::GD::Font::MediumBold();
}

#font control
sub SVG::GD::gdLargeFont {
	return SVG::GD::Font::Large();
}



#font control

sub SVG::GD::gdGiantFont {
	return SVG::GD::Font::Giant();
}

sub SVG::GD::gdBrushed { 
	return '';
}

#
#
# OO font support (encountered in GD::Graph::radar)
#
#

package SVG::GD::Font;

use strict;
use Data::Dumper;
use warnings;

sub registerFont($) {
	my $size = shift;
	$fontindex++;
	$font->{$fontindex}->{fontheight} = $size;
	$font->{$fontindex}->{fontstyle} = {'font-size'=>$size};
	return $fontindex;
}

sub Giant {
    my $class = shift;
    my $size = $giantfontsize;
	SVG::GD::Font::registerFont($size);
}

sub Large {
    my $class = shift;
    my $size = $largefontsize;
	SVG::GD::Font::registerFont($size);
}

sub Medium {
    my $class = shift;
    my $size = $mediumfontsize;
	SVG::GD::Font::registerFont($size);
}

sub MediumBold {
    my $class = shift;
    my $size = $mediumfontsize;
	SVG::GD::Font::registerFont($size);
}

sub Small {
    my $class = shift;
    my $size = $smallfontsize;
	SVG::GD::Font::registerFont($size);
}

sub Tiny {
    my $class = shift;
    my $size = $tinyfontsize;
	SVG::GD::Font::registerFont($size);
}

sub height {
	my $id = shift;
	return 10;
}

sub width {
	my $myfont = shift;
	return 8;
}

sub getSVGstyle {
	my $myfont = shift;
	if (eval{defined $font->{$myfont}->{fontstyle} eq 'HASH'}) {
		return %{$font->{$myfont}->{fontstyle}};
	} else {
		return ();
	}
	
}
#
# SVG::GD::Image
#

package SVG::GD::Image;

use warnings;
use strict;

#constructor
sub SVG::GD::Image::new {
    my $class = shift;
	my $self = {};
	bless $self, $class;
   	#$self->{_GD_} = new SVG::HGD::Image(@_) 
	#		|| print STDERR "Quitting. Unable to construct new SVG::HGD::Image
	#	object using SVG::GD!: $!\n";
	#return undef unless defined $self->{_GD_};

	my ($val_1,$val_2,$val_3) = @_;
	#do we have drawing sizes?
	if ($val_1 =~ /^\d+$/ && $val_2 =~ /^\d+$/) {
		$self->{_ATTRIBUTES_}->{width} = $val_1;
		$self->{_ATTRIBUTES_}->{height} = $val_2;
		$self->{_ATTRIBUTES_}->{-truecolor} = $val_3 
			if defined $val_3;

	}
	#do we have a valid filename?
	elsif (-r $val_1) {
		$self->{_ATTRIBUTES_}->{FILENAME} = $val_1;
	} 
	#do we have a file reference?
	elsif (ref $val_1) {
		$self->{_ATTRIBUTES_}->{FILEHANDLE} = $val_1;
	}
	#then we have raw image data.
	elsif (defined $val_1) {
		$self->{_ATTRIBUTES_}->{IMAGEDATA} = $val_1;
	}
	else {return undef}
	#build the svg drawing
	$self->{_SVG_} = SVG->new(%{$self->{_ATTRIBUTES_}});
	$self->{scratch}->{index_colours} = 0;
	$self->{_COLOUR_}->{named} = {
		white => {svg=>'white',rgb=>'white'}, 
		lgray => {svg=>'gray',rgb=>'lgray'}, 
		gray  => {svg=>'gray',rgb=>'gray'}, 
		dgray => {svg=>'gray',rgb=>'dgray'}, 
		black =>{svg=>'black',rgb=>'black'}, 
		lblue =>{svg=>'lightblue',rgb=>'lblue'}, 
		blue => {svg=>'blue',rgb=>'blue'}, 
		dblue =>, {svg=>'darkblue',rgb=>'dblue'},
		gold => {svg=>'gold',rgb=>'gold'}, 
		lyellow =>{svg=>'yellow',rgb=>'lyellow'}, 
		yellow =>{svg=>'yellow',rgb=>'yellow'},
		dyellow =>{svg=>'gold',rgb=>'gold'}, 
		lgreen =>{svg=>'mintgreen',rgb=>'lgreen'}, 
		green =>{svg=>'green',rgb=>'green'}, 
		dgreen =>{svg=>'darkgreen',rgb=>'dgreen'}, 
		lred =>{svg=>'red',rgb=>'dred'}, 
		red => {svg=>'red',rgb=>'red'}, 
		dred =>{svg=>'red',rgb=>'dred'}, 
		lpurple =>{svg=>'gold',rgb=>'gold'}, 
		purple => {svg=>'purple',rgb=>'purple'}, 
		dpurple =>{svg=>'dpurple ',rgb=>'dpurple'},
		lorange =>{svg=>'lorange ',rgb=>'lorange'}, 
		orange => {svg=>'orange',rgb=>'orange'}, 
		pink => {svg=>'pink',rgb=>'pink'}, 
		dpink =>{svg=>'pink',rgb=>'dpink'}, 
		marine =>{svg=>'navy',rgb=>'marine'}, 
		cyan => {svg=>'cyan',rgb=>'cyan'}, 
		lbrown =>{svg=>'brown',rgb=>'lbrown'}, 
		dbrown => {svg=>'brown',rgb=>'dbrown'},
		};
	return $self;
}


#--------------------
#Wrapper methods

sub SVG::GD::Image::setPixel($$$$) {
	my $self = shift;
	my ($x,$y,$colour) = @_;
	$self->{_SVG_}->rect(x=>$x,y=>$y,
		width=>1,height=>1,
		fill=>$self->getColour($colour));
#	$self->{_GD_}->setPixel($x,$y,$colour);	
}


sub SVG::GD::Image::colorAllocate($$$$) {
	my $self = shift;
	my ($red,$green,$blue) = @_;
#	my $code = $self->{_GD_}->colorAllocate($red,$green,$blue);
	#if we get an rgb triplet, handle as an rgb triplet
	my $code = $self->{index_colour}++;
	
	if (defined $green && defined $blue) {
		#$code = "$red.$green.$blue" if (defined $green && defined $blue);
		$self->{_COLOUR_}->{$code}->{svg} = 
		$self->{_SVG_}->colorAllocate($red,$green,$blue);
		$self->{_COLOUR_}->{$code}->{rgb} = [$red,$green,$blue];
	} 
	#otherwise assume this is a named colour.
	else {
		$code = $red;
		$self->{_COLOUR_}->{$code}->{rgb} = [$code];
		$self->{_COLOUR_}->{$code}->{svg} = [$code];
	}
	return $code;	
}

*SVG::GD::Image::colorResolve = \&SVG::GD::Image::colorAllocate;

sub SVG::GD::Image::colorsTotal ($) {
	my $self = shift;
	return scalar(keys %{$self->{_COLOUR_}});
}

sub SVG::GD::Image::colorExact ($$) {
	my $self = shift;
	my $colour = shift;
	return 1 if $self->{_COLOUR_}->{$colour};
	return -1;
}

sub SVG::GD::Image::colorClosest ($$$$) {
	my $self = shift;
	my ($red,$green,$blue) = @_;
	my $value = {};
	map {
		my $cc = $_; 
		#calculate the least-square distance
		my ($dr,$dg,$db) = (
			$red * $red -
			$self->{_COLOUR_}->{$cc}->[0] * $self->{_COLOUR_}->{$cc}->[0],
			$green * $blue -
			$self->{_COLOUR_}->{$cc}->[1] * $self->{_COLOUR_}->{$cc}->[1],
			$blue * $blue -
			$self->{_COLOUR_}->{$cc}->[2] * $self->{_COLOUR_}->{$cc}->[2],
		);
		
		$value->{$dr+$dg+$db} = $cc;

	}  keys %{$self->{_COLOUR_}};
	#
	my @array = sort {$a<=>$b} keys %$value;
	my $leastval = shift @array;
	my $code = $value->{$leastval};

}

sub SVG::GD::Image::line($$$$$$) {
	my $self = shift;
	my ($x1,$y1,$x2,$y2,$colour) = @_;
#	$self->{_GD_}->line(@_);
	$self->{_SVG_}->line(x1=>$x1,x2=>$x2,y1=>$y1,y2=>$y2,
		stroke=>$self->getColour($colour));
}

sub SVG::GD::Image::dashedLine($$$$$$) {
	my $self = shift;
	my ($x1,$y1,$x2,$y2,$colour) = @_;
#	$self->{_GD_}->dashedLine(@_);
	$self->{_SVG_}->line(x1=>$x1,x2=>$x2,y1=>$y1,y2=>$y2,
		stroke=>$self->getColour($colour));
}

sub SVG::GD::Image::filledRectangle($$$$$$$) {
	my $self = shift;
	my ($x1,$y1,$x2,$y2,$colour) = @_;
#	$self->{_GD_}->filledRectangle(@_);
	$self->{_SVG_}->rect(x=>$x1,y=>$y1,
			width=>$x2-$x1,height=>$y2-$y1,
			fill=>$self->getColour($colour),
			stroke=>$self->getColour($colour));
}

sub SVG::GD::Image::rectangle($$$$$$$) {
	my $self = shift;
	my ($x1,$y1,$x2,$y2,$colour) = @_;
#	$self->{_GD_}->rectangle(@_);
	$self->{_SVG_}->rect(x=>$x1,y=>$y1,
			width=>$x2-$x1,height=>$y2-$y1,fill=>'none',
			stroke=>$self->getColour($colour));
}
sub SVG::GD::Image::arc($$$$$$$$) {
	my $self = shift;
	my ($cx,$cy,$width,$height,$start,$end,$colour) = @_;
	$self->{_SVG_}->ellipse(cx=>$cx,cy=>$cy,
			rx=>$width/2,ry=>$height/2,fill=>'none',
			stroke=>$self->getColour($colour));
#	return $self->{_GD_}->arc(@_);
}

sub SVG::GD::Image::filledPolygon ($$$) {
	my $self = shift;
	my $poly = shift;
	my $fill = shift;
		
	my ($x,$y) = ([],[]);
	foreach my $set (@{$poly->{points}}) {
		my ($myx,$myy) = ($set->[0],$set->[1]);
		push @$x,$myx;
		push @$y,$myy;
	}
	my $points = $self->{_SVG_}->
	get_path(x=>$x, y=>$y,
		-type=>'path',
		-closed=>'true');
	$self->{_SVG_}->path(%$points,fill=>$self->getColour($fill));
}

sub SVG::GD::Image::polygon ($$$) {
	my $self = shift;
	my $poly = shift;
	my $stroke = shift;
		
	my ($x,$y) = ([],[]);
	foreach my $set (@{$poly->{points}}) {
		my ($myx,$myy) = ($set->[0],$set->[1]);
		push @$x,$myx;
		push @$y,$myy;
	}
	my $points = $self->{_SVG_}->
	get_path(x=>$x, y=>$y,
		-type=>'path',
		-closed=>'true');
	$self->{_SVG_}->path(%$points,stroke=>$self->getColour($stroke),fill=>'none');
}


#string methods

sub SVG::GD::Image::string ($$$$$$) {
	my $self = shift;
	my ($myfont,$x,$y,$text,$colour) = @_;
#	$self->{_GD_}->string(@_);
	$self->{_SVG_}->text(
		'baseline-shift'=>'sub',
		style=>{
			SVG::GD::Font::getSVGstyle($myfont),
			fill=>$self->getColour($colour),
		},
		x=>$x,
		y=>$y)->tspan(dy=>'1em') ->cdata($text);
}

*SVG::GD::Image::char = \&SVG::GD::Image::string;

sub SVG::GD::Image::stringUp ($$$$$$) {
    my $self = shift;
	my ($myfont,$x,$y,$text,$colour) = @_;
#	$self->{_GD_}->string(@_);
	$self->{_SVG_}->text(
		style=>{'writing-mode'=>'tb',
				SVG::GD::Font::getSVGstyle($myfont),
				fill=>$self->getColour($colour),
				},
		x=>$x,y=>$y,
		)->cdata($text);
}
*SVG::GD::Image::charUp = \&SVG::GD::Image::stringUp;

#---------------
#internal methods


sub SVG::GD::Image::getRGB($$) {
	my $self = shift;
	my $colour = shift;
	return $self->{_COLOUR_}->{$colour}->{rgb};
}

sub SVG::GD::Image::getColour($$) {
	my $self = shift;
	my $colour = shift;
	return $self->{_COLOUR_}->{$colour}->{svg};
}

sub SVG::GD::Image::rgb ($$) {
	my $self = shift;
	my $col = shift;
	return @{$self->getRBG($col)}; 
}

sub SVG::GD::Image::svg ($) {
	my $self = shift;
	return $self->{_SVG_}->xmlify;
}

sub SVG::GD::Image::png ($) {
	my $self = shift;
	return $self->svg;
#	return $self->{_GD_}->png;
}

sub SVG::GD::Image::wbmp ($$) {
	my $self = shift;
#	return $self->{_GD_}->wbmp(@_);
}	

sub SVG::GD::Image::gif ($) {
	my $self = shift;
	return $self->svg;
} 	
#------------------
#ignored methods that are meaningless
#or too difficult to implement


sub SVG::GD::Image::interlaced ($) {
	my $self = shift;
#	$self->{_GD_}->interlaced(@_);
}

sub SVG::GD::Image::transparent ($$) {
	my $self = shift;
	my $colour = shift;
#	$self->{_GD_}->transparent($colour)
}

sub SVG::GD::Image::fill ($$$$) {
	my $self = shift;
	my ($x,$y,$colour) = @_;
#	$self->{_GD_}->fill(@_);
}

sub SVG::GD::Image::fillToBorder ($$$$) {
	my $self = shift;
	my ($x,$y,$colour) = @_;
#	$self->{_GD_}->fillToBorder(@_);	
}

############################################################################
#
# new methods on GD::Image
#
############################################################################

sub SVG::GD::Image::polyline ($$$) {
    my $self = shift;   # the GD::Image
    my $p    = shift;   # the GD::Polyline (or GD::Polygon)
	my $c    = shift;   # the color

	my @points = $p->vertices();
	my $p1 = shift @points;
	my $p2;
	while ($p2 = shift @points) {
		$self->line(@$p1, @$p2, $c);
		$p1 = $p2;
	}
}

sub GD::Image::polydraw ($$$) {
	my $self = shift;   # the GD::Image
	my $p    = shift;   # the GD::Polyline or GD::Polygon
	my $c    = shift;
	# the color return
	$self->polyline($p, $c) if $p->isa('GD::Polyline');
	return $self->polygon($p, $c);
}
																	
sub setBrush ($$) {
	my $self = shift;
	my $brush = shift;
	return "Sorry..Ignoring this command. Unable to setBrush with this version
		of SVG::GD";
}