File Coverage

blib/lib/Term/Drawille.pm
Criterion Covered Total %
statement 52 53 98.1
branch 5 8 62.5
condition n/a
subroutine 13 13 100.0
pod 3 3 100.0
total 73 77 94.8


line stmt bran cond sub pod time code
1             ## no critic (RequireUseStrict)
2             package Term::Drawille;
3             $Term::Drawille::VERSION = '0.01';
4             ## use critic (RequireUseStrict)
5 1     1   21093 use strict;
  1         2  
  1         39  
6 1     1   4 use warnings;
  1         1  
  1         22  
7 1     1   5 use utf8;
  1         1  
  1         10  
8 1     1   14584 use charnames ();
  1         36411  
  1         816  
9              
10             my %BRAILLE_MAPPING; # 12374568 => braille char
11             my $VERT_PIXELS_PER_CELL = 4;
12             my $HORZ_PIXELS_PER_CELL = 2;
13              
14             $BRAILLE_MAPPING{'00000000'} = '⠀';
15             for my $value (1 .. 255) {
16             $value = sprintf('%08b', $value);
17             my @values = unpack('A' x 8, $value);
18              
19             # the braille character names order the dots as such:
20             #
21             # 1 4
22             # 2 5
23             # 3 6
24             # 7 8
25             #
26              
27             my @indices = ( 1, 2, 3, 7, 4, 5, 6, 8 );
28             my $char_name = 'BRAILLE PATTERN DOTS-' . join('', sort(map { $indices[$_] } grep {
29             $values[$_]
30             } ( 0 .. 7 )));
31              
32             $BRAILLE_MAPPING{$value} = charnames::string_vianame($char_name);
33             }
34              
35             sub new {
36 10     10 1 5234 my ( $class, %params ) = @_;
37              
38 10         21 my ( $width, $height ) = @params{qw/width height/};
39              
40 10 50       31 unless($width % $HORZ_PIXELS_PER_CELL == 0) {
41 0         0 $width = ($width - ($width % $HORZ_PIXELS_PER_CELL)) + $HORZ_PIXELS_PER_CELL;
42             }
43              
44 10 100       21 unless($height % $VERT_PIXELS_PER_CELL == 0) {
45 1         3 $height = ($height - ($height % $VERT_PIXELS_PER_CELL)) + $VERT_PIXELS_PER_CELL;
46             }
47              
48 10         22 my $grid = [ map { [ (0) x $width ] } ( 1 .. $height ) ];
  52         144  
49              
50 10         57 return bless {
51             grid => $grid,
52             }, $class;
53             }
54              
55             sub _grid {
56 62     62   64 my ( $self ) = @_;
57              
58 62         179 return $self->{'grid'};
59             }
60              
61             sub _width {
62 13     13   14 my ( $self ) = @_;
63              
64 13         13 return scalar(@{ $self->_grid->[0] });
  13         23  
65             }
66              
67             sub _height {
68 10     10   11 my ( $self ) = @_;
69              
70 10         12 return scalar(@{ $self->_grid });
  10         16  
71             }
72              
73             sub set {
74 26     26 1 110 my ( $self, $x, $y, $value );
75              
76 26 50       53 push @_, 1 if @_ == 3;
77 26         42 ( $self, $x, $y, $value ) = @_;
78              
79 26 50       71 $self->_grid->[$y][$x] = $value ? 1 : 0;
80             }
81              
82             sub _each_cell_row {
83 10     10   15 my ( $self, $action ) = @_;
84              
85 10         20 for my $row_num (0 .. ($self->_height / $VERT_PIXELS_PER_CELL) - 1) {
86 13         20 $action->($row_num);
87             }
88             }
89              
90             # $action is called with a sequence of $VERT_PIXELS_PER_CELL * $HORZ_PIXELS_PER_CELL
91             # values, going from left-to-right, top-to-bottom.
92             sub _each_cell_column {
93 13     13   18 my ( $self, $row_num, $action ) = @_;
94              
95 13         23 my $grid = $self->_grid;
96 13         27 for my $col_num (0 .. ($self->_width / $HORZ_PIXELS_PER_CELL) - 1) {
97 31         34 my @values;
98              
99 31         44 for my $col_offset (0 .. $HORZ_PIXELS_PER_CELL - 1) {
100 62         104 for my $row_offset (0 .. $VERT_PIXELS_PER_CELL - 1) {
101 248         457 push @values, $grid->[$row_num * $VERT_PIXELS_PER_CELL + $row_offset][$col_num * $HORZ_PIXELS_PER_CELL + $col_offset];
102             }
103             }
104              
105 31         76 $action->(@values);
106             }
107             }
108              
109             sub as_string {
110 10     10 1 36 my ( $self ) = @_;
111              
112 10         14 my $result = '';
113              
114             $self->_each_cell_row(sub {
115 13     13   17 my ( $row_num ) = @_;
116              
117             $self->_each_cell_column($row_num, sub {
118 31         66 my @values = @_;
119              
120 31         197 $result .= $BRAILLE_MAPPING{ join('', @values) };
121 13         49 });
122              
123 13         70 $result .= "\n";
124 10         91 });
125              
126 10         62 return $result;
127             }
128              
129             1;
130              
131             =pod
132              
133             =encoding UTF-8
134              
135             =head1 NAME
136              
137             Term::Drawille - Draw to your terminal using Braille characters
138              
139             =head1 VERSION
140              
141             version 0.01
142              
143             =head1 SYNOPSIS
144              
145             use Term::Drawille;
146              
147             binmode STDOUT, ':encoding(utf8)';
148             my $canvas = Term::Drawille->new(
149             width => 400,
150             height => 400,
151             );
152              
153             for(my $i = 0; $i < 400; $i++) {
154             $canvas->set($i, $i, 1);
155             }
156              
157             print $canvas->as_string;
158              
159             =head1 DESCRIPTION
160              
161             L makes use of Braille characters to allow you to draw
162             lines, circles, pictures, etc, to your terminal with a surprising amount
163             of precision. It's based on a Python library (L);
164             its page has some screenshots that demonstrate what it and this module can accomplish.
165              
166             =head1 METHODS
167              
168             =head2 Term::Drawille->new(%params)
169              
170             Creates a new canvas to draw on.
171              
172             Valid key value pairs for C<%params> are:
173              
174             =head3 width
175              
176             Specify the width of the canvas in pixels.
177              
178             =head3 height
179              
180             Specify the height of the canvas in pixels.
181              
182             =head2 $canvas->set($x, $y, [$value])
183              
184             Sets the value of the pixel at (C<$x>, C<$y>) to C<$value>. If
185             C<$value> is omitted, it defaults to C<1>.
186              
187             The $value is interpreted as a boolean: whether or not to draw
188             the pixel at the given position.
189              
190             =head2 $canvas->as_string
191              
192             Draws the canvas as a string of Braille characters and returns it.
193             Note that the string consists of Unicode B and not raw bytes;
194             this means you'll likely have to encode it before sending it to the terminal.
195             This may change in future releases.
196              
197             =head1 SEE ALSO
198              
199             L
200              
201             =head1 AUTHOR
202              
203             Rob Hoelz
204              
205             =head1 COPYRIGHT AND LICENSE
206              
207             This software is copyright (c) 2014 by Rob Hoelz.
208              
209             This is free software; you can redistribute it and/or modify it under
210             the same terms as the Perl 5 programming language system itself.
211              
212             =head1 BUGS
213              
214             Please report any bugs or feature requests on the bugtracker website
215             https://github.com/hoelzro/term-drawille/issues
216              
217             When submitting a bug or request, please include a test-file or a
218             patch to an existing test-file that illustrates the bug or desired
219             feature.
220              
221             =cut
222              
223             __END__