add eps preview to config, for RT#5025
authorivan <ivan>
Tue, 17 Mar 2009 09:58:17 +0000 (09:58 +0000)
committerivan <ivan>
Tue, 17 Mar 2009 09:58:17 +0000 (09:58 +0000)
FS/FS/Conf.pm
FS/FS/Mason.pm
FS/FS/Misc/eps2png.pm [new file with mode: 0644]
httemplate/config/config-image.cgi
httemplate/config/config-view.cgi
httemplate/docs/credits.html
httemplate/docs/license.html

index 3f150e1..8ea5730 100644 (file)
@@ -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
   },
 
index ee777a4..bcdc2fe 100644 (file)
@@ -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 (file)
index 0000000..49c1d56
--- /dev/null
@@ -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; #<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;
index 892f7c6..0de9d42 100644 (file)
@@ -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;
+
 </%init>
index 0f5fd62..f2ae892 100644 (file)
@@ -69,22 +69,32 @@ Click on a configuration value to change it.
 %   } elsif (   $type eq 'image' ) {
 
             <tr>
-
-              <% $conf->exists($i->key, $agentnum)
-                   ? '<img src="config-image.cgi?key='.      $i->key.
-                                               ';agentnum='. $agentnum. '">'
-                   : 'empty'
-              %>
+              <td bgcolor='#ffffff'>
+                <% $conf->exists($i->key, $agentnum)
+                     ? '<img src="config-image.cgi?key='.      $i->key.
+                                                 ';agentnum='. $agentnum. '">'
+                     : 'empty'
+                %>
+              </td>
+            </tr>
+            <tr>
+              <td>
+                <% $conf->exists($i->key, $agentnum)
+                     ? qq!<a href="config-download.cgi?key=!. $i->key. ';agentnum='. $agentnum. qq!">download</a>!
+                     : ''
+                %>
+              </td>
             </tr>
 
 %   } elsif (   $type eq 'binary' ) {
 
             <tr>
-
-              <% $conf->exists($i->key, $agentnum)
-                   ? qq!<a href="config-download.cgi?key=!. $i->key. ';agentnum='. $agentnum. qq!">download</a>!
-                   : 'empty'
-              %>
+              <td>
+                <% $conf->exists($i->key, $agentnum)
+                     ? qq!<a href="config-download.cgi?key=!. $i->key. ';agentnum='. $agentnum. qq!">download</a>!
+                     : 'empty'
+                %>
+              </td>
             </tr>
 
 %   } elsif (    $type eq 'textarea'
index 3c5564d..38d384b 100644 (file)
@@ -33,7 +33,7 @@
 
 <CENTER>
 
-<H3>Core team</H3>
+<H3>Core Team</H3>
 Peter Bowen<BR>
 Jeff Finucane<BR>
 Jason Hall<BR>
@@ -42,6 +42,11 @@ Ivan Kohler<BR>
 Richard Siddall<BR>
 <BR>
 
+<H3>Core Emeritus</H3>
+Brian McCane<BR>
+Matt Simerson<BR>
+<BR>
+
 <H3>Contributors</H3>
 Stephen Amadei<BR>
 Eric Arvidsson<BR>
@@ -57,6 +62,7 @@ Rebecca Cardennis<BR>
 Shane Chrisp<BR>
 Luke Crawford<BR>
 Brad Dameron<BR>
+Jeremy Davis<BR>
 Dave Denney<BR>
 Serge Dolgov<BR>
 Scott Edwards<BR>
@@ -74,19 +80,18 @@ Greg Kuhnert<BR>
 Randall Lucas<BR>
 Foteos Macrides<BR>
 Roger Mangraviti<BR>
-Brian McCane<BR>
 mimooh<BR>
 Mack Nagashima<BR>
 Matt Peterson<BR>
 Luke Pfeifer<BR>
 Ricardo Signes<BR>
-Matt Simerson<BR>
 Steve Simitzis<BR>
 Jason Spence<BR>
 James Switzer<BR>
 Audrey Tang<BR>
 Jason Thomas<BR>
 Jesse Vincent<BR>
+Johan Vromans<BR>
 Mark Wells<BR>
 Peter Wemm<BR>
 Mark Williamson<BR>
index 5453730..a673bc9 100644 (file)
@@ -100,6 +100,10 @@ terms of the BSD license.<BR>
 &copy; 2005 modernmethod, inc<BR>
 Perl backend version &copy; 2005 Nathan Schmidt
 
+<P>
+Contains code derived from eps2png by Johan Vromans, licensed under the same
+terms as Perl (GPL/Artistic).
+
 <!-- artwork -->
 
 <P>