Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Tk::Canvas to PDF module offer

20 views
Skip to first unread message

John

unread,
Nov 30, 2004, 2:31:10 AM11/30/04
to
Hello

How did you hack the module?

Does it work for you? With any encoding even with iso-8859-7 ?

Could you tell us more, because that is so intresting.

----- Original Message -----
From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
To: <p...@lists.Stanford.EDU>
Sent: Monday, November 29, 2004 8:06 PM
Subject: Tk::Canvas to PDF module offer

-++**==--++**==--++**==--++**==--++**==--++**==--++**==
This message was posted through the Stanford campus mailing list
server. If you wish to unsubscribe from this mailing list, send the
message body of "unsubscribe ptk" to majo...@lists.stanford.edu

Petr Pajas

unread,
Nov 30, 2004, 7:16:43 AM11/30/04
to
--nextPart19330464.Q7E6sxZdDT
Content-Type: multipart/mixed;
boundary="Boundary-01=_sSGrBn0Lgux9rmj"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

--Boundary-01=_sSGrBn0Lgux9rmj
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Dne =FAt 30. listopadu 2004 08:31 John napsal(a):


> Hello
>
> How did you hack the module?

Simply:-) It uses PDF::API2 module to create the actual PDF content.=20
It creates a new PDF object and a PDF page, then it examinines=20
every object on a given canvas one by one and translates it to a=20
corresponding PDF-object. It's really only a matter of itemCget,
some conversions on the object parameters and some PDF::API2 calls.

The only harder thing to implement were the arrows (if a multi-line=20
is smooth, you have to position the arrow head correctly) and=20
shapes.

> Does it work for you? With any encoding even with iso-8859-7 ?

