File Coverage

blib/lib/Image/PNG/Write/BW.pm
Criterion Covered Total %
statement 77 77 100.0
branch 26 52 50.0
condition n/a
subroutine 12 12 100.0
pod 4 4 100.0
total 119 145 82.0


line stmt bran cond sub pod time code
1             package Image::PNG::Write::BW;
2              
3 1     1   15843 use v5.10;
  1         2  
4 1     1   4 use strict;
  1         1  
  1         19  
5 1     1   3 use warnings FATAL => 'all';
  1         5  
  1         39  
6              
7 1     1   446 use Digest::CRC;
  1         1869  
  1         63  
8 1     1   673 use Compress::Raw::Zlib;
  1         4177  
  1         202  
9              
10 1     1   8 use base 'Exporter';
  1         2  
  1         903  
11              
12             our @EXPORT_OK = qw(
13             make_png_string
14             make_png_bitstream_array
15             make_png_bitstream_packed
16             make_png_bitstream_raw
17             );
18             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
19              
20             # ABSTRACT: Create minimal black-and-white PNG files.
21             our $VERSION = '0.01';
22              
23              
24             sub make_png_string($) {
25 1     1 1 332 my ( $data ) = @_;
26              
27 1 50       3 die "cannot make 0-height png" if @$data == 0;
28              
29 1 50       5 my $deflate = Compress::Raw::Zlib::Deflate->new( -AppendOutput => 1 ) or die "failed to create Deflate module";
30 1         276 my $out;
31              
32 1         1 my $width = undef;
33              
34 1         3 foreach my $line ( @$data ) {
35 1         1 my $lineCp = $line; # We actually need a copy;
36 1 50       3 if ( ! defined $width ) {
37 1         1 $width = length( $lineCp );
38 1 50       3 die "cannot make 0-width png" if $width == 0;
39             }
40 1 50       2 die "all lines must have same width" if $width != length( $lineCp );
41              
42 1         4 $lineCp =~ s/\S/0/g;
43 1         2 $lineCp =~ s/\s/1/g;
44              
45 1 50       9 $deflate->deflate( pack("xB*",$lineCp) , $out ) == Z_OK or die "failed to deflate";
46             }
47 1 50       7 $deflate->flush( $out, Z_FINISH ) == Z_OK or die "failed to finish";
48              
49 1         15 return _make_png_raw_idat( $out, $width, scalar( @$data ) );
50             }
51              
52              
53              
54             sub make_png_bitstream_array($$) {
55 1     1 1 333 my ( $data, $width ) = @_;
56              
57 1 50       3 die "cannot make 0-height png" if @$data == 0;
58 1 50       5 die "cannot make 0-width png" if $width <= 0;
59              
60 1         3 my $width_bytes = int( ( $width + 7 ) / 8 );
61              
62 1 50       4 my $deflate = Compress::Raw::Zlib::Deflate->new( -AppendOutput => 1 ) or die "failed to create Deflate module";
63 1         289 my $out;
64              
65 1         3 my $cBuf = "\0" . "\0" x $width_bytes;
66              
67 1         4 for ( my $i = 0; $i < @$data; ++$i ) {
68 1 50       4 die "data has wrong number of bytes on row $i" unless $width_bytes == length( $data->[$i] );
69            
70 1         3 substr( $cBuf, 1, $width_bytes ) = $data->[$i];
71 1 50       6 $deflate->deflate( $cBuf, $out ) == Z_OK or die "failed to deflate";
72             }
73              
74 1 50       6 $deflate->flush( $out, Z_FINISH ) == Z_OK or die "failed to finish";
75              
76 1         22 return _make_png_raw_idat( $out, $width, scalar( @$data ) );
77             }
78              
79              
80             sub make_png_bitstream_packed($$$) {
81 1     1 1 446 my ( $data, $width, $height ) = ( \$_[0], $_[1], $_[2] );
82              
83 1 50       4 die "cannot make 0-height png" if $height <= 0;
84 1 50       3 die "cannot make 0-width png" if $width <= 0;
85              
86 1         3 my $width_bytes = int( ( $width + 7 ) / 8 );
87 1 50       3 die "data has wrong number of bytes" unless $width_bytes*$height == length($$data);
88              
89 1 50       5 my $deflate = Compress::Raw::Zlib::Deflate->new( -AppendOutput => 1 ) or die "failed to create Deflate module";
90 1         303 my $out;
91              
92 1         4 my $cBuf = "\0" . "\0" x $width_bytes;
93              
94 1         3 for ( my $i = 0; $i < $height; ++$i ) {
95 1         3 substr( $cBuf, 1, $width_bytes ) = substr( $$data, $width_bytes * $i, $width_bytes );
96 1 50       8 $deflate->deflate( $cBuf, $out ) == Z_OK or die "failed to deflate";
97             }
98              
99 1 50       7 $deflate->flush( $out, Z_FINISH ) == Z_OK or die "failed to finish";
100              
101 1         15 return _make_png_raw_idat( $out, $width, $height );
102             }
103              
104              
105             sub make_png_bitstream_raw($$$) {
106 1     1 1 71913 my ( $data, $width, $height ) = ( \$_[0], $_[1], $_[2] );
107              
108 1 50       4 die "cannot make 0-height png" if $height <= 0;
109 1 50       3 die "cannot make 0-width png" if $width <= 0;
110              
111 1         4 my $width_bytes = int( ( $width + 7 ) / 8 ) + 1;
112 1 50       3 die "data has wrong number of bytes" unless $width_bytes*$height == length($$data);
113              
114 1 50       11 my $deflate = Compress::Raw::Zlib::Deflate->new( -AppendOutput => 1 ) or die "failed to create Deflate module";
115 1         444 my $out;
116              
117 1 50       4 if ( length($$data) ) {
118 1 50       16 $deflate->deflate( $$data, $out ) == Z_OK or die "failed to deflate";
119             }
120 1 50       28 $deflate->flush( $out, Z_FINISH ) == Z_OK or die "failed to finish";
121              
122 1         43 return _make_png_raw_idat( $out, $width, $height );
123             }
124              
125              
126             # Internal method to make a PNG file from all parts ( including raw IDAT content )
127              
128             my $PNG_SIGNATURE = pack("C8",137,80,78,71,13,10,26,10);
129             my $PNG_IEND = _make_png_chunk( "IEND", "" );
130             sub _make_png_raw_idat($$$) {
131 4     4   5 my ( $data, $width, $height ) = ( \$_[0], $_[1], $_[2] );
132              
133 4         18 return join("", $PNG_SIGNATURE,
134             _make_png_chunk( "IHDR", pack("NNCCCCC",$width,$height,1,0,0,0,0) ),
135             _make_png_chunk( "IDAT", $$data ),
136             $PNG_IEND);
137             }
138              
139             # Internal method to make a PNG chunk
140              
141             sub _make_png_chunk {
142 9     9   75 my ($type,$data) = ( $_[0], \$_[1] );
143              
144 9         30 my $ctx = Digest::CRC->new(type => "crc32");
145 9         464 $ctx->add( $type );
146 9         52 $ctx->add( $$data );
147              
148 9         50 return join("", pack("N",length($$data)), $type, $$data, pack("N",$ctx->digest) );
149             }
150              
151              
152             1; # End of Image::PNG::Write::BW
153              
154             __END__