Subject: | PATCH - adds AA and alpha support |
This patch adds truecolor, anti-aliasing and alpha support to most types
of charts. Truecolor only gets used if you have libgd2 (preferably
2.27+), and I can't guarantee what happens under GD1 if you try to use
AA or alpha (I'm guessing it breaks).
Mostly the changes to GD::Graph are not very noticeable, although I like
the effect it has on area graphs (see http://www.presinet.com/area.png,
alpha => 32, aa => 1, otherwise a normal area graph).
I haven't gone through it carefully, but I'm pretty sure this patch
could be greatly reduced by moving alpha up to the Graph object and
having the set_clr family automatically use it (from reading the library
source, all calls without alpha are automatically sent to the alpha
versions anyways, regardless of palette vs truecolor or anything else).
I have also done the same stuff for GD::Graph3d, including improved code
for 3d pies (see http://www.presinet.com/new_pie.png). I'll link these
two patches together in RT once I've created the other one.
Subject: | gdgraph-aaalpha.patch |
Index: Graph.pm
===================================================================
--- Graph.pm (.../Graph.pm) (revision 24071)
+++ Graph.pm (.../GDGraph/trunk/Graph.pm) (working copy)
@@ -109,7 +109,7 @@
#
# PUBLIC methods, documented in pod.
#
-sub new # ( width, height ) optional;
+sub new # ( width, height, truecolor ) optional;
{
my $type = shift;
my $self = {};
@@ -119,10 +119,12 @@
{
# If there are any parameters, they should be the size
return GD::Graph->_set_error(
- "Usage: GD::Graph::<type>::new(width, height)") unless @_ >= 2;
+ "Usage: GD::Graph::<type>::new(width, height, truecolor)") unless @_ >= 2;
$self->{width} = shift;
$self->{height} = shift;
+ $self->{truecolor} = shift;
+ $self->{truecolor} = 0 unless defined($self->{truecolor});
}
else
{
@@ -283,10 +285,15 @@
{
my $self = shift;
return $self->{graph} if exists $self->{graph};
- $self->{graph} = 2.0 <= $GD::VERSION
- ? GD::Image->newPalette($self->{width}, $self->{height})
- : GD::Image->new($self->{width}, $self->{height});
-
+ if (2.0 <= $GD::VERSION){
+ if ($self->{truecolor}){
+ $self->{graph} = GD::Image->newTrueColor($self->{width}, $self->{height});
+ } else {
+ $self->{graph} = GD::Image->newPalette($self->{width}, $self->{height});
+ }
+ } else {
+ $self->{graph} = GD::Image->new($self->{width}, $self->{height});
+ }
}
# Initialise the graph output canvas, setting colours (and getting back
@@ -298,6 +305,11 @@
my $self = shift;
$self->{bgci} = $self->set_clr(_rgb($self->{bgclr}));
+ if ($self->{truecolor}){
+ #fake up the background, since it doesn't work with the first allocated color,
+ #like in palette based images
+ $self->{graph}->filledRectangle(0,0,$self->{width},$self->{height},$self->{bgci});
+ }
$self->{fgci} = $self->set_clr(_rgb($self->{fgclr}));
$self->{tci} = $self->set_clr(_rgb($self->{textclr}));
$self->{lci} = $self->set_clr(_rgb($self->{labelclr}));
@@ -387,6 +399,8 @@
return unless @_;
my $gd = $self->{graph};
+ return $gd->colorResolveAlpha(@_) if @_ > 3;
+
# All of this could potentially be done by using colorResolve
# The problem is that colorResolve doesn't return an error
# condition (-1) if it can't allocate a color. Instead it always
@@ -399,13 +413,6 @@
# if this fails, we should use colorClosest.
$i = $gd->colorClosest(@_) if $i < 0;
- # TODO Deal with antialiasing here?
- if (0 && $self->can("setAntiAliased"))
- {
- $self->setAntiAliased($i);
- eval "$i = gdAntiAliased";
- }
-
return $i;
}
@@ -435,6 +442,8 @@
{
my $self = shift;
return unless @_;
+
+ return $self->{graph}->colorAllocateAlpha(@_) if @_ > 3;
$self->{graph}->colorAllocate(@_);
}
@@ -669,13 +678,32 @@
=over 4
-=item GD::Graph::chart-E<gt>new([width,height])
+=item GD::Graph::chart-E<gt>new([width,height,truecolor])
-Create a new object $graph with optional width and heigth.
-Default width = 400, default height = 300. I<chart> is either
-I<bars>, I<lines>, I<points>, I<linespoints>, I<area>, I<mixed> or
-I<pie>.
+Create a new object $graph with optional width, height and truecolor.
+Default width = 400, default height = 300, default truecolor = 0.
+I<chart> is either I<bars>, I<lines>, I<points>, I<linespoints>,
+I<area>, I<mixed> or I<pie>.
+If you pass a 3rd argument of 1 to the new method, you get a truecolor graph,
+instead of palette-based. This opens up some additional options for the
+3d graphs:
+
+=over 4
+
+=item alpha
+
+Sets the alpha channel component of the data point colours. This only has
+an effect on things coloured by dclrs. 0 is opaque (default),
+becoming more transparent up to 127 (completely transparent).
+
+=item aa
+
+1 or 0 (default). If this is set to one, the data points will be
+anti-aliased. This will smooth the lines/arcs used to make the graph.
+
+=back
+
=item $graph-E<gt>set_text_clr(I<colour name>)
Set the colour of the text. This will set the colour of the titles,
Index: Graph/area.pm
===================================================================
--- Graph/area.pm (revision 24074)
+++ Graph/area.pm (working copy)
@@ -16,6 +16,7 @@
use strict;
use GD::Graph::axestype;
+use GD;
@GD::Graph::area::ISA = qw( GD::Graph::axestype );
@@ -30,8 +31,14 @@
$self->{_data}->error);
# Select a data colour
- my $dsci = $self->set_clr($self->pick_data_clr($ds));
- my $brci = $self->set_clr($self->pick_border_clr($ds));
+ my $dsci = $self->set_clr($self->pick_data_clr($ds),$self->{alpha});
+ my $brci;
+ my @rgb = $self->pick_border_clr($ds);
+ if (@rgb > 0){
+ $brci = $self->set_clr(@rgb,$self->{alpha});
+ } else {
+ $brci = undef;
+ }
# Create a new polygon
my $poly = GD::Polygon->new();
@@ -84,10 +91,19 @@
}
# Draw a filled and a line polygon
- $self->{graph}->filledPolygon($poly, $dsci)
- if defined $dsci;
- $self->{graph}->polygon($poly, $brci)
- if defined $brci;
+ if ($self->{aa}){
+ $self->{graph}->setAntiAliased($dsci);
+ $self->{graph}->filledPolygon($poly, gdAntiAliased)
+ if defined $dsci;
+ $self->{graph}->setAntiAliased($brci);
+ $self->{graph}->polygon($poly, gdAntiAliased)
+ if defined $brci;
+ } else {
+ $self->{graph}->filledPolygon($poly, $dsci)
+ if defined $dsci;
+ $self->{graph}->polygon($poly, $brci)
+ if defined $brci;
+ }
# Draw the accent lines
if (defined $brci &&
Index: Graph/lines.pm
===================================================================
--- Graph/lines.pm (revision 24074)
+++ Graph/lines.pm (working copy)
@@ -31,7 +31,7 @@
return $self->_set_error("Impossible illegal data set: $ds",
$self->{_data}->error);
- my $dsci = $self->set_clr($self->pick_data_clr($ds) );
+ my $dsci = $self->set_clr($self->pick_data_clr($ds), $self->{alpha} );
my $type = $self->pick_line_type($ds);
my ($xb, $yb);
@@ -154,7 +154,12 @@
# Need the setstyle to reset
$self->{graph}->setStyle(@pattern) if (@pattern);
- $self->{graph}->line( $xs, $yslw, $xe, $yelw, $style );
+ if ($self->{aa}){
+ $self->{graph}->setAntiAliased($style);
+ $self->{graph}->line( $xs, $yslw, $xe, $yelw, gdAntiAliased);
+ } else {
+ $self->{graph}->line( $xs, $yslw, $xe, $yelw, $style );
+ }
}
}
@@ -163,7 +168,7 @@
my $self = shift;
my ($n, $x, $y) = @_;
- my $ci = $self->set_clr($self->pick_data_clr($n));
+ my $ci = $self->set_clr($self->pick_data_clr($n),$self->{alpha});
return unless defined $ci;
my $type = $self->pick_line_type($n);
Index: Graph/points.pm
===================================================================
--- Graph/points.pm (revision 24074)
+++ Graph/points.pm (working copy)
@@ -31,7 +31,7 @@
$self->{_data}->error);
# Pick a colour
- my $dsci = $self->set_clr($self->pick_data_clr($ds));
+ my $dsci = $self->set_clr($self->pick_data_clr($ds),$self->{alpha});
my $type = $self->pick_marker($ds);
for (my $i = 0; $i < @values; $i++)
@@ -163,7 +163,7 @@
my $x = shift;
my $y = shift;
- my $ci = $self->set_clr($self->pick_data_clr($n));
+ my $ci = $self->set_clr($self->pick_data_clr($n),$self->{alpha});
my $old_ms = $self->{marker_size};
my $ms = _min($self->{legend_marker_height}, $self->{legend_marker_width});
Index: Graph/bars.pm
===================================================================
--- Graph/bars.pm (revision 24074)
+++ Graph/bars.pm (working copy)
@@ -83,7 +83,7 @@
my $self = shift;
my ($ds, $i, $value, $topvalues, $l, $t, $r, $b) = @_;
my $bsd = $self->{shadow_depth} or return;
- my $bsci = $self->set_clr(_rgb($self->{shadowclr}));
+ my $bsci = $self->set_clr(_rgb($self->{shadowclr}),$self->{alpha});
if ($self->{cumulate})
{
@@ -136,9 +136,15 @@
my $bar_s = $self->{bar_spacing}/2;
# Pick a data colour
- my $dsci = $self->set_clr($self->pick_data_clr($ds));
+ my $dsci = $self->set_clr($self->pick_data_clr($ds),$self->{alpha});
# contrib "Bremford, Mike" <mike.bremford@gs.com>
- my $brci = $self->set_clr($self->pick_border_clr($ds));
+ my $brci;
+ my @rgb = $self->pick_border_clr($ds);
+ if (@rgb > 0){
+ $brci = $self->set_clr(@rgb,$self->{alpha});
+ } else {
+ $brci = undef;
+ }
my @values = $self->{_data}->y_values($ds) or
return $self->_set_error("Impossible illegal data set: $ds",
@@ -159,9 +165,9 @@
#
# cycle_clrs option sets the color based on the point,
# not the dataset.
- $dsci = $self->set_clr($self->pick_data_clr($i + 1))
+ $dsci = $self->set_clr($self->pick_data_clr($i + 1),$self->{alpha})
if $self->{cycle_clrs};
- $brci = $self->set_clr($self->pick_data_clr($i + 1))
+ $brci = $self->set_clr($self->pick_data_clr($i + 1),$self->{alpha})
if $self->{cycle_clrs} > 1;
# get coordinates of right and center of bar
@@ -212,9 +218,9 @@
my $bar_s = $self->{bar_spacing}/2;
# Pick a data colour
- my $dsci = $self->set_clr($self->pick_data_clr($ds));
+ my $dsci = $self->set_clr($self->pick_data_clr($ds),$self->{alpha});
# contrib "Bremford, Mike" <mike.bremford@gs.com>
- my $brci = $self->set_clr($self->pick_border_clr($ds));
+ my $brci = $self->set_clr($self->pick_border_clr($ds),$self->{alpha});
my @values = $self->{_data}->y_values($ds) or
return $self->_set_error("Impossible illegal data set: $ds",
@@ -242,9 +248,9 @@
#
# cycle_clrs option sets the color based on the point,
# not the dataset.
- $dsci = $self->set_clr($self->pick_data_clr($i + 1))
+ $dsci = $self->set_clr($self->pick_data_clr($i + 1),$self->{alpha})
if $self->{cycle_clrs};
- $brci = $self->set_clr($self->pick_data_clr($i + 1))
+ $brci = $self->set_clr($self->pick_data_clr($i + 1),$self->{alpha})
if $self->{cycle_clrs} > 1;
# get coordinates of top and center of bar
Index: Graph/axestype.pm
===================================================================
--- Graph/axestype.pm (revision 24074)
+++ Graph/axestype.pm (working copy)
@@ -147,6 +147,9 @@
borderclrs => undef,
+ aa => 0,
+ alpha => 0,
+
# XXX
# Multiple inheritance (linespoints and mixed) finally bit me. The
# _has_defaults and set methods can only work correctly when the
@@ -2095,7 +2098,7 @@
my $g = $s->{graph};
- my $ci = $s->set_clr($s->pick_data_clr($n));
+ my $ci = $s->set_clr($s->pick_data_clr($n),$s->{slpha});
return unless defined $ci;
$y += int($s->{lg_el_height}/2 - $s->{legend_marker_height}/2);