NAME

PDL::Drawing::Prima - PDL-aware drawing functions for Prima widgets

CPAN

You, gentle reader, are reading this documentation off of CPAN. I know this because this documentation does not show up in the final .pm files that are installed on a user's computer. I have gone to great lengths to ensure that the CPAN-visible documentation is up-to-date, but it may be incomplete in certain circumstances since PDL autogenerates some of its documentation. If you have any concerns regarding documentation skew, be sure to check the documentation on your local machine.

SYNOPSIS

Each of the methods comes with a small sample snippet. To see how it looks, copy this synopsis and replace the code in the Example code goes here block with the example code.

use strict;
use warnings;
use PDL;
use PDL::Drawing::Prima;
use Prima qw(Application);

my $window = Prima::MainWindow->create(
    text    => 'PDL::Drawing::Prima Test',
    onPaint => sub {
        my ( $self, $canvas) = @_;

        # wipe the canvas:
        $canvas->clear;
        
        ### Example code goes here ###
        
        # Draw a sine curve on the widget:
        my ($width, $height) = $canvas->size;
        my $x = sequence($width);
        my $y = ( sin($x / 20) + 1 ) * $height/2;
        $canvas->pdl_polylines($x, $y, lineWidths => 2);
        
        ### Example code ends here ###
    },
    backColor => cl::White,
);

run Prima;

DESCRIPTION

This module provides a number of PDL-threaded functions and bindings for use with the Prima toolkit. Many of the functions are PDL bindings for the standard Prima drawing functions. Others are useful functions for color manipulation, or getting data into a form that PDL knows how to handle. I generally divide the subroutines of this module into two categories: methods and functions. The methods are subroutines that operate on a Prima widget; the functions are subroutines that act on or return piddles.

Most of the methods given here are PDLified versions of the Prima drawing API functions, which are documented under Prima::Drawable. In general, where the Prima API uses singular nouns, I here use plural nouns. A few of the methods are only available in this module, mostly added to accomodate the needs of PDL::Graphics::Prima, the plotting library built on these bindings.

At the moment, only drawing on displayed widgets is supported. However, I believe it is possible to revise these bindings with only a few modifications to get them to work on any Prima::Drawable object. Hopefully those revisions will happen soon.

COORDINATE ORIGIN

The Prima image coordinate origin is located in lower left corner, which is where you would expect to find it when creating plots. However, it is different from the way that many graphics libraries do their coordinates.

FUNCTIONS

piddle_of_patterns_for

If you want PDL to thread over line patterns, but you want to use the standard Prima line patterns, you'll need to convert them line patterns to a piddle. This works very simply like this:

my $patterns = piddle_of_patterns_for(lp::Solid, lp::Dash);

This creates a piddle with the two patterns so that you could have PDL thread over them.

You can also create your own line pattern piddles by hand. I recommend you use byte array, since otherwise it will be converted to byte arrays for you. The first element of a row in your byte array specifies the number of pixels to be "on", the second specifies the number to be "off", the third specifies the number to be "on" again, the fourth "off", the fifth "on", etc. If that doesn't make sense, hopefull a couple of examples will help clarify.

This example creates the equivalent of lp::Dash:

my $dash_pattern = byte (9, 3);

This example creates a piddle with four line types: lp::Solid, lp::Dash, lp::ShortDash, and lp::DashDot:

my $patterns = byte q[ 1; 9 3; 3 3; 9 3 1 3];

and should be identical to

my $patterns = piddle_of_patterns_for(
    lp::Solid, lp::Dash, lp::ShortDash, lp::DashDot);

When you create a byte piddle, all of the patterns must have the same number of bytes in their specification. Of course, different patterns have different lengths, so in that case simply pad the shorter specifications with zeroes.

piddle_of_handles_for