Yes, of course, it works for me fine (Linux/Windows/MacOSX-X11) :-)=20
(I use it as one of Print outputs in a tree-editor called TrEd -=20
used mostly for linguistic annotation, see=20
a shot: http://ckl.mff.cuni.cz/pajas/tred_doc/pics/treddiff.png
or homepage: http://ckl.mff.cuni.cz/pajas/tred/),

Yes, I hope it should handle iso-8859-7 too (at least, it worked=20
with iso-8859-2 and iso-8859-6). If using "8bit" Tk (<800) only=20
have to specify the encoding to the PDF conversion routine. If you=20
use unicode/utf8 Tk>804, it should work out of the box.=20

> Could you tell us more, because that is so intresting.

It's attached. It's called Tk::Canvas::PDF and uses the same=20
namespace. It can be used in various ways, but as the simplest=20
approach it adds a new $canvas->pdf method (very similar to=20
$canvas->postscript) to the Tk::Canvas namespace.=20

It depends on the attached Tk::rgb.pm (it's just color-names to rgb=20
map) and the standard Encode module (perl>=3D5.7), but the later=20
dependency should be relatively easily to remove.

I think it gives best result with TrueType fonts, but PS fonts and=20
PDF-core fonts are supported as well.

It only lacks documentation, except for a short (probably outdated)=20
synopsis-like POD.

As I told earlier, I don't have time to put it all in shape, at=20
least not right now. So if anyone was interested in taking it,=20
probably going through the code, writing some POD and preparing it=20
for a release, I'd be glad. If not, you can use it as it is. Maybe=20
in the up-comming weeks I'll be able to find some to do that=20
myself...

=2D- Petr

> ----- Original Message -----
> From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
> To: <p...@lists.Stanford.EDU>
> Sent: Monday, November 29, 2004 8:06 PM
> Subject: Tk::Canvas to PDF module offer
>
>
>

> -++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--=
++**=3D=3D


> This message was posted through the Stanford campus mailing list
> server. If you wish to unsubscribe from this mailing list, send
> the message body of "unsubscribe ptk" to
> majo...@lists.stanford.edu

--Boundary-01=_sSGrBn0Lgux9rmj
Content-Type: application/x-perl-module;
name="PDF.pm"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="PDF.pm"

#$Id: PDF.pm,v 1.5 2003/12/12 12:01:10 pajas Exp $
# Tk::Canvas to PDF convertor.
# Copyright (c) 2003 by Petr Pajas
#
# This library is free software; you can use, modify, and
# redistribute it under the terms of GPL - The General Public
# Licence. Full text of the GPL can be found at
# http://www.gnu.org/copyleft/gpl.html
#

package Tk::Canvas::PDF;

BEGIN {
use Exporter;
use Tk::rgb;
use strict;
use base qw(Tk::Canvas Exporter);
use vars qw(%media %join %capstyle @EXPORT_OK);
@EXPORT_OK=(qw(%media));

eval "use Encode";

%join = (
bevel => 2,
miter => 0,
round => 1
);
%capstyle = (
butt => 0,
round => 1,
projecting => 2
);
%media = (
Letter => [612, 792],
LetterSmall => [612, 792],
Legal => [612, 1008],
Statement => [396, 612],
Tabloid => [792, 1224],
Ledger => [1224, 792],
Folio => [612, 936],
Quarto => [610, 780],
'7x9' => [504, 648],
'9x11' => [648, 792],
'9x12' => [648, 864],
'10x13' => [720, 936],
'10x14' => [720, 1008],
Executive => [540, 720],
A0 => [2384, 3370],
A1 => [1684, 2384],
A2 => [1191, 1684],
A3 => [842, 1191],
A4 => [595, 842],
A4Small => [595, 842],
A5 => [420, 595],
A6 => [297, 420],
A7 => [210, 297],
A8 => [148, 210],
A9 => [105, 148],
A10 => [73, 105],
B0 => [2920, 4127],
B1 => [2064, 2920],
B2 => [1460, 2064],
B3 => [1032, 1460],
B4 => [729, 1032],
B5 => [516, 729],
B6 => [363, 516],
B7 => [258, 363],
B8 => [181, 258],
B9 => [127, 181],
B10 => [91, 127],
ISOB0 => [2835, 4008],
ISOB1 => [2004, 2835],
ISOB2 => [1417, 2004],
ISOB3 => [1001, 1417],
ISOB4 => [709, 1001],
ISOB5 => [499, 709],
ISOB6 => [354, 499],
ISOB7 => [249, 354],
ISOB8 => [176, 249],
ISOB9 => [125, 176],
ISOB10 => [88, 125],
C0 => [2599, 3676],
C1 => [1837, 2599],
C2 => [1298, 1837],
C3 => [918, 1296],
C4 => [649, 918],
C5 => [459, 649],
C6 => [323, 459],
C7 => [230, 323]
);
}

=item $canvas->pdf(options)

Export cavnas content to PDF. Options:

=over 4

=item -media => media-name

A4,A5,B4,etc. or a bbox array of the form [x1,y1,x2,y2].
Defaults to A4.

=item -ttfont => filename

filename of a TrueType font

=item -psfont => [font-filename, afm-filename]

PostScript font as a pair of filenames of a PostScript font (pfb) and
a PostScript font metrics file (afm)

=item -font => name

PDF corefont filename

=item -file => filename

output filename

=back

=cut


sub __debug {
# print join "",@_; print "\n";
}

sub color2gray {
my ($color)=@_;
unless (ref($color)) {
if (!defined($color)) {
return undef;
} elsif ($color =~ /^#(..)(..)(..)/) {
$color = [map hex,$1,$2,$3];
} elsif (exists($Tk::rgb::rgb{$color})) {
$color = $Tk::rgb::rgb{$color};
} else {
warn "unknown color $color\n";
return 0;
}
}
no integer;
foreach (@$color) {
$_=$_ / 255;
$_=1-(1 - $_ ** 1.5);
$_=$_ * 255;
}
my $gray = int(sqrt($color->[0]**2+$color->[1]**2+$color->[2]**2)/sqrt(3));
return ("#".(sprintf("%02x",$gray) x 3));
}

sub new {
my ($class,%opts)=@_;

require PDF::API2;
my $pdf=PDF::API2->new;
my %fontmap;


my $unicode=$opts{-unicode}; # force unicode if possible
my $encoding=$opts{-encoding} || 'utf8';
$encoding = 'utf8' if $encoding =~ /^\s*unicode\s*$|^\s*utf-?8\s*$/i;
$encoding =~ s/^\s*windows-?/cp/i;
$encoding =~ s/^\s*latin-(\d+)?/latin$1/i;
$encoding =~ s/^\s*iso-?8859(\d+)/iso-8859-$1/i;

my @media;
if ($opts{-media}) {
if (ref($opts{-media})) {
@media=@{$opts{-media}};
} elsif (exists $media{$opts{-media}}) {
@media=(0,0,@{$media{$opts{-media}}});
} else {
die "Unknown media type $opts{-media}";
}
} else {
@media=(0,0,@{$media{A4}});
}
$pdf->mediabox(@media);
__debug("Media: @media, Encoding: $encoding\n");
if ($opts{-fontmap}) {
foreach my $fn (keys %{$opts{-fontmap}}) {
if ($opts{-fontmap}->{$fn}->[0] =~ /tt|truetype/i) {
if ($unicode or $encoding eq 'utf8') {
$fontmap{$fn}=$pdf->ttfont($opts{-fontmap}->{$fn}->[1])->unicode();
} else {
$fontmap{$fn}=$pdf->ttfont($opts{-fontmap}->{$fn}->[1],
-encode => $encoding);
}
} elsif ($opts{-fontmap}->{$fn}->[0] =~ /ps|postscript/i) {
$fontmap{$fn}=$pdf->psfont($opts{-fontmap}->{$fn}->[1],$opts{-fontmap}->{$fn}->[2],
$encoding ne 'utf8' ?
(-encode => $encoding) : ()
);
} elsif ($opts{-fontmap}->{$fn}->[0] =~ /core|builtin/i) {
$fontmap{$fn}=$pdf->corefont($opts{-fontmap}->{$fn}->[1],
$encoding ne 'utf8' ?
(-encode => $encoding) : ()
);
} else {
die "Canvas::PDF->pdf: unknown font type: $opts{-fontmap}->{$fn}";
}
}
}

my $font;
my $fontType;
if ($opts{-ttfont}) {
$fontType='TT';
if ($unicode or $encoding eq 'utf8') {
$font=$pdf->ttfont($opts{-ttfont})->unicode();
} else {
$font=$pdf->ttfont($opts{-ttfont},-encode => $encoding);
}
} elsif ($opts{-psfont}) {
$fontType='PS';
$font=$pdf->psfont($opts{-psfont}->[0],$opts{-psfont}->[1],
$encoding ne 'utf8' ?
(-encode => $encoding) : ()
);
} else {
$fontType='Core';
$font=$pdf->corefont('Helvetica',
$encoding ne 'utf8' ?
(-encode => $encoding) : ()
);
}

return bless {
Debug => $opts{-debug},
Encoding => $encoding,
Unicode => $unicode,
PDF => $pdf,
FontMap => \%fontmap,
Media => \@media,
DefaultFont => $font,
DefaultFontType => $fontType
},$class;
}


sub pdf {
my ($canvas,%opts)=@_;
my $P = __PACKAGE__->new(%opts);
$P->new_page(%opts);
$P->draw_canvas($canvas,%opts);
return $P->finish(%opts);
}

sub new_page {
my ($P,%opts)=@_;
$P->{current_page} = $P->{PDF}->page;
}

sub finish {
my ($P,%opts)=@_;
if ($opts{-file}) {
$P->{PDF}->saveas($opts{-file});
$P->{PDF}->end;
} else {
my $string = $P->{PDF}->stringify;
$P->{PDF}->end;
return $string;
}
}

sub draw_canvas {
my ($P,$canvas,%opts)=@_;
my $draw = $P->{current_page}->hybrid;
if ($opts{-transform}) {
$draw->transform(%{$opts{-transform}});
}
if ($opts{-translate}) {
$draw->translate(@{$opts{-translate}});
}
if ($opts{-rotate}) {
$draw->rotate($opts{-rotate});
}
if ($opts{-scale}) {
$draw->scale(@{$opts{-scale}});
}
if ($opts{-skew}) {
$draw->skew(@{$opts{-skew}});
}
if ($opts{-matrix}) {
$draw->matrix(@{$opts{-matrix}});
}

$draw->linedash();
$draw->linecap(0);
$draw->linejoin(0);

my $x = 0;
my $y = 0;
my $w = $opts{-width} || $P->{Media}[2];
my $h = $opts{-height} || $P->{Media}[3];
my $i;
foreach my $item ($canvas->find('all')) {
$draw->save;
my $type=$canvas->type($item);
my $state = $canvas->itemcget($item, '-state');
next if $state eq 'hidden';
$state = $state eq 'disabled' ? $state : '';
my @coords=$canvas->coords($item);
__debug("$type: orig @coords");
# recalculate coords for bottom/up
my $even=0;
foreach (@coords) {
$_=$h-$_ if $even;
$even=!$even;
}
__debug "$type: new @coords";
if ($type eq 'text') {
$draw->textstart;
my $anchor=$canvas->itemcget($item,'-anchor') || 'center';
my $color=$canvas->itemcget($item,"-${state}fill");
next unless defined($color); # transparent text = no text
$color = color2gray($color) if $opts{-grayscale};
my %canvasfont = $canvas->fontActual($canvas->itemcget($item,"-font"));
__debug "FONT:", (map {" $_ => $canvasfont{$_}, "} keys %canvasfont),"\n";
my $fn;
my $font_lookup_string = lc($canvasfont{-family}." ".$canvasfont{-weight}." ".$canvasfont{-slant});
if ($P->{FontMap}{$font_lookup_string}) {
$fn=$P->{FontMap}{$font_lookup_string};
} else {
warn ("'$font_lookup_string' font isn't mapped\n") if $P->{Debug};
$fn = $P->{DefaultFont};
}
my $fnsize=abs($canvasfont{-size});
my $text=$canvas->itemcget($item,"-text");
my $textwidth=$canvas->itemcget($item,"-width");

# TODO: width
__debug "$anchor\n";
$draw->linewidth(1);
$draw->linedash();
$draw->font($fn,$fnsize);
$draw->fillcolor($color);
my ($posx,$posy)=@coords;
my $ascent=$fn->ascender*$fnsize/1000;
my $descent=-$fn->descender*$fnsize/1000;
my $height=$ascent+$descent;
# my $height = $fn->capheight*$fnsize/1000;
my $width;

if (eval "Encode::is_utf8(\$text)" and not $@) {
$width = $fn->width_utf8($text)*$fnsize;
} elsif ($P->{Unicode}) {
eval "\$text= Encode::decode(\$P->{Encoding},\$text);";
$width = $fn->width_utf8($text)*$fnsize;
} else {
$width = $fn->width($text)*$fnsize;
}
__debug "Width: $width";
$posx-=$width/2;
$posy-=$height/2;
$anchor = '' if $anchor eq 'center';
if ($anchor =~ /s/) { $posy+=$height/2 }
elsif ($anchor =~ /n/) { $posy-=$height/2 }
if ($anchor =~ /e/) { $posx-=$width/2 }
elsif ($anchor =~ /w/) { $posx+=$width/2 }

$draw->translate($posx,$posy+$descent);
__debug "Text: $posx $posy $anchor";
if (eval "Encode::is_utf8(\$text)" and not $@ or $P->{Encoding} eq 'utf8') {
$draw->text($text,-utf8 => 1);
} else {
$draw->text($text);
}
$draw->textend;
} elsif ($type eq 'line') {
my $color=$canvas->itemcget($item,"-${state}fill");
next unless defined $color; # transparent line = no line
$color = color2gray($color) if $opts{-grayscale};
my $join=$canvas->itemcget($item,'-joinstyle');
my $capstyle=$canvas->itemcget($item,'-capstyle');
my $width=$canvas->itemcget($item,'-width');
my @dash=_canvas_to_pdf_dash($width,$canvas->itemcget($item,"-${state}dash"));
@dash=() if @dash<2;
my $smooth = $canvas->itemcget($item,"-smooth");
my $arrow = $canvas->itemcget($item,"-arrow");
my $ars = $canvas->itemcget($item,"-arrowshape") || [8,10,3];

# TODO: dashoffset
$draw->linewidth($width);
$draw->linedash(@dash);
$draw->linejoin($join{$join});
$draw->linecap($capstyle{$capstyle});
$draw->strokecolor($color);
$draw->fillcolor($color);
__debug "Line: @coords";
my @c=@coords;
# shorten line for arrows
for (qw(first last)) {
if ($arrow eq $_ or $arrow eq 'both') {
# we should adjust the enpoints to make space for the arrows
my ($x1,$y1,$x2,$y2) = $_ eq 'first' ? (0..3) : (-2,-1,-4,-3);
my $len = sqrt(($c[$x2]-$c[$x1])**2 + ($c[$y2]-$c[$y1])**2);
$c[$x1]+=($c[$x2]-$c[$x1])*0.9*$ars->[0]/$len;
$c[$y1]+=($c[$y2]-$c[$y1])*0.9*$ars->[0]/$len;
}
}
# draw line
if ($smooth and @c>=6) {
$draw->move(@c[0,1]);
$draw->curve(@c);
} else {
$draw->move(@c[0,1]);
$draw->line(@c[2..$#c]);
}
$draw->stroke;
# draw arrows
for (qw(first last)) {
if ($arrow eq $_ or $arrow eq 'both') {
@c=$_ eq 'first' ? @coords[0..3] : @coords[-2,-1,-4,-3];
my $angle = 180*atan2($c[2]-$c[0],$c[1]-$c[3])/3.14159265;
$draw->save;
$draw->translate(@c[0,1]);
$draw->linedash();
$draw->linecap(0);
$draw->linejoin(0);
$draw->rotate($_ eq 'first' ? -$angle : $angle-90);
$draw->move(0,0);
$draw->line($ars->[1],$ars->[2], $ars->[0],0, $ars->[1],-$ars->[2], 0,0);
$draw->close;
$draw->fillstroke;
$draw->restore;
}
}
} elsif ($type eq 'oval') {
my $width=$canvas->itemcget($item,'-width');
my @dash=_canvas_to_pdf_dash($width,$canvas->itemcget($item,"-${state}dash"));
@dash=() if @dash<2;
my $color=$canvas->itemcget($item,"-${state}fill");
my $outlinecolor=$canvas->itemcget($item,"-${state}outline");
$outlinecolor=$color if !defined($outlinecolor);

if ($opts{-grayscale}) {
$color = color2gray($color);
$outlinecolor = color2gray($outlinecolor);
}

# TODO: dashoffset

$draw->linewidth($width);
$draw->linedash(@dash);
$draw->strokecolor($outlinecolor) if defined $outlinecolor;
$draw->fillcolor($color) if defined $color;
my @c = (($coords[2]+$coords[0])/2,($coords[3]+$coords[1])/2,
($coords[2]-$coords[0])/2,($coords[3]-$coords[1])/2);
__debug "Ellipse: @c";
$draw->ellipse(@c);
if (defined($color)) {
$draw->fillstroke;
} else {
$draw->stroke;
}
} elsif ($type eq 'polygon') {
my $width=$canvas->itemcget($item,'-width');
my $join=$canvas->itemcget($item,'-joinstyle');
my @dash=_canvas_to_pdf_dash($width,$canvas->itemcget($item,"-${state}dash"));
@dash=() if @dash<2;
my $color=$canvas->itemcget($item,"-${state}fill");
my $outlinecolor=$canvas->itemcget($item,"-${state}outline");
$outlinecolor=$color if !defined($outlinecolor);

if ($opts{-grayscale}) {
$color = color2gray($color);
$outlinecolor = color2gray($outlinecolor);
}

my $smooth = $canvas->itemcget($item,"-smooth");
# TODO: dashoffset
$draw->linewidth($width);
$draw->linedash(@dash);
$draw->linejoin($join{$join});
$draw->strokecolor($outlinecolor) if defined($color);
$draw->fillcolor($color) if defined($color);
__debug "Polygon: @coords";
if ($smooth) {
$draw->move(@coords[0,1]);
$draw->curve(@coords);
$draw->close();
} else {
$draw->rect(@coords);
}
if (defined $color) {
$draw->fillstroke;
} else {
$draw->stroke;
}
} elsif ($type eq 'rectangle') {
my $width=$canvas->itemcget($item,'-width');
my @dash=_canvas_to_pdf_dash($width,$canvas->itemcget($item,"-${state}dash"));
@dash=() if @dash<2;
my $color=$canvas->itemcget($item,"-${state}fill");
my $outlinecolor=$canvas->itemcget($item,"-${state}outline");
$outlinecolor=$color if !defined($outlinecolor);

if ($opts{-grayscale}) {
$color = color2gray($color);
$outlinecolor = color2gray($outlinecolor);
}

# TODO: dashoffset
$draw->linewidth($width);
$draw->linedash(@dash);
$draw->linejoin(0);
$draw->linecap(0);
$draw->strokecolor($outlinecolor) if defined($outlinecolor);
$draw->fillcolor($color) if defined($color);
__debug "Rectangle: @coords";
$draw->rectxy(@coords);
if (defined $color) {
$draw->fillstroke;
} else {
$draw->stroke;
}
}
# TODO image, ...
} continue {
$draw->restore;
}
}

sub _canvas_to_pdf_dash {
my ($linewidth,@dash)=@_;
my $dash = join " ",@dash;
my %d=qw(. 40 - 120 , 80 _ 160);
$dash =~ s/(\d+)/$1*$linewidth/ge;
$dash =~ s/[-.,_]( *)/$d{$1}." ".40*(1+length($2))." "/ge;
$dash =~ s/[{}]//;
return split /\s*/,$dash;
}

package Tk::Canvas;

sub pdf {
my $self = shift;
Tk::Canvas::PDF::pdf($self,@_);
}

1;

--Boundary-01=_sSGrBn0Lgux9rmj
Content-Type: application/x-perl-module;
name="rgb.pm"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="rgb.pm"

package Tk::rgb;

BEGIN {
%rgb = (
'snow' => [255,250,250],
'ghost white' => [248,248,255],
'GhostWhite' => [248,248,255],
'white smoke' => [245,245,245],
'WhiteSmoke' => [245,245,245],
'gainsboro' => [220,220,220],
'floral white' => [255,250,240],
'FloralWhite' => [255,250,240],
'old lace' => [253,245,230],
'OldLace' => [253,245,230],
'linen' => [250,240,230],
'antique white' => [250,235,215],
'AntiqueWhite' => [250,235,215],
'papaya whip' => [255,239,213],
'PapayaWhip' => [255,239,213],
'blanched almond' => [255,235,205],
'BlanchedAlmond' => [255,235,205],
'bisque' => [255,228,196],
'peach puff' => [255,218,185],
'PeachPuff' => [255,218,185],
'navajo white' => [255,222,173],
'NavajoWhite' => [255,222,173],
'moccasin' => [255,228,181],
'cornsilk' => [255,248,220],
'ivory' => [255,255,240],
'lemon chiffon' => [255,250,205],
'LemonChiffon' => [255,250,205],
'seashell' => [255,245,238],
'honeydew' => [240,255,240],
'mint cream' => [245,255,250],
'MintCream' => [245,255,250],
'azure' => [240,255,255],
'alice blue' => [240,248,255],
'AliceBlue' => [240,248,255],
'lavender' => [230,230,250],
'lavender blush' => [255,240,245],
'LavenderBlush' => [255,240,245],
'misty rose' => [255,228,225],
'MistyRose' => [255,228,225],
'white' => [255,255,255],
'black' => [0,0,0],
'dark slate gray' => [47,79,79],
'DarkSlateGray' => [47,79,79],
'dark slate grey' => [47,79,79],
'DarkSlateGrey' => [47,79,79],
'dim gray' => [105,105,105],
'DimGray' => [105,105,105],
'dim grey' => [105,105,105],
'DimGrey' => [105,105,105],
'slate gray' => [112,128,144],
'SlateGray' => [112,128,144],
'slate grey' => [112,128,144],
'SlateGrey' => [112,128,144],
'light slate gray' => [119,136,153],
'LightSlateGray' => [119,136,153],
'light slate grey' => [119,136,153],
'LightSlateGrey' => [119,136,153],
'gray' => [190,190,190],
'grey' => [190,190,190],
'light grey' => [211,211,211],
'LightGrey' => [211,211,211],
'light gray' => [211,211,211],
'LightGray' => [211,211,211],
'midnight blue' => [25,25,112],
'MidnightBlue' => [25,25,112],
'navy' => [0,0,128],
'navy blue' => [0,0,128],
'NavyBlue' => [0,0,128],
'cornflower blue' => [100,149,237],
'CornflowerBlue' => [100,149,237],
'dark slate blue' => [72,61,139],
'DarkSlateBlue' => [72,61,139],
'slate blue' => [106,90,205],
'SlateBlue' => [106,90,205],
'medium slate blue' => [123,104,238],
'MediumSlateBlue' => [123,104,238],
'light slate blue' => [132,112,255],
'LightSlateBlue' => [132,112,255],
'medium blue' => [0,0,205],
'MediumBlue' => [0,0,205],
'royal blue' => [65,105,225],
'RoyalBlue' => [65,105,225],
'blue' => [0,0,255],
'dodger blue' => [30,144,255],
'DodgerBlue' => [30,144,255],
'deep sky blue' => [0,191,255],
'DeepSkyBlue' => [0,191,255],
'sky blue' => [135,206,235],
'SkyBlue' => [135,206,235],
'light sky blue' => [135,206,250],
'LightSkyBlue' => [135,206,250],
'steel blue' => [70,130,180],
'SteelBlue' => [70,130,180],
'light steel blue' => [176,196,222],
'LightSteelBlue' => [176,196,222],
'light blue' => [173,216,230],
'LightBlue' => [173,216,230],
'powder blue' => [176,224,230],
'PowderBlue' => [176,224,230],
'pale turquoise' => [175,238,238],
'PaleTurquoise' => [175,238,238],
'dark turquoise' => [0,206,209],
'DarkTurquoise' => [0,206,209],
'medium turquoise' => [72,209,204],
'MediumTurquoise' => [72,209,204],
'turquoise' => [64,224,208],
'cyan' => [0,255,255],
'light cyan' => [224,255,255],
'LightCyan' => [224,255,255],
'cadet blue' => [95,158,160],
'CadetBlue' => [95,158,160],
'medium aquamarine' => [102,205,170],
'MediumAquamarine' => [102,205,170],
'aquamarine' => [127,255,212],
'dark green' => [0,100,0],
'DarkGreen' => [0,100,0],
'dark olive green' => [85,107,47],
'DarkOliveGreen' => [85,107,47],
'dark sea green' => [143,188,143],
'DarkSeaGreen' => [143,188,143],
'sea green' => [46,139,87],
'SeaGreen' => [46,139,87],
'medium sea green' => [60,179,113],
'MediumSeaGreen' => [60,179,113],
'light sea green' => [32,178,170],
'LightSeaGreen' => [32,178,170],
'pale green' => [152,251,152],
'PaleGreen' => [152,251,152],
'spring green' => [0,255,127],
'SpringGreen' => [0,255,127],
'lawn green' => [124,252,0],
'LawnGreen' => [124,252,0],
'green' => [0,255,0],
'chartreuse' => [127,255,0],
'medium spring green' => [0,250,154],
'MediumSpringGreen' => [0,250,154],
'green yellow' => [173,255,47],
'GreenYellow' => [173,255,47],
'lime green' => [50,205,50],
'LimeGreen' => [50,205,50],
'yellow green' => [154,205,50],
'YellowGreen' => [154,205,50],
'forest green' => [34,139,34],
'ForestGreen' => [34,139,34],
'olive drab' => [107,142,35],
'OliveDrab' => [107,142,35],
'dark khaki' => [189,183,107],
'DarkKhaki' => [189,183,107],
'khaki' => [240,230,140],
'pale goldenrod' => [238,232,170],
'PaleGoldenrod' => [238,232,170],
'light goldenrod yellow' => [250,250,210],
'LightGoldenrodYellow' => [250,250,210],
'light yellow' => [255,255,224],
'LightYellow' => [255,255,224],
'yellow' => [255,255,0],
'gold' => [255,215,0],
'light goldenrod' => [238,221,130],
'LightGoldenrod' => [238,221,130],
'goldenrod' => [218,165,32],
'dark goldenrod' => [184,134,11],
'DarkGoldenrod' => [184,134,11],
'rosy brown' => [188,143,143],
'RosyBrown' => [188,143,143],
'indian red' => [205,92,92],
'IndianRed' => [205,92,92],
'saddle brown' => [139,69,19],
'SaddleBrown' => [139,69,19],
'sienna' => [160,82,45],
'peru' => [205,133,63],
'burlywood' => [222,184,135],
'beige' => [245,245,220],
'wheat' => [245,222,179],
'sandy brown' => [244,164,96],
'SandyBrown' => [244,164,96],
'tan' => [210,180,140],
'chocolate' => [210,105,30],
'firebrick' => [178,34,34],
'brown' => [165,42,42],
'dark salmon' => [233,150,122],
'DarkSalmon' => [233,150,122],
'salmon' => [250,128,114],
'light salmon' => [255,160,122],
'LightSalmon' => [255,160,122],
'orange' => [255,165,0],
'dark orange' => [255,140,0],
'DarkOrange' => [255,140,0],
'coral' => [255,127,80],
'light coral' => [240,128,128],
'LightCoral' => [240,128,128],
'tomato' => [255,99,71],
'orange red' => [255,69,0],
'OrangeRed' => [255,69,0],
'red' => [255,0,0],
'hot pink' => [255,105,180],
'HotPink' => [255,105,180],
'deep pink' => [255,20,147],
'DeepPink' => [255,20,147],
'pink' => [255,192,203],
'light pink' => [255,182,193],
'LightPink' => [255,182,193],
'pale violet red' => [219,112,147],
'PaleVioletRed' => [219,112,147],
'maroon' => [176,48,96],
'medium violet red' => [199,21,133],
'MediumVioletRed' => [199,21,133],
'violet red' => [208,32,144],
'VioletRed' => [208,32,144],
'magenta' => [255,0,255],
'violet' => [238,130,238],
'plum' => [221,160,221],
'orchid' => [218,112,214],
'medium orchid' => [186,85,211],
'MediumOrchid' => [186,85,211],
'dark orchid' => [153,50,204],
'DarkOrchid' => [153,50,204],
'dark violet' => [148,0,211],
'DarkViolet' => [148,0,211],
'blue violet' => [138,43,226],
'BlueViolet' => [138,43,226],
'purple' => [160,32,240],
'medium purple' => [147,112,219],
'MediumPurple' => [147,112,219],
'thistle' => [216,191,216],
'snow1' => [255,250,250],
'snow2' => [238,233,233],
'snow3' => [205,201,201],
'snow4' => [139,137,137],
'seashell1' => [255,245,238],
'seashell2' => [238,229,222],
'seashell3' => [205,197,191],
'seashell4' => [139,134,130],
'AntiqueWhite1' => [255,239,219],
'AntiqueWhite2' => [238,223,204],
'AntiqueWhite3' => [205,192,176],
'AntiqueWhite4' => [139,131,120],
'bisque1' => [255,228,196],
'bisque2' => [238,213,183],
'bisque3' => [205,183,158],
'bisque4' => [139,125,107],
'PeachPuff1' => [255,218,185],
'PeachPuff2' => [238,203,173],
'PeachPuff3' => [205,175,149],
'PeachPuff4' => [139,119,101],
'NavajoWhite1' => [255,222,173],
'NavajoWhite2' => [238,207,161],
'NavajoWhite3' => [205,179,139],
'NavajoWhite4' => [139,121,94],
'LemonChiffon1' => [255,250,205],
'LemonChiffon2' => [238,233,191],
'LemonChiffon3' => [205,201,165],
'LemonChiffon4' => [139,137,112],
'cornsilk1' => [255,248,220],
'cornsilk2' => [238,232,205],
'cornsilk3' => [205,200,177],
'cornsilk4' => [139,136,120],
'ivory1' => [255,255,240],
'ivory2' => [238,238,224],
'ivory3' => [205,205,193],
'ivory4' => [139,139,131],
'honeydew1' => [240,255,240],
'honeydew2' => [224,238,224],
'honeydew3' => [193,205,193],
'honeydew4' => [131,139,131],
'LavenderBlush1' => [255,240,245],
'LavenderBlush2' => [238,224,229],
'LavenderBlush3' => [205,193,197],
'LavenderBlush4' => [139,131,134],
'MistyRose1' => [255,228,225],
'MistyRose2' => [238,213,210],
'MistyRose3' => [205,183,181],
'MistyRose4' => [139,125,123],
'azure1' => [240,255,255],
'azure2' => [224,238,238],
'azure3' => [193,205,205],
'azure4' => [131,139,139],
'SlateBlue1' => [131,111,255],
'SlateBlue2' => [122,103,238],
'SlateBlue3' => [105,89,205],
'SlateBlue4' => [71,60,139],
'RoyalBlue1' => [72,118,255],
'RoyalBlue2' => [67,110,238],
'RoyalBlue3' => [58,95,205],
'RoyalBlue4' => [39,64,139],
'blue1' => [0,0,255],
'blue2' => [0,0,238],
'blue3' => [0,0,205],
'blue4' => [0,0,139],
'DodgerBlue1' => [30,144,255],
'DodgerBlue2' => [28,134,238],
'DodgerBlue3' => [24,116,205],
'DodgerBlue4' => [16,78,139],
'SteelBlue1' => [99,184,255],
'SteelBlue2' => [92,172,238],
'SteelBlue3' => [79,148,205],
'SteelBlue4' => [54,100,139],
'DeepSkyBlue1' => [0,191,255],
'DeepSkyBlue2' => [0,178,238],
'DeepSkyBlue3' => [0,154,205],
'DeepSkyBlue4' => [0,104,139],
'SkyBlue1' => [135,206,255],
'SkyBlue2' => [126,192,238],
'SkyBlue3' => [108,166,205],
'SkyBlue4' => [74,112,139],
'LightSkyBlue1' => [176,226,255],
'LightSkyBlue2' => [164,211,238],
'LightSkyBlue3' => [141,182,205],
'LightSkyBlue4' => [96,123,139],
'SlateGray1' => [198,226,255],
'SlateGray2' => [185,211,238],
'SlateGray3' => [159,182,205],
'SlateGray4' => [108,123,139],
'LightSteelBlue1' => [202,225,255],
'LightSteelBlue2' => [188,210,238],
'LightSteelBlue3' => [162,181,205],
'LightSteelBlue4' => [110,123,139],
'LightBlue1' => [191,239,255],
'LightBlue2' => [178,223,238],
'LightBlue3' => [154,192,205],
'LightBlue4' => [104,131,139],
'LightCyan1' => [224,255,255],
'LightCyan2' => [209,238,238],
'LightCyan3' => [180,205,205],
'LightCyan4' => [122,139,139],
'PaleTurquoise1' => [187,255,255],
'PaleTurquoise2' => [174,238,238],
'PaleTurquoise3' => [150,205,205],
'PaleTurquoise4' => [102,139,139],
'CadetBlue1' => [152,245,255],
'CadetBlue2' => [142,229,238],
'CadetBlue3' => [122,197,205],
'CadetBlue4' => [83,134,139],
'turquoise1' => [0,245,255],
'turquoise2' => [0,229,238],
'turquoise3' => [0,197,205],
'turquoise4' => [0,134,139],
'cyan1' => [0,255,255],
'cyan2' => [0,238,238],
'cyan3' => [0,205,205],
'cyan4' => [0,139,139],
'DarkSlateGray1' => [151,255,255],
'DarkSlateGray2' => [141,238,238],
'DarkSlateGray3' => [121,205,205],
'DarkSlateGray4' => [82,139,139],
'aquamarine1' => [127,255,212],
'aquamarine2' => [118,238,198],
'aquamarine3' => [102,205,170],
'aquamarine4' => [69,139,116],
'DarkSeaGreen1' => [193,255,193],
'DarkSeaGreen2' => [180,238,180],
'DarkSeaGreen3' => [155,205,155],
'DarkSeaGreen4' => [105,139,105],
'SeaGreen1' => [84,255,159],
'SeaGreen2' => [78,238,148],
'SeaGreen3' => [67,205,128],
'SeaGreen4' => [46,139,87],
'PaleGreen1' => [154,255,154],
'PaleGreen2' => [144,238,144],
'PaleGreen3' => [124,205,124],
'PaleGreen4' => [84,139,84],
'SpringGreen1' => [0,255,127],
'SpringGreen2' => [0,238,118],
'SpringGreen3' => [0,205,102],
'SpringGreen4' => [0,139,69],
'green1' => [0,255,0],
'green2' => [0,238,0],
'green3' => [0,205,0],
'green4' => [0,139,0],
'chartreuse1' => [127,255,0],
'chartreuse2' => [118,238,0],
'chartreuse3' => [102,205,0],
'chartreuse4' => [69,139,0],
'OliveDrab1' => [192,255,62],
'OliveDrab2' => [179,238,58],
'OliveDrab3' => [154,205,50],
'OliveDrab4' => [105,139,34],
'DarkOliveGreen1' => [202,255,112],
'DarkOliveGreen2' => [188,238,104],
'DarkOliveGreen3' => [162,205,90],
'DarkOliveGreen4' => [110,139,61],
'khaki1' => [255,246,143],
'khaki2' => [238,230,133],
'khaki3' => [205,198,115],
'khaki4' => [139,134,78],
'LightGoldenrod1' => [255,236,139],
'LightGoldenrod2' => [238,220,130],
'LightGoldenrod3' => [205,190,112],
'LightGoldenrod4' => [139,129,76],
'LightYellow1' => [255,255,224],
'LightYellow2' => [238,238,209],
'LightYellow3' => [205,205,180],
'LightYellow4' => [139,139,122],
'yellow1' => [255,255,0],
'yellow2' => [238,238,0],
'yellow3' => [205,205,0],
'yellow4' => [139,139,0],
'gold1' => [255,215,0],
'gold2' => [238,201,0],
'gold3' => [205,173,0],
'gold4' => [139,117,0],
'goldenrod1' => [255,193,37],
'goldenrod2' => [238,180,34],
'goldenrod3' => [205,155,29],
'goldenrod4' => [139,105,20],
'DarkGoldenrod1' => [255,185,15],
'DarkGoldenrod2' => [238,173,14],
'DarkGoldenrod3' => [205,149,12],
'DarkGoldenrod4' => [139,101,8],
'RosyBrown1' => [255,193,193],
'RosyBrown2' => [238,180,180],
'RosyBrown3' => [205,155,155],
'RosyBrown4' => [139,105,105],
'IndianRed1' => [255,106,106],
'IndianRed2' => [238,99,99],
'IndianRed3' => [205,85,85],
'IndianRed4' => [139,58,58],
'sienna1' => [255,130,71],
'sienna2' => [238,121,66],
'sienna3' => [205,104,57],
'sienna4' => [139,71,38],
'burlywood1' => [255,211,155],
'burlywood2' => [238,197,145],
'burlywood3' => [205,170,125],
'burlywood4' => [139,115,85],
'wheat1' => [255,231,186],
'wheat2' => [238,216,174],
'wheat3' => [205,186,150],
'wheat4' => [139,126,102],
'tan1' => [255,165,79],
'tan2' => [238,154,73],
'tan3' => [205,133,63],
'tan4' => [139,90,43],
'chocolate1' => [255,127,36],
'chocolate2' => [238,118,33],
'chocolate3' => [205,102,29],
'chocolate4' => [139,69,19],
'firebrick1' => [255,48,48],
'firebrick2' => [238,44,44],
'firebrick3' => [205,38,38],
'firebrick4' => [139,26,26],
'brown1' => [255,64,64],
'brown2' => [238,59,59],
'brown3' => [205,51,51],
'brown4' => [139,35,35],
'salmon1' => [255,140,105],
'salmon2' => [238,130,98],
'salmon3' => [205,112,84],
'salmon4' => [139,76,57],
'LightSalmon1' => [255,160,122],
'LightSalmon2' => [238,149,114],
'LightSalmon3' => [205,129,98],
'LightSalmon4' => [139,87,66],
'orange1' => [255,165,0],
'orange2' => [238,154,0],
'orange3' => [205,133,0],
'orange4' => [139,90,0],
'DarkOrange1' => [255,127,0],
'DarkOrange2' => [238,118,0],
'DarkOrange3' => [205,102,0],
'DarkOrange4' => [139,69,0],
'coral1' => [255,114,86],
'coral2' => [238,106,80],
'coral3' => [205,91,69],
'coral4' => [139,62,47],
'tomato1' => [255,99,71],
'tomato2' => [238,92,66],
'tomato3' => [205,79,57],
'tomato4' => [139,54,38],
'OrangeRed1' => [255,69,0],
'OrangeRed2' => [238,64,0],
'OrangeRed3' => [205,55,0],
'OrangeRed4' => [139,37,0],
'red1' => [255,0,0],
'red2' => [238,0,0],
'red3' => [205,0,0],
'red4' => [139,0,0],
'DeepPink1' => [255,20,147],
'DeepPink2' => [238,18,137],
'DeepPink3' => [205,16,118],
'DeepPink4' => [139,10,80],
'HotPink1' => [255,110,180],
'HotPink2' => [238,106,167],
'HotPink3' => [205,96,144],
'HotPink4' => [139,58,98],
'pink1' => [255,181,197],
'pink2' => [238,169,184],
'pink3' => [205,145,158],
'pink4' => [139,99,108],
'LightPink1' => [255,174,185],
'LightPink2' => [238,162,173],
'LightPink3' => [205,140,149],
'LightPink4' => [139,95,101],
'PaleVioletRed1' => [255,130,171],
'PaleVioletRed2' => [238,121,159],
'PaleVioletRed3' => [205,104,137],
'PaleVioletRed4' => [139,71,93],
'maroon1' => [255,52,179],
'maroon2' => [238,48,167],
'maroon3' => [205,41,144],
'maroon4' => [139,28,98],
'VioletRed1' => [255,62,150],
'VioletRed2' => [238,58,140],
'VioletRed3' => [205,50,120],
'VioletRed4' => [139,34,82],
'magenta1' => [255,0,255],
'magenta2' => [238,0,238],
'magenta3' => [205,0,205],
'magenta4' => [139,0,139],
'orchid1' => [255,131,250],
'orchid2' => [238,122,233],
'orchid3' => [205,105,201],
'orchid4' => [139,71,137],
'plum1' => [255,187,255],
'plum2' => [238,174,238],
'plum3' => [205,150,205],
'plum4' => [139,102,139],
'MediumOrchid1' => [224,102,255],
'MediumOrchid2' => [209,95,238],
'MediumOrchid3' => [180,82,205],
'MediumOrchid4' => [122,55,139],
'DarkOrchid1' => [191,62,255],
'DarkOrchid2' => [178,58,238],
'DarkOrchid3' => [154,50,205],
'DarkOrchid4' => [104,34,139],
'purple1' => [155,48,255],
'purple2' => [145,44,238],
'purple3' => [125,38,205],
'purple4' => [85,26,139],
'MediumPurple1' => [171,130,255],
'MediumPurple2' => [159,121,238],
'MediumPurple3' => [137,104,205],
'MediumPurple4' => [93,71,139],
'thistle1' => [255,225,255],
'thistle2' => [238,210,238],
'thistle3' => [205,181,205],
'thistle4' => [139,123,139],
'gray0' => [0,0,0],
'grey0' => [0,0,0],
'gray1' => [3,3,3],
'grey1' => [3,3,3],
'gray2' => [5,5,5],
'grey2' => [5,5,5],
'gray3' => [8,8,8],
'grey3' => [8,8,8],
'gray4' => [10,10,10],
'grey4' => [10,10,10],
'gray5' => [13,13,13],
'grey5' => [13,13,13],
'gray6' => [15,15,15],
'grey6' => [15,15,15],
'gray7' => [18,18,18],
'grey7' => [18,18,18],
'gray8' => [20,20,20],
'grey8' => [20,20,20],
'gray9' => [23,23,23],
'grey9' => [23,23,23],
'gray10' => [26,26,26],
'grey10' => [26,26,26],
'gray11' => [28,28,28],
'grey11' => [28,28,28],
'gray12' => [31,31,31],
'grey12' => [31,31,31],
'gray13' => [33,33,33],
'grey13' => [33,33,33],
'gray14' => [36,36,36],
'grey14' => [36,36,36],
'gray15' => [38,38,38],
'grey15' => [38,38,38],
'gray16' => [41,41,41],
'grey16' => [41,41,41],
'gray17' => [43,43,43],
'grey17' => [43,43,43],
'gray18' => [46,46,46],
'grey18' => [46,46,46],
'gray19' => [48,48,48],
'grey19' => [48,48,48],
'gray20' => [51,51,51],
'grey20' => [51,51,51],
'gray21' => [54,54,54],
'grey21' => [54,54,54],
'gray22' => [56,56,56],
'grey22' => [56,56,56],
'gray23' => [59,59,59],
'grey23' => [59,59,59],
'gray24' => [61,61,61],
'grey24' => [61,61,61],
'gray25' => [64,64,64],
'grey25' => [64,64,64],
'gray26' => [66,66,66],
'grey26' => [66,66,66],
'gray27' => [69,69,69],
'grey27' => [69,69,69],
'gray28' => [71,71,71],
'grey28' => [71,71,71],
'gray29' => [74,74,74],
'grey29' => [74,74,74],
'gray30' => [77,77,77],
'grey30' => [77,77,77],
'gray31' => [79,79,79],
'grey31' => [79,79,79],
'gray32' => [82,82,82],
'grey32' => [82,82,82],
'gray33' => [84,84,84],
'grey33' => [84,84,84],
'gray34' => [87,87,87],
'grey34' => [87,87,87],
'gray35' => [89,89,89],
'grey35' => [89,89,89],
'gray36' => [92,92,92],
'grey36' => [92,92,92],
'gray37' => [94,94,94],
'grey37' => [94,94,94],
'gray38' => [97,97,97],
'grey38' => [97,97,97],
'gray39' => [99,99,99],
'grey39' => [99,99,99],
'gray40' => [102,102,102],
'grey40' => [102,102,102],
'gray41' => [105,105,105],
'grey41' => [105,105,105],
'gray42' => [107,107,107],
'grey42' => [107,107,107],
'gray43' => [110,110,110],
'grey43' => [110,110,110],
'gray44' => [112,112,112],
'grey44' => [112,112,112],
'gray45' => [115,115,115],
'grey45' => [115,115,115],
'gray46' => [117,117,117],
'grey46' => [117,117,117],
'gray47' => [120,120,120],
'grey47' => [120,120,120],
'gray48' => [122,122,122],
'grey48' => [122,122,122],
'gray49' => [125,125,125],
'grey49' => [125,125,125],
'gray50' => [127,127,127],
'grey50' => [127,127,127],
'gray51' => [130,130,130],
'grey51' => [130,130,130],
'gray52' => [133,133,133],
'grey52' => [133,133,133],
'gray53' => [135,135,135],
'grey53' => [135,135,135],
'gray54' => [138,138,138],
'grey54' => [138,138,138],
'gray55' => [140,140,140],
'grey55' => [140,140,140],
'gray56' => [143,143,143],
'grey56' => [143,143,143],
'gray57' => [145,145,145],
'grey57' => [145,145,145],
'gray58' => [148,148,148],
'grey58' => [148,148,148],
'gray59' => [150,150,150],
'grey59' => [150,150,150],
'gray60' => [153,153,153],
'grey60' => [153,153,153],
'gray61' => [156,156,156],
'grey61' => [156,156,156],
'gray62' => [158,158,158],
'grey62' => [158,158,158],
'gray63' => [161,161,161],
'grey63' => [161,161,161],
'gray64' => [163,163,163],
'grey64' => [163,163,163],
'gray65' => [166,166,166],
'grey65' => [166,166,166],
'gray66' => [168,168,168],
'grey66' => [168,168,168],
'gray67' => [171,171,171],
'grey67' => [171,171,171],
'gray68' => [173,173,173],
'grey68' => [173,173,173],
'gray69' => [176,176,176],
'grey69' => [176,176,176],
'gray70' => [179,179,179],
'grey70' => [179,179,179],
'gray71' => [181,181,181],
'grey71' => [181,181,181],
'gray72' => [184,184,184],
'grey72' => [184,184,184],
'gray73' => [186,186,186],
'grey73' => [186,186,186],
'gray74' => [189,189,189],
'grey74' => [189,189,189],
'gray75' => [191,191,191],
'grey75' => [191,191,191],
'gray76' => [194,194,194],
'grey76' => [194,194,194],
'gray77' => [196,196,196],
'grey77' => [196,196,196],
'gray78' => [199,199,199],
'grey78' => [199,199,199],
'gray79' => [201,201,201],
'grey79' => [201,201,201],
'gray80' => [204,204,204],
'grey80' => [204,204,204],
'gray81' => [207,207,207],
'grey81' => [207,207,207],
'gray82' => [209,209,209],
'grey82' => [209,209,209],
'gray83' => [212,212,212],
'grey83' => [212,212,212],
'gray84' => [214,214,214],
'grey84' => [214,214,214],
'gray85' => [217,217,217],
'grey85' => [217,217,217],
'gray86' => [219,219,219],
'grey86' => [219,219,219],
'gray87' => [222,222,222],
'grey87' => [222,222,222],
'gray88' => [224,224,224],
'grey88' => [224,224,224],
'gray89' => [227,227,227],
'grey89' => [227,227,227],
'gray90' => [229,229,229],
'grey90' => [229,229,229],
'gray91' => [232,232,232],
'grey91' => [232,232,232],
'gray92' => [235,235,235],
'grey92' => [235,235,235],
'gray93' => [237,237,237],
'grey93' => [237,237,237],
'gray94' => [240,240,240],
'grey94' => [240,240,240],
'gray95' => [242,242,242],
'grey95' => [242,242,242],
'gray96' => [245,245,245],
'grey96' => [245,245,245],
'gray97' => [247,247,247],
'grey97' => [247,247,247],
'gray98' => [250,250,250],
'grey98' => [250,250,250],
'gray99' => [252,252,252],
'grey99' => [252,252,252],
'gray100' => [255,255,255],
'grey100' => [255,255,255],
'dark grey' => [169,169,169],
'DarkGrey' => [169,169,169],
'dark gray' => [169,169,169],
'DarkGray' => [169,169,169],
'dark blue' => [0,0,139],
'DarkBlue' => [0,0,139],
'dark cyan' => [0,139,139],
'DarkCyan' => [0,139,139],
'dark magenta' => [139,0,139],
'DarkMagenta' => [139,0,139],
'dark red' => [139,0,0],
'DarkRed' => [139,0,0],
'light green' => [144,238,144],
'LightGreen' => [144,238,144]
);

foreach (keys %rgb) {
$rgb{lc($_)}=$rgb{$_} if (lc($_) ne $_ and !exists($rgb{lc($_)}))
}

}

1;

--Boundary-01=_sSGrBn0Lgux9rmj--

--nextPart19330464.Q7E6sxZdDT
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQBBrGSxQfxdLDi03+IRAkF3AKCPNCMS08kAG/EXIvI26bm3rMo1wACbBuj0
TOrzf21mHbsX+E1RQCPTQgw=
=2b+Y
-----END PGP SIGNATURE-----

--nextPart19330464.Q7E6sxZdDT--

John

unread,
Nov 30, 2004, 7:58:14 AM11/30/04
to
Well, I installed the PDF::API2 through the ppm (Activestate perl)

Now what?

giving

>perldoc Tk::Canvas::PDF

i receive no results (i tried to install the Tk::Canvas::PDF using ppm but
it cannot find that module)

How to unify the Canvas and Pdf api now?

----- Original Message -----
From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>

To: "John" <isof...@cc.uoi.gr>
Cc: <p...@lists.Stanford.EDU>
Sent: Tuesday, November 30, 2004 2:16 PM
Subject: Re: Tk::Canvas to PDF module offer


Dne út 30. listopadu 2004 08:31 John napsal(a):


> Hello
>
> How did you hack the module?

Simply:-) It uses PDF::API2 module to create the actual PDF content.

It creates a new PDF object and a PDF page, then it examinines

every object on a given canvas one by one and translates it to a

corresponding PDF-object. It's really only a matter of itemCget,
some conversions on the object parameters and some PDF::API2 calls.

The only harder thing to implement were the arrows (if a multi-line

is smooth, you have to position the arrow head correctly) and

shapes.

> Does it work for you? With any encoding even with iso-8859-7 ?

Yes, of course, it works for me fine (Linux/Windows/MacOSX-X11) :-)

(I use it as one of Print outputs in a tree-editor called TrEd -

used mostly for linguistic annotation, see

Yes, I hope it should handle iso-8859-7 too (at least, it worked

with iso-8859-2 and iso-8859-6). If using "8bit" Tk (<800) only

have to specify the encoding to the PDF conversion routine. If you

use unicode/utf8 Tk>804, it should work out of the box.

> Could you tell us more, because that is so intresting.

It's attached. It's called Tk::Canvas::PDF and uses the same

namespace. It can be used in various ways, but as the simplest

approach it adds a new $canvas->pdf method (very similar to

$canvas->postscript) to the Tk::Canvas namespace.

It depends on the attached Tk::rgb.pm (it's just color-names to rgb
map) and the standard Encode module (perl>=5.7), but the later


dependency should be relatively easily to remove.

I think it gives best result with TrueType fonts, but PS fonts and

PDF-core fonts are supported as well.

It only lacks documentation, except for a short (probably outdated)

synopsis-like POD.

As I told earlier, I don't have time to put it all in shape, at

least not right now. So if anyone was interested in taking it,

probably going through the code, writing some POD and preparing it

for a release, I'd be glad. If not, you can use it as it is. Maybe

in the up-comming weeks I'll be able to find some to do that

myself...

-- Petr

> ----- Original Message -----
> From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
> To: <p...@lists.Stanford.EDU>
> Sent: Monday, November 29, 2004 8:06 PM
> Subject: Tk::Canvas to PDF module offer
>
>
>

Petr Pajas

unread,
Nov 30, 2004, 8:59:16 AM11/30/04
to
--nextPart2459768.kkZDaMRiHV

Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Dne =FAt 30. listopadu 2004 13:58 jste napsal(a):


> Well, I installed the PDF::API2 through the ppm (Activestate
> perl)
>
> Now what?

See the attachment of my previous post. It's not click&install!=20
There are too files: PDF.pm and rgb.pm. PDF.pm is intended to be=20
placed in a directory structure Tk/Canvas/PDF.pm while rgb.pm is in=20
Tk/rgb.pm. Take these attachments and install them somewhere in=20
your PERLLIB to the above subdirectories.

In your code, you would ten

use Tk;
use Tk::Canvas::PDF;
=2E..
$canvas->pdf( ...arguments... );=20

see the POD info in PDF.pm for the arguments syntax. If in doubt,=20
look at the code.=20

I'm sorry, as I said, the module isn't ready for deployment, you'll=20
have to invest some time to find out how to use it.

=2D- Petr

> giving
>
> >perldoc Tk::Canvas::PDF
>
> i receive no results (i tried to install the Tk::Canvas::PDF
> using ppm but it cannot find that module)
>
> How to unify the Canvas and Pdf api now?
>
>
>
> ----- Original Message -----
> From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
> To: "John" <isof...@cc.uoi.gr>
> Cc: <p...@lists.Stanford.EDU>
> Sent: Tuesday, November 30, 2004 2:16 PM
> Subject: Re: Tk::Canvas to PDF module offer
>

> Dne =FAt 30. listopadu 2004 08:31 John napsal(a):

> rgb map) and the standard Encode module (perl>=3D5.7), but the


> later dependency should be relatively easily to remove.
>
> I think it gives best result with TrueType fonts, but PS fonts
> and PDF-core fonts are supported as well.
>
> It only lacks documentation, except for a short (probably
> outdated) synopsis-like POD.
>
> As I told earlier, I don't have time to put it all in shape, at
> least not right now. So if anyone was interested in taking it,
> probably going through the code, writing some POD and preparing
> it for a release, I'd be glad. If not, you can use it as it is.
> Maybe in the up-comming weeks I'll be able to find some to do
> that myself...
>
> -- Petr
>
> > ----- Original Message -----
> > From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
> > To: <p...@lists.Stanford.EDU>
> > Sent: Monday, November 29, 2004 8:06 PM
> > Subject: Tk::Canvas to PDF module offer
> >
> >
> >

> > -++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D=
=2D-++**=3D=3D


> > This message was posted through the Stanford campus mailing
> > list server. If you wish to unsubscribe from this mailing
> > list, send the message body of "unsubscribe ptk" to
> > majo...@lists.stanford.edu
>

> -++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--++**=3D=3D--=
++**=3D=3D


> This message was posted through the Stanford campus mailing list
> server. If you wish to unsubscribe from this mailing list, send
> the message body of "unsubscribe ptk" to
> majo...@lists.stanford.edu

--nextPart2459768.kkZDaMRiHV
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQBBrHy7QfxdLDi03+IRAkP9AJ4sK2Rk9AZ/6Dw6TQ0lNclVp1zbRQCfVt7u
D1UcitLk40SlfTbphpo6yC0=
=59xF
-----END PGP SIGNATURE-----

--nextPart2459768.kkZDaMRiHV--

John

unread,
Nov 30, 2004, 10:24:12 AM11/30/04
to
well, do you mean in the c:\perl\lib\Tk\Canvas?

Unfortunately i cannot find the above dir (\Tk)

Petr Pajas

unread,
Nov 30, 2004, 11:05:32 AM11/30/04
to
--nextPart3283091.KRacYrWZ6E

Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On Tuesday 30 of November 2004 16:24, John wrote:
> well, do you mean in the c:\perl\lib\Tk\Canvas?
>

Yes for example,
but c:\perl\site_lib\Tk\Canvas or something is a better idea. In=20
general, anywhere in your perl search path. Run perl -V to see the=20
default paths.

> Unfortunately i cannot find the above dir (\Tk)

In that case find where your Tk is installed and use it's directory=20
structure. You might also create those dirs anywhere and just point=20
PERLLIB to it.=20

Sorry, but these are all perl basics, that's why my answers might=20
seem too concise.

=2D- Petr

--nextPart3283091.KRacYrWZ6E
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQBBrJpXQfxdLDi03+IRAv3ZAJ9aiWTDFQXMrJmbZADlr/H1RWEvbACghzhW
D5Xk8x+Q0BOIyFK6GsnQyN4=
=Lo+P
-----END PGP SIGNATURE-----

--nextPart3283091.KRacYrWZ6E--

Dean Arnold

unread,
Nov 30, 2004, 11:26:15 AM11/30/04
to
John wrote:
> well, do you mean in the c:\perl\lib\Tk\Canvas?
>
> Unfortunately i cannot find the above dir (\Tk)
>

It looks like you're on Windows, so its likely you're
using ActiveState perl, in which case the directory
path is likely

C:\Perl\site\lib\Tk

Dean Arnold
Presicient Corp.

John

unread,
Nov 30, 2004, 12:33:36 PM11/30/04
to
Ok.

All the pm files reside in the c:\perl\site\lib\Tk


SO, i created the folder Canvas in (\Tk)

The what should i copy there?
What files exactly?

----- Original Message -----
From: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
To: "John" <isof...@cc.uoi.gr>
Cc: "Perl/Tk" <p...@lists.Stanford.EDU>
Sent: Tuesday, November 30, 2004 6:05 PM
Subject: Re: Tk::Canvas to PDF module offer

Slaven Rezic

unread,
Nov 30, 2004, 5:09:58 PM11/30/04
to
Petr Pajas <pa...@ufal.ms.mff.cuni.cz> writes:

> Dne út 30. listopadu 2004 08:31 John napsal(a):


> > Hello
> >
> > How did you hack the module?
>
> Simply:-) It uses PDF::API2 module to create the actual PDF content.
> It creates a new PDF object and a PDF page, then it examinines
> every object on a given canvas one by one and translates it to a
> corresponding PDF-object. It's really only a matter of itemCget,
> some conversions on the object parameters and some PDF::API2 calls.
>
> The only harder thing to implement were the arrows (if a multi-line
> is smooth, you have to position the arrow head correctly) and
> shapes.
>

