#!/usr/bin/perl -w ############################################################################# # Project: Web-Utilities # Descr: Create an button image usable e.g. in menus # Author: Dr. Jürgen Vollmer # Id: create-button,v 1.3 2004/03/04 09:08:56 vollmer Exp $ ############################################################################# require 5.008; =pod =head1 NAME create-button - a script to create button images used in web pages =head1 SYNOPSIS create-button []* text ... =head1 OPTIONS =over =item B<--output> I Write output to the given file (default: display it). "-" indicates the PNG data are written to stdout. The generated graphics format is determined by the given file suffix. See L(1) for the list of acceptable picture formats. If no output file is specified the image is shown using the L(1) routine. =item B<--font> I Use true-type font specified by I (default Arial bold italics). =item B<--size> I Render text in the give size (default 14). =item B<--foreground> I =item B<--fg> I The foreground color of the text, default black. =item B<--background> I =item B<--bg> I The background color of the image, default white. =item B<--center> Center the rendered text (default). =item B<--left> Left adjust the rendered text. =item B<--right> Right adjust the rendered text. =item B<--top> Place the text at the top of the image. =item B<--middle> Place the text in the middle of the image (default). =item B<--bottom> Place the text at the bottom of the image. Right adjust the rendered text. =item B<--rotate> I Rotate the text -360 <= I <= 360 (default 0). Right adjust the rendered text. =item B<-W> I =item B<--width> I Width of the image. =item B<-H> I =item B<--height> I Height of the image. =item B<--Raise> IxI Raises the image into 3D. (Not available, if written to stdout). =item B<--raise> Just an abbreviation for B<--Raise> I<5x5> =item B<--Show> Show the size of the created picture and text. =item B<-h> =item B<--help> Print a brief help message and exits. =item B<-M> =item B<--manual> Prints the manual page and exits. =item B<--debug> Enable debugging. =back Options names may be abbreviated to uniqueness. Single letter options may be used with only one dash. Colors may be given as RGB triples: III where I, I and I are hexadecimal values: E.g. I means black and I<0> means white. Those color values may be separated by a , (comma) or : (colon). E.g. I or I<0,0,0>. If no height or width is given, the width and height of the button text will be used. =head1 DESCRIPTION create-button is a simple script to create images containing some text. =head1 EXAMPLE create-button -bg 9933CC -fg FFFFFF -size 20 test and more tests displays a button containing the text "test and more tests". create-button -bg 9933CC -fg FFFFFF -rotate 10 -raise -o test.gif test creates the file test.gif containing an image with the text "test" which is rotated to 10 degrees and the entire image is raised. =head1 REQUIREMENTS The GD perl package and the ImageMagik tools. =head1 AUTHOR Dr. Juergen Vollmer If you find this software useful, I would be glad to receive a postcard from you, showing the place where you're living. =head1 HOMEPAGE http://www.informatik-vollmer.de/software/create-button.html =head1 COPYRIGHT Copyright (C) 2004 Dr. Juergen Vollmer, Viktoriastrasse 15, D-76133 Karlsruhe, Germany. =head1 LICENSE 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 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 =head1 VERSION 1.2 =cut use strict; use English; use Getopt::Long; use File::Basename; use Pod::Usage; use Math::Trig; use GD; our $CMD = basename ($0); our ($VERSION) = 'Revision: 1.3 $' =~ '(\d*\.\d*)'; our ($VERSION_DATE) = 'Date: 2004/03/04 09:08:56 $' =~ '(\d*/\d*/\d*)'; our ( $option_output, $option_font, $option_font_size, $option_fg, $option_bg, $option_text_angle, $option_width, $option_height, $option_align_x, $option_align_y, $option_raise, $option_show_size, $option_help, $option_manual, $option_debug); ############################################################################# ## functions ############################################################################# sub error { die "$CMD error: " . join (" ", @_) . "\n"; } ############################################################################# sub debug { my $format = shift; ($option_debug) && printf STDERR "$format", @_; } ############################################################################# sub do_output($) # output the generated image # Arguments: $image an GD-object { my $image = shift; my $convert = "| convert"; $convert .= " -raise $option_raise" if ($option_raise); if (defined $option_output) { if ($option_output eq "-") { # write to a STDOUT binmode STDOUT; print STDOUT $image->png; } else { # write to a file open (F, "$convert - $option_output") || error "can not call \"convert $option_output\""; binmode F; print F $image->png; close F; } } else { # display it open (F,"$convert - -| display -") || error "can not call \"display\""; binmode F; print F $image->png; close F; } } ############################################################################# sub size_of($) # compute height and width of the given text, and the hight of the first # letter. The hight of the first letter is diffrent from the entire hight, # if the text contains a character with unter-length, i.e. one of: gjpqy # Arguments: $text # Returns: ($width, $height, $hight_first) { my $text = shift; my $image = new GD::Image; my $black = $image->colorAllocate(255,255,255); my ($ll_x, $ll_y, # lower left egde $lr_x, $lr_y, # lower right edge $ul_x, $ul_y, # upper left edge $ur_x, $ur_y) = $image->stringFT ($black, $option_font, $option_font_size, $option_text_angle, 0, 0, $text); defined $ll_x || error ("can not render $text: $@"); my $width = $lr_x - $ll_x; my $height = $ll_y - $ul_y; my $height_first; if ($text =~ /[gjpqy]/) { # text contains letter with under-length my $letter = substr ($text, 0,1); # text contains text with upper-length, e.g: if ($text =~ /[bdfhijkltöäüßÖÄÜA-Z0-9]/) { # use "A" as canonical letter for the hight_first computation $letter = "A"; } ($ll_x, $ll_y, # lower left egde $lr_x, $lr_y, # lower right edge $ul_x, $ul_y, # upper left edge $ur_x, $ur_y) = $image->stringFT ($black, $option_font, $option_font_size, $option_text_angle, 0, 0, $letter); $height_first = $ll_y - $ul_y; } else { $height_first = $height; } debug ("size: width = %3d, height = %3d, height_first = %3d \n", $width, $height, $height_first); return ($width, $height, $height_first); } ############################################################################# sub do_render(@) # render the given text # Arguments: $text # Returns: $image a GD-object { my $text = join (" ", @_); my ($width, $height, $height_first) = size_of ($text); $option_width = $width if (!defined $option_width); $option_height = $height if (!defined $option_height); if ($option_show_size) { printf "$CMD: text: width = %3d height = %d\n", $width, $height; printf "$CMD: picture: width = %3d height = %d\n", $option_width, $option_height; } my $image = new GD::Image($option_width, $option_height); # allocate some colors my ($bg_r, $bg_g, $bg_b) = (($option_bg >> 16) & 0xFF, ($option_bg >> 8) & 0xFF, $option_bg & 0xFF); my ($fg_r, $fg_g, $fg_b) = (($option_fg >> 16) & 0xFF, ($option_fg >> 8) & 0xFF, $option_fg & 0xFF); my $bg = $image->colorAllocate($bg_r, $bg_g, $bg_b); my $fg = $image->colorAllocate($fg_r, $fg_g, $fg_b); $image->filledRectangle(0, 0, $option_width, $option_height, $bg); my ($x, $y); my $offset = 2; # offset to one of the borders if ($option_raise) { $option_raise =~ /^(\d+)x\d+$/; $offset += $1; } if ($option_align_x eq "center") { $x = ($option_width - $width) / 2; } elsif ($option_align_x eq "left") { $x = $offset; } else { # right $x = $option_width - $width - $offset; } if ($option_align_y eq "middle") { $y = ($option_height + $height) / 2; } elsif ($option_align_y eq "top") { $y = $height + $offset; } else { # bottom $y = $option_height - $offset; } $y -= $height - $height_first; debug ("align_x = $option_align_x; align_y = $option_align_y\n"); debug ("pos: x = %3d, y = %3d\n", $x, $y); debug ("rec: x = %3d, y = %3d\n", $option_width, $option_height); $image->stringFT ($fg, $option_font, $option_font_size, $option_text_angle, $x, $y, $text); return $image; } ############################################################################# ############################################################################# ## check command line options and arguments ############################################################################# Getopt::Long::Configure ("auto_abbrev", "no_ignore_case", "getopt_compat", "require_order"); $option_font = "/usr/X11R6/lib/X11/fonts/truetype/arialbi.ttf"; $option_font_size = 14; $option_text_angle = 0; # in rad $option_align_x = "center"; $option_align_y = "middle"; $option_fg = "0,0,0"; # black $option_bg = "FF,FF,FF"; # white GetOptions("output=s" => \$option_output, "foreground=s" => \$option_fg, "fg=s" => \$option_fg, "background=s" => \$option_bg, "bg=s" => \$option_bg, "font=s" => \$option_font, "size=i" => \$option_font_size, "rotate=i" => \$option_text_angle, "width|W=i" => \$option_width, "height|H=i" => \$option_height, "Raise=s" => \$option_raise, "raise" => sub {$option_raise = "5x5"; }, "center" => sub {$option_align_x = "center";}, "left" => sub {$option_align_x = "left"; }, "right" => sub {$option_align_x = "right"; }, "top" => sub {$option_align_y = "top"; }, "middle" => sub {$option_align_y = "middle";}, "bottom" => sub {$option_align_y = "bottom";}, "Show" => \$option_show_size, "help|h" => \$option_help, "manual|M" => \$option_manual, "debug" => \$option_debug, ) or pod2usage(-exitval => 2, -verbose => 0, -message => "Try --help or --man."); pod2usage (-exitval => 1, -verbose => 1) if ($option_help); pod2usage (-exitval => 0, -verbose => 2) if ($option_manual); pod2usage (-exitval => 2, -verbose => 0, -message => "$CMD: No arguments given.\n") if ($#ARGV < 0); # make it a decimal value $option_bg =~ s/[,:]//g; $option_fg =~ s/[,:]//g; $option_bg = hex ($option_bg); $option_fg = hex ($option_fg); # convert degree to radians $option_text_angle = deg2rad($option_text_angle); [ -f $option_font ] || error "no such font file: $option_font"; do_output (do_render (@ARGV)); ############################################################################# # Log: create-button,v $ # Revision 1.3 2004/03/04 09:08:56 vollmer # Added automatic computation of the size of the picture (by not setting the # default hight and width). # Take care of under-length of charcters like "g" (quite a simple heuristics). # # Revision 1.2 2004/02/15 11:37:23 vollmer # Insert a small offset for -left/-right/-bottom/-top and -raise in those # cases. # # Revision 1.1 2004/02/14 17:13:24 vollmer # Initial revision # #############################################################################