You can call a single drawing function on multiple widgets and have PDL thread over the widgets for you. Why would anyone ever want to do that, you ask? The only reason I can imagine is if somebody wanted to create a new set of widget skins, in which case you'd want to call the same drawing function on various widgets (with various parameters, obviously). Will this ever happen in practice? Probably not, but if I can come up with a use case, I'm sure somebody else can come up with a different use case, so I've implemented it.

When you call piddle_of_handles_for, you get back a PDL_LongLong piddle. The values returned are the actual integer values used as the handles to the widgets, i.e. they are pointers, which means you SHOULD NOT MODIFY THEM or you will almost certainly get a segmentation fault. I believe there is a way to mark a piddle as read-only, but I'm not quite sure how to do that.

METHODS

The methods described below are a bit unusual for PDL functions. First, they are not actually PDL functions at all but are methods for Prima::Drawable objects. Second, their signatures will look a bit funny. Don't worry too much about that, though, because they will resemble normal signatures close enough that you should be able to understand them, I hope.

pdl_arcs

Prima Signature: (widget; x(); y(); x_diameter(); y_diameter();
                   start_angle(); end_angle(); properties)

Draws arcs, i.e. incomplete ellipses.

The arcs go from the start_angles to the end_angles along the ellipses centered at the xs and ys, with the specified x- and y-diameters. The angles are measured in degrees, not radians. The difference between this command and "chords" or "sectors" is that arcs does not connect the dangling ends.

Here's a simple example:

# Draw a bunch of random arcs on $canvas:
my $N_arcs = 20;
my ($x_max, $y_max) = $canvas->size;
my $xs = zeroes($N_arcs)->random * $x_max;
my $ys = $xs->random * $y_max;
my $dxs = $xs->random * $x_max / 4;
my $dys = $xs->random * $y_max / 4;
my $th_starts = $xs->random * 360;
my $th_stops = $xs->random * 360;

# Now that we've generated the data, call the command:
$canvas->pdl_arcs($xs, $ys, $dxs
               , $dys, $th_starts, $th_stops);

If you put that snippet of code in the onPaint method, as suggested in the synopsis, a completely new set of arcs will get redrawn whenever you resize your window.

Compare to the Prima method "arc" in Prima::Drawable. Closely related routines include "pdl_chords" and "pdl_sectors". See also "pdl_fill_chords", and "pdl_fill_sectors", "pdl_ellipses", and "pdl_fill_ellipses".

Spline drawing provides a similar functionality, though more complex and more powerful. There are no PDL bindings for the spline functions yet. See "spline" in Prima::Drawable for more information.

Applicable properties are likely to include handles, colors, backColors, lineEnds, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_bars

Prima Signature: (widget; x1(); y1(); x2(); y2(); properties)

Draws filled rectangle from corner (x1, y1) to (x2, y2).

# Draw 20 random filled rectangles on $canvas:
my $N_bars = 20;
my ($x_max, $y_max) = $canvas->size;
my $x1s = zeroes($N_bars)->random * $x_max;
my $y1s = $x1s->random * $y_max;
my $x2s = $x1s + $x1s->random * ($x_max - $x1s);
my $y2s = $y1s + $x1s->random * ($y_max - $y1s);
my $colors = $x1s->random * 2**24;

# Now that we've generated the data, call the command:
$canvas->pdl_bars($x1s, $y1s, $x2s, $y2s
        , colors => $colors);

If you put that snippet of code in the onPaint method, as suggested in the synopsis, a completely new set of filled rectangles will get redrawn whenever you resize your window.

Compare to the Prima method "bar" in Prima::Drawable. See also "pdl_rectangles", which is the unfilled equivalent, and "pdl_clears", which is sorta the opposite of this.

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_chords

Prima Signature: (widget; x(); y(); x_diameter(); y_diameter();
                         start_angle(); end_angle(); properties)

Draws arcs (i.e. incomplete ellipses) whose ends are connected by a line.