The module looks promising. When trying the pdf() method I get the
following error message:

## Can't locate object method "hybrid" via package "PDF::API2::Page" at /tmp/Tk/Canvas/PDF.pm line 271

both with the stable and the development versions of PDF::API2.
Replacing the hybrid() method by gfx() made the module work.

Lines, circles and rectangles of all shapes seem to work, while
polygons are not handled correctly (it seems that rectangles are used
instead of polygons).

Regards,
Slaven

--
Slaven Rezic - slaven <at> rezic <dot> de
BBBike - route planner for cyclists in Berlin
WWW version: http://www.bbbike.de
Perl/Tk version for Unix and Windows: http://bbbike.sourceforge.net

John

unread,
Dec 1, 2004, 2:55:04 AM12/1/04
to

----- Original Message -----
From: "Slaven Rezic" <sla...@rezic.de>
To: "Petr Pajas" <pa...@ufal.ms.mff.cuni.cz>
Cc: "John" <isof...@cc.uoi.gr>; <p...@lists.Stanford.EDU>
Sent: Wednesday, December 01, 2004 12:09 AM
Subject: Re: Tk::Canvas to PDF module offer

Did you try to compile your perl script (using perlapp) ?
Did it work correctly?

Mine isn't as far as is looking for

Tk::Error: Can't locate PDF/API2/TTF/Table.pm in @INC (@INC contains:
C:\DOCUME~
1\ADMINI~1\LOCALS~1\Temp\pdk-Administrator-1496\ C:\progs\Canvas) at
/PerlApp/PD
F/API2/TTF/Font.pm line 333.

