HiPi
Perl Modules for Raspberry Pi
Version 0.92 - released 28 March 2024

HiPi::Interface::EPaper::PartialContext

The PartialContext is used to support partial updates for HiPi::Interface::EPaper.

Creation and use

use HiPi qw( :epaper );
use HiPi::Interface::EPaper;
my $epd = HiPi::Interface::EPaper->new(
    type              => EPD_WS_2_13_250_X_122_A,
    skip_sleep_onexit => 1,
);

# want to do partial update on an area 80 pixels
# wide by 24 pixels high in the centre of this display

# do initial drawing
.....
$epd->display_update;
# now set partial mode
$epd->set_update_mode( EPD_UPD_MODE_PARTIAL );
# first update the whole display with a partial update
$epd->display_update;

my $pctx = $epd->create_partial_context( 80, 40 );
$pctx->draw_text(0,0, 'Raspberry Pi', 'SansEPD15');

# update the partial area at x = 85, y = 41
$epd->display_update_partial( 85, 41, $pctx);

Methods

The module writes all drawing operations to a local buffer that you write to the display using display_partial_update. You can clear all pixels set in the buffer using clear_buffer.

$ctx->clear_buffer();
# optionally send to display
$epd->display_partial_update($x, $y, $ctx)

Where displays support a colour in addition to black, you set the colour for all drawing operations using the set_pen() method.

use HiPi qw( :epaper );
...
            
$ctx->set_pen( EPD_BLACK_PEN );
$ctx->draw_text(0,0, 'This is black text', 'SansEPD15');
$ctx->set_pen( EPD_RED_PEN );
$ctx->draw_text(0,20, 'This is red text', 'SansEPD15');

The module provides the following constants

  • EPD_BLACK_PEN
  • the following are all equivalent for the alternate colour in a tri colour display but all are provided for convenience
  • EPD_RED_PEN
  • EPD_YELLOW_PEN
  • EPD_COLOUR_PEN
  • EPD_COLOR_PEN

Where a display only supports black / white specifying EPD_RED_PEN or equivalent has no effect.

Set invert_pen to set pixels you write using the drawing methods to 'off' rather than on. This is useful to draw items as 'off' over areas you may have previously set 'on'

# draw a filled rectangle
$ctx->draw_rectangle(10,20, 60, 40, 1);
$ctx->invert_pen(1);
# write some text over the rectangle
$ctx->draw_text(12, 25, 'Hello World', 'SansEPD15');
# restore normal pen
$ctx->invert_pen(0);

Returns the logical width. All drawing methods use logical coordinates. logical_width returns the width of the drawing area adjusted for its rotation.

For example, if using a 296 x 128 display

     rotation      logical width
     EPD_ROTATION_0      128
     EPD_ROTATION_90      296
     EPD_ROTATION_180      128
     EPD_ROTATION_270      296
my $width = $epd->logical_width;

Returns the logical height. All drawing methods use logical coordinates. logical_height returns the height of the drawing area adjusted for its rotation.

For example, if using a 296 x 128 display

     rotation      logical height
     EPD_ROTATION_0      296
     EPD_ROTATION_90      128
     EPD_ROTATION_180      296
     EPD_ROTATION_270      128
my $height = $epd->logical_height;

Instead of writing to the PartialContext directly, you can use drawing methods on a HiPi::Graphics::DrawingContext which can then be written to the buffer using draw_context.

You can draw the same drawing context on PartialContext many times. You can rotate all the pixels in a context as you write it to the PartialContext.

my $ctx = $pctx->create_context();
$ctx->draw_text(0,0,'Hello World'. 'SansEPD15');
# write it to the PartialContext at position 10,20 and rotate it 90 degrees.
$pctx->draw_context( 10, 20, $ctx->rotated_context( 90, 0, 0) );
# write it to the PartialContext at position 100,30 and rotate it 180 degrees.
$pctx->draw_context( 100, 30, $ctx->rotated_context( 180, 0, 0 ) );

Draw an arc.

  • $x,$y is the origin of the arc
  • $rw and $rh are the horizontal ( $rw - width ) and vertical ( $rh - height ) radius to use when drawing the arc. If $rw and $rh are equal, you will draw the arc of a circle
  • $start and $end denote the start and end of the arc in degrees. See the diagram below
  • $join is optional. If specified ( $join == 1 ) lines are drawn from the origin to the end points of the arc
  • $fill is optional. If specified ( $fill == 1 ) the arc is filled.