The chord starts at start_angle and runs to end_angle along the ellipse centered at x, y, with their specified diameters x_diameter, y_diameter. Unlike "arcs" or "sectors", it connects the ends of the arc with a straight line. The angles are measured in degrees, not radians.

# For this example, you will need:
use PDL::Char;

# Draw a bunch of random arcs on $canvas:
my $N_chords = 20;
my ($x_max, $y_max) = $canvas->size;
my $xs = zeroes($N_chords)->random * $x_max;
my $ys = $xs->random * $y_max;
my $dxs = $xs->random * $x_max / 4;
my $dys = $xs->random * $y_max / 4;
my $th_starts = $xs->random * 360;
my $th_stops = $xs->random * 360;

# make a small list of patterns:
my $patterns_list = PDL::Char->new(
         [lp::Solid, lp::Dash, lp::DashDot]);

# Randomly select 20 of those patterns:
my $rand_selections = ($xs->random * 3)->byte;
use PDL::NiceSlice;
my $patterns = $patterns_list($rand_selections)->transpose;

# Now that we've generated the data, call the command:
$canvas->pdl_chords($xs, $ys, $dxs
               , $dys, $th_starts, $th_stops
               , linePatterns => $patterns);

If you put that snippet of code in the onPaint method, as suggested in the synopsis, a completely new set of chords will get redrawn whenever you resize your window.

Compare to the Prima method "chord" in Prima::Drawable. The filled equivalent is "pdl_fill_chords". Closely related routines are "pdl_arcs" and "pdl_sectors". See also "pdl_fill_sectors", "pdl_ellipses", and "pdl_fill_ellipses", as well as "spline" in Prima::Drawable.

Applicable properties are likely to include handles, colors, backColors, clipRects, lineEnds, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_clears

Prima Signature: (widget; x1(); y1(); x2(); y2(); properties)

Clears the specified rectangle(s).

my ($width, $height) = $canvas->size;
# Begin by drawing a filled rectangle:
$canvas->color(cl::Blue);
$canvas->bar(0, 0, $width, $height);

# Now cut random rectangles out of it:
my $N_chunks = 20;
my $x1 = random($N_chunks) * $width;
my $x2 = random($N_chunks) * $width;
my $y1 = random($N_chunks) * $width;
my $y2 = random($N_chunks) * $width;
$canvas->pdl_clears($x1, $y1, $x2, $y2);

Like the other examples, this will give you something new whenever you resize the window if you put the code in the onPaint method, as the Synopsis suggests.

Compare to the Prima method "clear" in Prima::Drawable. In practice I suppose this might be considered the opposite of "pdl_bars", though technically this is meant for erasing, not drawing.

Applicable properties are likely to include handles, backColors, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_ellipses

Prima Signature: (widget; x(); y(); x_diameter();
                        y_diameter(); properties)

Draws an ellipse centered at x, y with diameters x_diameter and y_diameter. To draw circles, just use the same x- and y-diameter.

working here

Compare to the Prima method "ellipse" in Prima::Drawable. The filled equivalent is "pdl_fill_ellipses". See also "pdl_arcs", "pdl_chords", and "pdl_sectors" as well as "pdl_fill_chords" and "pdl_fill_sectors". You may also be interested in "spline" in Prima::Drawable, which does not yet have a PDL interface.

Applicable properties are likely to include handles, colors, backColors, clipRects, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_fill_chords

Prima Signature: (widget; x(); y(); x_diameter(); y_diameter();
                        start_angle(); end_angle(); properties)

Draws an arc from start_angle to end_angle along the ellipse centered at x, y, each with their specified diameters. The ends are connected with a line and the interior is filled. Use this to draw the open-mouth part of a smiley face.

# working here:
$canvas->pdl_fill_chords($x, $y, $xd, $yd, $ti, $tf);

Compare to the Prima method "fill_chord" in Prima::Drawable. The unfilled equivalent is "pdl_chords". Closely related to "pdl_fill_ellipses" and "pdl_fill_sectors". See also "pdl_arcs", "pdl_ellipses", and "pdl_sectors".

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_fill_ellipses