Possibly, because i have set pdf font arial.ttf (arial.ttf is in my current
directory)

Petr Pajas

unread,
Dec 1, 2004, 5:40:17 AM12/1/04
to
--nextPart2761029.FO2SFpG3F3
Content-Type: multipart/mixed;
boundary="Boundary-01=_T+ZrBXOyvuO1Tkr"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

--Boundary-01=_T+ZrBXOyvuO1Tkr


Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On Tuesday 30 of November 2004 23:09, Slaven Rezic wrote:
> Petr Pajas <pa...@ufal.ms.mff.cuni.cz> writes:

> > Dne =FAt 30. listopadu 2004 08:31 John napsal(a):


> > > Hello
> > >
> > > How did you hack the module?
> >
> > Simply:-) It uses PDF::API2 module to create the actual PDF
> > content. It creates a new PDF object and a PDF page, then it
> > examinines every object on a given canvas one by one and
> > translates it to a corresponding PDF-object. It's really only a
> > matter of itemCget, some conversions on the object parameters
> > and some PDF::API2 calls.
> >
> > The only harder thing to implement were the arrows (if a
> > multi-line is smooth, you have to position the arrow head
> > correctly) and shapes.
>
> The module looks promising. When trying the pdf() method I get
> the following error message:
>
> ## Can't locate object method "hybrid" via package
> "PDF::API2::Page" at /tmp/Tk/Canvas/PDF.pm line 271

