NAME

Graphics::Framebuffer - A Simple Framebuffer Graphics Library

SYNOPSIS

use Graphics::Framebuffer;

my $fb = Graphics::Framebuffer->new('FB_DEVICE' => '/dev/fb0');

$fb->cls();
$fb->set_color({'red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 255});
$fb->plot({'x' => 28, 'y' => 79,'pixel_size' => 1});
$fb->drawto({'x' => 405,'y' => 681,'pixel_size' => 1});
$fb->circle({'x' => 200, 'y' => 200, 'radius' => 100, 'filled' => 1});
$fb->polygon({'coordinates' => [20,20,  53,3,  233,620], 'pixel_size' => 5});
$fb->box({'x' => 95, 'y' => 100, 'xx' => 400, 'yy' => 600, 'filled' => 1});

# ... and many many more

EXTREMELY IMPORTANT

##### DO NOT TRUST THE CPAN TESTERS DATA FOR THIS MODULE!!  #####
##### This module requires specific hardware configurations #####
##### That typically are not configured for automated CPAN  #####
##### tester systems! You MUST have a system that supports  #####
##### a graphics framebuffer, typically "/dev/fb0".  You    #####
##### also need to test and install in the Linux/FreeBSD    #####
##### console only, not X-Windows.                          #####
#####                                                       #####
##### It is highly likely this will work on your system if  #####
##### the prerequisites are met, regardless of the Perl     #####
##### version.                                              #####

To all of the CPAN testers that are testing with systems meeting the proper system prerequisites and test environments, I thank you greatly. You rock.

DESCRIPTION

A (mostly) Perl graphics library for exclusive use in a Linux/FreeBSD/Unix console framebuffer environment. It is written for simplicity, without the need for complex API's and drivers with "surfaces" and such.

Back in the old days, computers drew graphics this way, and it was simple and easy to do. I was writing a console based media playing program, and was not satisfied with the limited abilities offered by the nCurses library, and I did not want the overhead of the X-Windows environment to get in the way. My intention was to create a mobile media server. In case you are wondering, that project has been quite successful, and I am still making improvements to it. I may even include it in the "examples" directory on future versions.

There are places where Perl just won't cut it. So I use the Imager library to take up the slack. It's just used to load images,, save images, merge, rotate, and draw TrueType/Type1 text. I am also incorporating compiled C to further assist with speed. That is being implemented step by step, but "acceleration" will always be optional, and pure Perl routines always available for those systems without a C compiler or "Inline:C" available.

I cannot guarantee this will work on your video card, but I have successfully tested it on NVidia GeForce, AMD Radeon, Matrox, Raspberry PI, Odroid XU3/XU4, and VirtualBox displays. However, you MUST remember, your video driver MUST be framebuffer based. The proprietary Nvidia and AMD drivers will NOT work with this module. You must use the open source video drivers, such as Nouveau, to be able to use this library (with output to see). Also, it is not going to work from within X-Windows, so don't even try it, it will either crash X, or make a mess on the screen. This is a console only graphics library.

NOTE:

If a framebuffer is not available, the module will go into emulation mode and open a pseudo-screen in the object's hash variable 'SCREEN'

You can write this to a file, whatever. It defaults to a 640x480x32 RGB graphics 'buffer'. However, you can change that by passing parameters to the 'new' method.

You will not be able to see the output directly when in emulation mode. I mainly created this mode so that you could install this module (on systems without a framebuffer) and test code you may be writing to be used on other devices that have accessible framebuffer devices. Nevertheless, I have learned that people use emulation mode as an offscreen drawing surface, and blit from one to the other. Which is pretty clever.

Make sure you have read/write access to the framebuffer device. Usually this just means adding your account to the "video" group. Alternately, you can just run your script as root. Although I don't recommend it.

INSTALLATION

Before you install this, please note it requires the Perl module "Imager". If you are installing via CPAN, then please first make sure your system has the appropriate JPEG, GIF, TIFF, Freetype, and Type1 development libraries installed first. If you don't, then Imager will just be compiled without support for those kinds of files, which pretty much makes it useless.

If you are using a Debian based system (Ubuntu, Weezy, Mint, etc.) then run the following command (and answer yes to the prompt) before doing anything else:

    sudo apt-get install build-essential kernel-headers libjpeg-dev libgif-dev libtiff5-dev libfreetype6-dev fbset

* Those with RedHat based systems, use Yum in place of apt-get.

After you have done this, Then install Imager and the rest of the needed modules.

NOTE: The packaged version of Imager for your distribution should always work (libimager-perl). I also highly suggest installing the packaged version of "Inline::C" (libinline-perl).

When you install this module, please do it within a console, not a console window in X-Windows, but the actual Linux/FreeBSD console outside of X-Windows.

If you are in X-Windows, and don't know how to get to a console, then just hit CTRL-ALT-F1 and it should show you a console. ALT-F7 or ALT-F8 will get you back to X-Windows.

If you are using CPAN, then installation is simple, but if you are installing manually, then the typical steps apply:

    perl Build.pl
    ./Build
    ./Build test
    ./Build install
    
    or...
    
    perl Makefile.PL
    make
    make test
    make install

Please note, that the install step my require root permissions (run it with sudo).

If testing fails, it will usually be ok to install it anyway, as it will likely work. The testing is flakey (thank Perl's test mode for that).

I recommend running the scripts inside of the "examples" directory for real testing instead. In fact, the script "mmapvsfile.pl" will tell which mode you should be running this module in for the fastest speed.

SPECIAL VARIABLES

The following are hash keys to the main object variable. For example, if you use the variable $fb as the object variable, then the following are $fb->{VARIABLE_NAME}

FONTS
List of system fonts

Contains a hash of every font found in the system in the format:
    'FaceName' => {
        'path' => 'Path To Font',
        'font' => 'File Name of Font'
    },
    ...
Imager-Has-TrueType

If your installation of Imager has TrueType font capability, then this will be 1

Imager-Has-Type1

If your installation of Imager has Adobe Type 1 font capability, then this will be 1

Imager-Has-Freetype2

If your installation of Imager has the FreeType2 library rendering capability, then this will be 1

X_CLIP

The top left-hand corner X location of the clipping region

Y_CLIP

The top left-hand corner Y location of the clipping region

XX_CLIP

The bottom right-hand corner X location of the clipping region

YY_CLIP

The bottom right-hand corner Y location of the clipping region.

CLIPPED

If this is true, then the clipping region is smaller than the full screen

If false, then the clipping region is the screen dimensions.

DRAW_MODE

The current drawing mode. This is a numeric value corresponding to the constants described in the method 'draw_mode'

COLOR

The current foreground color encoded as a string.

B_COLOR

The current background color encoded as a string.

ACCELERATED

Indicates if C code or hardware acceleration is being used.

Possible Values
0 = Perl code only (Default)
1 = Some functions accelerated by compiled code
2 = All of #1 plus additional functions accelerated by hardware

Many of the parameters you pass to the "new" method are also special variables.

METHODS

new

This instantiates the framebuffer object

    my $fb = Graphics::Framebuffer->new(parameter => value);

PARAMETERS

FB_DEVICE

Framebuffer device name. If this is not defined, then it tries the following devices in the following order:

*  /dev/fb0 - 31
*  /dev/graphics/fb0 - 31

If none of these work, then the module goes into emulation mode.

FILE_MODE [1 or 0]

Sets the internal drawing system to use file handle mode instead of memory mapped mode. File mode is more stable, but a bit slower. I recommend doing this ONLY if you are having issues with memory mapped mode.

Note:  On TFT modules with a SPI interface, FILE_MODE may
       actually be much faster.  This is the only exception
       to the above that I have found.
FOREGROUND

Sets the default foreground color for when 'attribute_reset' is called. It is in the same format as "set_color" expects:

{ # This is the default value
  'red'   => 255,
  'green' => 255,
  'blue'  => 255,
  'alpha' => 255
}

Do not use this to change colors, as "set_color" is intended for that. Use this to set the DEFAULT foreground color for when "attribute_reset" is called.

BACKGROUND

Sets the default background color for when 'attribute_reset' is called. It is in the same format as "set_b_color" expects:

{ # This is the default value
  'red'   => 0,
  'green' => 0,
  'blue'  => 0,
  'alpha' => 255
}

Do not use this to change background colors, as "set_b_color" is intended for that. Use this to set the DEFAULT background color.

SPLASH

The splash screen is or is not displayed

A value other than zero turns on the splash screen, and the value is the wait time to show it (default 2 seconds) A zero value turns it off

FONT_PATH

Overrides the default font path for TrueType/Type1 fonts

If 'ttf_print' is not displaying any text, then this may need to be overridden.

FONT_FACE

Overrides the default font filename for TrueType/Type 1 fonts.

If 'ttf_print' is not displaying any text, then this may need to be overridden.

SHOW_ERRORS

Normally this module is completely silent and does not display errors or warnings (to the best of its ability). This is to prevent corruption of the graphics. However, you can enable error reporting by setting this to 1.

This is helpful for troubleshooting.

EMULATION MODE OPTIONS

The options here only apply to emulation mode.

Emulation mode can be used as a secondary off-screen drawing surface, if you are clever.

VXRES

Width of the emulation framebuffer in pixels. Default is 640.

VYRES

Height of the emulation framebuffer in pixels. Default is 480.

BITS

Number of bits per pixel in the emulation framebuffer. Default is 32.

BYTES

Number of bytes per pixel in the emulation framebuffer. It's best to keep it BITS/8. Default is 4.

COLOR_ORDER

Defines the colorspace for the graphics routines to draw in. The possible (and only accepted) values are:

'RGB'  for Red-Green-Blue (the default)
'RBG'  for Red-Blue-Green
'GRB'  for Green-Red-Blue
'GBR'  for Green-Blue-Red
'BRG'  for Blue-Red-Green
'BGR'  for Blue-Green-Red (Many video cards are this)

which_console

Returns two values, the current console number and the console number when the module started

This comes in handy for determining whether to draw to the screen or not (which is YOUR job as the programmer to manage). The reason why the module doesn't manage whether to draw or not is a simple matter of speed and efficiency. If it had to check before each and every draw operation, it would be considerably slower. Therefore, it is more efficient for YOU, the programmer, to check this before you call a series of operations to draw a screen.

    my ($current_console,$original_console) = $fb->which_console();

* This method only works if the 'fgconsole' program is installed on your system. It's typically in "console-setup" or "console-utilities" packages, or something similar.

active_console

Returns 1 (true) if running in the console it was started in, else if returns 0 (false);

Handy for semaphore style determination if it's ok to draw. This functionality is not part of each primitive on purpose, as it would slow the module down. It's best to use this before a series of drawing commands rather than for each one.

    if ($fb->active_console()) {
        ... draw some stuff
    }

wait_for_console

Blocks until the console is the same console when the module was started.

    $fb->wait_for_console();
    ...draw some stuff

You can also enable/disable auto-blocking for the internal drawing methods.

    $fb->wait_for_console(1); # Turn on auto-blocking
    
    $fb->wait_for_console(0); # Turn off auto-blocking

screen_dimensions

When called in an array/list context:

Returns the size and nature of the framebuffer in X,Y pixel values.

It also returns the bits per pixel.

    my ($width,$height,$bits_per_pixel) = $fb->screen_dimensions();

When called in a scalar context, it returns a hash reference:

    {
        'width'          => pixel width of physical screen,
        'height'         => pixel height of physical screen,
        'bits_per_pixel' => bits per pixel (16, 24, or 32),
        'bytes_per_line' => Number of bytes per scan line,
        'top_clip'       => top edge of clipping rectangle (Y),
        'left_clip'      => left edge of clipping rectangle (X),
        'bottom_clip'    => bottom edge of clipping rectangle (YY),
        'right_clip'     => right edge of clipping rectangle (XX)
    }

splash

Displays the Splash screen. It automatically scales and positions to the clipping region.

This is automatically displayed when this module is initialized, and the variable 'SPLASH' is true (which is the default).

    $fb->splash();

get_font_list

Returns an anonymous hash containing the font face names as keys and another anonymous hash assigned as the values for each key. This second hash contains the path to the font and the font's file name.

    'face name' => {
         'path' => 'path to font',
         'font' => 'file name of font'
    },
    ... The rest of the system fonts here

You may also pass in a face name and it will return that face's information:

    my $font_info = $fb->get_font_list('DejaVuSerif');

Would return something like:

    {
        'font' => 'dejavuserif.ttf',
        'path' => '/usr/share/fonts/truetype/'
    }

When passing a name, it will return a hash reference (if only one match), or an array reference of hashes of fonts matching that name. Passing in "Arial" would return the font information for "Arial Black, Arial Narrow, and Arial Rounded (if they are installed on your system).

draw_mode

Sets or returns the drawing mode, depending on how it is called.

    my $draw_mode = $fb->draw_mode();     # Returns the current
                                          # Drawing mode.
    
    # Modes explained.  These settings are global
    
                                          # When you draw it...
    
    $fb->draw_mode($fb->{'NORMAL_MODE'}); # Replaces the screen pixel
                                          # with the new pixel. Imager
                                          # assisted drawing (acceleration)
                                          # only works in this mode.
    
    $fb->draw_mode($fb->{'XOR_MODE'});    # Does a bitwise XOR with
                                          # the new pixel and screen
                                          # pixel.
    
    $fb->draw_mode($fb->{'OR_MODE'});     # Does a bitwise OR with
                                          # the new pixel and screen
                                          # pixel.
    
    $fb->draw_mode($fb->{'ALPHA_MODE'});  # Does a bitwise AND with
                                          # the new pixel and the alpha
                                          # value, then a bitwise OR
                                          # with the screen pixel.
    
    $fb->draw_mode($fb->{'AND_MODE'});    # Does a bitwise AND with
                                          # the new pixel and screen
                                          # pixel.
    ###########################################
    # MASK and UNMASK only apply to blitting  #
    ###########################################
    # You are encouraged to use               #
    # "blit_transform" in "merge" mode for    #
    # much faster results (if in 32 bit mode) #
    ###########################################
    $fb->draw_mode($fb->{'MASK_MODE'});   # If pixels in the source
                                          # are equal to the global
                                          # background color, then they
                                          # are not drawn (transparent).
    
    $fb->draw_mode($fb->{'UNMASK_MODE'}); # Draws the new pixel on
                                          # screen areas only equal to
                                          # the background color. (SLOW)

normal_mode

This is an alias to draw_mode(NORMAL_MODE)

    $fb->normal_mode();

xor_mode

This is an alias to draw_mode(XOR_MODE)

    $fb->xor_mode();

or_mode

This is an alias to draw_mode(OR_MODE)

    $fb->or_mode();

alpha_mode

This is an alias to draw_mode(ALPHA_MODE)

    $fb->alpha_mode();

and_mode

This is an alias to draw_mode(AND_MODE)

    $fb->and_mode();

mask_mode

This is an alias to draw_mode(MASK_MODE)

    $fb->mask_mode();

unmask_mode

This is an alias to draw_mode(UNMASK_MODE)

    $fb->unmask_mode();

clear_screen

Fills the entire screen with the background color

You can add an optional parameter to turn the console cursor on or off too.

    $fb->clear_screen(); # Leave cursor as is.
    
    $fb->clear_screen('OFF'); # Turn cursor OFF.
    
    $fb->clear_screen('ON'); # Turn cursor ON.

cls

The same as clear_screen

    $fb->cls();      # Leave cursor as-is
    $fb->cls('OFF'); # Turn cursor off
    $fb->cls('ON');  # Turn cursor on

attribute_reset

Resets the plot point at 0,0. Resets clipping to the current screen size. Resets the global color to whatever 'FOREGROUND' is set to, and the global background color to whatever 'BACKGROUND' is set to, and resets the drawing mode to NORMAL.

    $fb->attribute_reset();

plot

Set a single pixel in the globally set color at position x,y with the given pixel size (or default). Clipping applies.

With 'pixel_size', if a positive number greater than 1, is drawn with square pixels. If it's a negative number, then it's drawn with round pixels. Square pixels are much faster.

    $fb->plot(
        {
            'x'          => 20,
            'y'          => 30,
            'pixel_size' => 3
        }
    );

* This is not affected by the Acceleration setting

setpixel

Same as 'plot' above

last_plot

Returns the last plotted position

    my $last_plot = $fb->last_plot();

    This returns an anonymous hash reference in the form:

    {
        'x' => x position,
        'y' => y position
    }

Or, if you want a simple array returned:

    my ($x,$y) = $fb->last_plot();

    This returns the position as a two element array:

    ( x position, y position )

line

Draws a line, in the global color, from point x,y to point xx,yy. Clipping applies.

    $fb->line({
       'x'           => 50,
       'y'           => 60,
       'xx'          => 100,
       'yy'          => 332
       'pixel_size'  => 1,
       'antialiased' => 1
    });

angle_line

Draws a line, in the global foreground color, from point x,y at an angle of 'angle', of length 'radius'. Clipping applies.

    $fb->angle_line({
       'x'           => 50,
       'y'           => 60,
       'radius'      => 50,
       'angle'       => 30.3, # Compass coordinates (0-360)
       'pixel_size'  => 3,
       'antialiased' => 0
    });

* This is not affected by the Acceleration setting

drawto

Draws a line, in the global color, from the last plotted position to the position x,y. Clipping applies.

    $fb->drawto({
       'x'           => 50,
       'y'           => 60,
       'pixel_size'  => 2,
       'antialiased' => 1
    });

* This is not affected by the Acceleration setting

bezier

Draws a Bezier curve, based on a list of control points.

    $fb->bezier(
        {
            'coordinates' => [
                x0,y0,
                x1,y1,
                ...              # As many as needed
            ],
            'points'     => 100, # Number of total points plotted for curve
                                 # The higher the number, the smoother the curve.
            'pixel_size' => 2,   # optional
            'closed'     => 1,   # optional, close it and make it a full shape.
            'filled'     => 1    # Results may vary, optional
            'gradient' => {
                 'direction' => 'horizontal', # or vertical
                 'colors'    => { # 2 to any number of transitions allowed
                     'red'   => [255,255,0], # Red to yellow to cyan
                     'green' => [0,255,255],
                     'blue'  => [0,0,255]
                 }
             }
        }
    );

* This is not affected by the Acceleration setting

cubic_bezier

DISCONTINUED, use 'bezier' instead.

draw_arc

Draws an arc/pie/poly arc of a circle at point x,y.

    x             = x of center of circle 
    y             = y of center of circle
    radius        = radius of circle
    
    start_degrees = starting point, in degrees, of arc
    
    end_degrees   = ending point, in degrees, of arc
    
    granularity   = This is used for accuracy in drawing
                    the arc.  The smaller the number, the
                    more accurate the arc is drawn, but it
                    is also slower.  Values between 0.1
                    and 0.01 are usually good.  Valid values
                    are any positive floating point number
                    down to 0.0001.  Anything smaller than
                    that is just silly.
    
    mode          = Specifies the drawing mode.
                     0 > arc only
                     1 > Filled pie section
                         Can have gradients, textures, and hatches
                     2 > Poly arc.  Draws a line from x,y to the
                         beginning and ending arc position.
    
    $fb->draw_arc({
       'x'             => 100,
       'y'             => 100,
       'radius'        => 100,
       'start_degrees' => -40, # Compass coordinates
       'end_degrees'   => 80,
       'granularity   => .05,
       'mode'          => 2    # The object hash has 'ARC', 'PIE',
                               # and 'POLY_ARC' as a means of filling
                               # this value.
    });

* Only PIE is affected by the acceleration setting.

arc

Draws an arc of a circle at point x,y. This is an alias to draw_arc above, but no mode parameter needed.

    x             = x of center of circle
    
    y             = y of center of circle
    
    radius        = radius of circle
    
    start_degrees = starting point, in degrees, of arc
    
    end_degrees   = ending point, in degrees, of arc
    
    granularity   = This is used for accuracy in drawing
                    the arc.  The smaller the number, the
                    more accurate the arc is drawn, but it
                    is also slower.  Values between 0.1
                    and 0.01 are usually good.  Valid values
                    are any positive floating point number
                    down to 0.0001.
    
    $fb->arc({
       'x'             => 100,
       'y'             => 100,
       'radius'        => 100,
       'start_degrees' => -40,
       'end_degrees'   => 80,
       'granularity   => .05,
    });

* This is not affected by the Acceleration setting

filled_pie

Draws a filled pie wedge at point x,y. This is an alias to draw_arc above, but no mode parameter needed.

    x             = x of center of circle
    
    y             = y of center of circle
    
    radius        = radius of circle
    
    start_degrees = starting point, in degrees, of arc
    
    end_degrees   = ending point, in degrees, of arc
    
    granularity   = This is used for accuracy in drawing
                    the arc.  The smaller the number, the
                    more accurate the arc is drawn, but it
                    is also slower.  Values between 0.1
                    and 0.01 are usually good.  Valid values
                    are any positive floating point number
                    down to 0.0001.
    
    $fb->filled_pie({
       'x'             => 100,
       'y'             => 100,
       'radius'        => 100,
       'start_degrees' => -40,
       'end_degrees'   => 80,
       'granularity   => .05,
       'gradient' => {  # optional
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       },
       'texture'  => { # Same as what blit_read or load_image returns
           'width'  => 320,
           'height' => 240,
           'image'  => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* This is affected by the Acceleration setting

poly_arc

Draws a poly arc of a circle at point x,y. This is an alias to draw_arc above, but no mode parameter needed.

    x             = x of center of circle
    
    y             = y of center of circle
    
    radius        = radius of circle
    
    start_degrees = starting point, in degrees, of arc
    
    end_degrees   = ending point, in degrees, of arc
    
    granularity   = This is used for accuracy in drawing
                    the arc.  The smaller the number, the
                    more accurate the arc is drawn, but it
                    is also slower.  Values between 0.1
                    and 0.01 are usually good.  Valid values
                    are any positive floating point number
                    down to 0.0001.
    
    $fb->poly_arc({
       'x'             => 100,
       'y'             => 100,
       'radius'        => 100,
       'start_degrees' => -40,
       'end_degrees'   => 80,
       'granularity   => .05,
    });

* This is not affected by the Acceleration setting

ellipse

Draw an ellipse at center position x,y with XRadius, YRadius. Either a filled ellipse or outline is drawn based on the value of $filled. The optional factor value varies from the default 1 to change the look and nature of the output.

    $fb->ellipse({
       'x'          => 200, # Horizontal center
       'y'          => 250, # Vertical center
       'xradius'    => 50,
       'yradius'    => 100,
       'factor'     => 1, # Anything other than 1 has funkiness
       'pixel_size' => 4, # optional
       'filled'     => 1, # optional
    
       ## Only one of the following may be used
    
       'gradient'   => {  # optional, but 'filled' must be set
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       }
       'texture'    => {  # Same format blit_read or load_image uses.
           'width'   => 320,
           'height'  => 240,
           'image'   => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* This is not affected by the Acceleration setting

circle

Draws a circle at point x,y, with radius 'radius'. It can be an outline, solid filled, or gradient filled. Outlined circles can have any pixel size.

    $fb->circle({
       'x'        => 300, # Horizontal center
       'y'        => 300, # Vertical center
       'radius'   => 100,
       'filled'   => 1, # optional
       'gradient' => {  # optional
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       },
       'texture'  => { # Same as what blit_read or load_image returns
           'width'  => 320,
           'height' => 240,
           'image'  => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* This is not affected by the Acceleration setting

polygon

Creates a polygon drawn in the global color value. The parameter 'coordinates' is a reference to an array of x,y values. The last x,y combination is connected automatically with the first to close the polygon. All x,y values are absolute, not relative.

It is up to you to make sure the coordinates are "sane". Weird things can result from twisted or complex filled polygons.

    $fb->polygon({
       'coordinates' => [
           5,5,
           23,34,
           70,7
       ],
       'pixel_size'  => 1, # optional
       'antialiased' => 1, # optional only for non-filled
       'filled'      => 1, # optional
    
       ## Only one of the following, "filled" must be set
    
       'gradient'    => {  # optional
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       },
       'texture'     => { # Same as what blit_read or load_image returns
           'width'  => 320,
           'height' => 240,
           'image'  => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* Filled polygons are affected by the acceleration setting.

box

Draws a box from point x,y to point xx,yy, either as an outline, if 'filled' is 0, or as a filled block, if 'filled' is 1. You may also add a gradient or texture.

    $fb->box({
       'x'          => 20,
       'y'          => 50,
       'xx'         => 70,
       'yy'         => 100,
       'rounded'    => 0, # optional
       'pixel_size' => 1, # optional
       'filled'     => 1, # optional
    
       ## Only one of the following, "filled" must be set
    
       'gradient'    => {  # optional
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       },
       'texture'     => { # Same as what blit_read or load_image returns
           'width'  => 320,
           'height' => 240,
           'image'  => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* This is not affected by the Acceleration setting

rbox

Draws a box at point x,y with the width 'width' and height 'height'. It draws a frame if 'filled' is 0 or a filled box if 'filled' is 1. 'pixel_size' only applies if 'filled' is 0. Filled boxes draw faster than frames. Gradients or textures are also allowed.

    $fb->rbox({
       'x'          => 100,
       'y'          => 100,
       'width'      => 200,
       'height'     => 150,
       'rounded'    => 0, # optional
       'pixel_size' => 2, # optional
       'filled'     => 0, # optional
    
       ## Only one of the following, "filled" must be set
    
       'gradient'    => {  # optional
           'direction' => 'horizontal', # or vertical
           'colors'    => { # 2 to any number of transitions allowed
               'red'   => [255,255,0], # Red to yellow to cyan
               'green' => [0,255,255],
               'blue'  => [0,0,255]
           }
       },
       'texture'     => { # Same as what blit_read or load_image returns
           'width'  => 320,
           'height' => 240,
           'image'  => $raw_image_data
       },
       'hatch'      => 'hatchname' # The exported array @HATCHES contains
                                   # the names of all the hatches
    });

* This is not affected by the Acceleration setting

set_color

Sets the drawing color in red, green, and blue, absolute 8 bit values.

Even if you are in 16 bit color mode, use 8 bit values. They will be automatically scaled.

    $fb->set_color({
       'red'   => 255,
       'green' => 255,
       'blue'  => 0,
       'alpha' => 255
    });

set_foreground_color

Sets the drawing color in red, green, and blue, absolute values. This is the same as 'set_color' above.

    $fb->set_foreground_color({
       'red'   => 255,
       'green' => 255,
       'blue'  => 0,
       'alpha' => 255
    });

set_b_color

Sets the background color in red, green, and blue values.

The same rules as set_color apply.

    $fb->set_b_color({
       'red'   => 0,
       'green' => 0,
       'blue'  => 255,
       'alpha' => 255
    });

set_background_color

Same as set_b_color

pixel

Returns the color of the pixel at coordinate x,y.

    my $pixel = $fb->pixel({'x' => 20,'y' => 25});

    $pixel is a hash reference in the form:

    {
       'red'   => integer value, # 0 - 255
       'green' => integer value, # 0 - 255
       'blue'  => integer value, # 0 - 255
       'alpha' => integer value, # 0 - 255
       'raw'   => 16/24/32bit encoded string
    }

get_pixel

Returns the color of the pixel at coordinate x,y. It is the same as 'pixel' above.

fill

Does a flood fill starting at point x,y. It samples the color at that point and determines that color to be the "background" color, and proceeds to fill in, with the current global color, until the "background" color is replaced with the new color.

    $fb->fill({'x' => 334, 'y' => 23});

* This one is greatly affected by the acceleration setting, and likely the one that may give the most trouble. I have found on some systems Imager just doesn't do what it is asked to, but on others it works fine. Go figure. Some if you are getting your entire screen filled and know you are placing the X,Y coordinate correctly, then disabling acceleration before calling this should fix it. Don't forget to re-enable acceleration when done.

replace_color

This replaces one color with another inside the clipping region. Sort of like a fill without boundary checking.

In 32 bit mode, the replaced alpha channel is ALWAYS set to 255.

    $fb->replace_color({
       'old' => { # Changed as of 5.56
           'red'   => 23,
           'green' => 48,
           'blue'  => 98
       },
       'new' => {
           'red'   => 255,
           'green' => 255,
           'blue'  => 0
       }
    });

* This is not affected by the Acceleration setting, and is just as fast in 16 bit as it is in 24 and 32 bit modes. Which means, very fast.

blit_copy

Copies a square portion of screen graphic data from x,y,w,h to x_dest,y_dest. It copies in the current drawing mode.

    $fb->blit_copy({
       'x'      => 20,
       'y'      => 20,
       'width'  => 30,
       'height' => 30,
       'x_dest' => 200,
       'y_dest' => 200
    });

blit_move

Moves a square portion of screen graphic data from x,y,w,h to x_dest,y_dest. It moves in the current drawing mode. It differs from "blit_copy" in that it removes the graphic from the original location (via XOR).

    $fb->blit_move({
       'x'      => 20,
       'y'      => 20,
       'width'  => 30,
       'height' => 30,
       'x_dest' => 200,
       'y_dest' => 200
    });

play_animation

Plays an animation sequence loaded from "load_image"

    my $animation = $fb->load_image(
        {
            'file'   => 'filename.gif',
            'center' => CENTER_XY
        }
    );
    
    $fb->play_animation($animation);

The animation is played at the speed described by the file's metadata.

You need to enclose this in a loop if you wish it to play more than once.

acceleration

Enables/Disables all Imager or C language acceleration.

In 24 and 32 bit modes, GFB uses the Imager library to do some drawing. In some cases, these may not function as they should on some systems. This method allows you to toggle this acceleration on or off.

When acceleration is off, the underlying (slower) Perl algorithms are used. It is advisable to leave acceleration on for those methods which it functions correctly, and only shut it off when calling the problem ones.

When called without parameters, it returns the current setting.

    $fb->acceleration(1); # Turn acceleration ON
    
    $fb->acceleration(0); # Turn acceleration OFF
    
    my $accel = $fb->acceleration(); # Get current acceleration state.

blit_read

Reads in a square portion of screen data at x,y,width,height, and returns a hash reference with information about the block, including the raw data as a string, ready to be used with 'blit_write'.

Passing no parameters automatically grabs the clipping region (the whole screen if clipping is off).

    my $blit_data = $fb->blit_read({
       'x'      => 30,
       'y'      => 50,
       'width'  => 100,
       'height' => 100
    });

Returns:

    {
        'x'      => original X position,
        'y'      => original Y position,
        'width'  => width,
        'height' => height,
        'image'  => string of image data for the block
    }

All you have to do is change X and Y, and just pass it to "blit_write" and it will paste it there.

* Not Imager accelerated, but pretty darn fast regardless.

blit_write

Writes a previously read block of screen data at x,y,width,height.

It takes a hash reference. It draws in the current drawing mode. Note, the "Mask" modes are slower, as it has to go pixel by pixel to determine if it should or should not write it.

    $fb->blit_write({
       'x'      => 0,
       'y'      => 0,
       'width'  => 100,
       'height' => 100,
       'image'  => $blit_data
    });

* Not Imager accelerated, but pretty darn fast regardless.

blit_transform

This performs transformations on your blit objects.

You can only have one of "rotate", "scale", "merge" or "flip".

blit_data (mandatory)

Used by all transformations. It's the image data to process, in the format that "blit_write" uses. See the example below.

flip

Flips the image either "horizontally, "vertically, or "both"

merge

Merges one image on top of the other. "blit_data" is the top image, and "dest_blit_data" is the background image. This takes into account alpha data values for each pixel (if in 32 bit mode).

This is very usefull in 32 bit mode due to its alpha channel capabilities.

rotate

Rotates the "blit_data" image an arbitrary degree. Positive degree values are counterclockwise and negative degree values are clockwise.

Two types of rotate methods are available, an extrememly fast, but visually slightly less appealing method, and a slower, but looks better, method.

scale

Scales the image to "width" x "height". This is the same as how scale works in "load_image". The "type" value tells it how to scale (see the example).

    $fb->blit_transform(
        {
            # blit_data is mandatory
            'blit_data' => { # Same as what blit_read or load_image returns
                'x'      => 0, # This is relative to the dimensions of "dest_blit_data" for "merge"
                'y'      => 0, # ^^
                'width'  => 300,
                'height' => 200,
                'image'  => $image_data
            },
    
            'merge'  => {
                'dest_blit_data' => { # MUST have same or greater dimensions as 'blit_data'
                    'x'      => 0,
                    'y'      => 0,
                    'width'  => 300,
                    'height' => 200,
                    'image'  => $image_data
                }
            },
    
            'rotate' => {
                'degrees' => 45, # 0-360 degrees. Negative numbers rotate clockwise.
                'quality' => 'high', # "high" or "fast" are your choices, with "fast" being the default
            },
    
            'flip' => 'horizontal', # or "vertical" or "both"
    
            'scale'  => {
                'x'          => 0,
                'y'          => 0,
                'width'      => 500,
                'height'     => 300,
                'scale_type' => 'min' #  'min'     = The smaller of the two
                                      #              sizes are used (default)
                                      #  'max'     = The larger of the two
                                      #              sizes are used
                                      #  'nonprop' = Non-proportional sizing
                                      #              The image is scaled to
                                      #              width x height exactly.
            },
    
            'monochrome' => 1         # Makes the image data monochrome
        }
    );

It returns the transformed image in the same format the other BLIT methods use. Note, the width and height may be changed!

    {
        'x'      => 0,     # copied from "blit_data"
        'y'      => 0,     # copied from "blit_data"
        'width'  => 100,   # width of transformed image data
        'height' => 100,   # height of transformed image data
        'image'  => $image # image data
    }

* Rotate and Flip is affected by the acceleration setting.

clip_reset

Turns off clipping, and resets the clipping values to the full size of the screen.

    $fb->clip_reset();

clip_off

Turns off clipping, and resets the clipping values to the full size of the screen. It is the same as clip_reset.

    $fb->clip_off();

clip_set

Sets the clipping rectangle starting at the top left point x,y and ending at bottom right point xx,yy.

    $fb->clip_set({
       'x'  => 10,
       'y'  => 10,
       'xx' => 300,
       'yy' => 300
    });

clip_rset

Sets the clipping rectangle to point x,y,width,height

    $fb->clip_rset({
       'x'      => 10,
       'y'      => 10,
       'width'  => 600,
       'height' => 400
    });

monochrome

Removes all color information from an image, and leaves everything in greyscale.

    Expects two parameters, 'image' and 'bits'.  The parameter 'image' is a string containing the image data.  The parameter 'bits' is how many bits per pixel make up the image.  Valid values are 16, 24, and 32 only.
    
    $fb->monochrome({
        'image' => "image data",
        'bits'  => 32
    });
    
    It returns 'image' back, but now in greyscale (still the same RGB formnat though).
    
    {
        'image' => "monochrome image data"
    }

ttf_print

Prints TrueType text on the screen at point x,y in the rectangle width,height, using the color 'color', and the face 'face' (using the Imager library as its engine).

Note, 'y' is the baseline position, not the top left of the bounding box. This is a change from before!!!

This is best called twice, first in bounding box mode, and then in normal mode.

Bounding box mode gets the actual values needed to display the text.

If you are trying to print on top of other graphics, then normal drawing mode would not be the best choice, even though it is the fastest. Mask mode would visually be the best choice. However, it's also the slowest. Experiment with AND, OR, and XOR modes instead.

    my $bounding_box = $fb->ttf_print({
        'x'            => 20,
        'y'            => 100, # baseline position
        'height'       => 16,
        'wscale'       => 1,   # Scales the width.  1 is normal
        'color'        => 'FFFF00FF', # Hex value of color 00-FF (RRGGBBAA)
        'text'         => 'Hello World!',
        'font_path'    => '/usr/share/fonts/truetype',
        'face'         => 'Arial.ttf',
        'bounding_box' => 1,
        'center'       => $fb->{'CENTER_X'},
        'antialias'    => 1
    });
    
    $fb->ttf_print($bounding_box);

Here's a shortcut:

    $fb->ttf_print(
        $fb->ttf_print({
            'x'            => 20,
            'y'            => 100, # baseline position
            'height'       => 16,
            'color'        => 'FFFF00FF', # RRGGBBAA
            'text'         => 'Hello World!',
            'font_path'    => '/usr/share/fonts/truetype',
            'face'         => 'Arial.ttf',
            'bounding_box' => 1,
            'rotate'       => 45,    # optonal
            'center'       => CENTER_X,
            'antialias'    => 1
        })
    );

Failures of this method are usually due to it not being able to find the font. Make sure you have the right path and name.

This works best in 24 or 32 bit color modes. If you are running in 16 bit mode, then output will be slower, as Imager only works in bit modes >= 24; and this module has to convert its output to your device's 16 bit colors. Which means the larger the characters and wider the string, the longer it will take to display. The splash screen is an excellent example of this behavior.

get_face_name

Returns the TrueType face name based on the parameters passed.

my $face_name = $fb->get_face_name({
    'font_path' => '/usr/share/fonts/TrueType/',
    'face'      => 'FontFileName.ttf'
});

load_image

Loads an image at point x,y[,width,height]. To display it, pass it to blit_write.

If you give centering options, the position to display the image is part of what is returned, and is ready for blitting.

If 'width' and/or 'height' is given, the image is resized. Note, resizing is CPU intensive. Nevertheless, this is done by the Imager library (compiled C) so it is relatively fast.

    $fb->blit_write(
        $fb->load_image(
            {
                'x'          => 0,    # Optional (only applies if
                                      # CENTER_X or CENTER_XY is not
                                      # used)
    
                'y'          => 0,    # Optional (only applies if
                                      # CENTER_Y or CENTER_XY is not
                                      # used)
    
                'width'      => 1920, # Optional. Resizes to this maximum
                                      # width.  It fits the image to this
                                      # size.
    
                'height'     => 1080, # Optional. Resizes to this maximum
                                      # height.  It fits the image to this
                                      # size
    
                'scale_type' => 'min',# Optional. Sets the type of scaling
                                      #
                                      #  'min'     = The smaller of the two
                                      #              sizes are used (default)
                                      #  'max'     = The larger of the two
                                      #              sizes are used
                                      #  'nonprop' = Non-proportional sizing
                                      #              The image is scaled to
                                      #              width x height exactly.
    
                'autolevels' => 0,    # Optional.  It does a color
                                      # correction. Sometimes this
                                      # works well, and sometimes it
                                      # looks quite ugly.  It depends
                                      # on the image
    
                'center'     => $fb->{'CENTER_XY'},
                                      # Three centering options are available
                                      #  CENTER_X  = center horizontally
                                      #  CENTER_Y  = center vertically
                                      #  CENTER_XY = center horizontally and
                                      #              vertically.  Placing it
                                      #              right in the middle of
                                      #              the screen.
    
                'file'       => 'RWBY_Faces.png', # Usually needs full path
                'convertalpha' => 1   # Converts the color matching the global
                                      # background color to have the same alpha
                                      # channel value as the global background,
                                      # which is beneficial for using 'merge'
                                      # in 'blit_transform'.
            }
        )
    );

If a single image is loaded, it returns a reference to an anonymous hash, of the format:

    {
         'x'           => horizontal position calculated (or passed through),
    
         'y'           => vertical position calculated (or passed through),
    
         'width'       => Width of the image,
    
         'height'      => Height of the image,
    
         'tags'        => The tags of the image (hashref)
    
         'image'       => [raw image data]
    }

If the image has multiple frames, then a reference to an array of hashes is returned:

    # NOTE:  X and Y positions can change frame to frame, so use them for each frame!
    #        Also, X and Y are based upon what was originally passed through, else they
    #        reference 0,0 (but only if you didn't give an X,Y value initially).
    
    [
        { # Frame 1
            'x'           => horizontal position calculated (or passed through),
    
            'y'           => vertical position calculated (or passed through),
    
            'width'       => Width of the image,
    
            'height'      => Height of the image,
    
            'tags'        => The tags of the image (hashref)
    
            'image'       => [raw image data]
        },
        { # Frame 2 (and so on)
            'x'           => horizontal position calculated (or passed through),
    
            'y'           => vertical position calculated (or passed through),
    
            'width'       => Width of the image,
    
            'height'      => Height of the image,
    
            'tags'        => The tags of the image (hashref)
    
            'image'       => [raw image data]
        }
    ]

screen_dump

Dumps the screen to a file given in 'file' in the format given in 'format'

Formats can be (they are case-insensitive):

JPEG

The most widely used format. This is a "lossy" format. The default quality setting is 75%, but it can be overriden with the "quality" parameter.

GIF

The CompuServe "Graphics Interchange Format". A very old and outdated format, but still widely used. It only allows 256 "indexed" colors, so quality is very lacking. The "dither" paramter determines how colors are translated from 24 bit truecolor to 8 bit indexed.

PNG

The Portable Network Graphics format. Widely used, very high quality.

PNM

The Portable aNy Map format. These are typically "PPM" files. Not widely used.

TGA

The Targa image format. This is a high-color, lossless format, typically used in photography

TIFF

The Tagged Image File Format. Sort of an older version of PNG (but not the same, just similar in capability). Sometimes used in FAX formats.

$fb->screen_dump(
    {
    	 'file'   => '/path/filename', # name of file to be written
	 	 'format' => 'jpeg',           # jpeg, gif, png, pnm, tga, or tiff

	 	 # for JPEG formats only
	 	 'quality' => 75,              # quality of the JPEG file 1-100% (the
	 	                               # higher the number, the better the
	 	                               # quality, but the larger the file)

	 	 # for GIF formats only
	 	 'dither'  => 'floyd',         # Can be "floyd", "jarvis" or "stucki"
    }
);

USAGE HINTS

GRADIENTS

Gradients can have any number (actually 2 or greater) of color key points (transitions). Vertical gradients cannot have more key points than the object is high. Horizontal gradients cannot have more key points that the object is wide. Just keep your gradients "sane" and things will go just fine.

Make sure the number of color key points matches for each primary color (red, green, and blue);

PERL OPTIMIZATION

This module is highly CPU dependent. So the more optimized your Perl installation is, the faster it will run.

THREADS

The module can NOT have separate threads calling the same object. You WILL crash. However, you can instantiate an object for each thread to use, and it will work just fine.

See the "examples" directory for "threadstest.pl" as an example of a threading script that uses this module. Just add the number of threads you want it to use to the command line when you run it.

If you are running a threaded Perl, this module opens its own thread to monitor and update the status of the active console.

FORKS

I have never tested with forks. Do at your own risk, but follow the same rules as in threads, and it should work.

BLITTING

Use "blit_read" and "blit_write" to save portions of the screen instead of redrawing everything. It will speed up response tremendously.

SPRITES

Someone asked me about sprites. Well, that's what blitting is for. You'll have to do your own collision detection.

HORIZONTAL "MAGIC"

Horizontal lines and filled boxes draw very fast. Learn to exploit them.

PIXEL SIZE

Pixel sizes over 1 utilize a filled "box" or "circle" (negative numbers for circle) to do the drawing. This is why the larger the "pixel", the slower the draw.

MAKING WINDOWS

So, you want to be able to manage some sort of windows...

You just instantiate a new instance of the module per "Window" and give it its own clipping region. This region is your drawing space for your window.

It is up to you to actually decorate (draw) the windows.

Perhaps in the future I may add windowing ability, but not right now, as it can be pretty involved (especially redraw tracking and event managing).

Nothing is preventing you from writing your own window handler.

RUNNING IN MICROSOFT WINDOWS

It doesn't work natively, (other than in emulation mode) and likely never will. However...

You can run Linux inside VirtualBox and it works fine. Put it in full screen mode, and voila, it's "running in Windows" in an indirect kinda-sorta way. Make sure you install the VirtualBox extensions, as it has the correct video driver for framebuffer access. It's as close as you'll ever get to get it running in MS Windows. Seriously...

This isn't a design choice nor preference. It's simply because of the fact MS Windows does not allow file mapping of the display, nor variable memory mapping of the display (that I know of), both are the techniques this module uses to achieve its magic. DirectX is more like OpenGL in how it works, and thus defeats the purpose of this module. You're better off with SDL instead, if you want to draw in MS Windows from Perl.

* However, if someone knows how to access the framebuffer in MS Windows, and be able to do it reasonable from within Perl, then send me instructions on how to do it, and I'll do my best to get it to work.

TROUBLESHOOTING

Ok, you've installed the module, but can't seem to get it to work properly. Here are some things you can try:

** make sure you turn on the "SHOW_ERRORS" parameter when calling "new" to create the object. This helps with troubleshooting.

You Have To Run From The Console

A console window doesn't count as "the console". You cannot use this module from within X-Windows. It won't work, and likely will only go into emulation mode if you do, or maybe crash, or even corrupt your X-Windows screen.

If you want to run your program within X-Windows, then you have the wrong module. Use SDL or GTK or something similar.

You HAVE to have a framebuffer based video driver for this to work. The device ("/dev/fb0" for example) must exist.

If it does exist, but is not "/dev/fb0", then you can define it in the 'new' method with the "FB_DEVICE" parameter.

It Just Plain Isn't Working

Well, either your system doesn't have a framebuffer driver, or perhaps the module is getting confusing data back from it and can't properly initialize.

First, make sure your system has a framebuffer by seeing if "/dev/fb0" (actually "fb" then any number). If you don't see any "fb0" - "fb31" files inside "/dev", then you don't have a framebuffer driver running. You need to fix that first.

Second, ok, you have a framebuffer driver, but nothing is showing, or it's all funky looking. Now make sure you have the program "fbset" installed. It's used as a last resort by this module to figure out how to draw on the screen when all else fails. To see if you have "fbset" installed, just type "fbset -i" and it should show you information about the framebuffer. If you get an error, then you need to install "fbset".

The Text Cursor Is Messing Things Up

It is? Well then turn it off. Use the $obj->cls('OFF') method to do it. Use $obj->cls('ON') to turn it back on.

If your script exits without turning the cursor back on, then it will still be off. To get your cursor back, just type the command "reset" (and make sure you turn it back on before your code exits).

TrueType Printing isn't working

This is likely caused by the Imager library either being unable to locate the font file, or when it was compiled, it couldn't find the FreeType development libraries, and was thus compiled without TrueType text support.

See the README file for instructions on getting Imager properly compiled. If you have a package based Perl installation, then installing the Imager (usually "libimager-perl") package will always work. If you already installed Imager via CPAN, then you should uninstall it via CPAN, then go install the package version, in that order.

It's Too Slow

Ok, it does say a PERL graphics library in the description, if I am not mistaken. This means Perl is doing most of the work. This also means it is only as fast as your system and its CPU.

You could try recompiling Perl with optimizations specific to your hardware. That can help.

You can also try simplifying your drawing to exploit the speed of horizontal lines. Horizonal line drawing is incredibly fast, even for very slow systems.

Only use pixel sizes of 1. Anything larger requires a box to be drawn at the pixel size you asked for. Pixel sizes of 1 only use plot to draw, no boxes, so it is much faster.

Try using 'polygon' to draw complex shapes instead of a series of plot or line commands.

Does your device have more than one core? Well, how about using threads? Just make sure you do it according to the example "threadstest.pl" in the "examples" directory.

Plain and simple, your device just may be too slow for some CPU intensive operations, specifically anything involving images and blitting. If you must use images, then make sure they are already the right size for your needs. Don't force the module to resize them when loading.

Ask For Help

If none of these ideas work, then send me an email, and I may be able to get it functioning for you. I may have you run the "dump.pl" script in the "examples" directory. So you might as well send me the output of that anyway:

perl dump.pl 2> dump.txt

AUTHOR

Richard Kelsch <rich@rk-internet.com>

COPYRIGHT

Copyright 2003-2015 Richard Kelsch, All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

VERSION

Version 5.83 (June 19, 2016)

THANKS

My thanks go out to those using this module and submitting helpful patches and suggestions for improvement, as well as those who asked for help. Your requests for help actually gave me ideas.

TELL ME ABOUT YOUR PROJECT

I'd love to know if you are using this library in your project. So send me an email, with pictures and/or a URL (if you have one) showing what it is. If you have a YouTube video, then that would be cool to see too.

YOUTUBE

There is a YouTube channel with demonstrations of the module's capabilities. Eventually it will have examples of output from a variety of different types of hardware.

https://youtu.be/4Yzs55Wpr7E

1 POD Error

The following errors were encountered while parsing the POD:

Around line 1121:

You forgot a '=back' before '=head2'