Prima Signature: (widget; x(); y(); x_diameter();
                        y_diameter(); properties)

Draws a filled ellipse centered at x, y, with diameters x_diameter and y_diameter. To draw filled circles, use the same value for both diameters.

# working here
$canvas->pdl_fill_ellipses($x, $y, $xd, $yd);

Compare to the Prima method "fill_ellipse" in Prima::Drawable. The unfilled equivalent is "pdl_ellipses". Closely related to "pdl_fill_chords" and "pdl_fill_ellipses", and "pdl_fill_sectors". See also "pdl_arcs", "pdl_ellipses", and "pdl_sectors". Also, check out "fill_spline" in Prima::Drawable, which does not yet have PDL bindings.

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_fillpolys

Prima Signature: (widget; x(n); y(n); properties)

Draws and fills a polygon with (mostly) arbitrary edge vertices.

NOTE: there is no underscore between fill and poly, which is different from the other fill methods!

This is useful for drawing arbitrary filled shapes and for visualizing integrals. Splines would be the better choice if you want to draw curves, but a PDL interface to splines is not (yet) implemented.

Unlike most of the other methods, this one actually makes a half-hearted effort to process bad values. In addition to the IEEE bad values of nan and inf, PDL has support for bad values. Unlike in pdl_polys, pdl_fillpolys will simply skip any point that is marked as bad, but drawing the rest of the polygon. In other words, it reduces the degree of your polygon by one. If you sent it four points and one of them was bad, you would get a triangle instead of a quadralaters.

Infinities are also handled, though not perfectly. There are a few situations where pdl_polys will correctly draw what you mean but pdl_fillpolys will not.

Because this skips bad data altogether, if you have too much bad data (i.e. fewer than three good points), the routine will simply not draw anything. I'm debating if this should croak, or at least give a warning. (Of course, a warning to STDOUT is rather silly for a GUI toolkit.)

For example:

# working here
$canvas->pdl_fillpolys($x, $y);

Compare to the Prima method "fillpoly" in Prima::Drawable. See also "pdl_bars" and pdl_polylines.

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, fillWindings, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_fill_sectors

Prima Signature: (widget; x(); y(); x_diameter(); y_diameter();
                        start_angle(); end_angle(); properties)

Draws an arc from start_angle to end_angle along the ellipse centered at x, y, with specified x- and y-diameters. Like "fill_chords", this command connects the end points of the arc, but unlike "fill_chords", it does so by drawing two lines, both of which also connect to the ellipse's center. This results in shapes that look like pie pieces.

# working here
$canvas->pdl_fill_sectors($x, $y, $xd, $yd, $th1, $th2);

Compare to the Prima method "fill_sector" in Prima::Drawable. The unfilled equivalent is "pdl_sectors". This is closely related to /pdl_fill_chords and /pdl_fill_ellipses. See also "pdl_arcs", "pdl_chords", and "pdl_ellipses".

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_flood_fills

Prima Signature: (widget; x(); y(); color();
                 singleborder(); properties)

# working here:

Fills an area of the canvas...

working here

Applicable properties are likely to include handles, colors, backColors, clipRects, fillPatterns, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_lines

Prima Signature: (widget; x1(); y1(); x2(); y2(); properties)

Draws a line from (x1, y1) to (x2, y2).

In contrast to polylines, which are supposed to be connected, these lines are meant to be independent.

working here

Applicable properties are likely to include handles, colors, backColors, clipRects, lineEnds, lineJoins, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_polylines

Prima Signature: (widget; x(n); y(n); properties)

Draws a multi-segment line on a widget with the given x- and y-coordinates.

This is useful for making line-drawings, such as plotting data.