Hm, works here, but I use PDF::API2 version

'$Revisioning: 0.40_01 Mon Jul 14 12:56:43 2003 $'

Maybe the new versions miss Hybrid.pm? In my version, it says that=20
Hybrid is subclassed from PDF::API2::Gfx+Text+Content and=20
$page->hybrid simply calls it's constructor.

> both with the stable and the development versions of PDF::API2.
> Replacing the hybrid() method by gfx() made the module work.

Does text work with gfx too? If hybrid was removed from PDF::API2,=20
then Tk::Canvas::PDF should probably create two objects: Text and=20
Gfx and use them separately... Should be simple, but I have no time=20
to play with that.

> Lines, circles and rectangles of all shapes seem to work, while
> polygons are not handled correctly (it seems that rectangles are
> used instead of polygons).

Yes, you're right. I never really tested polygons. The attached=20
version FIXES this. I also attach my ugly test script, I sent John=20
yesterday. I added a new smooth polygon to it.

Strangely, it seems that PostScript command curveto and PDF command=20
'c' produce slightly different Bezier curves (the one in PDF with=20
higher curvature), even if given exactly the same coords. As a=20
result, all "smooth" object exported from canvas to PDF look little=20
different from those seen in PostScript.

=2D- Petr

--Boundary-01=_T+ZrBXOyvuO1Tkr
Content-Type: application/x-perl;
name="tkpdfcanvastest_greek.pl"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="tkpdfcanvastest_greek.pl"