# draw 20 degree arc of a circle at x = 63, y = 15, 10 pixel radius
$ctx->draw_arc(63, 15, 10, 10, 350, 10);

# same arc, but draw lines from origin to edges
$ctx->draw_arc(63, 15, 10, 10, 350, 10, 1);

# same arc, but filled
$ctx->draw_arc(63, 15, 10, 10, 350, 10, 0, 1);

Draw an array of 1 / 0 values as a bitmap.

  • $x, $y is the origin to draw at
  • $bitarray is a reference to an array defining the points
  • $fill is optional but if specified, bits that are 0 in the array will be explicitly written to the buffer. If fill is not specified, only bits that are 1 are explicitly written. Using $fill is usefull if you want to overwrite an area of the buffer that has previously been written to.

# Draw a 'raspberry' starting at x = 10, y = 15
my $bitarray =  [ 
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,   0, 0, 0, 1, 1, 1, 1, 0, 0, 0 ],
    [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,   0, 0, 1, 0, 0, 0, 0, 1, 0, 0 ],
    [ 0, 0, 1, 0, 1, 1, 0, 0, 1, 0,   0, 1, 0, 0, 1, 1, 0, 1, 0, 0 ],
    [ 0, 0, 1, 0, 0, 0, 1, 0, 1, 0,   0, 1, 0, 1, 0, 0, 0, 1, 0, 0 ],
    
    [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,   1, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
    [ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,   0, 0, 0, 1, 1, 1, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,   0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,   1, 0, 0, 0, 1, 1, 0, 0, 0, 0 ],
    [ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,   0, 1, 0, 0, 0, 0, 1, 0, 0, 0 ],
    
    [ 0, 0, 1, 0, 0, 1, 1, 0, 0, 1,   1, 0, 0, 1, 1, 0, 0, 1, 0, 0 ],
    [ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0,   0, 0, 1, 0, 0, 1, 0, 1, 0, 0 ],
    [ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,   0, 0, 1, 0, 0, 1, 0, 0, 1, 0 ],
    [ 0, 1, 0, 0, 0, 1, 1, 0, 0, 1,   1, 0, 0, 1, 1, 0, 0, 0, 1, 0 ],
    [ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,   0, 1, 0, 0, 0, 0, 0, 0, 1, 0 ],
    
    [ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,   0, 1, 0, 0, 1, 1, 0, 0, 1, 0 ],
    [ 0, 0, 1, 0, 1, 0, 1, 0, 0, 1,   1, 0, 0, 1, 0, 1, 0, 1, 0, 0 ],
    [ 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,   0, 0, 0, 1, 1, 0, 0, 1, 0, 0 ],
    [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,   1, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
    [ 0, 0, 0, 0, 1, 1, 0, 0, 1, 0,   0, 1, 0, 0, 1, 1, 0, 0, 0, 0 ],
    
    [ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,   0, 0, 1, 1, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,   1, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
];

$epd->draw_bit_array( 10, 15, $bitarray );

Draw a circle at origin $x $y using radius $r. If $fill is specified, fill the circle

$epd->draw_circle( 15, 15, 10 );

Write a drawing context to the buffer.

Instead of writing to the buffer directly, you can use drawing methods on a HiPi::Graphics::DrawingContext which can then be written to the buffer using draw_context.

You can draw the same context on the buffer many times. You can rotate all the pixels in a context as you write it to the buffer.

my $ctx = $pctx->create_context();
$ctx->draw_text(0,0,'Hello World'. 'SansEPD15');

# write it to the buffer at position 10,20 and rotate it 90 degrees.
$pctx->draw_context( 10, 20, $ctx->rotated_context( 90, 0, 0) );

# write it to the buffer at position 100,30 and rotate it 180 degrees.
$pctx->draw_context( 100, 30, $ctx->rotated_context( 180, 0, 0) );

Draw an ellipse.

  • $x,$y is the origin of the ellipse
  • $rw and $rh are the horizontal ( $rw - width ) and vertical ( $rh - height ) radius to use when drawing the $ellipse. If $rw and $rh are equal, you will draw a circle
  • $fill is optional. If specified ( $fill == 1 ) the ellipse is filled.

$ctx->draw_ellipse(20, 15, 10, 7);

Draw a line between $x1,$y1 and $x2,$y2. $endpoint denotes whether the pixel at $x2,$y2 should be written. The default value for $endpoint is 1 ( true ).

$ctx->draw_line( 0, 0, 127, 31);

Set a single pixel to 1 (on) or 0 (off).

$x, $y define the pixel to write. $on can be 1 or 0 ( default 1 )

# set pixel at 0,0 to 'on'
$ctx->draw_pixel( 0, 0 );
            
# set same pixel to 'off'
$ctx->draw_pixel( 0, 0, 0 );

Draw a polygon

  • $vertices is a reference to an array of points representing the vertices of the polygon. If the final point is not equal to the first point, the polygon will be closed anyway.
  • $fill may be optionally set to fill the polygon.
$ctx->draw_polygon( [ [41,32],[63,60],[84,32],[78,53],[46,53] ] );
# draw it filled
$ctx->draw_polygon( [ [41,32],[63,60],[84,32],[78,53],[46,53] ], 1 );

Draw a rectangle

  • $x1, $y1 is the top left of the rectangle
  • $x2, $y2 is the bottom right of the rectangle
  • $fill can be optionally be specified ( 1 ) to fill the rectangle

$ctx->draw_rectangle( 10, 15, 30, 20 );

Draw a rectangle with rounded corners

  • $x1, $y1 is the top left of the rectangle
  • $x2, $y2 is the bottom right of the rectangle
  • $r is the radius to use for the arc that will form the rounded corners. The default value is 4.
  • $fill can be optionally be specified ( 1 ) to fill the rectangle

$ctx->draw_rounded_rectangle( 10, 15, 30, 20, 5 );

Draw text to the buffer

  • $x, $y is the origin for drawing the text. The origin is in the top left corner of the text.
  • $text is the text string to be written
  • $font can either be a string naming one of the builtin fonts, or a reference to a font object. The default font is Mono10

The method returns the width and height of the text as written to the buffer

my $y = 0;
my( $w, $h ) = $ctx->draw_text(0, $y, 'Hello World', 'Sans12');
$y += $h;
( $w, $h ) = $ctx->draw_text(0, $y, 'Raspberry Pi', 'Sans12');
$y += $h;
( $w, $h ) = $ctx->draw_text(0, $y, 'HiPi Perl', 'Sans12');

Several builtin fonts are provided.

EPD fonts are included intended for use with E-Paper displays but you may use any of the bitmap font types with both OLED and EPaper displays. THE EPD fonts include all the Latin-1 Supplement characters.

  • SansEPD15, SansEPD19, SansEPD23, SansEPD28, SansEPD31, SansEPD38, SansEPD50, SansEPD76, SansEPD102
  • MonoEPD15, MonoEPD19, MonoEPD23, MonoEPD28, MonoEPD31, MonoEPD38, MonoEPD50, MonoEPD76, MonoEPD102
  • SerifEPD15, SerifEPD19, SerifEPD23, SerifEPD28, SerifEPD31, SerifEPD38, SerifEPD50, SerifEPD76, SerifEPD102

The standard fonts include the printable ascii characters and the 'degree' character ( U+00B0 )

  • Sans10, Sans12, Sans14, Sans15, Sans19, Sans20, Sans26, Sans33
  • Mono10, Mono12, Mono14, Mono15, Mono19, Mono20, Mono26, Mono33
  • Serif10, Serif12, Serif14, Serif15, Serif19, Serif20, Serif26, Serif33

There are also extended fonts that include all the Latin-1 Supplement characters

  • SansExtended11, SansExtended13, SansExtended15, SansExtended17, SansExtended21, SansExtended23, SansExtended30, SansExtended38
  • MonoExtended11, MonoExtended13, MonoExtended15, MonoExtended17, MonoExtended21, MonoExtended23, MonoExtended30, MonoExtended38
  • SerifExtended11, SerifExtended13, SerifExtended15, SerifExtended17, SerifExtended21, SerifExtended23, SerifExtended30, SerifExtended38

The fonts are derived from the Bitstream Vera family.

It is expected that many users will need characters outside the builtin range. HiPi includes tools to create your own bitmapped fonts in the same way the builtins were created.

See: Creating Bitmap Fonts

Get the width and height of the text, without writing to the buffer. This can be helpful to work out where to position the text.

# Write the text to the centre of the OLED
my( $w, $h ) = $pctx->get_text_extents( 'Raspberry Pi', 'SansEPD15' );
# centre of text
my $x = int(0.5 + ($pctx->logical_width - $w) / 2);
my $y = int(0.5 + ($pctx->logical_height - $h) / 2);
$pctx->draw_text( $x, $y, 'Raspberry Pi', 'SansEPD15' );