# Draw a sine curve on the widget:
my $x = sequence(200);
my $y = ( sin($x / 20) + 1 ) * 50;
$canvas->pdl_polylines($x, $y);

Applicable properties are likely to include handles, colors, backColors, clipRects, lineEnds, lineJoins, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order. color, backColor, linePattern, lineWidth, lineJoin, lineEnd, rop, rop2

pdl_rectangles

Prima Signature: (widget; x1(); y1(); x2(); y2(); properties)

Draws a rectangle from corner (x1, y1) to (x2, y2).

working here

Applicable properties are likely to include handles, colors, backColors, clipRects, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

pdl_sectors

Prima Signature: (widget; x(); y(); x_diameter(); y_diameter(); start_angle(); end_angle(); properties)

Draws an arc from start_angle to end_angle along the ellipse centered at x, y, each with their specified diameters. The difference between this command and chords is that this command does not connect the ends of the arcs with straight lines but leaves the arcs open

working here

Applicable properties are likely to include handles, colors, backColors, clipRects, lineEnds, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date or out of order. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties, in their correct order.

PDL-ONLY METHODS

These are drawing methods that have no analogous Prima::Drawable function.

pdl_symbols

Signature: (widget; x(); y(); N_points(); orientation(); filled(); size(); skip(); properties)

Draws a wide variety of symbols centered at (x, y).

Through various combinations of N_points, filled, and skip, you can generate many different regular symbols, including dashes, stars, asterisks, triangles, and diamonds. You can also specify each symbol's size and orientation. The size is the radius of a circle that would circumscribe the shape. The orientation is... well... just keep reading.

The shape drawn depends on N_points. If N_points is:

zero or one

This will draw a circle with a radius of the given size. The circle will be filled or not based on the value passed for filled, but the orientation and skip parameters are ignored. This is almost redundant compared with the ellipse functions, except that this arrangement makes it very easy to thead over filled/not-filled, and you cannot specify an eccentricity for your points using pdl_symbols.

two

This will draw a line centered at (x, y) and with a length of 2*size. The orientation is measured in degrees, starting from horizontal, with increasing angles rotating the line counter-clockwise. The value for skip is ignored.

This is particulary useful for visualizing slope-fields (although calculating the angles for the slope field is surprisingly tricky).

three or more

This will draw a shape related to a regular polygon with the specified number of sides. Precisely what kind of polygon it draws is based on the value of skip. For example, a five-sided polygon with a skip of one would give you a pentagon:

             second point
                 _
 third   __..--'' \
 point  |          \
        |           \
        |            \  first
        |            /  point
        |           /
        |__        /
fourth     ``--.._/
point
             fifth point

             skip = 1

In contrast, a five-sided polygon with a skip of 2 will give you a star:

                          fourth point
                          
             second          /|                
             point   \`~.._/  |            
                      `\ / `--|.__          
                        X     | __>  first point       
                      ,/ \_,--|'                
             fifth   /_~'' \  |                 
             point           \|
                           
                          third point

                          skip = 2

A skip of three would give visually identical results but the actual order in which the vertices are drawn is different:

                          third point
                          
             fifth           /|                
             point   \`~.._/  |            
                      `\ / `--|.__          
                        X     | __>  first point       
                      ,/ \_,--|'                
             second  /_~'' \  |                 
             point           \|
                           
                          fourth point

                          skip = 3

A skip of zero is a special case, and means draw lines to each point from the center. In other words, create an asterisk:

                          second point
                              
              third            /
              point   `.      / 
                        `.   /   
                          `./_______  first
                          .'\         point
                        .'   \
                      .'      \
             fourth            \
             point
                          fifth point

                          skip = 0

In summary, a skip of zero gives you an N-asterisk. A skip of one gives you a regular polygon. A skip of two gives you a star. And so forth. Higher values of skip are allowed; they simply add to the winding behavior.

