SPUG: Dealing with version incompatibility

Doug Beaver dougb at scalar.org
Mon May 29 20:08:06 CDT 2000


On Mon, May 29, 2000 at 03:02:02PM -0700, Sanford Morton wrote:
> Here's a longish question on dealing with version incompatibility. 
> 
> I am revising my Chart::Plot module, which is an interface to GD to
> draw charts. GD has a complicated history in the image formats it can
> draw. Early versions could draw only gif, recent versions could draw
> only png, and the latest version can draw both jpeg and png. 

[snip]
 
> There is no obvious choice about what format to use as default. I
> initially thought the default should vary depending on the GD version,
> on the grounds that a default should at least be valid. However a user
> wrote:
> 
>   I'm not so keen on having a default value change dependant upon the
>   level of an external library. IMHO it would be best to stick with
>   the 'gif' default, and enforce explicit changes to png or jpeg.  ...
>   [E]xternal programs ... are expecting specific image types to be
>   generated. It seems a little overkill to have to load a module just
>   to find out what it's going to generate! ... [T]he documentation
>   only gets read when something doesn't work, and it's better that it
>   doesn't work on installation, than 6 months down the line...
> 
> This seems like a good argument, though on a server, the installer may
> not be the only user of Chart::Plot; also someone else may upgrade GD
> after installation.

The other thing is that they might never even have the gif version of GD
installed, so you wouldn't be able to make gif the default anyways.

This is a tough call, but I think you should change the interface for
your module so that the user is expected to call $self->image_type() in
a list context in order to figure out what formats are supported.  Then
they can pick which one they like and call $self->image_type('gif') if
their GD supports gif or $self->image_type('png') if theirs supports
png.  I think it makes more sense to set the output format through the
image_type() method instead of the draw() method, so that users of your
module would do this:

use Chart::Plot;

my $plot = new Chart::Plot;
$plot->setData(\@data);
$plot->setGraphOptions (
    'horGraphOffset'  => 75,
    'vertGraphOffset' => 100,
    'title'           => 'My Graph Title',
    'horAxisLabel'    => 'my X label',
    'vertAxisLabel'   => 'my Y label'
);

my @favored_format_order = qw/gif png jpeg/;
my %image_types = map { $_ => 1 } $plot->image_type();
my $image_format;

for my $format (@favored_format_order) {
    if ($image_types{$format}) {
        $image_format = $format;
        last;
    }
}
$plot->image_type($image_format);

my $image = "$image.$image_format";
open(OUT, ">$image") || die "Can't write $image: $!";
print OUT $plot->draw;
close OUT;
__END__

Of course, then they have to write code to select which format they
want.  But you could easily write a couple of methods that let them
input the formats they want in preferential order and then the module
could figure out what formats are supported and return the best choice
for the user.

Maybe something like this:

$plot->setPreferredImageTypes(qw/gif png jpeg/);
my $output_format = $plot->pickBestImageType;
$plot->image_type($output_format);
print $plot->draw;

That way, they could pick by hand if they wanted to by passing an
argument to the image_type() method, or they could just pass a list to
the module and let it pick the best format for them.

Feel free to ignore what I said, I just went and took a quick look at
the pod below and the current module's interface and made a few quick
suggestions based on what sort of interface I'd like to use if I was
using the module on a regular basis...

Doug

> This is likely to be a script breaking issue, since the user must know
> the type to save to a file with the correct extension (on some
> platforms) or to return the correct content type from a cgi script.
> Further, a number of users persist in older versions of GD which write
> gif files (myself included) so making png the default independent of
> GD version, assuming older versions will be little used, will break a
> lot of scripts.
> 
> So, what's a module writer to do? I'd appreciate comments on what
> users are likely to find most rational and convenient. Below is a
> current draft of the relevant pod section.
>
> 
> Thanks, 
> Sandy Morton
> 
> ======================= pod =============================
> 
> Draw the image: draw()
> 
>      $img->draw();
>      $img->draw('png') or die "$img->error()"; 
> 
> This method draws the image and returns it as a string, which you can
> print to a file or to STDOUT. (This should be the last method called
> from the $img object.)  You will generally need to know which image
> format your version of GD supports: if it supports png, then to save
> the image in a file:
> 
>     open (WR,'>plot.png') or die ("Failed to open file: $!");
>     binmode WR;            # for DOSish platforms
>     print WR $img->draw();
>     close WR;
> 
> Of course, if you have a version of GD which supports only gif, change
> the file extension to gif.  Versions of GD 1.19 and below supported
> only gif image format. Versions between 1.20 and 1.26 support only png
> format.  $img->draw() will use whatever format your version of GD
> supports. Yet often, you must know the type to write the correct file
> extension or to return the correct content type from a cgi script. If
> you are not sure, or suspect the GD version may change, you can use
> 
>     $extension = $img->image_type();
>     open (WR,">plot.$extension");
> 
> to return the type, 'png' or 'gif'. 
> 
> GD version 1.27 supports both png and jpeg image formats. For this
> version, $img->draw() will default to 'png' unless you supply 'jpeg'
> as the argument.  $img->image_type() will return 'png' in scalar
> context and the list (png,jpeg) in array context.
> 
> If $img->draw() fails, it will return undef and an error messgae will
> be set. $img->error() will return 'The image format ... is not
> supported by this version ... of GD.' or whatever error message is
> returned by GD (such as an out of memory error).
> 
> 
>  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>      POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
>  Seattle Perl Users Group (SPUG) Home Page: http://www.halcyon.com/spug/
>  For Subscriptions, Email to majordomo at pm.org:  ACTION  spug-list  EMAIL
>   Replace ACTION by subscribe or unsubscribe, EMAIL by your Email address
> 
> 

-- 
Smithers: I'm afraid we have a bad image, Sir.  Market research shows
          people see you as somewhat of an ogre.
   Burns: I ought to club them and eat their bones!

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
 Seattle Perl Users Group (SPUG) Home Page: http://www.halcyon.com/spug/
 For Subscriptions, Email to majordomo at pm.org:  ACTION  spug-list  EMAIL
  Replace ACTION by subscribe or unsubscribe, EMAIL by your Email address





More information about the spug-list mailing list