#!/usr/bin/perl # web interface cgi script to gif2png # Copyright (C) 2003-2004 Richard Stanway # # This program is free software; you can redistribute it and/or modify # it under the terms of 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # http://www.gnu.org/licenses/gpl.txt # # Live demo: http://www.r1ch.net/stuff/gif2png/webinterface/ #required modules use CGI; use HTTP::Date; use Digest::SHA1; use Fcntl ':flock'; #barf totally at 250kB uploads $CGI::POST_MAX = 1024 * 250; #binaries and directories needed - note, tempdir and stats #must be writable by whoever the cgi runs as! $tempdir = '/home/r1ch/gif2png/temp'; $statsfile = '/home/r1ch/gif2png/stats'; $gif2png_location = '/home/r1ch/gif2png/gif2png'; $pngcrush_location = '/home/r1ch/gif2png/pngcrush'; #load an already converted image if ($ENV{'REQUEST_URI'} =~ /loadimg\/(.+)\//) { $match = $1; #illegal request if ($match !~ /^[a-fA-F0-9]{40}$/) { print "Status: 403 Unauthorized\nContent-type: text/plain\n\nIllegal request."; exit (1); } #tell browser to use cached version if ($ENV{'HTTP_IF_MODIFIED_SINCE'} ne '' || $ENV{'HTTP_IF_MATCH'} ne '') { print "Status: 304 Not Modified\n\n"; exit(0); } #open existing temp image $fname = "$tempdir/gif2pngcgitemp" . $match; $last_modified = (stat($fname))[9]; open (GIF2PNG, "$fname.png") or perror(); if (read(GIF2PNG, $buffer, 1024)) { #file exists, dump it to browser print "Content-type: image/png\n"; print "Last-Modified: " . time2str($last_modified) . "\n\n"; print $buffer; while (read(GIF2PNG, $buffer, 1024)) { print $buffer; } exit(0); } else { #file is missing, probably pruned perror(); } } $query = new CGI; $file_handle = $query->upload('file'); print < gif2png web interface

gif2png web interface

EOF #read stats open (STATS, "<$statsfile"); @stats = ; close (STATS); if ($file_handle eq '') { #no image uploaded, show form $gifkb = sprintf ("%.3f", $stats[1] / 1024.0 / 1024.0); $pngkb = sprintf ("%.3f", $stats[2] / 1024.0 / 1024.0); $avpercent = sprintf ("%.2f%%", 100 - (($stats[2] / $stats[1]) * 100)); print <Upload a .gif file and it will be converted to an optimized PNG file which has no quality loss and is usually smaller than the original .gif. The maximum permitted size .gif is 250kb. Please keep in mind PNG does not support animations, hence animated .gif files will not be accepted.

For 99.9% of browsers, the output PNG file will display exactly the same as the .gif file, including transparency. PNG files work on Internet Explorer 4.0+, Netscape 4.0+, Mozilla, and many more browsers.

$stats[0] files processed: $gifkb MB of .gif files converted to $pngkb MB of .png files. Average saving of $avsave $avpercent per file. Original site (GPL'ed source available).

EOF } else { #image uploaded, process it srand(time()); $fh = $query->upload('file'); binmode ($fh); #get unique temp filename $fcode = Digest::SHA1::sha1_hex($ENV{REMOTE_ADDR}.time().$$.$query->param ('file')); $fname = "$tempdir/gif2pngcgitemp" . $fcode; #write upload to temp file open (GIF2PNG, ">$fname.gif") or error(); binmode (GIF2PNG); $bytestotal = 0; if ($bytesread = read($fh, $buffer, 1024)) { print 'Converting file, please wait...'; $donemsg = 1; print GIF2PNG $buffer; $bytestotal += $bytesread; while ($bytesread = read($fh, $buffer, 1024)) { $bytestotal += $bytesread; print GIF2PNG $buffer; } close (GIF2PNG); if ($bytestotal == 0) { $errdetails = "upload failure."; error(); } #run gif2png $undef = `$gif2png_location -a $fname.gif 2>&1`; $beforec = (stat("$fname.png"))[7]; if ($beforec > 0) { #run pngcrush on the resultant png (assuming one is made) @undef = `ulimit -v 16384 ; ulimit -m 16384 ; ulimit -l 16384 ; $pngcrush_location -rem alla -brute -l 8 $fname.png $fname-crushed.png`; $afterc = (stat("$fname-crushed.png"))[7]; if ($afterc < $beforec) { unlink ("$fname.png"); rename ("$fname-crushed.png", "$fname.png"); } else { unlink ("$fname-crushed.png"); } } else { #gif2png failed for some reason, find out why if ($undef =~ /is animated/) { $errdetails = "upload was an animated .gif (png does not support animation)"; } elsif ($undef =~ /not a GIF file/) { $errdetails = "upload was not a valid .gif file"; } else { $errdetails = "gif2png failure."; } unlink ("$fname.gif"); error(); } #conversion/crushing finished ok $fsize = (stat("$fname.png"))[7]; print "\n\n"; $donemsg = 0; if ($fsize == 0) { $errdetails = "pngcrush failure."; error(); } $userfname = $query->param ('file'); if ($userfname =~ /(.*(\\|\/))*(.+)$/) { $userfname = $3; } if ($userfname eq '') { $userfname = "tempupload.gif"; } $pngname = $userfname; $pngname =~ s/\.gif$/\.png/i; $pcc = int(100 - (($fsize / $bytestotal) * 100)); print <Original image ($userfname): $bytestotal bytes.

Optimized .png image ($pngname): $fsize bytes ($pcc% smaller):

Please save the above .png file to your hard disk if you wish to keep it. It will be deleted from this server in one hour. Right-click here and choose 'save link target' or 'save target as' to save this .png

Convert another

EOF #update stats $stats[0]++; $stats[1] += $bytestotal; $stats[2] += $fsize; $stats[3] += ($beforec - $fsize); open (STATS, ">$statsfile"); flock(STATS,LOCK_EX); seek(STATS, 0, 2); foreach (@stats) { s/[\r|\n]//g; print STATS "$_\n"; } flock(STATS,LOCK_UN); close (STATS); } else { $errdetails = "upload failure."; error(); } } #die with 404 and error sub perror() { print "Status: 404 Not Found\nContent-type: text/plain\n\nInvalid image."; exit (1); } #die with an error sub error() { if ($donemsg == 1 ) { print ""; } print "

Error: $errdetails

Try again

"; exit(1); } #1 end