From 2755d4a4810600f4392eaf73f362b4f358adeec6 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 09:58:17 +0000 Subject: [PATCH] add eps preview to config, for RT#5025 --- FS/FS/Conf.pm | 2 +- FS/FS/Mason.pm | 1 + FS/FS/Misc/eps2png.pm | 278 +++++++++++++++++++++++++++++++++++++ httemplate/config/config-image.cgi | 5 +- httemplate/config/config-view.cgi | 32 +++-- httemplate/docs/credits.html | 11 +- httemplate/docs/license.html | 4 + 7 files changed, 317 insertions(+), 16 deletions(-) create mode 100644 FS/FS/Misc/eps2png.pm diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 3f150e1e7..8ea57304c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2304,7 +2304,7 @@ worry that config_items is freeside-specific and icky. 'key' => 'logo.eps', 'section' => 'billing', #? 'description' => 'Company logo for printed and PDF invoices, in EPS format.', - 'type' => 'binary', + 'type' => 'image', 'per_agent' => 1, #XXX as above, kinda }, diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ee777a485..bcdc2fe8e 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -91,6 +91,7 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. use FS::UI::bytecount; use FS::Msgcat qw(gettext geterror); use FS::Misc qw( send_email send_fax states_hash counties state_label ); + use FS::Misc::eps2png qw( eps2png ); use FS::Report::Table::Monthly; use FS::TicketSystem; use FS::Tron qw( tron_lint ); diff --git a/FS/FS/Misc/eps2png.pm b/FS/FS/Misc/eps2png.pm new file mode 100644 index 000000000..49c1d5682 --- /dev/null +++ b/FS/FS/Misc/eps2png.pm @@ -0,0 +1,278 @@ +package FS::Misc::eps2png; + +#based on eps2png by Johan Vromans +#Copyright 1994,2008 by Johan Vromans. +#This program is free software; you can redistribute it and/or +#modify it under the terms of the Perl Artistic License or the +#GNU General Public License as published by the Free Software +#Foundation; either version 2 of the License, or (at your option) any +#later version. + +use strict; +use vars qw( @ISA @EXPORT_OK ); +use Exporter; +use File::Temp; +use File::Slurp qw( slurp ); +#use FS::UID; + +@ISA = qw( Exporter ); +@EXPORT_OK = qw( eps2png ); + +################ Program parameters ################ + +# Some GhostScript programs can produce GIF directly. +# If not, we need the PBM package for the conversion. +# NOTE: This will be changed upon install. +my $use_pbm = 0; + +my $res = 82; # default resolution +my $scale = 1; # default scaling +my $mono = 0; # produce BW images if non-zero +my $format; # output format +my $gs_format; # GS output type +my $output; # output, defaults to STDOUT +my $antialias = 8; #4; # antialiasing +my $DEF_width; # desired widht +my $DEF_height; # desired height +#my $DEF_width = 90; # desired widht +#my $DEF_height = 36; # desired height + +my ($verbose,$trace,$test,$debug) = (0,0,0,1); +#handle_options (); +set_out_type ('png'); # unless defined $format; +warn "Producing $format ($gs_format) image.\n" if $verbose; + +$trace |= $test | $debug; +$verbose |= $trace; + +################ Presets ################ + +################ The Process ################ + +my $err = 0; + +sub eps2png { + my( $eps, %options ) = @_; #well, no options yet + + my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc; + my $eps_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.eps', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + print $eps_file $eps; + close $eps_file; + + my @eps = split(/\r?\n/, $eps); + + warn "converting eps (". length($eps). " bytes, ". scalar(@eps). " lines)\n" + ;#if $verbose; + + my $line = shift @eps; #; + unless ( $eps =~ /^%!PS-Adobe.*EPSF-/ ) { + warn "not EPS file (no %!PS-Adobe header)\n"; + return; #empty png file? + } + + my $ps = ""; # PostScript input data + my $xscale; + my $yscale; + my $gotbb; + + # Prevent derived values from propagating. + my $width = $DEF_width; + my $height = $DEF_height; + + while ( @eps ) { + + $line = shift(@eps)."\n"; + + # Search for BoundingBox. + if ( $line =~ /^%%BoundingBox:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/i ) { + $gotbb++; + warn "$eps_file: x0=$1, y0=$2, w=", $3-$1, ", h=", $4-$2 + if $verbose; + + if ( defined $width ) { + $res = 72; + $xscale = $width / ($3 - $1); + if ( defined $height ) { + $yscale = $height / ($4 - $2); + } + else { + $yscale = $xscale; + $height = ($4 - $2) * $yscale; + } + } + elsif ( defined $height ) { + $res = 72; + $yscale = $height / ($4 - $2); + if ( defined $width ) { + $xscale = $width / ($3 - $1); + } + else { + $xscale = $yscale; + $width = ($3 - $1) * $xscale; + } + } + unless ( defined $xscale ) { + $xscale = $yscale = $scale; + # Calculate actual width. + $width = $3 - $1; + $height = $4 - $2; + # Normal PostScript resolution is 72. + $width *= $res/72 * $xscale; + $height *= $res/72 * $yscale; + # Round up. + $width = int ($width + 0.5) + 1; + $height = int ($height + 0.5) + 1; + } + warn ", width=$width, height=$height\n" if $verbose; + + # Scale. + $ps .= "$xscale $yscale scale\n" + if $xscale != 1 || $yscale != 1; + + # Create PostScript code to translate coordinates. + $ps .= (0-$1) . " " . (0-$2) . " translate\n" + unless $1 == 0 && $2 == 0; + + # Include the image, show and quit. + $ps .= "($eps_file) run\n". + "showpage\n". + "quit\n"; + + last; + } + elsif ( $line =~ /^%%EndComments/i ) { + last; + } + } + + unless ( $gotbb ) { + warn "No bounding box in $eps_file\n"; + return; + } + + #it would be better to ask gs to spit out files on stdout, but c'est la vie + + #my $out_file; # output file + #my $pbm_file; # temporary file for PBM conversion + + my $out_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.png', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + + my $pbm_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.pbm', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + + # Note the temporary PBM file is created where the output file is + # located, since that will guarantee accessibility (and a valid + # filename). + warn "Creating $out_file\n" if $verbose; + + my $gs0 = "gs -q -dNOPAUSE -r$res -g${width}x$height"; + my $gs1 = "-"; + $gs0 .= " -dTextAlphaBits=$antialias -dGraphicsAlphaBits=$antialias" + if $antialias; + if ( $format eq 'png' ) { + mysystem ("$gs0 -sDEVICE=". ($mono ? "pngmono" : $gs_format). + " -sOutputFile=$out_file $gs1", $ps); + } + elsif ( $format eq 'jpg' ) { + mysystem ("$gs0 -sDEVICE=". ($mono ? "jpeggray" : $gs_format). + " -sOutputFile=$out_file $gs1", $ps); + } + elsif ( $format eq 'gif' ) { + if ( $use_pbm ) { + # Convert to PPM and use some of the PBM converters. + mysystem ("$gs0 -sDEVICE=". ($mono ? "pbm" : "ppm"). + " -sOutputFile=$pbm_file $gs1", $ps); + # mysystem ("pnmcrop $pbm_file | ppmtogif > $out_file"); + mysystem ("ppmtogif $pbm_file > $out_file"); + unlink ($pbm_file); + } + else { + # GhostScript has GIF drivers built-in. + mysystem ("$gs0 -sDEVICE=". ($mono ? "gifmono" : "gif8"). + " -sOutputFile=$out_file $gs1", $ps); + } + } + else { + warn "ASSERT ERROR: Unhandled output type: $format\n"; + exit (1); + } + +# unless ( -s $out_file ) { +# warn "Problem creating $out_file for $eps_file\n"; +# $err++; +# } + + slurp($out_file); + +} + +exit 1 if $err; + +################ Subroutines ################ + +sub mysystem { + my ($cmd, $data) = @_; + warn "+ $cmd\n" if $trace; + if ( $data ) { + if ( $trace ) { + my $dp = ">> " . $data; + $dp =~ s/\n(.)/\n>> $1/g; + warn "$dp"; + } + open (CMD, "|$cmd") or die ("$cmd: $!\n"); + print CMD $data; + close CMD or die ("$cmd close: $!\n"); + } + else { + system ($cmd); + } +} + +sub set_out_type { + my ($opt) = lc (shift (@_)); + if ( $opt =~ /^png(mono|gray|16|256|16m|alpha)?$/ ) { + $format = 'png'; + $gs_format = $format.(defined $1 ? $1 : '16m'); + } + elsif ( $opt =~ /^gif(mono)?$/ ) { + $format = 'gif'; + $gs_format = $format.(defined $1 ? $1 : ''); + } + elsif ( $opt =~ /^(jpg|jpeg)(gray)?$/ ) { + $format = 'jpg'; + $gs_format = 'jpeg'.(defined $2 ? $2 : ''); + } + else { + warn "ASSERT ERROR: Invalid value to set_out_type: $opt\n"; + exit (1); + } +} + +# 'antialias|aa=i' => \$antialias, +# 'noantialias|noaa' => sub { $antialias = 0 }, +# 'scale=f' => \$scale, +# 'width=i' => \$width, +# 'height=i' => \$height, +# 'resolution=i' => \$res, + +# die ("Antialias value must be 0, 1, 2, 4, or 8\n") + +# -width XXX desired with +# -height XXX desired height +# -resolution XXX resolution (default = $res) +# -scale XXX scaling factor +# -antialias XX antialias factor (must be 0, 1, 2, 4 or 8; default: 4) +# -noantialias no antialiasing (same as -antialias 0) + +1; diff --git a/httemplate/config/config-image.cgi b/httemplate/config/config-image.cgi index 892f7c65b..0de9d4278 100644 --- a/httemplate/config/config-image.cgi +++ b/httemplate/config/config-image.cgi @@ -1,4 +1,4 @@ -<% $conf->config_binary($name, $agentnum) %> +<% $logo %> <%init> die "access denied" @@ -16,4 +16,7 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { $agentnum = $1; } +my $logo = $conf->config_binary($name, $agentnum); +$logo = eps2png($logo) if $name =~ /\.eps$/i; + diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 0f5fd6213..f2ae892a6 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -69,22 +69,32 @@ Click on a configuration value to change it. % } elsif ( $type eq 'image' ) { - - <% $conf->exists($i->key, $agentnum) - ? '' - : 'empty' - %> + + <% $conf->exists($i->key, $agentnum) + ? '' + : 'empty' + %> + + + + + <% $conf->exists($i->key, $agentnum) + ? qq!download! + : '' + %> + % } elsif ( $type eq 'binary' ) { - - <% $conf->exists($i->key, $agentnum) - ? qq!download! - : 'empty' - %> + + <% $conf->exists($i->key, $agentnum) + ? qq!download! + : 'empty' + %> + % } elsif ( $type eq 'textarea' diff --git a/httemplate/docs/credits.html b/httemplate/docs/credits.html index 3c5564da3..38d384bcf 100644 --- a/httemplate/docs/credits.html +++ b/httemplate/docs/credits.html @@ -33,7 +33,7 @@
-

