1: #!/usr/bin/perl
   2: #By Ben Jacobs <dooberwah> 2001
   3: #    "Use": Colors a string with a gradient. The user inputs
   4: #the string and two colors in hexedcimal.
   5: #    Comments welcome, I know this isn't a very efficient
   6: #script but it's the best I could come up with. 
   7: 
   8: # Update 5/24/01: Fixed a bug in the HTML code. Before there was an
   9: # extra </HTML> Tag that was messing some browsers up
  10: 
  11: # Update 5/23/01: You can now see this script in action at
  12: # http://dooberwah.perlmonk.org/cgi-bin/gradient.pl. 
  13: 
  14: # Update 5/22/01: Added in the use of the <b>abs</b> function instead
  15: # of writing my own function to do the exact same thing.
  16: 
  17: use strict;
  18: #use warnings;
  19: 
  20: use CGI;
  21: 
  22: sub hexify {
  23:     my $red = shift;
  24:     my $green = shift;
  25:     my $blue = shift;
  26: 
  27:     my $hexed = sprintf("%.2x%.2x%.2x", $red, $green, $blue);
  28: }
  29: 
  30: sub color {
  31:     my $string = shift;
  32:     my $FromColor = shift;
  33:     my $ToColor = shift;
  34: 
  35:     my @letters = split //, $string;
  36: 
  37:     my ($fromR, $fromG, $fromB) = $FromColor =~/(\w{2})(\w{2})(\w{2})/;
  38:     my ($toR, $toG, $toB) = $ToColor =~ /(\w{2})(\w{2})(\w{2})/; 
  39: 
  40:     $fromR = hex($fromR);
  41:     $toR = hex($toR);
  42: 
  43:     $fromG = hex($fromG);
  44:     $toG = hex($toG);
  45: 
  46:     $fromB = hex($fromB);
  47:     $toB = hex($toB);
  48: 
  49:     my $rstep;
  50:     my $gstep;
  51:     my $bstep;
  52: 
  53:     $rstep = abs($fromR - $toR) / length($string);
  54:     $gstep = abs($fromG - $toG) / length($string);
  55:     $rstep = abs($fromB - $toB) / length($string);
  56: 
  57:     my $happystring;
  58:     my $r;
  59:     my $g;
  60:     my $b;
  61: 
  62:     foreach my $letter (@letters) {
  63:         if($r == 1) { $fromR -= $rstep; } else { $fromR += $rstep; }
  64:         if($g == 1) { $fromG -= $rstep; } else { $fromG += $gstep; } 
  65:         if($b == 1) { $fromB -= $bstep; } else { $fromB += $bstep; } 
  66: 
  67:         if ( $fromR > 255) {
  68:             $r = 1;
  69:         }elsif ( $fromR < 0) {
  70:             $r = 0;
  71:         }
  72: 
  73:         if ( $fromG > 255) {
  74:             $g = 1;
  75:         }elsif ( $fromG < 0) {
  76:             $g = 0;
  77:         }
  78: 
  79:         if ( $fromB > 255) {
  80:             $b = 1;
  81:         }elsif ( $fromB < 0) {
  82:             $b = 0;
  83:         }
  84: 
  85:         my $hexcolors = hexify($fromR, $fromG, $fromB);
  86:         $happystring .= "<FONT COLOR=\"#$hexcolors\">$letter</FONT>";
  87:     }
  88:     $happystring;
  89: }
  90: 
  91: my %input = CGI::Vars();
  92: 
  93: my $string = %input->{'string'};
  94: my $fromcolor = %input->{'fromcolor'};
  95: my $tocolor = %input->{'tocolor'};
  96: 
  97: print "Content type: text/html\n\n";
  98: print "<HTML><HEAD><TITLE>Text Gradient</TITLE></HEAD>\n";
  99: print "<BODY BGCOLOR=\"#000000\" TEXT=\"#e0e0e0\">\n";
 100: 
 101: print "<form action=\"./gradient.pl\" method=\"GET\">\n";
 102: print "String <input type=\"text\" name=\"string\" value=\"$string\"><br>\n";
 103: print "FromColor <input type=\"text\" name=\"fromcolor\" value=\"$fromcolor\"><br>\n";
 104: print "ToColor <input type=\"text\" name=\"tocolor\" value=\"$tocolor\"><br>\n";
 105: print "<input type=\"submit\" value=\"Make it So\">\n";
 106: print "</form>\n";
 107: 
 108: print color($string, $fromcolor, $tocolor) . "<br>\n";
 109: print "</BODY></HEAD>\n";

