#!/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); }