File Coverage

blib/lib/Image/PNG/FileConvert.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Image::PNG::FileConvert;
2             require Exporter;
3             @ISA = qw(Exporter);
4             @EXPORT_OK = qw/file2png png2file/;
5 1     1   85181 use warnings;
  1         3  
  1         51  
6 1     1   9 use strict;
  1         2  
  1         57  
7             our $VERSION = '0.10';
8 1     1   8 use Carp;
  1         3  
  1         82  
9 1     1   169 use Image::PNG::Libpng ':all';
  0            
  0            
10             use Image::PNG::Const ':all';
11              
12             use constant {
13             default_row_length => 0x800,
14             default_max_rows => 0x800,
15             };
16              
17             sub file2png
18             {
19             my ($file, $png_file, $options) = @_;
20             if (! -f $file) {
21             carp "I can't find '$file'";
22             return;
23             }
24             if (! $png_file) {
25             carp "I need a name for the PNG output";
26             return;
27             }
28             if (-f $png_file) {
29             carp "Output PNG file '$png_file' already exists";
30             return;
31             }
32             if (! $options) {
33             $options = {};
34             }
35             if (! $options->{row_length}) {
36             $options->{row_length} = default_row_length;
37             }
38             if (! $options->{max_rows}) {
39             $options->{max_rows} = default_max_rows;
40             }
41             my @rows;
42             my $bytes = -s $file;
43             open my $input, "<:raw", $file;
44             my $i = 0;
45             my $total_red = 0;
46             while (! eof ($input)) {
47             my $red = read ($input, $rows[$i], $options->{row_length});
48             if ($red != $options->{row_length}) {
49             if ($total_red + $red != $bytes) {
50             warn "Short read of $red bytes at row $i.\n"
51             }
52             }
53             $total_red += $red;
54             $i++;
55             }
56             close $input;
57             if ($options->{verbose}) {
58             printf "Read 0x%X rows.\n", $i;
59             }
60              
61             # Fill the final row up with useless bytes so that we are not
62             # reading from unallocated memory.
63              
64             # The number of bytes in the last row.
65             my $end_bytes = $bytes % $options->{row_length};
66             if ($end_bytes > 0) {
67             $rows[-1] .= "X" x ($options->{row_length} - $end_bytes);
68             }
69              
70             # Create the PNG data in a Perl structure.
71              
72             my $png = create_write_struct ();
73             my %IHDR = (
74             width => $options->{row_length},
75             height => scalar @rows,
76             color_type => PNG_COLOR_TYPE_GRAY,
77             bit_depth => 8,
78             );
79             set_IHDR ($png, \%IHDR);
80             set_rows ($png, \@rows);
81              
82             # Write the PNG data to a file.
83              
84             open my $output, ">:raw", "$png_file";
85             init_io ($png, $output);
86              
87             # Set the timestamp of the PNG file to the current time.
88              
89             set_tIME ($png);
90             my $name;
91             if ($options->{name}) {
92             $name = $options->{name};
93             }
94             else {
95             $name = $file;
96             }
97             # Put the name and size of the file into the file as text
98             # segments.
99             set_text ($png, [{key => 'bytes',
100             text => $bytes,
101             compression => PNG_TEXT_COMPRESSION_NONE},
102             {key => 'name',
103             text => $name,
104             compression => PNG_TEXT_COMPRESSION_NONE},
105             ]);
106             write_png ($png);
107             close $output;
108             }
109              
110             sub png2file
111             {
112             my ($png_file, %options) = @_;
113             my $me = __PACKAGE__ . "::png2file";
114             if (! $png_file) {
115             croak "$me: please specify a file";
116             }
117             if (! -f $png_file) {
118             croak "$me: can't find the PNG file '$png_file'";
119             }
120             my $verbose = $options{verbose};
121             open my $input, "<:raw", $png_file;
122             my $png = create_read_struct ();
123             init_io ($png, $input);
124             if ($verbose) {
125             print "Reading file\n";
126             }
127             read_png ($png);
128             my $IHDR = get_IHDR ($png);
129             # Check that the IHDR data looks like something created by
130             # file2png.
131             if ($IHDR->{color_type} != PNG_COLOR_TYPE_GRAY) {
132             croak "$me: Wrong color type $IHDR->{color_type}; expected " .
133             PNG_COLOR_TYPE_GRAY;
134             }
135             if ($IHDR->{bit_depth} != 8) {
136             croak "$me: Wrong bit depth $IHDR->{bit_depth}; expected 8";
137             }
138             if ($verbose) {
139             print "Getting rows\n";
140             }
141             my $rows = get_rows ($png);
142             if ($verbose) {
143             print "Finished reading file\n";
144             }
145             close $input;
146             my $text_segments = get_text ($png);
147             if (! defined $text_segments) {
148             croak "$me: the PNG file '$png_file' does not have any text segments, so either it was not created by " . __PACKAGE__ . "::file2png, or it has had its text segments removed";
149             return;
150             }
151             my $name;
152             my $bytes;
153             for my $text_segment (@$text_segments) {
154             if ($text_segment->{key} eq 'name') {
155             $name = $text_segment->{text};
156             }
157             elsif ($text_segment->{key} eq 'bytes') {
158             $bytes = $text_segment->{text};
159             }
160             else {
161             carp "$me: unknown text segment with key '$text_segment->{key}' in '$png_file'";
162             }
163             }
164             if ($options{name}) {
165             if ($verbose) {
166             print "Overriding file name $name to $options{name}.\n";
167             }
168             $name = $options{name};
169             }
170             if (! $name) {
171             croak "$me: no file name for '$png_file'";
172             }
173             if (! $bytes) {
174             croak "$me: byte count is missing from '$png_file'";
175             }
176             if ($bytes <= 0) {
177             croak "$me: the byte file size $bytes in '$png_file' is impossible";
178             }
179             my $row_bytes = get_rowbytes ($png);
180             if (-f $name) {
181             croak "$me: a file with the name '$name' already exists";
182             }
183             open my $output, ">:raw", $name or die "Can't open $name: $!";
184             for my $i (0..$#$rows - 1) {
185             print $output $rows->[$i];
186             }
187             my $final_row = substr ($rows->[-1], 0, $bytes % $row_bytes);
188             print $output $final_row;
189             close $output;
190             return;
191             }
192              
193             1;