#!/usr/bin/perl -w
##
# Make some pie graphics for the %ages of usage.
# We create a bunch of images for %ages 0-100, named
# "
/.gif".
#
# The pie graphs are generated with a colour indicating the state.
# There are 3 colours - green, yellow, red - for good, ok, and bad.
# The thresholds are configurable, as is the ordering.
#
# Requires GD::Graph to provide the actual pies.
#
# History:
#
# 1.00 (12 May 2012) Initial version for rack state
# 1.01 (06 Jun 2012) Updated for ipv6 statistics
# 1.02 (11 Feb 2013) Genericised the pie generation
# 1.03 (12 Feb 2013) Added resampling and simple font labels,
# fixed thresholds and colours.
#
# @author Justin Fletcher
#
use Getopt::Long;
use Data::Dumper;
use GD::Graph::pie;
use GD::Text;
use GD;
my $dir = "imgs";
my $prefix = 'pie';
my $size = 24;
my $use3d = 0;
my $border = 'lgray';
my $fill = 'lgray';
my $label = 0;
my $resample = 0;
my $usefonts = 0;
my @colours = ( 'lgreen', 'lyellow', 'lred' );
my @thresholds = ( 80, 95, 101 );
GetOptions('dir=s' => \$dir,
'prefix=s' => \$prefix,
'size=s' => \$size,
'3d' => \$use3d,
'border=s' => \$border,
'fill=s' => \$fill,
'label' => \$label,
'thresholds=s' => sub {
# comma separated list
my ($arg, $val) = @_;
@thresholds = ( (split /,/, $val), 101 );
},
'colours=s' => sub {
# comma separated list
my ($arg, $val) = @_;
@colours = split /,/, $val;
},
'reverse' => sub { @colours = reverse @colours },
'resample' => sub { $resample = 2; },
'fonts' => \$usefonts,
'help' => sub {
$" = ', '; # Magic: interpolate lists separated by commas
die <
Options:
-dir Directory to write to (default: $dir)
-prefix Leafname prefix for files (default: $prefix)
-thresholds Comma-separated list of colour threshold points
(default: @thresholds)
-colours Comma-separated list of colours for pies below
thresholds (default: @colours)
-reverse Reverse the colour list
-size Size of the pie (default: $size)
-3d Whether the chart is 3D
(appears to break GD::Graph at some percentage)
-border Border colour (default: $border)
-fill Empty colour (default: $fill)
-label Enable labeling (increases the vertical size)
-resample Resample the image, making the edges smoother.
(this breaks the non-font rendered labels)
-fonts Use fonts in place of bitmap characters.
(may be unreliable)
EOM
}
) || exit 1;
my $font;
my $fontsize = 0;
if ($label)
{
if ($size < 32)
{
$font = GD::Font->Tiny if (!defined $font);
$fontsize = 8;
}
elsif ($size < 48)
{
$font = GD::Font->Small if (!defined $font);
$fontsize = 12;
}
else
{
$font = GD::Font->Large if (!defined $font);
$fontsize = 16;
}
}
if ($resample)
{
$size = $size * $resample;
$fontsize = $fontsize * $resample;
}
my $fontpoint = $fontsize;
# Add the font paths (this might need modifying for your system)
if ($usefonts)
{
my $fontroot = '/usr/share/fonts/truetype/';
opendir(my $dh, $fontroot);
my @fontpaths;
for my $path (grep { !/^\./ } readdir($dh))
{
push @fontpaths, "$fontroot/$path";
}
closedir($dh);
GD::Text->font_path( join ":", @fontpaths);
$font = [ 'Arial', 'DejaVuSans', 'Vera' ];
# Using a raw point height won't work; we need to make the size
# of the font scale to the size we wanted.
my $gd_text = GD::Text->new();
$gd_text->set_font($font, $fontpoint);
my $fontheight = $gd_text->get('height');
if ($fontheight != $fontsize)
{
$fontpoint = $fontpoint / ($fontheight / $fontsize);
}
}
for my $percent (0..100)
{
my @data = ( [undef,undef],
[ $percent, 100-$percent ]
);
my $width = $size;
my $height = $size + $fontsize;
my $pie = new GD::Graph::pie( $width, $height );
# Find the correct colour from our thresholds
my $colour = 'white'; # Should never happen
for my $index (0..$#colours)
{
if (defined $thresholds[$index] &&
$percent < $thresholds[$index])
{
$colour = $colours[$index];
last;
}
}
$pie->set( 'dclrs' => [ $colour,
$fill
],
'accentclr' => $border,
'transparent' => 1,
'l_margin' => 0,
'r_margin' => 0,
'start_angle' => 180,
'3d' => $use3d,
'pie_height' => $use3d ? $height * 0.2 : 0,
'text_space' => 0,
'label' => $label ? $percent.'%' : undef,
);
if ($label)
{
$pie->set_label_font($font, $fontpoint);
}
$pie->plot( \@data );
my $gd = $pie->gd;
if ($resample)
{
# Create a new image to write into
$dest = new GD::Image( $width / $resample, $height / $resample, 1 );
# Make a background colour to fill with
my $bg = $dest->colorAllocate(254,254,254);
$dest->transparent($bg);
$dest->filledRectangle(0,0, $width, $height, $bg);
# Copy the image into it
$dest->copyResampled($gd,
0, 0, # Dest x,y
0, 0, # Source x,y
$width / $resample, $height / $resample, # Dest width,height
$width, $height # Source width, height
);
# reduce to paletted, without dithering
$dest->trueColorToPalette(0);
# Our result is the one we write out.
$gd = $dest;
}
# Save the images out
open(my $fh, ">", "$dir/$prefix$percent.gif")
|| die "Cannot create pie: $!\n";
binmode $fh;
print $fh $gd->gif();
close($fh);
}