Core team

+

Core Team

Peter Bowen
Jeff Finucane
Jason Hall
@@ -42,6 +42,11 @@ Ivan Kohler
Richard Siddall

+

Core Emeritus

+Brian McCane
+Matt Simerson
+
+

Contributors

Stephen Amadei
Eric Arvidsson
@@ -57,6 +62,7 @@ Rebecca Cardennis
Shane Chrisp
Luke Crawford
Brad Dameron
+Jeremy Davis
Dave Denney
Serge Dolgov
Scott Edwards
@@ -74,19 +80,18 @@ Greg Kuhnert
Randall Lucas
Foteos Macrides
Roger Mangraviti
-Brian McCane
mimooh
Mack Nagashima
Matt Peterson
Luke Pfeifer
Ricardo Signes
-Matt Simerson
Steve Simitzis
Jason Spence
James Switzer
Audrey Tang
Jason Thomas
Jesse Vincent
+Johan Vromans
Mark Wells
Peter Wemm
Mark Williamson
diff --git a/httemplate/docs/license.html b/httemplate/docs/license.html index 54537307e..a673bc9dd 100644 --- a/httemplate/docs/license.html +++ b/httemplate/docs/license.html @@ -100,6 +100,10 @@ terms of the BSD license.
© 2005 modernmethod, inc
Perl backend version © 2005 Nathan Schmidt +

+Contains code derived from eps2png by Johan Vromans, licensed under the same +terms as Perl (GPL/Artistic). +

-- 2.11.0