Specifying the orientation changes the position of the first point and, therefore, all subsequent points. A positive orientation rotates the first point counter-clockwise by the specified number of degrees. Obviously, due to the symmetry of the shapes, rotations of 360 / N_points look identical to not performing any rotation.

For all nonzero values of skip, specifying a fill will end up with a filled shape instead of a line drawing.

By default, filled stars and other symbols with odd numbers of points have a hole in their middle. However, Prima provides a means for indicating that you want such shapes filled; that is the fillWinding property. As with almost all graphical properties, you can specify the fillWinding property for each symbol by specifying the fillWindings piddle.

This example creates a table of shapes. It uses an argument from the command line to determine the line width.

use PDL::NiceSlice;

# Generate a table of shapes:
my @dims = (40, 1, 30);
my $N_points = xvals(@dims)->clump(2) + 1;
my $orientation = 0;
my $filled = yvals(@dims)->clump(2) + 1;
my $size = 10;
my $skip = zvals(@dims)->clump(2);
my $x = $N_points->xvals * 25 + 25;
my $y = $N_points->yvals * 25 + 25;
my $lineWidths = $ARGV[0] || 1;

# Draw them:
$canvas->pdl_symbols($x, $y, $N_points, 0, $filled, 10, $skip

Bad values are handled by pdl_symbols. If any of the values you pass in are bad, the symbol is not drawn at that x/y coordinate.

Applicable properties are likely to include colors, backColors, clipRects, fillPatterns, fillWindings, lineEnds, linePatterns, lineWidths, rops, rop2s, and translates. However, this list could be out of date. If you've installed this module on your own machine, the documentation is guaranteed to describe the applicable properties.

ERROR MESSAGE

These functions may throw the following exception:

Your widget must be derived from Prima::Drawable

This means that you tried to draw on something that is not a Prima::Drawable object, or a class derived from it. I don't know enough about the Prima internals to know if that has any hope of working, but why do it in the first place?

PDL::PP DETAILS

Those well versed in PDL::PP might ask how I manage to produce pdlified methods that take variable numbers of arguments. That is a long story, and it is told in the volumes of comments in pdlprima.pd. Give it a read if you want to know what goes on behind the scenes.

TODO

These are all the things I wish to do:

Full Drawabel API

I would like a PDL function for every drawable function in the API. Prima Drawable functions that currently do not have an equivalent PDL implementation include "draw_text" in Prima::Drawable, "fill_spline" in Prima::Drawable, "put_image" in Prima::Drawable, "put_image_indirect" in Prima::Drawable, "rect3d" in Prima::Drawable, "rect_focus" in Prima::Drawable, "spline" in Prima::Drawable, "stretch_image" in Prima::Drawable, and "text_out" in Prima::Drawable

Bad Value Support

Bad values are handled decently in "polylines" and "fillpolys", but not for the other functions. Bad x/y values should be skipped for almost all the drawing primitives, but what about bad colors for valid coordinates? I could not draw the primitive, defer to the widget's default color, or use the value associated with the singular key (i.e. color). But I haven't decided which of these is best.

"Atomic" Operations

I would like to be able to specify colors, for example, and have the state of the widget revert back to the original color after the drawing command has finished. In other words, I would like the state of the widget after these drawing commands to be the same that it was before these commands. This can be implemented by having the drawing commands backup the widget's properties before running, and restoring them afterwards.

AUTHOR

David Mertens, <dcmertens.perl@gmail.com>.

SEE ALSO

Some useful PDL/Prima functions are defined in PDL::Drawing::Prima::Utils, especially for converting among simple color formats.

This is built as an extension for the Prima toolkit, http://www.prima.eu.org/, Prima.

This is built using (and targeted at users of) the Perl Data Language, PDL.

This is the bedrock for the plotting package PDL::Graphics::Prima.

Another interface between PDL and Prima is <PDL::PrimaImage>. I am indebted to Dmitry for that module because it gave me a working template for this module, including a working Makefile.PL. Thanks Dmitry!