#!/usr/bin/perl # # RRDtool stripgraph maker - version 0.3 # Copyright 2006 by Howard Jones, howie@thingy.com # http://wotsit.thingy.com/haj/ # # All rights reserved. This program is free software; you may # redistribute it and/or modify it under the same terms as Perl itself. # # See the website for documentation. This is rough and ready at the moment # use Imager; use XML::Simple; use Data::Dumper; use Number::Format qw(:subs); use Getopt::Long; $twidth = 128; $theight = 48; $tfont = "./ArialN.TTF"; $tfontsize = 11; $tfilename = "strip.png"; $theight = 48; $twidth = 128; $nonzero = 0; $unformatted=0; $tlinethickness=1; $linecolour = "8080ff"; $bgcolour = "dedeff"; $blacktext = "System Name"; $redtext = "1000M"; $scalefactor = 3; $verbose = 0; GetOptions ( "wanted=i" => \$wanted, "font=s" => \$font, "fontsize=i" => \$tfontsize, "label=s" => \$blacktext, "width=i" => \$twidth, "height=i" => \$theight, "nonzero" => \$nonzero, "unformatted" => \$unformatted, "verbose" => \$verbose, "rescaling=i" => \$scalefactor, "linethickness=i" => \$tlinethickness, "backgroundcolour=s" => \$bgcolour, "linecolour=s" => \$linecolour, "outputfilename=s" => \$tfilename ); if($verbose) { print STDERR "Supported Image formats: ", join(", ", sort keys %Imager::formats),"\n"; print STDERR "Supported Font formats: "; print STDERR "Has truetype. " if $Imager::formats{tt}; print STDERR "Has t1 postscript. " if $Imager::formats{t1}; print STDERR "Has Win32 fonts. " if $Imager::formats{w32}; print STDERR "Has Freetype2. " if $Imager::formats{ft2}; print STDERR "\n"; } ##################### # scale up here, so we can scale down later # $width = $twidth * $scalefactor; $height = $theight * $scalefactor; $fontsize = $tfontsize * $scalefactor; $linethickness= $tlinethickness * $scalefactor/2; ########### my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>3); $black = Imager::Color->new(0,0,0); $white = Imager::Color->new(255,255,255); $paleblue = Imager::Color->new("#${bgcolour}"); $linecolour = Imager::Color->new("#${linecolour}"); $red = Imager::Color->new("#ff0000"); # background fill $img->box(filled=>1, color=>$white); # figure out how big the chart part needs to be... $font = Imager::Font->new(file => $tfont, size => $fontsize) || die($!); # here's a string with the tallest letters... ($neg_width, $global_descent, $pos_width,$global_ascent, $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>"yyAAIIjygzwjjjww"); $chartheight = $height - ($global_ascent - $global_descent + 2 * $scalefactor); $chartwidth = $width; # print "Chart height is $chartheight, width is $chartwidth\n"; # graph background fill $img->box(filled=>1, color=>$paleblue, xmin => 0, xmax => $width, ymin => 0, ymax => $chartheight ); # read in the XML data from stdin read_xml(); ########## ($neg_width, $global_descent, $pos_width,$global_ascent, $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>$blacktext); $img->string(font => $font, text => $blacktext, color => $black, align => 1, x => 1*$scalefactor, y => $height + $global_descent, aa => 1); #### ($neg_width, $global_descent, $pos_width,$global_ascent, $descent, $ascent, $advance_width, $right_bearing) = $font->bounding_box(string=>$redtext); $img->string(font => $font, text => $redtext, color => $red, align => 1, x => $width - 1*$scalefactor - $advance_width, y => $height + $global_descent, aa => 1); ########## # now all the drawing is done, we should scale back down again... $newimg = $img->scale(xpixels=>$twidth, ypixels=>$theight); $newimg->write(file=>$tfilename) or die $newimg->errstr; ####################################################################### sub read_xml { $ref = XMLin('-',ForceArray=>['v','entry']); $rowcount = $ref->{meta}->{rows}; # take one off for the NaN at the end, and another to make the index 0-based $rowcount--; $rowcount--; # This is a bodge. Have a look for the perl equiv of limits.h.... $valmin = 99e80; $valmax = -99e80; $label = $ref->{meta}->{legend}->{entry}->[$wanted]; $blacktext = $label; foreach $i (1..$rowcount) { $timet = $ref->{data}->{row}->[$i-1]->{t},"\t"; $val = $ref->{data}->{row}->[$i-1]->{v}->[$wanted],"\t"; if($val ne "NaN") { $valmin = min($valmin,$val); $valmax = max($valmax,$val); } } # just so the graph isn't 1-dimensional if($valmax==$valmin) { $valmax++; } $chartheight = $chartheight-$linethickness*2; for $i (0..$rowcount) { $x = (($i/$rowcount)*$chartwidth)+1; $v = $ref->{data}->{row}->[$i-1]->{v}->[$wanted]; if($nonzero) { $y = $chartheight - (($v-$valmin)/($valmax-$valmin))*$chartheight + $linethickness*2; } else { $y = $chartheight - ($v/$valmax)*$chartheight + $linethickness*2; } $xpts[$i] = $x; $ypts[$i] = $y; $lastval = $v; } for $i (2..$rowcount) { $colour = $linecolour; if($i==$rowcount) { $colour=$red; } # now set that as the anti-alias colour # $colour = $im->setAntiAliased($colour); # $colour = gdAntiAliased; # $img->line($xpts[$i-1],$chartheight-$ypts[$i-1],$xpts[$i],$chartheight-$ypts[$i],$colour); # $img->line(color=>$colour, # x1=>$xpts[$i-1], y1=>$ypts[$i-1], # x2=>$xpts[$i], y2=>$ypts[$i], # aa=>1, endp=>1 # ); thickline(image => $img, color=>$colour, x1=>$xpts[$i-1], y1=>$ypts[$i-1], x2=>$xpts[$i], y2=>$ypts[$i], aa=>1, endp=>1, thickness => $linethickness ); # print "LINE: x1=>$xpts[$i-1], y1=>$ypts[$i-1], x2=>$xpts[$i], y2=>$ypts[$i]\n"; } $redtext = format_bytes($lastval); if($unformatted) { $redtext = sprintf("%d",$lastval); } } sub thickline { my %params = @_; my $dx = $params{'x2'} - $params{'x1'}; my $dy = $params{'y2'} - $params{'y1'}; my $len = sqrt($dx*$dx + $dy*$dy); my $ndx = $dx/$len; my $ndy = $dy/$len; # find the normal. my $nx = $ndy; my $ny = -$ndx; my $img = $params{'image'}; my $x1a = $params{'x1'} + $params{'thickness'}*$nx; my $x1b = $params{'x1'} - $params{'thickness'}*$nx; my $x2a = $params{'x2'} + $params{'thickness'}*$nx; my $x2b = $params{'x2'} - $params{'thickness'}*$nx; my $y1a = $params{'y1'} + $params{'thickness'}*$ny; my $y1b = $params{'y1'} - $params{'thickness'}*$ny; my $y2a = $params{'y2'} + $params{'thickness'}*$ny; my $y2b = $params{'y2'} - $params{'thickness'}*$ny; if(1==0) { $img->line( aa => $params{'aa'}, endp => $params{'endp'}, x1 => $params{'x1'} + $params{'thickness'}*$nx, y1 => $params{'y1'} + $params{'thickness'}*$ny, x2 => $params{'x2'} + $params{'thickness'}*$nx, y2 => $params{'y2'} + $params{'thickness'}*$ny, color=>$params{'color'} ); $img->line( aa => $params{'aa'}, endp => $params{'endp'}, x1 => $params{'x1'} - $params{'thickness'}*$nx, y1 => $params{'y1'} - $params{'thickness'}*$ny, x2 => $params{'x2'} - $params{'thickness'}*$nx, y2 => $params{'y2'} - $params{'thickness'}*$ny, color=>$params{'color'} ); } else { $img->polygon( points => [ [$x1a,$y1a], [$x2a,$y2a], [$x2b,$y2b], [$x1b,$y1b] ], color=>$params{'color'} ); } } sub min { if($_[0] < $_[1]) { return $_[0]; } else { return $_[1]; } } sub max { if($_[0] > $_[1]) { return $_[0]; } else { return $_[1]; } }