#!/usr/bin/perl
use lib qw(.);


use Tk;
use Tk::Canvas::PDF;

# perl >=3D 5.7:

# what encoding will we get by calling itemcget on canvas text items
# and what encoding should we use to pass strings to it

use if ($Tk::VERSION >=3D 804), encoding =3D> 'iso-8859-7';
if ($Tk::VERSION >=3D 804) {
$encoding =3D 'utf-8';
} else {
$encoding =3D 'iso-8859-7';
}

$pdfFont =3D '/home/pajas/.fonts/arial.ttf';
$TEXT =3D $ARGV[1] || "=C1=C2=C3=C4=C5=C6=C7=C8=C9=CA=CB=CC=CD=CE=CFDx=D0=
=D1=D3=D4=D5=D6=D7=D8=D9=DA=DB=DC=DD=DE=DFEx=E0=E1=E2=E3=E4=E5=E6=E7=E8=E9=
=EA=EB=EC=ED=EE=EFFx=F0=F1=F2=F3=F4=F5=F6=F7=F8=F9=FA=FB=FC=FD=FE";


$top =3D MainWindow->new;
$c=3D$top->Canvas(-width =3D> 300, -height =3D> 300);

# draw various stuff
$c->createOval(10,10,20,20,-fill =3D> 'white',-outline =3D> 'black');
$c->createOval(-10,290,10,310,-fill =3D> 'red',-outline =3D> 'black');