Replies are listed 'Best First'.
(Ovid) Re: Text Gradient
by Ovid (Cardinal) on May 23, 2001 at 04:04 UTC
    Since dooberwah wrote "Comments welcome", I thought I would toss some in.

    First, I like what you did. It's fun. However, you're not taking full advantage of CGI.pm. I made a few changes to bring in closer to what I would call "production" code. This is a fun script you wrote and I didn't make these changes as criticism. I made them because I have spare time at work and this was fun to play with :)

    Features:

    • Uses taint checking
    • There is no longer any HTML in the code
    • Useful error messages
    • Sticky fields so user doesn't need to re-enter all of the data
    • No longer issues warnings about unitialized variables
    • Uses a hidden field to determine if this is the first time the script has been run. This suppresses error messages on the first run.
    • Now allows users to select the background color for better contrast.
    #!/usr/bin/perl -T #By Ben Jacobs <dooberwah> 2001 # "Use": Colors a string with a gradient. The user inputs # the string and two colors in hexedcimal. # Comments welcome, I know this isn't a very efficient # script but it's the best I could come up with. use strict; use warnings; use CGI qw/:standard/; use HTML::Entities; # Set globals my $error = ''; my $string_length_limit = 50; $|++; # kill buffering # Grab params my $string = param('string'); my $bgcolor = param('bgcolor'); my $fromcolor = param('fromcolor'); my $tocolor = param('tocolor'); # untaint everything my ( $safe_string ) = ( $string =~ /^(.*)$/ ); $safe_string = encode_entities( $safe_string ); my ( $safe_bgcolor ) = ( $bgcolor =~ /^([a-fA-F0-9]{6})$/ ); my ( $safe_fromcolor ) = ( $fromcolor =~ /^([a-fA-F0-9]{6})$/ ); my ( $safe_tocolor ) = ( $tocolor =~ /^([a-fA-F0-9]{6})$/ ); # validate data if ( length $safe_string > $string_length_limit ) { $safe_string = substr $safe_string, 0, $string_length_limit; param( 'string', $safe_string ); # truncate param to 50 characters + so sticky fields # don't overflow $error .= p( 'Length of input string must not be longer than 50 ch +aracters' ); } if ( ! defined $safe_bgcolor ) { $error .= p( '"Background Color" must be a six digit hexadecimal n +umber.' ); } if ( ! defined $safe_fromcolor ) { $error .= p( '"From Color" must be a six digit hexadecimal number. +' ); } if ( ! defined $safe_tocolor ) { $error .= p( '"To Color" must be a six digit hexadecimal number.' +); } my $error_html = ''; if ( $error and param( 'not_first_run' ) ) { $error_html = error( $error ); } print header, start_html( -title => 'Text Gradient', -bgcolor => $bgcolor ), start_form, $error_html, table( { -border => 0, -cellspacing => 0, -cellpadding => 3 }, Tr( [ td( [ 'String', textfield( -name => 'str +ing', -default => 'Thi +s is a test', -size => $str +ing_length_limit, -maxlength => $str +ing_length_limit ) ], ), td( [ 'Background', textfield( -name => 'bgc +olor', -default => 'FFF +FFF', -size => 6, -maxlength => 6 ) +], ), td( [ 'From color', textfield( -name => 'toc +olor', -default => 'FFF +FCC', -size => 6, -maxlength => 6 ) +], ), td( [ 'To color', textfield( -name => 'fro +mcolor', -default => '000 +0CC', -size => 6, -maxlength => 6 ) +], ) ] ) ), submit, hidden( -name => "not_first_run", -value => "yes" ), end_form; print p( color($string, $fromcolor, $tocolor) ) if ! $error; print end_html; sub hexify { my $red = shift; my $green = shift; my $blue = shift; sprintf("%.2x%.2x%.2x", $red, $green, $blue); } sub color { my $string = shift; my $FromColor = shift; my $ToColor = shift; my @letters = split //, $string; my ($fromR, $fromG, $fromB) = ( $FromColor =~ /(\w{2})(\w{2})(\w{2 +})/ ); my ($toR, $toG, $toB) = ( $ToColor =~ /(\w{2})(\w{2})(\w{2 +})/ ); $fromR = hex($fromR); $toR = hex($toR); $fromG = hex($fromG); $toG = hex($toG); $fromB = hex($fromB); $toB = hex($toB); my $rstep; my $gstep; my $bstep; if ( $fromR > $toR) { $rstep = ($fromR - $toR) / length($string); } elsif ( $fromR < $toR) { $rstep = ($toR - $fromR) / length($string); } if ( $fromG > $toG) { $gstep = ($fromG - $toG) / length($string); } elsif ( $fromR < $toR) { $gstep = ($toG - $fromG) / length($string); } if ( $fromB > $toB) { $bstep = ($fromB - $toB) / length($string); } elsif ( $fromR < $toR) { $bstep = ($toB - $fromB) / length($string); } my $happystring = ''; my $r = 0; my $g = 0; my $b = 0; foreach my $letter (@letters) { if($r == 1) { $fromR -= $rstep; } else { $fromR += $rstep; } if($g == 1) { $fromG -= $rstep; } else { $fromG += $gstep; } if($b == 1) { $fromB -= $bstep; } else { $fromB += $bstep; } if ( $fromR > 255) { $r = 1; } elsif ( $fromR < 0) { $r = 0; } if ( $fromG > 255) { $g = 1; } elsif ( $fromG < 0) { $g = 0; } if ( $fromB > 255) { $b = 1; } elsif ( $fromB < 0) { $b = 0; } my $hexcolors = hexify($fromR, $fromG, $fromB); $happystring .= font( { -color => "#$hexcolors" }, $letter ); } $happystring; } sub error { my $error = shift; return ( h1( 'Error in User Input' ) . p( $error ) ); }

    Cheers,
    Ovid

    Update: I've added a few more features since dooberwah is making the code available on his site.

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      Update: Added in the abs function which cuts down code size a bit. I had been using my own abs function of sorts which was very ugly.

      Thanks for the comments. It's great to get helpful commentary like this. While we're on the subject of efficiency I noticed this code:

      if ( $fromR > $toR) { $rstep = ($fromR - $toR) / length($string); } elsif ( $fromR < $toR) { $rstep = ($toR - $fromR) / length($string); }
      is really just the same as abs($fromR - $toR). I'd edit this in but chipmunk currently has me locked out because he's editing it.

      -Ben Jacobs
      one thing i can tell you is you got to be free