| Image-TextMode documentation | Contained in the Image-TextMode distribution. |
Image::TextMode::Reader::AVATAR - Reads AVATAR files
Provides reading capabilities for the AVATAR format.
The reader implements all of the AVT/0 specification as well as the majority of the AVT/0+ specification. The main difference being that AVT/0+ character expansion is not re-interpreted, thus expansions containing further AVT/0 codes will simply be written as characters to the canvas.
Moves the cursor to $x, $y.
Moves the cursor up $y lines.
Moves the cursor down $y lines.
Moves the cursor left $x columns.
Moves the cursor right $x columns.
Scrolls box bound by ($x0, $y0) and ($x1, $y1) in direction
$dir (up or down), by $n lines.
Clears box bound from current cursor position for $rows rows and $cols
columns using $char as the character.
Clears all data on the canvas.
Clears the remainder of the current line.
Simulates a \n character.
Simulates a \t character.
Stores $char at position $x, $y with either the supplied attribute
or the current attribute setting.
Brian Cassidy <bricas@cpan.org>
Copyright 2008-2011 by Brian Cassidy
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Image-TextMode documentation | Contained in the Image-TextMode distribution. |
package Image::TextMode::Reader::AVATAR; use Moose; use charnames ':full'; extends 'Image::TextMode::Reader'; has 'tabstop' => ( is => 'rw', isa => 'Int', default => sub { 8 } ); has 'x' => ( is => 'rw', isa => 'Int', default => sub { 0 } ); has 'y' => ( is => 'rw', isa => 'Int', default => sub { 0 } ); has 'insert' => ( is => 'rw', isa => 'Bool', default => sub { 0 } ); has 'attr' => ( is => 'rw', isa => 'Int', default => sub { 3 } ); has 'image' => ( is => 'rw', isa => 'Object' ); has 'linewrap' => ( is => 'rw', isa => 'Int', default => sub { 80 } ); sub _read { my ( $self, $image, $fh, $options ) = @_; $self->image( $image ); if ( $options->{ width } ) { $self->linewrap( $options->{ width } ); } if ( $image->has_sauce ) { $image->render_options->{ blink_mode } = $image->sauce->flags_id ^ 1; } seek( $fh, 0, 0 ); my $ch; while ( read( $fh, $ch, 1 ) ) { if ( $ch eq "\N{SUBSTITUTE}" ) { last; } elsif ( $ch eq "\n" ) { $self->new_line; } elsif ( $ch eq "\r" ) { # do nothing } elsif ( $ch eq "\t" ) { $self->tab; } elsif ( ord $ch == 12 ) { $self->clear_screen; $self->attr( 3 ); $self->insert( 0 ); } elsif ( ord $ch == 25 ) { my $i; read( $fh, $ch, 1 ); read( $fh, $i, 1 ); $self->store( $ch ) for 1 .. ord $i; } elsif ( ord $ch == 22 ) { read( $fh, $ch, 1 ); my $c = ord $ch; if ( $c == 1 ) { my $a; read( $fh, $a, 1 ); $self->attr( ord $a & 0x7f ); } elsif ( $c == 2 ) { $self->attr( $self->attr | 0x80 ); } elsif ( $c == 3 ) { $self->move_up; } elsif ( $c == 4 ) { $self->move_down; } elsif ( $c == 5 ) { $self->move_left; } elsif ( $c == 6 ) { $self->move_right; } elsif ( $c == 7 ) { $self->clear_line; } elsif ( $c == 8 ) { my ( $x, $y ); read( $fh, $y, 1 ); read( $fh, $x, 1 ); $self->set_position( ord $y, ord $x ); } # AVT/0+ spec starts here elsif ( $c == 9 ) { $self->insert( 1 ); } elsif ( $c == 10 || $c == 11 ) { my ( $n, $x0, $y0, $x1, $y1 ); read( $fh, $n, 1 ); read( $fh, $x0, 1 ); read( $fh, $y0, 1 ); read( $fh, $x1, 1 ); read( $fh, $y1, 1 ); $self->scroll( $c == 10 ? 'up' : 'down', $n, $x0, $y0, $x1, $y1 ); } elsif ( $c == 12 || $c == 13 ) { my ( $a, $char, $rows, $cols ); read( $fh, $a, 1 ); read( $fh, $char, 1 ) if $c == 13; read( $fh, $rows, 1 ); read( $fh, $cols, 1 ); $self->attr( ord $a & 0x7f ); $self->clear_box( ord $rows, ord $cols, $char ); } elsif ( $c == 14 ) { splice( @{ $self->image->pixeldata->[ $self->y ] }, $self->x, 1 ); } elsif ( $c == 25 ) { my ( $n, $buf, $i ); read( $fh, $n, 1 ); read( $fh, $buf, ord $n ); read( $fh, $i, 1 ); my @chars = split //s, $buf; # According to spec, this can contain AVT/0 codes and should # probably be written back to the stream for parsing. # We'll send it directly to the screen for now. for ( 1 .. ord $i ) { $self->store( $_ ) for @chars; } } $self->insert( 0 ) if $c < 9; } else { $self->store( $ch ); } } return $image; } sub set_position { my ( $self, $y, $x ) = @_; $y = ( $y || 1 ) - 1; $x = ( $x || 1 ) - 1; $y = 0 if $y < 0; $x = 0 if $x < 0; $self->x( $x ); $self->y( $y ); } sub move_up { my $self = shift; my $y = $self->y - ( shift || 1 ); $y = 0 if $y < 0; $self->y( $y ); } sub move_down { my $self = shift; my $y = shift || 1; $self->y( $self->y + $y ); } sub move_right { my $self = shift; my $x = shift || 1; $self->x( $self->x + $x ); } sub move_left { my $self = shift; my $x = $self->x - ( shift || 1 ); $x = 0 if $x < 0; $self->x( $x ); } sub scroll { ## no critic (Subroutines::ProhibitManyArgs) my ( $self, $dir, $n, $x0, $y0, $x1, $y1 ) = @_; $x0--; $y0--; $x1--; $y1--; my $pixeldata = $self->image->pixeldata; my $cols = $x1 - $x0; my @rows = $y0 .. $y1; if ( $dir eq 'down' ) { @rows = reverse @rows; } else { $n = 0 - $n; } my $attr = $self->attr; my @blank = ( { char => ' ', attr => $attr } ) x $cols; for my $from ( @rows ) { my $to = $from + $n; next if $to < 0; splice( @{ $pixeldata->[ $to ] }, $x0, $cols, @{ $pixeldata->[ $from ] }[ $x0 .. $x1 ] ); splice( @{ $pixeldata->[ $from ] }, $x0, $cols, @blank ); } } sub clear_box { my ( $self, $rows, $cols, $char ) = @_; $char = ' ' unless defined $char; my $sx = $self->x; my $sy = $self->y; for my $x ( map { $sx + $_ } 0 .. $cols - 1 ) { for my $y ( map { $sy + $_ } 0 .. $rows - 1 ) { $self->store( $char, $x, $y ); } } $self->x( $sx ); $self->y( $sy ); } sub clear_line { my $self = shift; $self->image->clear_line( $self->y, [ $self->x, -1 ] ); } sub clear_screen { my $self = shift; $self->image->clear_screen; } sub new_line { my $self = shift; $self->y( $self->y + 1 ); $self->x( 0 ); } sub tab { my $self = shift; my $count = ( $self->x + 1 ) % $self->tabstop; if ( $count ) { $count = $self->tabstop - $count; for ( 1 .. $count ) { $self->store( ' ' ); } } } sub store { my $self = shift; my $char = shift; my $x = shift; my $y = shift; my $attr = shift || $self->attr; if ( $self->insert ) { my $col = $self->x; my $row = $self->image->pixeldata->[ $self->y ]; splice( @$row, $col + 1, @$row - 1 - $col, @{ $row }[ $col .. -1 ] ); } if ( defined $x and defined $y ) { $self->image->putpixel( { char => $char, attr => $attr }, $x, $y ); } else { $self->image->putpixel( { char => $char, attr => $attr }, $self->x, $self->y ); $self->x( $self->x + 1 ); } if ( $self->x >= $self->linewrap ) { $self->new_line; } } no Moose; __PACKAGE__->meta->make_immutable;
1;