$c->createPolygon(100,100,150,120,200,100,180,150,200,200,150,180,100,200,1=
20,150,-fill =3D> 'orange',-outline =3D> 'black',-smooth=3D>1);

$c->createRectangle(98,98,202,202,-outline =3D> 'green');
$c->createRectangle(122,122,178,178,-outline =3D> 'green');
$c->createPolygon(150,120,180,150,150,180,120,150,-outline =3D> 'green',-fi=
ll=3D>undef);

$line=3D$c->createLine(15,15,50,50,40,90,-arrow =3D> both,-dash =3D> [6,14,=
2,4,2,4]);
my $x=3D70;
my $y=3D30;
foreach (qw(e w n s ne se nw sw center)) {
$c->createText($x,$y,-text =3D> "yQ$_ $TEXT", -anchor =3D> $_);
$c->createOval($x-1,$y-1,$x+1,$y+1,-fill =3D> 'red',-outline =3D> 'red');
$y+=3D30;
}


$c->pack;

# use detailed API, rotation, scale, translation, media, ...
$b=3D$top->Button(-text =3D> 'print PDF1',
-command =3D> sub {
my $P =3D Tk::Canvas::PDF->new(-media =3D> [0,0,300,300],
-encoding =3D> $encoding,
-ttfont =3D> $pdfFont);
$P->new_page();
$P->draw_canvas($c,
-rotate =3D> -75,
-scale =3D> [1,0.5],
-translate =3D> [100,300]
);
$P->finish(-file =3D> "$0.pdf");
print "Created $0.pdf\n";
$top->destroy();
})->pack();

