eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q' if 0; use strict; # ============================================================================== # psftopst # Version 1.0 (Mercredi 19 octobre 2011) Jean-Michel Sarlat # Ce script fait partie du projet pst-anamorphosis (Gilg, Luque, Sarlat) # http://melusine.eu.org/syracuse/G/pst-anamorphosis Checkout # http://melusine.eu.org/syracuse/G/git/?p=pst-anamorphosis.git git # ============================================================================== our $windows_pstoedit = 'chemin vers pstoedit.exe'; our $on_windows = $^O =~ /^MSWin/; our $GS = $on_windows ? "gswin32c" : "gs"; our $PS = $on_windows ? $windows_pstoedit : "pstoedit"; # === Acquisition des options de la ligne de commande ------------------------- $::opt_dimmax = 4; # Dimension maximale : 4 cm par défaut $::opt_ps = 0; # Transformation initiale par pstoedit use Getopt::Long; GetOptions( "dimmax=s", "ps" ); our $debug = 1; our $GSBBOX = "$GS -sDEVICE=bbox -dBATCH -dNOPAUSE -dNOSAFER -P -c save pop -f"; our $cm = 28.3464567; our $Fichier = $ARGV[0]; -f $Fichier or die "Fichier <$Fichier> introuvable !\n"; our ($Nom, $Dir, $Ext) = &FichierNRE($Fichier); # === Transformation éventuelle par pstoedit ----------------------------------- if ($::opt_ps) { use File::Copy; my $f = "$Nom-original.$Ext"; copy($Fichier, $f); my @a = ($PS, "-f", "ps", $f, $Fichier); $debug and print STDERR "Processing by pstoedit...\n"; system(@a) == 0 or die "Running pstoedit failed\nCommand :".join(" ",@a)."\n"; $debug and print STDERR "Ok!\n"; } # ============================================================================== our $ps = &FichierListe($Fichier); our $table = []; our @Bbox = (); our $cmyk = {}; our $centrex = 0; our $centrey = 0; our $facteur = 1; our $DimMax = $::opt_dimmax; our $PageSizeX = 0; our $PageSizeY = 0; our @currentpoint = (); our @lastpoint = (); our $dmax = 0; # ============================================================================== # === Analyse # ============================================================================== $$table[0] = { fichier => $Fichier, source => &FichierScalaire($Fichier), createur => "psftopst" }; &LecturePostScript($table, $ps); $$table[0]->{bbox} = \@Bbox; # ============================================================================== # === Production # ============================================================================== our $pst = &EcritureFichierPST($table, $Nom); open PST, ">$Nom.pst" and print PST $pst and close PST; # ============================================================================== sub EcritureFichierPST { my ($r, $n) = @_; my $c = $$r[0]->{cmyk}; my $nc = 1; my $out = "%\@PATRON:pstricks\n"; $out .= "\\makeatletter\n\\def\\psfs\@asolid{\\pst\@fill{\\pst\@usecolor\\psfillcolor eofill}}\n\\makeatother\n"; # Définition des couleurs dans le fichier pstricks # Elles sont reprises dans la table représentant le fichier ps $out .= "%\@COULEURS:\n"; foreach (@$c) { my $roman = &Roman($nc); $$cmyk{$_} = "Couleur$roman"; s/\s/\,/g; $out .= "\\definecolor{Couleur$roman}{cmyk}{$_}\n"; $nc++; } # Acquisition du centre de l'image my $b = $$r[0]->{bbox}; $out .= "%\@BOUNDINGBOX: " . join(" ", @$b) . "\n"; $centrex = ($$b[2] + $$b[0]) / 2; $centrey = ($$b[3] + $$b[1]) / 2; $out .= "%\@TRANSLATION: -($centrex,$centrey)\n"; my $l = ($$b[2] - $$b[0]); my $h = ($$b[3] - $$b[1]); my $max = $l; $max = $h if $h > $l; $facteur = $DimMax / $max; $out .= "%\@FACTEUR: $facteur\n"; my $abox = &xy_couple_modifie($b); $out .= "%\@PSPICTURE:\n"; $out .= "% \\begin{pspicture}$abox\n"; if ($PageSizeX) { my $clipframe = &xy_couple_modifie([0, 0, $PageSizeX, $PageSizeY]); $out .= "%\@CLIPPING: $PageSizeX $PageSizeY\n"; $out .= "% \\begin{psclip}{\\psframe[linestyle=none]$clipframe}\n"; } $out .= "%\@PICTURE:\n"; # Éléments de construction for (my $i = 1; $i < scalar @$r; $i++) { if ($$r[$i]->{path}) { $out .= "%% Path : $i\n"; my $couleur = $$cmyk{$$r[$i]->{setcmykcolor}}; my $epaisseur = $$r[$i]->{setlinewidth}; $epaisseur = sprintf("linewidth=%0.5fpt", $epaisseur * $facteur * $cm); my $t = $$r[$i]->{type}; $t eq "fill" and $out .= "\\pscustom[fillstyle=solid,fillcolor=$couleur,linestyle=none]{\n"; $t eq "eofill" and $out .= "\\pscustom[fillstyle=asolid,fillcolor=$couleur,linestyle=none]{\n"; $t eq "clip" and $out .= "\\psclip{\\psframe[fillstyle=none,linestyle=none]$abox}\%\n\\pscustom{\n"; $t eq "stroke" and $out .= "\\pscustom[$epaisseur,linecolor=$couleur]{\n"; my $p = $$r[$i]->{path}; my $n = $$r[$i]->{closepath}; foreach (@$p) { my %e = %$_; $e{t} eq "moveto" and $out .= "\\moveto".&xy_couple_modifie($e{p}); $e{t} eq "lineto" and $out .= "\\psline".&xy_couple_modifie($e{p}); $e{t} eq "curveto" and $out .= "\\psbezier".&xy_couple_modifie($e{p}); $e{t} eq "closepath" and $out .= "\\closepath"; $out .= "\n"; @lastpoint = @currentpoint; } $out .= "}\n"; $$r[$i]->{type} eq "clip" and $out .= "\\endpsclip\n"; } } $out .= "%\@---\n"; $out .= "% \\end{psclip}\n" if $PageSizeX; $out .= "% \\end{pspicture}\n"; } sub LecturePostScript { my ($t, $p) = @_; my $pathnumber = 0; my $natpath = ""; my $path = []; my $fpath = 0; my $niveau = 0; my $nclosepath = 0; # Nombre de closepath rencontrés foreach (@$p) { /^\%\s*(\d+)\s+pathnumber/ and $pathnumber = $1 and $$t[$pathnumber] = {}; /^\s*gsave/ and $niveau++; /^\s*grestore/ and $niveau--; s/setPageSize\s*$// and &setPageSize($_); /^\%\%BoundingBox\: ([\d\.-]+) ([\d\.-]+) ([\d\.-]+) ([\d\.-]+)/ and &setBbox($1,$2,$3,$4); if ($pathnumber) { /^\%\s*filledpath/ and $natpath = "filledpath" and next; /^\%\s*eofilledpath/ and $natpath = "eofilledpath" and next; /^\%\s*strokedpath/ and $natpath = "strokedpath" and next; /^\%\s*clippath/ and $natpath = "clippath" and next; /setlinewidth$/ and $$t[$pathnumber]->{setlinewidth} = &setlinewidth($_) and next; /setcmykcolor$/ and $$t[$pathnumber]->{setcmykcolor} = &setcmykcolor($_) and next; /^newpath/ and $fpath = 1 and $path = [] and next; if ($fpath) { s/moveto\s*$// and push(@$path, {t => "moveto", p => &xy($_)}); s/lineto\s*$// and push(@$path, {t => "lineto", p => &xy($_)}); s/curveto\s*$// and push(@$path, {t => "curveto", p => &xy($_)}); /closepath/ and push(@$path, {t => "closepath", p => 1}) and $nclosepath++; if (/(stroke)/ or /(eofill)/ or /(fill)/ or /(clip)/) { $fpath = 0; $$t[$pathnumber]->{path} = $path; $$t[$pathnumber]->{type} = $1; $$t[$pathnumber]->{niveau} = $niveau; $$t[$pathnumber]->{closepath} = $nclosepath; $pathnumber = 0; $nclosepath = 0; } } } } $$t[0]->{cmyk} = []; foreach (keys %$cmyk) { push @{$$t[0]->{cmyk}}, $_; } } sub setPageSize { my $s = shift; $s =~ s/^\s*|\s*$//g; ($PageSizeX, $PageSizeY) = split /\s+/, $s; } sub setlinewidth { my $s = shift; $s =~ s/^\s*|\s+setlinewidth$//g; return $s; } sub setcmykcolor { my $s = shift; $s =~ s/^\s*|\s+setcmykcolor$//g; $$cmyk{$s} = 1; return $s; } sub xy { my $s = shift; $s =~ s/^\s*|\s*$//g; my @xy = split /\s+/, $s; return \@xy; } sub xy_couple_modifie { my $xy = shift; my @l = @$xy; @currentpoint = ($l[-2],$l[-1]); my $s = ""; while (my ($x, $y) = splice(@l, 0, 2)) { $s .= sprintf("(%0.8f,%0.8f)", ($x - $centrex) * $facteur, ($y - $centrey) * $facteur); } return $s; } # === Contenu d'un fichier et éléments du nom ---------------------------------- # ------------------------------------------------------------------------------ # Contenu sous forme d'une liste de lignes sub FichierListe { my $f = shift; open(FICH, $f) or die "Le fichier $f est introuvable !\n"; my @l = ; close FICH; chomp @l; return \@l; } # Contenu en un seul élément sub FichierScalaire { my $f = shift; local $/; open(FICH, $f) or die "Le fichier $f est introuvable !\n"; my $c = ; close FICH; return $c; } # Nom, Repertoire et Extension d'un fichier sub FichierNRE { my $f = shift; use File::Basename; my ($n, $r, $e) = fileparse($f,qw{\..*}); $e =~ s/^\.//; return ($n, $r, $e); } # === Acquisition de la BoundingBox -------------------------------------------- sub setBbox { @Bbox = @_; } # === Écriture d'un nombre en chiffres romains --------------------------------- # Code emprunté au module Roman.pm ; http://search.cpan.org/dist/Roman # AUTEURS: # OZAWA Sakuro 1995-1997 # Alexandr Ciornii, C<< >> 2007 # ------------------------------------------------------------------------------ sub Roman { my $arg = shift; 0 < $arg and $arg < 4000 or return undef; my %roman_digit = qw(1 IV 10 XL 100 CD 1000 MMMMMM); my @figure = reverse sort keys %roman_digit; $roman_digit{$_} = [split(//, $roman_digit{$_}, 2)] foreach @figure; my($x, $roman); foreach (@figure) { my($digit, $i, $v) = (int($arg / $_), @{$roman_digit{$_}}); if (1 <= $digit and $digit <= 3) { $roman .= $i x $digit; } elsif ($digit == 4) { $roman .= "$i$v"; } elsif ($digit == 5) { $roman .= $v; } elsif (6 <= $digit and $digit <= 8) { $roman .= $v . $i x ($digit - 5); } elsif ($digit == 9) { $roman .= "$i$x"; } $arg -= $digit * $_; $x = $i; } return $roman; } # === Wanda -------------------------------------------------------------------- sub WandaExecutePlugin { my ($cnf, $elm, $args) = @_; } sub WandaAnalyseLignes { my $cnf = shift; my $l = shift; my $c = {}; my $e = "CORPS"; my @p = (); # Traitement for(my $i=0; $i < scalar @$l; $i++) { if ($$l[$i] =~ /^%@([\da-zA-Z_]+)\s*:\s*(.+?)\s*$/) { # Affectation simple : la valeur suit le nom dans la ligne ----- $$c{$1} = $2; } elsif ($$l[$i] =~ /^%@([\da-zA-Z_]+)\s*:\s*$/) { # Affectation bloc : la valeur est constituée du bloc à suivre - push @p, $e; $e = $1; } elsif ($$l[$i] =~ /^%@\-\-\-/) { # On ferme l'élément en cours... ------------------------------- $e = pop @p; } elsif ($$l[$i] =~ /^%@\@lib:\s*(.+?)\s+$/) { # On ajoute le contenu d'un fichier de la librairie ------------ if (-f "$$cnf{DIR}/lib/$1") { $$c{$e} .= qx{cat "$$cnf{DIR}/lib/$1"} if $e; } } elsif ($$l[$i] =~ /^%@\@inc:\s*(.+?)\s+$/) { # On ajoute le contenu d'un fichier local ---------------------- if (-f $1) { $$c{$e} .= qx{cat $1} if $e; } } elsif ($$l[$i] =~ /^%@\@exec:\s*(.+?)\s+$/) { # On éxécute un plugin ----------------------------------------- $$c{$e} .= &WandaExecutePlugin($cnf, $c, $1); } else { # La ligne est enregistrée dans l'éventuel élément en cours ---- $$c{$e} .= $$l[$i] if $e; } } return $c; } sub WandaAnalyseContenu { my ($cnf, $fichier) = @_; open(SRC, $fichier); my @LIGNES = ; close(SRC); return &WandaAnalyseLignes($cnf, \@LIGNES); }