Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

ButtonFactory

by t0mas (Priest)
on Jun 28, 2000 at 16:40 UTC ( [id://20139]=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info t0mas@netlords.net
Description: A package that creates custom png buttons.
#!/usr/local/bin/perl -w
#
# ButtonFactory package
# by t0mas@netlords.net
#

package ButtonFactory;

use strict;
use GD;

# libgd should be compiled with TrueType support. The built-in fonts a
+re
# pretty lame IMO (international characters work poorly).

######################################################################
# Config section start

# Location of my ttf fonts
# If set to "", the full path to the font file must be supplied. Windo
+ws
# users might want to set it to c:\\windows\\fonts\\ and *nix users to
# /my/path/to/the/ttf/fonts/
my $FONTDIR="c:\\windows\\fonts\\";

# Fonts will be black or white.
# This value is the breakpoint where it turns white. It is compared to
+ the
# sum of baseR+baseG+baseB. Fonts turn white when this sum drops below
# the breakpoint.
my $FONTCOLORBREAKPOINT=255;

# Height and width of the sides (4 by default)
# Use a sane value > 1 or UltraBad(tm) things will happen
my $SIDE_X_WIDTH=4;
my $SIDE_Y_WIDTH=4;

# Config section end
######################################################################

######################################################################
# My view of a button.
#
# Based on a 4 pixel wide side on all sides :)
#
# Map of the four corners (1-M refers to factors to use)
#
# 69333 333EB
# 97A22 22GCF
# 3A7A2 2GCH5
# 32A83 3DH45
# 32231 15445
#
# 32231 15445
# 32GD5 5KM45
# 3GCH4 4MJM5
# ECH44 44MJL
# BF555 555LI 
#
# Above is the map of the normal (up) state, the pressed state uses
# the same map rotated 180 degrees.
######################################################################

#
# Factors for colors                # on Map
#

my $dark_side_factor =                0.03;    # 4
my $lr_edge_bevel_factor =            0.03;    # M
my $lr_edge_factor =                0.04;    # J
my $llur_b_edge_bevel_factor =        0.24;    # H
my $lr_i_corner_factor =            0.31;    # K
my $dark_edge_factor =                0.44;    # 5
my $lr_o_corner_bevel_factor =        0.47;    # L
my $lr_o_corner_factor =            0.65;    # I
my $llur_edge_factor =                0.72;    # C
my $llur_b_o_corner_bevel_factor =    0.75;    # F
my $llur_i_corner_factor =            0.85;    # D
my $llur_o_corner_factor =            0.95;    # B
my $base_factor =                    1.00;    # 1
my $llur_l_o_corner_bevel_factor =    1.03;    # E
my $llur_l_edge_bevel_factor =        1.07;    # G
my $light_side_factor =                1.17;    # 2
my $light_edge_factor =                1.23;    # 3
my $ul_o_corner_factor =            1.26;    # 6
my $ul_edge_bevel_factor =            1.29;    # A
my $ul_o_corner_bevel_factor =        1.33;    # 9
my $ul_i_corner_factor =            1.39;    # 8
my $ul_edge_factor =                1.41;    # 7

######################################################################
sub new {

    #
    # Create new ButtonFactory
    #

    # Hello, this is me...
    my $self={};

    # Get class and parameters
    my $class=shift;
    
    # Set attributes or defaults 
    $self->{sizeX}=shift    || 100;
    $self->{sizeY}=shift    || 20;
    $self->{baseR}=shift    || 70;
    $self->{baseG}=shift    || 82;
    $self->{baseB}=shift    || 157;
    $self->{text}=shift     || "Hello World";
    $self->{font}=shift     || "arial.ttf";
    $self->{fontsize}=shift || 8;

    # Create images for normal and pressed state
    $self->{imNormal}=new GD::Image($self->{sizeX},$self->{sizeY});
    $self->{imNormalPrinted}=0;
    $self->{imPressed}=new GD::Image($self->{sizeX},$self->{sizeY});
    $self->{imPressedPrinted}=0;

    # Bless and return
    bless $self, $class;
    return $self;
};

######################################################################
sub color {

    #
    # Allocate colors for GD::Image
    #

    # Me
    my $self=shift;

    # Which state
    my $stateName=shift || "imNormal";

    # Factor for this color
    my $factor=shift || 1;

    # Multiply base colors with factor
    my $Red=int($self->{baseR}*$factor);
    my $Green=int($self->{baseG}*$factor);
    my $Blue=int($self->{baseB}*$factor);

    # Validity check
    $Red=$Red>255 ? 255 : $Red;
    $Green=$Green>255 ? 255 : $Green;
    $Blue=$Blue>255 ? 255 : $Blue;

    # Return allocated color
    return $self->{$stateName}->colorAllocate($Red,$Green,$Blue);
};

######################################################################
sub printNormal {

    #
    # Wrapper to print and/or create Normal (up) state
    #

    # Me
    my $self=shift;

    # Check if image is already generated
    if ($self->{imNormalPrinted}) {
        return $self->{imNormal}->png;
    } else {
        return $self->print(1);
        $self->{imNormalPrinted}=1;
    }
};

######################################################################
sub printPressed {

    #
    # Wrapper to print and/or create Pressed (down) state
    #

    # Me
    my $self=shift;

    # Check if image is already generated
    if ($self->{imPressedPrinted}) {
        return $self->{imPressed}->png;
    } else {
        return $self->print(0);
        $self->{imPressedPrinted}=1;
    }
};

######################################################################
sub print {

    #
    # Print a button
    # (Please, don't use me, use printNormal or printPressed instead.)
    #

    # Me
    my $self=shift;

    # Normal or Pressed state?
    my $state=shift;
    my $stateName=$state ? "imNormal" : "imPressed";

    # Allocate colors
    my $base = $self->color($stateName,$base_factor);
    my $light_edge = $self->color($stateName,$light_edge_factor);
    my $ul_o_corner = $self->color($stateName,$ul_o_corner_factor);
    my $ul_edge = $self->color($stateName,$ul_edge_factor);
    my $ul_i_corner = $self->color($stateName,$ul_i_corner_factor);
    my $ul_o_corner_bevel = $self->color($stateName,
        $ul_o_corner_bevel_factor);
    my $ul_edge_bevel = $self->color($stateName,$ul_edge_bevel_factor)
+;
    my $llur_o_corner = $self->color($stateName,$llur_o_corner_factor)
+;
    my $llur_edge = $self->color($stateName,$llur_edge_factor);
    my $llur_i_corner = $self->color($stateName,$llur_i_corner_factor)
+;
    my $llur_l_o_corner_bevel = $self->color($stateName,
        $llur_l_o_corner_bevel_factor);
    my $llur_b_o_corner_bevel = $self->color($stateName,
        $llur_b_o_corner_bevel_factor);
    my $llur_l_edge_bevel = $self->color($stateName,
        $llur_l_edge_bevel_factor);
    my $llur_b_edge_bevel = $self->color($stateName,
        $llur_b_edge_bevel_factor);
    my $dark_edge = $self->color($stateName,$dark_edge_factor);
    my $light_side = $self->color($stateName,$light_side_factor);
    my $dark_side = $self->color($stateName,$dark_side_factor);
    my $lr_o_corner = $self->color($stateName,$lr_o_corner_factor);
    my $lr_edge = $self->color($stateName,$lr_edge_factor);
    my $lr_i_corner = $self->color($stateName,$lr_i_corner_factor);
    my $lr_o_corner_bevel = $self->color($stateName,
        $lr_o_corner_bevel_factor);
    my $lr_edge_bevel = $self->color($stateName,$lr_edge_bevel_factor)
+;

    # Set the color of the fonts based on the value of $FONTCOLORBREAK
+POINT
    my $fontColor=($self->{baseR}+$self->{baseG}+$self->{baseB})>
        $FONTCOLORBREAKPOINT?$self->{$stateName}->colorAllocate(0,0,0)
+:
        $self->{$stateName}->colorAllocate(255,255,255);

    # Fill everything with base color
    $self->{$stateName}->fill(int($self->{sizeX}/2),int($self->{sizeY}
+/2),
        $base);

    # Draw edge and center rectangles
    $self->{$stateName}->rectangle(0,0,$self->{sizeX}-1,$self->{sizeY}
+-1,
        $light_edge);
    $self->{$stateName}->rectangle($SIDE_X_WIDTH-1,$SIDE_Y_WIDTH-1,
        $self->{sizeX}-$SIDE_X_WIDTH,$self->{sizeY}-$SIDE_Y_WIDTH,
        $light_edge);

    # Draw upper left corner
    $self->{$stateName}->setPixel(0,0,$state?$ul_o_corner:$lr_o_corner
+);
    $self->{$stateName}->line(1,1,$SIDE_X_WIDTH-2,$SIDE_Y_WIDTH-2,$sta
+te?
        $ul_edge:$lr_edge);
    $self->{$stateName}->setPixel($SIDE_X_WIDTH-1,$SIDE_Y_WIDTH-1,$sta
+te?
        $ul_i_corner:$lr_i_corner);
    $self->{$stateName}->line(0,1,1,0,$state?$ul_o_corner_bevel:
        $lr_o_corner_bevel);
    $self->{$stateName}->line(2,1,$SIDE_X_WIDTH-1,$SIDE_Y_WIDTH-2,$sta
+te?
        $ul_edge_bevel:$lr_edge_bevel);
    $self->{$stateName}->line(1,2,$SIDE_X_WIDTH-2,$SIDE_Y_WIDTH-1,$sta
+te?
        $ul_edge_bevel:$lr_edge_bevel);

    # Draw lower left corner
    $self->{$stateName}->setPixel(0,$self->{sizeY}-1,$llur_o_corner);
    $self->{$stateName}->line(1,$self->{sizeY}-2,$SIDE_X_WIDTH-2,
        $self->{sizeY}-$SIDE_Y_WIDTH+1,$llur_edge);
    $self->{$stateName}->setPixel($SIDE_X_WIDTH-1,$self->{sizeY}-$SIDE
+_Y_WIDTH,
        $llur_i_corner);
    $self->{$stateName}->setPixel(0,$self->{sizeY}-2,$state?
        $llur_l_o_corner_bevel:$llur_b_o_corner_bevel);
    $self->{$stateName}->setPixel(1,$self->{sizeY}-1,$state?
        $llur_b_o_corner_bevel:$llur_l_o_corner_bevel);
    $self->{$stateName}->line(1,$self->{sizeY}-3,$SIDE_X_WIDTH-2,
        $self->{sizeY}-$SIDE_Y_WIDTH,$state?$llur_l_edge_bevel:
        $llur_b_edge_bevel);
    $self->{$stateName}->line(2,$self->{sizeY}-2,$SIDE_X_WIDTH-1,
        $self->{sizeY}-$SIDE_Y_WIDTH+1,$state?$llur_b_edge_bevel:
        $llur_l_edge_bevel);

    # Draw upper right corner
    $self->{$stateName}->setPixel($self->{sizeX}-1,0,$llur_o_corner);
    $self->{$stateName}->line($self->{sizeX}-2,1,
        $self->{sizeX}-$SIDE_X_WIDTH+1,$SIDE_Y_WIDTH-2,$llur_edge);
    $self->{$stateName}->setPixel($self->{sizeX}-$SIDE_X_WIDTH,$SIDE_Y
+_WIDTH-1,
        $llur_i_corner);
    $self->{$stateName}->setPixel($self->{sizeX}-2,0,$state?
        $llur_l_o_corner_bevel:$llur_b_o_corner_bevel);
    $self->{$stateName}->setPixel($self->{sizeX}-1,1,$state?
        $llur_b_o_corner_bevel:$llur_l_o_corner_bevel);
    $self->{$stateName}->line($self->{sizeX}-3,1,$self->{sizeX}-$SIDE_
+X_WIDTH,
        $SIDE_Y_WIDTH-2,$state?$llur_l_edge_bevel:$llur_b_edge_bevel);
    $self->{$stateName}->line($self->{sizeX}-2,2,$self->{sizeX}-$SIDE_
+X_WIDTH+1,
        $SIDE_Y_WIDTH-1,$state?$llur_b_edge_bevel:$llur_l_edge_bevel);

    # Draw lower right corner
    $self->{$stateName}->setPixel($self->{sizeX}-1,$self->{sizeY}-1,$s
+tate?
        $lr_o_corner:$ul_o_corner);
    $self->{$stateName}->line($self->{sizeX}-2,$self->{sizeY}-2,
        $self->{sizeX}-$SIDE_X_WIDTH+1,$self->{sizeY}-$SIDE_Y_WIDTH+1,
        $state?$lr_edge:$ul_edge);
    $self->{$stateName}->setPixel($self->{sizeX}-$SIDE_X_WIDTH,
        $self->{sizeY}-$SIDE_Y_WIDTH,$state?$lr_i_corner:$ul_i_corner)
+;
    $self->{$stateName}->line($self->{sizeX}-1,$self->{sizeY}-2,
        $self->{sizeX}-2,$self->{sizeY}-1,$state?$lr_o_corner_bevel:
        $ul_o_corner_bevel);
    $self->{$stateName}->line($self->{sizeX}-3,$self->{sizeY}-2,
        $self->{sizeX}-$SIDE_X_WIDTH,$self->{sizeY}-$SIDE_Y_WIDTH+1,$s
+tate?
        $lr_edge_bevel:$ul_edge_bevel);
    $self->{$stateName}->line($self->{sizeX}-2,$self->{sizeY}-3,
        $self->{sizeX}-$SIDE_X_WIDTH+1,$self->{sizeY}-$SIDE_Y_WIDTH,$s
+tate?
        $lr_edge_bevel:$ul_edge_bevel);


    # Draw dark edges
    $self->{$stateName}->line(2,$state?$self->{sizeY}-1:0,$self->{size
+X}-3,
        $state?$self->{sizeY}-1:0,$dark_edge);
    $self->{$stateName}->line($state?$self->{sizeX}-1:0,2,$state?
        $self->{sizeX}-1:0,$self->{sizeY}-3,$dark_edge);
    $self->{$stateName}->line(
        $state?$self->{sizeX}-$SIDE_X_WIDTH:$SIDE_X_WIDTH-1,
        $SIDE_Y_WIDTH,
        $state?$self->{sizeX}-$SIDE_X_WIDTH:$SIDE_X_WIDTH-1,
        $self->{sizeY}-$SIDE_Y_WIDTH-1,
        $dark_edge);
    $self->{$stateName}->line(
        $SIDE_X_WIDTH,
        $state?$self->{sizeY}-$SIDE_Y_WIDTH:$SIDE_Y_WIDTH-1,
        $self->{sizeX}-$SIDE_X_WIDTH-1,
        $state?$self->{sizeY}-$SIDE_Y_WIDTH:$SIDE_Y_WIDTH-1,
        $dark_edge);

    # Fill sides
    $self->{$stateName}->fill(int($self->{sizeX}/2),1,
        $state?$light_side:$dark_side);
    $self->{$stateName}->fill(1,int($self->{sizeY}/2),
        $state?$light_side:$dark_side);
    $self->{$stateName}->fill($self->{sizeX}-2,int($self->{sizeY}/2),
        $state?$dark_side:$light_side);
    $self->{$stateName}->fill(int($self->{sizeX}/2),$self->{sizeY}-2,
        $state?$dark_side:$light_side);

    # Print text
    # The text must be able to be printed in a box of
    # @bounds[0,1]=5,$self->{sizeY}-7
    # @bounds[2,3]=$self->{sizeX}-7,$self->{sizeY}-7
    # @bounds[4,5]=$self->{sizeX}-7,5
    # @bounds[6,7]=5,5

    # Set wanted fontsize (could be smaller after TEXTRESIZE)
    my $textHeight=$self->{fontsize};
    my @bounds=[];

    # Loop to size text to button area
    TEXTRESIZE: while (1) {
        # See what bounds we get if we would print
        @bounds = GD::Image->stringTTF(
            $fontColor,
            $FONTDIR.$self->{font},
            $textHeight,
            0,
            ($SIDE_X_WIDTH+1),
            ($self->{sizeY}-($SIDE_Y_WIDTH+3)),
            $self->{text});
        if ($@) {
            # Some error (like no TTF support)
            last TEXTRESIZE;
        }

        # If text is out of bounds, try to resize it
        if ($bounds[4]>($self->{sizeX} - ($SIDE_X_WIDTH+3)) || 
            $bounds[4]<0 || 
            $bounds[5]<($SIDE_Y_WIDTH+1) || 
            $bounds[5]<0) {
            if (--$textHeight<1) {
                # Couldn't fit text in button
                last TEXTRESIZE;            
            }
            next TEXTRESIZE;
        }

        # Set fontsize to the new? value
        $self->{fontsize}=$textHeight;

        # Print the text (centered on button)
        $self->{$stateName}->stringTTF(
            $fontColor,
            $FONTDIR.$self->{font},
            $textHeight,
            0,
            ($SIDE_X_WIDTH+1)+
                int(($self->{sizeX}-($bounds[4]-$bounds[6])-
                (($SIDE_X_WIDTH*2)+2))/2),
            $self->{sizeY}-($SIDE_Y_WIDTH+3)-
                int(($self->{sizeY}-($bounds[1]-$bounds[7])-
                (($SIDE_Y_WIDTH*2)+2))/2),
            $self->{text});
        last TEXTRESIZE;
    }

    # Convert the image to PNG and return it
    return $self->{$stateName}->png;
};

######################################################################
1;

__END__


=head1 NAME

ButtonFactory - A button factory

=head1 DESCRIPTION

A package that creates custom png buttons.

=head1 SYNOPSIS

A non-web example to generate buttons to files:

 #!/usr/local/bin/perl -w
 use ButtonFactory;

 my $x=new ButtonFactory(100,20,70,82,157,"Hello World","arial.ttf",8)
+;

 open (FILE,">Normal.png") or die $!;
 binmode FILE;
 print FILE $x->printNormal();
 close (FILE);

 open (FILE,">Pressed.png") or die $!;
 binmode FILE;
 print FILE $x->printPressed();
 close (FILE);

A web example (let's call it getbutt.cgi :) to print buttons to a brow
+ser:

 #!/usr/local/bin/perl -w
 use ButtonFactory;
 use CGI qw(:standard);

 # Get query parameters
 my $query = new CGI;
 $x = $query->param('x');
 $y = $query->param('y');
 $r = $query->param('r');
 $g = $query->param('g');
 $b = $query->param('b');
 $txt = $query->param('txt');
 $ttf = $query->param('ttf');
 $fs = $query->param('fs');
 $state = $query->param('state');

 # Create the button
 my $butt=new ButtonFactory($x,$y,$r,$g,$b,$txt,$ttf,$fs);

 # Calculate size of button and pour it out to the user
 print "Content-Type: image/png\n\n";
 binmode STDOUT;
 print $state?$butt->printNormal():$butt->printPressed();

And a sample (pretty_silly.html) html page for it:    

 <html>
 <head><title>Buttons</title>
 <script language="JavaScript">
     // browser detection
     var OK = ((navigator.appName.charAt(0)=='N' && 
         navigator.appVersion.charAt(0)=='3') || 
         navigator.appVersion.charAt(0)=='4');
     // Preload clicked image
     if (OK) {
         preload = new Image();
         preload.src ='cgi-bin/getbutt.cgi?x=100&y=20&r=70&g=82&b=157&
+' + 
             'txt=Hello+World&ttf=arial.ttf&fs=8&state=0';
     }
     // mouseclick f/x
     function click(i) {if (OK) {document['butt'+i].src = 
         'cgi-bin/getbutt.cgi?x=100&y=20&r=70&g=82&b=157&txt=Hello+Wor
+ld&' +
         'ttf=arial.ttf&fs=8&state=0';}}
     function out(i) {if (OK) {document['butt'+i].src = 
         'cgi-bin/getbutt.cgi?x=100&y=20&r=70&g=82&b=157&txt=Hello+Wor
+ld&' +
         'ttf=arial.ttf&fs=8&state=1';}}
 </script>
 </head>
 <body bgcolor=#ffffff>
 A button test...<br>
 <a href="helloworld.html" onClick="click(0);alert('Click...');out(0);
+">
 <img name="butt0" src=
 "cgi-bin/getbutt.cgi?x=100&y=20&r=70&g=82&b=157&txt=Hello+World&ttf=a
+rial.ttf&fs=8&state=1" 
 alt="Hello World" width=100 height=20 border=0></a><br>
 </body>
 </html>

=head1 Methods

=over 4

=item new(sizeX,sizeY,red,green,blue,text,font,fontsize)

Creates a new ButtonFactory object with sizeX*sizeY pixel size. Values
+ for red,
green and blue in decimal range 0-255. ButtonFactory will try its best
+ to size
the font to make the text fit on the button, so the fontsize supplied 
+is the
largest size the text can have.
The font should be a TrueType font with its .ttf extension, 'arial.ttf
+'. In the
configuration section of ButtonFactory you may set $FONTDIR to the dir
+ectory
where you store your TrueType fonts. If $FONTDIR is set to '' (empty s
+tring)
you must supply the whole path to the font you want to use.   

=item printNormal()

Prints the button in its up state. The GD image is stored internaly so
+ the 
second time you use printNormal, ButtonFactory can use the stored imag
+e. This
improves speed if you need to get the size of the printed button befor
+e printing
it. Useful when you need to print Content-length before the image on a
+ 
multipart/x-mixed-replace HTML documet. 

=back

=head1 SEE ALSO

L<GD>

=head1 DISCLAIMER

I do not guarantee B<ANYTHING> with this package. If you use it you
are doing so B<AT YOUR OWN RISK>! I may or may not support this
depending on my time schedule...

=head1 AUTHOR

t0mas@netlords.net

=head1 COPYRIGHT

Copyright 1999-2000, t0mas@netlords.net

This package is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
Replies are listed 'Best First'.
RE: ButtonFactory
by Intrepid (Deacon) on Aug 14, 2000 at 06:50 UTC

    Updated 22 Oct 2005

    Brother t0mas -- Thanks so much for adding the button bevel size change to ButtonFactory. What was once good is even better!

    In the interest of sharing, just for fun, I am posting some code I quickly hacked up last night to do something a little different with ButtonFactory from the command line. Based on what you include as a sample command-line script in the POD, here is what I am doing:

    #!perl -w ## ------------------------------------------------------------ # MS Windoze-specific script. Sorry :-). ## ------------------------------------------------------------ # NOT like t0mas' original idea -- this makes buttons for # horizontal row use only bec if button text is longer # than 20 chars, it expands the length by 8 px for each one # (based on 8pt Myriad font). use ButtonFactory; use Win32::Clipboard; my ( $N_state $P_state @RGBt $BWi ); my $clipping; my $name_it = shift @ARGV; my $btnText = shift @ARGV; my $expsn = ((length ($btnText) - 20) > 0)? (length ($btnText) - 20) * 8 : 0 ; $BWi = 90 + $expsn; @RGBt = ($clipping=Win32::Clipboard::Get()) # Pick-'o-Color format for rgb triplet: "RGB(155, 50, 23)" ? grep /\d+/, (split /[^\d]/,$clipping) : split(/[^\w]/, shift @ARGV); if (scalar @RGBt == 3) { print "Using ", join( ', ',@RGBt ), " for color specification for b +uttons\n"; } else { die "No color as RGB triplet gotten! \nContents of \@RGBt if any: " ." $clipping ". "@RGBt"; } my $x=new ButtonFactory($BWi,21, $RGBt[0],$RGBt[1],$RGBt[2], $btnText =>"Myriad Web Bold.ttf"=>8); $N_state = $name_it .'N_state.png'; $P_state = $name_it .'P_state.png'; open (FILE,">$N_state") or die $!; binmode FILE; my $Ntime = time; print FILE $x->printNormal(); close (FILE); open (FILE,">$P_state") or die $!; binmode FILE; print FILE $x->printPressed(); close (FILE); utime $Ntime, $Ntime, ($N_state, $P_state); _END_

    Pick'o'Color is  (was) a  Windows app found at:
    http://www.itsme.de/software/index.html



     Best,
       soren      Intrepid
RE: ButtonFactory
by Intrepid (Deacon) on Jun 29, 2000 at 14:41 UTC

    I do not have any expert and insightful comment to make since all I can do right now is look at all this code (and whistle quietly between my teeth and go " WOW ") .. but I needed to write that I am simply impressed as heck. Thanks for contributing this great-looking, POD-documented application.

    I have to check and see if my GD module version has TrueType support compiled in. If so I may be going to town, absolutely having a riot with the ButtonFactory .

    BTW I wish I could say my trailing sig (if it works) was a button made with your app, but it isn't.

    Intrepid <IMG SRC="http://www.wonderstorm.com/cgi-bin/PiNGMe.pl?wonderstorm-com_stonebutton" WIDTH=150 HEIGHT=20 BORDER=0>
    www.wonderstorm.com
    How-To's on hacking PNG and other stuff on my Website img data served to some browsers as a PNG img
      Even if you don't have TrueType support, you can make textless buttons. You can supply text with your favorite image manipulation program (ie. GIMP). I havn't been able to work out how to recalculate and choose the best built-in font (haven't put much effort in it either), thats why they aren't supported yet.
      Thanks for your input :)

      /brother t0mas

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://20139]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (6)
As of 2024-03-28 22:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found