$b2=3D$top->Button(-text =3D> 'print PDF2',
-command =3D> sub {
$c->pdf(-file =3D> "$0.pdf",
-encoding =3D> $encoding,
-ttfont =3D> $pdfFont);
print "Created $0.pdf\n";
$top->destroy();
})->pack();

$b2=3D$top->Button(-text =3D> 'print postscript',
-command =3D> sub {
open PS, ">$0.ps";
print PS $c->postscript();
close PS;
})->pack();

MainLoop;

--Boundary-01=_T+ZrBXOyvuO1Tkr

package Tk::Canvas::PDF;

eval "use Encode";

=item $canvas->pdf(options)

=over 4

=item -media => media-name

=item -ttfont => filename

=item -font => name

PDF corefont filename

=item -file => filename

output filename

=back

=cut

sub new {
my ($class,%opts)=@_;

# TODO: dashoffset

if ($opts{-grayscale}) {
$color = color2gray($color) if defined $color;
$outlinecolor = color2gray($outlinecolor);
}

my $smooth = $canvas->itemcget($item,"-smooth");
# TODO: dashoffset
$draw->linewidth($width);
$draw->linedash(@dash);
$draw->linejoin($join{$join});
$draw->strokecolor($outlinecolor) if defined($color);
$draw->fillcolor($color) if defined($color);

__debug "Polygon: @c\n";
if ($smooth) {
no integer;
my @c=(@coords,@coords[0..3]);
my $first=1;
while (@c>5) {
my @d = (($c[2]+$c[0])/2,($c[3]+$c[1])/2,$c[2],$c[3],($c[4]+$c[2])/2,($c[5]+$c[3])/2);
$draw->move(@d[0,1]) if $first;
$draw->curve(@d[2,3,2,3,4,5]);
splice @c,0,2;
$first = 0;
}
$draw->close();
if (defined $color) {
$draw->fillstroke(0);
} else {
$draw->stroke;
}
} else {
$draw->poly(@coords,@coords[0,1]);
if (defined $color) {
$draw->fillstroke(0);

package Tk::Canvas;

1;

--Boundary-01=_T+ZrBXOyvuO1Tkr--

--nextPart2761029.FO2SFpG3F3
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQBBrZ+ZQfxdLDi03+IRArG0AJsFipcRYP18e/eEWDdT+CqXV4d3XQCfU6y1
ID0fMdT2/668LKmtG/AbLKU=
=p0xo
-----END PGP SIGNATURE-----

--nextPart2761029.FO2SFpG3F3--

0 new messages