| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Image::PNG; | 
| 2 |  |  |  |  |  |  | require Exporter; | 
| 3 |  |  |  |  |  |  | @ISA = qw(Exporter); | 
| 4 |  |  |  |  |  |  | @EXPORT_OK = qw/display_text/; | 
| 5 | 1 |  |  | 1 |  | 22653 | use Image::PNG::Const ':all'; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | use Image::PNG::Libpng; | 
| 7 |  |  |  |  |  |  | use Image::PNG::Container; | 
| 8 |  |  |  |  |  |  | use warnings; | 
| 9 |  |  |  |  |  |  | use strict; | 
| 10 |  |  |  |  |  |  | use Carp; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our $VERSION = '0.23'; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | sub error | 
| 16 |  |  |  |  |  |  | { | 
| 17 |  |  |  |  |  |  | my ($png) = @_; | 
| 18 |  |  |  |  |  |  | return $png->{error_string}; | 
| 19 |  |  |  |  |  |  | } | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | sub fatal_error | 
| 22 |  |  |  |  |  |  | { | 
| 23 |  |  |  |  |  |  | my ($png) = @_; | 
| 24 |  |  |  |  |  |  | return $png->{error_string}; | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | my %IHDR_fields = ( | 
| 28 |  |  |  |  |  |  | width => { | 
| 29 |  |  |  |  |  |  | }, | 
| 30 |  |  |  |  |  |  | height => { | 
| 31 |  |  |  |  |  |  | }, | 
| 32 |  |  |  |  |  |  | bit_depth => { | 
| 33 |  |  |  |  |  |  | default => 8, | 
| 34 |  |  |  |  |  |  | }, | 
| 35 |  |  |  |  |  |  | color_type => { | 
| 36 |  |  |  |  |  |  | }, | 
| 37 |  |  |  |  |  |  | interlace_type => { | 
| 38 |  |  |  |  |  |  | default => PNG_INTERLACE_NONE, | 
| 39 |  |  |  |  |  |  | }, | 
| 40 |  |  |  |  |  |  | ); | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | sub write_info_error | 
| 44 |  |  |  |  |  |  | { | 
| 45 |  |  |  |  |  |  | my ($png) = @_; | 
| 46 |  |  |  |  |  |  | my @unset; | 
| 47 |  |  |  |  |  |  | for my $field (sort keys %IHDR_fields) { | 
| 48 |  |  |  |  |  |  | if (!$IHDR_fields{$field}{default}) { | 
| 49 |  |  |  |  |  |  | push @unset, $field; | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  | print "Set the following fields: ", join ", ", @unset; | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # Return the verbosity. | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | sub verbose | 
| 58 |  |  |  |  |  |  | { | 
| 59 |  |  |  |  |  |  | my ($png) = @_; | 
| 60 |  |  |  |  |  |  | return $png->{verbosity}; | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | # Set the verbosity. | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | sub verbosity | 
| 66 |  |  |  |  |  |  | { | 
| 67 |  |  |  |  |  |  | my ($png, $verbosity) = @_; | 
| 68 |  |  |  |  |  |  | if ($verbosity) { | 
| 69 |  |  |  |  |  |  | printf "I am a %s. I am going to print messages about what I'm doing. You can surprsss this by calling \$me->verbosity () or by using an option %s->new ({verbosity} = 0);.\n", (__PACKAGE__) x 2; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  | $png->{verbosity} = 1; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | # Make the object. | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | sub new | 
| 77 |  |  |  |  |  |  | { | 
| 78 |  |  |  |  |  |  | my ($package, $options) = @_; | 
| 79 |  |  |  |  |  |  | my $png = {}; | 
| 80 |  |  |  |  |  |  | bless $png; | 
| 81 |  |  |  |  |  |  | # The marker "error_string" contains the most recent error. | 
| 82 |  |  |  |  |  |  | $png->{error_string} = ''; | 
| 83 |  |  |  |  |  |  | if ($options && ref $options eq 'HASH') { | 
| 84 |  |  |  |  |  |  | if ($options->{verbosity}) { | 
| 85 |  |  |  |  |  |  | $png->verbosity ($options->{verbosity}); | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  | if ($options->{file}) { | 
| 88 |  |  |  |  |  |  | $png->read ($options->{file}); | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  | return $png; | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | # Read a file | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | sub Image::PNG::read | 
| 97 |  |  |  |  |  |  | { | 
| 98 |  |  |  |  |  |  | my ($png, $file_name) = @_; | 
| 99 |  |  |  |  |  |  | if ($png->verbose) { | 
| 100 |  |  |  |  |  |  | print "I am going to try to read a file called '$file_name'.\n"; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  | if (! defined $file_name) { | 
| 103 |  |  |  |  |  |  | carp __PACKAGE__, ": You called 'read' without giving a file name"; | 
| 104 |  |  |  |  |  |  | return; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  | my $read = Image::PNG::Container->new ({read_only => 1}); | 
| 107 |  |  |  |  |  |  | $read->set_file_name ($file_name); | 
| 108 |  |  |  |  |  |  | $read->open (); | 
| 109 |  |  |  |  |  |  | $read->read (); | 
| 110 |  |  |  |  |  |  | if ($png->verbose) { | 
| 111 |  |  |  |  |  |  | my $ihdr = Image::PNG::Libpng::get_IHDR ($read->png ()); | 
| 112 |  |  |  |  |  |  | printf ("The size of the image is %d X %d; its colour type is %s; its bit depth is %d\n", $ihdr->{width}, $ihdr->{height}, Image::PNG::Libpng::color_type_name ($ihdr->{color_type}), $ihdr->{bit_depth}); | 
| 113 |  |  |  |  |  |  | } | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | $png->{read} = $read; | 
| 116 |  |  |  |  |  |  | return 1; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | sub handle_error | 
| 120 |  |  |  |  |  |  | { | 
| 121 |  |  |  |  |  |  | my ($png, $message) = @_; | 
| 122 |  |  |  |  |  |  | croak $message; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | sub Image::PNG::write | 
| 126 |  |  |  |  |  |  | { | 
| 127 |  |  |  |  |  |  | my ($png, $file_name) = @_; | 
| 128 |  |  |  |  |  |  | if ($png->verbose) { | 
| 129 |  |  |  |  |  |  | print "I am going to try to write a PNG file called '$file_name'.\n"; | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  | if (! $png->{write_ok}) { | 
| 132 |  |  |  |  |  |  | if (! $png->{read}) { | 
| 133 |  |  |  |  |  |  | $png->write_info_error (); | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  | $png->init_write (); | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  | my $write = $png->{write}; | 
| 138 |  |  |  |  |  |  | $write->{file_name} = $file_name; | 
| 139 |  |  |  |  |  |  | # Check whether the image to be written has all of its IHDR information. | 
| 140 |  |  |  |  |  |  | if (! $write->{ihdr_set}) { | 
| 141 |  |  |  |  |  |  | if ($png->verbose) { | 
| 142 |  |  |  |  |  |  | print "The image to be written doesn't seem to know what its header is supposed to be, so I'm going to try to find a substitute.\n"; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | if ($png->{read}) { | 
| 145 |  |  |  |  |  |  | if ($png->verbose) { | 
| 146 |  |  |  |  |  |  | print "I am copying the header from the image which I read in.\n"; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | my $ihdr = Image::PNG::Libpng::get_IHDR ($png->{read}->png ()); | 
| 149 |  |  |  |  |  |  | if ($png->verbose) { | 
| 150 |  |  |  |  |  |  | print "I've got a header and now I'm going to try to put it into the output.\n"; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  | Image::PNG::Libpng::set_IHDR ($write->{png}, $ihdr); | 
| 153 |  |  |  |  |  |  | $write->{ihdr} = $ihdr; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | else { | 
| 156 |  |  |  |  |  |  | $png->handle_error ("I have no IHDR (header) data for the image; use the 'IHDR' method to set the IHDR values"); | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  | if ($png->verbose) { | 
| 160 |  |  |  |  |  |  | print "I've got a header to write. Now I'm going to check the image data before writing it out.\n"; | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | # Check whether the image data (the rows of the image) exist in | 
| 163 |  |  |  |  |  |  | # some form or other. | 
| 164 |  |  |  |  |  |  | if (! $write->{rows_set}) { | 
| 165 |  |  |  |  |  |  | if ($png->verbose) { | 
| 166 |  |  |  |  |  |  | print "You haven't specified what data you want me to write.\n"; | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  | # If the user has not specified what rows to write, assume | 
| 169 |  |  |  |  |  |  | # that he wants to use the rows from a PNG object which has | 
| 170 |  |  |  |  |  |  | # already been read in. | 
| 171 |  |  |  |  |  |  | if ($png->{read}) { | 
| 172 |  |  |  |  |  |  | if ($png->verbose) { | 
| 173 |  |  |  |  |  |  | print "I am setting the image data for the image to write to data which I read in from another image."; | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  | my $rows = Image::PNG::Libpng::get_rows ($png->{read}->png ()); | 
| 176 |  |  |  |  |  |  | if ($png->verbose) { | 
| 177 |  |  |  |  |  |  | print "I've got the data from the read image and now I'm going to set up the writing to write that data.\n"; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  | Image::PNG::Libpng::set_rows ($write->{png}, $rows); | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  | else { | 
| 182 |  |  |  |  |  |  | # There is no row data for the image. | 
| 183 |  |  |  |  |  |  | $png->handle_error ("I have no row data for the image; use the 'rows' method to set the rows."); | 
| 184 |  |  |  |  |  |  | return; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | if ($png->verbose) { | 
| 188 |  |  |  |  |  |  | printf ("Its colour type is %s.\n", Image::PNG::Libpng::color_type_name ($write->{ihdr}->{color_type})); | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | if ($write->{ihdr}->{color_type} == PNG_COLOR_TYPE_PALETTE) { | 
| 191 |  |  |  |  |  |  | if ($png->verbose) { | 
| 192 |  |  |  |  |  |  | print "The image you want to write has a palette, so I am going to check whether the palette is ready to be written.\n"; | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  | if (! $write->{palette_set}) { | 
| 195 |  |  |  |  |  |  | print "The image doesn't have a palette set.\n"; | 
| 196 |  |  |  |  |  |  | if ($png->{read}) { | 
| 197 |  |  |  |  |  |  | print "I am going to try to get one from the image I read in.\n"; | 
| 198 |  |  |  |  |  |  | my $palette = Image::PNG::Libpng::get_PLTE ($png->{read}->png ()); | 
| 199 |  |  |  |  |  |  | for my $color (@$palette) { | 
| 200 |  |  |  |  |  |  | for my $hue (qw/red green blue/) { | 
| 201 |  |  |  |  |  |  | printf "%s: %d ", $hue, $color->{$hue}; | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | print "\n"; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  | Image::PNG::Libpng::set_PLTE ($write->{png}, $palette); | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  | else { | 
| 208 |  |  |  |  |  |  | $png->handle_error ("You asked me to write an image with a palette, but I don't have any information about the palette for the image."); | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | if ($png->verbose) { | 
| 214 |  |  |  |  |  |  | print "I've got the data for the header and the image now so I can write a minimal PNG.\n"; | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  | # Now the rows are set. | 
| 217 |  |  |  |  |  |  | open my $output, ">:raw", $write->{file_name} | 
| 218 |  |  |  |  |  |  | or $png->handle_error ("opening file '$write->{file_name}' failed: $!'"); | 
| 219 |  |  |  |  |  |  | Image::PNG::Libpng::init_io ($write->{png}, $output); | 
| 220 |  |  |  |  |  |  | Image::PNG::Libpng::write_png ($write->{png}); | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | # Private | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | sub do_not_write | 
| 226 |  |  |  |  |  |  | { | 
| 227 |  |  |  |  |  |  | my ($png, $chunk) = @_; | 
| 228 |  |  |  |  |  |  | push @{$png->{write}->{ignored_chunks}}, $chunk; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | # Public | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | sub Image::PNG::delete | 
| 234 |  |  |  |  |  |  | { | 
| 235 |  |  |  |  |  |  | my ($png, @chunks) = @_; | 
| 236 |  |  |  |  |  |  | if (! $png->{write_ok}) { | 
| 237 |  |  |  |  |  |  | if (! $png->{read}) { | 
| 238 |  |  |  |  |  |  | $png->write_info_error (); | 
| 239 |  |  |  |  |  |  | } | 
| 240 |  |  |  |  |  |  | $png->init_write (); | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  | for my $chunk (@chunks) { | 
| 243 |  |  |  |  |  |  | $png->do_not_write ($chunk); | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | sub write_set | 
| 248 |  |  |  |  |  |  | { | 
| 249 |  |  |  |  |  |  | my ($png, $key, $value) = @_; | 
| 250 |  |  |  |  |  |  | if (! $png->{write_ok}) { | 
| 251 |  |  |  |  |  |  | $png->init_write (); | 
| 252 |  |  |  |  |  |  | } | 
| 253 |  |  |  |  |  |  | $png->{write}->{$key} = $value; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | # Initialize the object $png for writing (get the libpng things we | 
| 257 |  |  |  |  |  |  | # need to write an image, set a flag "write_ok" in the image.). | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | sub init_write | 
| 260 |  |  |  |  |  |  | { | 
| 261 |  |  |  |  |  |  | my ($png) = @_; | 
| 262 |  |  |  |  |  |  | if ($png->{write_ok}) { | 
| 263 |  |  |  |  |  |  | $png->error ("Writing already initialized"); | 
| 264 |  |  |  |  |  |  | return; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  | $png->{write} = {}; | 
| 267 |  |  |  |  |  |  | $png->{write}->{png} = | 
| 268 |  |  |  |  |  |  | Image::PNG::Libpng::create_write_struct (); | 
| 269 |  |  |  |  |  |  | $png->{write_ok} = 1; | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | sub raise_error | 
| 273 |  |  |  |  |  |  | { | 
| 274 |  |  |  |  |  |  | my ($png, $error_level) = @_; | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | sub print_error | 
| 278 |  |  |  |  |  |  | { | 
| 279 |  |  |  |  |  |  | my ($png, $error_level) = @_; | 
| 280 |  |  |  |  |  |  | } | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | sub data | 
| 283 |  |  |  |  |  |  | { | 
| 284 |  |  |  |  |  |  | my ($png, $data) = @_; | 
| 285 |  |  |  |  |  |  | if (! $data) { | 
| 286 |  |  |  |  |  |  | # Return the existing data | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  | else { | 
| 289 |  |  |  |  |  |  | # Put $data into the PNG | 
| 290 |  |  |  |  |  |  | if ($png->{data}) { | 
| 291 |  |  |  |  |  |  | carp __PACKAGE__, ": you have asked me to put a scalar value as the PNG data, but I already have PNG data inside me. Please use a fresh object."; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  | elsif ($png->{read_file_name}) { | 
| 294 |  |  |  |  |  |  | carp __PACKAGE__, ": you have asked me to put a scalar value as the PNG data, but I already contain PNG data from a file called '$png->{read_file_name}. Please use a fresh object."; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  | return $png->{data}; | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # Public | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | sub IHDR | 
| 303 |  |  |  |  |  |  | { | 
| 304 |  |  |  |  |  |  | my ($png, $ihdr) = @_; | 
| 305 |  |  |  |  |  |  | if ($ihdr) { | 
| 306 |  |  |  |  |  |  | Image::PNG::Libpng::set_IHDR ($png->{write}->{png}, | 
| 307 |  |  |  |  |  |  | $ihdr); | 
| 308 |  |  |  |  |  |  | $png->{write}->{ihdr_set} = 1; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  | else { | 
| 311 |  |  |  |  |  |  | $ihdr = Image::PNG::Libpng::get_IHDR ($png->{read}->png ()); | 
| 312 |  |  |  |  |  |  | } | 
| 313 |  |  |  |  |  |  | return $ihdr; | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # Private | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | sub get_IHDR | 
| 319 |  |  |  |  |  |  | { | 
| 320 |  |  |  |  |  |  | my ($png) = @_; | 
| 321 |  |  |  |  |  |  | if ($png->{IHDR}) { | 
| 322 |  |  |  |  |  |  | carp __PACKAGE__, ": I was requested to read the IHDR of the PNG data, but I have already read it."; | 
| 323 |  |  |  |  |  |  | return; | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  | $png->{IHDR} = Image::PNG::Libpng::get_IHDR ($png->{read}->png ()); | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | # Get $key from the PNG. | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | sub get | 
| 331 |  |  |  |  |  |  | { | 
| 332 |  |  |  |  |  |  | my ($png, $key) = @_; | 
| 333 |  |  |  |  |  |  | if (! $png->{IHDR}) { | 
| 334 |  |  |  |  |  |  | $png->get_IHDR (); | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  | return $png->{IHDR}->{$key}; | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | # Get/set width of PNG | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | sub width | 
| 342 |  |  |  |  |  |  | { | 
| 343 |  |  |  |  |  |  | my ($png, $width) = @_; | 
| 344 |  |  |  |  |  |  | if ($width) { | 
| 345 |  |  |  |  |  |  | write_set ($png, 'width', $width); | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  | else { | 
| 348 |  |  |  |  |  |  | return get ($png, 'width'); | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  | } | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | # Get/set height of PNG | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | sub height | 
| 355 |  |  |  |  |  |  | { | 
| 356 |  |  |  |  |  |  | my ($png, $height) = @_; | 
| 357 |  |  |  |  |  |  | if ($height) { | 
| 358 |  |  |  |  |  |  | write_set ($png, 'height', $height); | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | else { | 
| 361 |  |  |  |  |  |  | return get ($png, 'height'); | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  | sub color_type | 
| 366 |  |  |  |  |  |  | { | 
| 367 |  |  |  |  |  |  | my ($png, $color_type) = @_; | 
| 368 |  |  |  |  |  |  | if ($color_type) { | 
| 369 |  |  |  |  |  |  | write_set ($png, 'color_type', $color_type); | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  | else { | 
| 372 |  |  |  |  |  |  | return | 
| 373 |  |  |  |  |  |  | Image::PNG::Libpng::color_type_name ( | 
| 374 |  |  |  |  |  |  | get ($png, 'color_type') | 
| 375 |  |  |  |  |  |  | ); | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | sub bit_depth | 
| 380 |  |  |  |  |  |  | { | 
| 381 |  |  |  |  |  |  | my ($png, $bit_depth) = @_; | 
| 382 |  |  |  |  |  |  | if ($bit_depth) { | 
| 383 |  |  |  |  |  |  | write_set ($png, 'bit_depth', $bit_depth); | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  | else { | 
| 386 |  |  |  |  |  |  | return get ($png, 'bit_depth') | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | sub rows | 
| 391 |  |  |  |  |  |  | { | 
| 392 |  |  |  |  |  |  | my ($png, $rows) = @_; | 
| 393 |  |  |  |  |  |  | if ($rows) { | 
| 394 |  |  |  |  |  |  | # Set the rows | 
| 395 |  |  |  |  |  |  | if (! $png->{write_ok}) { | 
| 396 |  |  |  |  |  |  | $png->init_write (); | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  | if (! $png->{write}->{set_IHDR}) { | 
| 399 |  |  |  |  |  |  | $png->{write}->{set_IHDR} = 1; | 
| 400 |  |  |  |  |  |  | Image::PNG::Libpng::set_IHDR ($png->{write}->{png}, | 
| 401 |  |  |  |  |  |  | $png->{write}->{IHDR}); | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  | Image::PNG::Libpng::set_rows ($png->{write_png}, $rows); | 
| 404 |  |  |  |  |  |  | $png->{write}->{rows_set} = 1; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  | else { | 
| 407 |  |  |  |  |  |  | # Read the rows | 
| 408 |  |  |  |  |  |  | if (! $png->{read}) { | 
| 409 |  |  |  |  |  |  | #        $png->handle_error (""); | 
| 410 |  |  |  |  |  |  | return; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  | return Image::PNG::Libpng::get_rows ($png->{read}->png ()); | 
| 413 |  |  |  |  |  |  | } | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | sub rowbytes | 
| 417 |  |  |  |  |  |  | { | 
| 418 |  |  |  |  |  |  | my ($png) = @_; | 
| 419 |  |  |  |  |  |  | if (! $png->{read}) { | 
| 420 |  |  |  |  |  |  | #        $png->handle_error (""); | 
| 421 |  |  |  |  |  |  | return; | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  | return Image::PNG::Libpng::get_rowbytes ($png->{read}->png ()); | 
| 424 |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | sub text | 
| 427 |  |  |  |  |  |  | { | 
| 428 |  |  |  |  |  |  | my ($png, $text) = @_; | 
| 429 |  |  |  |  |  |  | if (! $png->{text}) { | 
| 430 |  |  |  |  |  |  | my $text_ref = | 
| 431 |  |  |  |  |  |  | Image::PNG::Libpng::get_text ($png->{read}->png ()); | 
| 432 |  |  |  |  |  |  | $png->{text} = $text_ref; | 
| 433 |  |  |  |  |  |  | # Change the text compression field to words rather than numbers. | 
| 434 |  |  |  |  |  |  | for my $text (@{$png->{text}}) { | 
| 435 |  |  |  |  |  |  | $text->{compression} = | 
| 436 |  |  |  |  |  |  | Image::PNG::Libpng::text_compression_name ($text->{compression}); | 
| 437 |  |  |  |  |  |  | } | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  | if (! wantarray) { | 
| 440 |  |  |  |  |  |  | carp __PACKAGE__, ": the 'text' method returns an array"; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  | return @{$png->{text}}; | 
| 443 |  |  |  |  |  |  | } | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | sub time | 
| 446 |  |  |  |  |  |  | { | 
| 447 |  |  |  |  |  |  | my ($png) = @_; | 
| 448 |  |  |  |  |  |  | if (! $png->{read}) { | 
| 449 |  |  |  |  |  |  | return undef; | 
| 450 |  |  |  |  |  |  | } | 
| 451 |  |  |  |  |  |  | return Image::PNG::Libpng::get_tIME ($png->{read}->{png}); | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | # The text segment of the PNG should probably be an object in its own | 
| 455 |  |  |  |  |  |  | # right. | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | sub display_text | 
| 458 |  |  |  |  |  |  | { | 
| 459 |  |  |  |  |  |  | my ($text) = @_; | 
| 460 |  |  |  |  |  |  | if (! $text || ref $text ne 'HASH' || ! $text->{key}) { | 
| 461 |  |  |  |  |  |  | carp __PACKAGE__, "::display_text called with something which doesn't seem to be a PNG text chunk"; | 
| 462 |  |  |  |  |  |  | return; | 
| 463 |  |  |  |  |  |  | } | 
| 464 |  |  |  |  |  |  | print "\n"; | 
| 465 |  |  |  |  |  |  | print "Key: $text->{key}"; | 
| 466 |  |  |  |  |  |  | if ($text->{translated_keyword}) { | 
| 467 |  |  |  |  |  |  | print " [$text->{translated_keyword}"; | 
| 468 |  |  |  |  |  |  | if ($text->{lang}) { | 
| 469 |  |  |  |  |  |  | print " in language $text->{lang}"; | 
| 470 |  |  |  |  |  |  | } | 
| 471 |  |  |  |  |  |  | print "]"; | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | print "\n"; | 
| 474 |  |  |  |  |  |  | print "Compression: $text->{compression}\n"; | 
| 475 |  |  |  |  |  |  | if ($text->{text}) { | 
| 476 |  |  |  |  |  |  | printf "Text"; | 
| 477 |  |  |  |  |  |  | if (defined $text->{text_length}) { | 
| 478 |  |  |  |  |  |  | printf " (length %d)", $text->{text_length}; | 
| 479 |  |  |  |  |  |  | } | 
| 480 |  |  |  |  |  |  | print ":\n$text->{text}\n" | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  | else { | 
| 483 |  |  |  |  |  |  | print "Text is empty.\n"; | 
| 484 |  |  |  |  |  |  | } | 
| 485 |  |  |  |  |  |  | } | 
| 486 |  |  |  |  |  |  |  | 
| 487 |  |  |  |  |  |  | 1; | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | =head1 NAME | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | Image::PNG - Read and write PNG files | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | my $png = Image::PNG->new (); | 
| 498 |  |  |  |  |  |  | $png->read_file ("crazy.png"); | 
| 499 |  |  |  |  |  |  | printf "Your PNG is %d x %d\n", $png->width, $png->height; | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | =head1 VERSION | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | This documents version 0.23 of Image::PNG corresponding | 
| 504 |  |  |  |  |  |  | to git commit L made on Sun Dec 11 08:12:23 2016 +0900. | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | Image::PNG is a layer on top of L. Whereas | 
| 510 |  |  |  |  |  |  | L copies the interface of the C library C, | 
| 511 |  |  |  |  |  |  | Image::PNG is intended to be a more intuitive way to handle PNG | 
| 512 |  |  |  |  |  |  | images. | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | Please note that this module is not completed yet and is still under | 
| 515 |  |  |  |  |  |  | development, so the interface may change. It's also open to | 
| 516 |  |  |  |  |  |  | suggestions for improvements. | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | =head1 General methods | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | =head2 new | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | my $png = Image::PNG->new (); | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | Create a new PNG-file reading or writing object. | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | Options are | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | =over | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | =item read | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  | my $png = Image::PNG->new ({read => 'some.png'}); | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | Set the file to read. The file is then read at the time of object | 
| 535 |  |  |  |  |  |  | creation. | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | =item verbosity | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | my $png = Image::PNG->new ({verbosity => 1}); | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | If C is set to a true value, print verbose messages about | 
| 542 |  |  |  |  |  |  | what the module is doing. | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | =back | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | =head2 read | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | $png->read ("crazy.png") | 
| 549 |  |  |  |  |  |  | or die "Can't read it: " . $png->error (); | 
| 550 |  |  |  |  |  |  |  | 
| 551 |  |  |  |  |  |  | Read the PNG from the file name specified as the argument. This dies | 
| 552 |  |  |  |  |  |  | if there is an error. | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =head2 write | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | $png->write ("crazy.png") | 
| 557 |  |  |  |  |  |  | or die "Can't write it: " . $png->error (); | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | Write the PNG to the file name specified as the argument. This dies | 
| 560 |  |  |  |  |  |  | if there is an error. | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =head2 data | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | my $data = $png->data (); | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | Get the PNG image data as a Perl scalar. | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | =head2 error | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | Print the most recent error message. | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | =head1 PNG header-related methods | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | These methods are related to the PNG header (the IHDR chunk of the PNG | 
| 575 |  |  |  |  |  |  | file). | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | =head2 width | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | my $height = $png->width (); | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | Get the width of the current PNG image. | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | =head2 height | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | my $height = $png->height (); | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | Get the height of the current PNG image. | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | =head2 color_type | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | my $color_type = $png->color_type (); | 
| 592 |  |  |  |  |  |  |  | 
| 593 |  |  |  |  |  |  | Get the name of the colour type of the current PNG image. The possible | 
| 594 |  |  |  |  |  |  | return values are | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | =over | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | =item PALETTE | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | =item GRAY | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | =item GRAY_ALPHA | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | =item RGB | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | =item RGB_ALPHA | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | =back | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | =head2 bit_depth | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | my $bit_depth = $png->bit_depth (); | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | Get the bit depth of the current PNG image. | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | =head2 interlacing_method | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | my $interlacing_method = $png->interlacing_method (); | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | Get the name of the method of interlacing of the current PNG image. | 
| 621 |  |  |  |  |  |  |  | 
| 622 |  |  |  |  |  |  | There is no method for dealing with the compression method | 
| 623 |  |  |  |  |  |  | field of the header, since this only has one possible value. | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | =head1 Image data-related methods | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | =head2 rowbytes | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | my $rowbytes = $png->rowbytes; | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  | This method returns the number of bytes in each row of the image. If | 
| 632 |  |  |  |  |  |  | no image has been read yet, it returns the undefined value. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | =head2 rows | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | my $rows = $png->rows; | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | This method returns the rows of the image as an array reference, | 
| 639 |  |  |  |  |  |  | C<$rows>. The array reference is a size equal to the height of the | 
| 640 |  |  |  |  |  |  | image. Each element has the length of the number of bytes in one row | 
| 641 |  |  |  |  |  |  | (as given by L) plus one final zero byte. | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | The row data returned is binary data and may contain several bytes | 
| 644 |  |  |  |  |  |  | with the value zero. | 
| 645 |  |  |  |  |  |  |  | 
| 646 |  |  |  |  |  |  | =head1 Non-image chunks | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | =head2 text | 
| 649 |  |  |  |  |  |  |  | 
| 650 |  |  |  |  |  |  | my @text = $png->text; | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | Get the text chunks of the image. Each element of the return value is | 
| 653 |  |  |  |  |  |  | a hash reference. The keys are the fields of the PNG text chunk, and | 
| 654 |  |  |  |  |  |  | the values are the values of those fields in the text chunk. The size | 
| 655 |  |  |  |  |  |  | of the array is equal to the number of text chunks. | 
| 656 |  |  |  |  |  |  |  | 
| 657 |  |  |  |  |  |  | =head2 time | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | my $time_ref = $png->time; | 
| 660 |  |  |  |  |  |  | print "The PNG was last modified in $time_ref->{year}.\n"; | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  | Get the last modified time of the image. The return value is a hash | 
| 663 |  |  |  |  |  |  | reference containing the following six fields, | 
| 664 |  |  |  |  |  |  |  | 
| 665 |  |  |  |  |  |  | =over | 
| 666 |  |  |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | =item year | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | =item month | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | =item day | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | =item hour | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | =item minute | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  | =item second | 
| 678 |  |  |  |  |  |  |  | 
| 679 |  |  |  |  |  |  | =back | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | These represent the last modification time of the image. The | 
| 682 |  |  |  |  |  |  | modification time of a PNG file is meant to be in the GMT (UCT) time | 
| 683 |  |  |  |  |  |  | zone so there is no time zone information. | 
| 684 |  |  |  |  |  |  |  | 
| 685 |  |  |  |  |  |  | If there is no last modification time, the undefined value is returned | 
| 686 |  |  |  |  |  |  | instead of a hash reference. | 
| 687 |  |  |  |  |  |  |  | 
| 688 |  |  |  |  |  |  | =head1 FUNCTIONS | 
| 689 |  |  |  |  |  |  |  | 
| 690 |  |  |  |  |  |  | There are some convenience functions in this module, exported on request. | 
| 691 |  |  |  |  |  |  |  | 
| 692 |  |  |  |  |  |  | =head2 display_text | 
| 693 |  |  |  |  |  |  |  | 
| 694 |  |  |  |  |  |  | use Image::PNG qw/display_text/; | 
| 695 |  |  |  |  |  |  | my @text = $png->text; | 
| 696 |  |  |  |  |  |  | display_text ($text[3]); | 
| 697 |  |  |  |  |  |  |  | 
| 698 |  |  |  |  |  |  | Display the text chunk given as an argument on C. | 
| 699 |  |  |  |  |  |  |  | 
| 700 |  |  |  |  |  |  | This is a convenience function for debugging rather than a | 
| 701 |  |  |  |  |  |  | general-purpose routine. | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 704 |  |  |  |  |  |  |  | 
| 705 |  |  |  |  |  |  | =head2 In this distribution | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | =head3 Image::PNG::Const | 
| 708 |  |  |  |  |  |  |  | 
| 709 |  |  |  |  |  |  | L contains the libpng constants taken from the libpng | 
| 710 |  |  |  |  |  |  | header file "png.h". | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | =head3 Image::PNG::Libpng | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | L provides a Perl mirror of the interface of the C | 
| 715 |  |  |  |  |  |  | PNG library "libpng". Image::PNG is built on top of this module. | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | =head2 libpng download | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | To download libpng, see | 
| 720 |  |  |  |  |  |  | L. See also L. | 
| 721 |  |  |  |  |  |  |  | 
| 722 |  |  |  |  |  |  | =head2 Other Perl modules on CPAN | 
| 723 |  |  |  |  |  |  |  | 
| 724 |  |  |  |  |  |  | =head3 Image::ExifTool | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | L is a pure Perl (doesn't require a C compiler) | 
| 727 |  |  |  |  |  |  | solution for accessing the text segments of images. It has extensive | 
| 728 |  |  |  |  |  |  | support for PNG text segments. | 
| 729 |  |  |  |  |  |  |  | 
| 730 |  |  |  |  |  |  | =head3 Alien::PNG | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | L claims to be a way of "building, finding and using PNG | 
| 733 |  |  |  |  |  |  | binaries". It may help in installing libpng. I didn't use it as a | 
| 734 |  |  |  |  |  |  | dependency for this module because it seems not to work in batch mode, | 
| 735 |  |  |  |  |  |  | but stop and prompt the user. I'm interested in hearing feedback from | 
| 736 |  |  |  |  |  |  | users whether this works or not on various platforms. | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | =head3 Image::PNG::Rewriter | 
| 739 |  |  |  |  |  |  |  | 
| 740 |  |  |  |  |  |  | L is a utility for unpacking and recompressing | 
| 741 |  |  |  |  |  |  | the IDAT (image data) part of a PNG image. The main purpose seems to | 
| 742 |  |  |  |  |  |  | be to recompress the image data with the module author's other module | 
| 743 |  |  |  |  |  |  | L. Unfortunately that only works with Perl | 
| 744 |  |  |  |  |  |  | versions 5.12. | 
| 745 |  |  |  |  |  |  |  | 
| 746 |  |  |  |  |  |  | =head3 Image::Pngslimmer | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | L reduces the size of dynamically created PNG | 
| 749 |  |  |  |  |  |  | images. It's very, very slow at reading PNG data, but seems to work | 
| 750 |  |  |  |  |  |  | OK. | 
| 751 |  |  |  |  |  |  |  | 
| 752 |  |  |  |  |  |  | =head3 Image::Info | 
| 753 |  |  |  |  |  |  |  | 
| 754 |  |  |  |  |  |  | L is a module for getting information out of various | 
| 755 |  |  |  |  |  |  | types of images. It has good support for PNG and is written in pure | 
| 756 |  |  |  |  |  |  | Perl (doesn't require a C compiler). As well as basics such as height, | 
| 757 |  |  |  |  |  |  | width, and colour type, it can get text chunks, modification time, | 
| 758 |  |  |  |  |  |  | palette, gamma (gAMA chunk), resolution (pHYs chunk), and significant | 
| 759 |  |  |  |  |  |  | bits (sBIT chunk). At the time of writing (version 1.31) it doesn't | 
| 760 |  |  |  |  |  |  | support other chunks. | 
| 761 |  |  |  |  |  |  |  | 
| 762 |  |  |  |  |  |  | =head3 Image::Size | 
| 763 |  |  |  |  |  |  |  | 
| 764 |  |  |  |  |  |  | If you only need to find the size of an image, L can give | 
| 765 |  |  |  |  |  |  | you the size of PNG and various other image formats. This module is | 
| 766 |  |  |  |  |  |  | highly recommended on CPAN ratings. | 
| 767 |  |  |  |  |  |  |  | 
| 768 |  |  |  |  |  |  | =head3 Image::PNGwriter | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | L is an interface to a project called | 
| 771 |  |  |  |  |  |  | "PNGwriter". At the time of writing (2013-12-01), only one version has | 
| 772 |  |  |  |  |  |  | been released, in 2005. The most recent version of PNGwriter itself is | 
| 773 |  |  |  |  |  |  | from 2009. | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  |  | 
| 776 |  |  |  |  |  |  |  | 
| 777 |  |  |  |  |  |  |  | 
| 778 |  |  |  |  |  |  | =head2 About the PNG format | 
| 779 |  |  |  |  |  |  |  | 
| 780 |  |  |  |  |  |  | =head3 Wikipedia article | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | There is L. | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | =head3 The PNG specification | 
| 785 |  |  |  |  |  |  |  | 
| 786 |  |  |  |  |  |  | L (link to W3 | 
| 787 |  |  |  |  |  |  | consortium) explains the details of the PNG format. | 
| 788 |  |  |  |  |  |  |  | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | =head3 PNG The Definitive Guide by Greg Roelofs | 
| 791 |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  | The book "PNG - The Definitive Guide" by Greg Roelofs, published in | 
| 793 |  |  |  |  |  |  | 1999 by O'Reilly is available online at | 
| 794 |  |  |  |  |  |  | L. | 
| 795 |  |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  | =head1 AUTHOR | 
| 797 |  |  |  |  |  |  |  | 
| 798 |  |  |  |  |  |  | Ben Bullock, | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENCE | 
| 801 |  |  |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | The Image::PNG package and associated files are copyright (C) | 
| 803 |  |  |  |  |  |  | 2016 Ben Bullock. | 
| 804 |  |  |  |  |  |  |  | 
| 805 |  |  |  |  |  |  | You can use, copy, modify and redistribute Image::PNG and | 
| 806 |  |  |  |  |  |  | associated files under the Perl Artistic Licence or the GNU General | 
| 807 |  |  |  |  |  |  | Public Licence. | 
| 808 |  |  |  |  |  |  |  | 
| 809 |  |  |  |  |  |  | =head1 FOR PROGRAMMERS | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | The distributed files are not the source code of the module. The | 
| 812 |  |  |  |  |  |  | source code lives in the "tmpl" directory of the distribution and the | 
| 813 |  |  |  |  |  |  | distribution is created via scripts. | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  |  | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | =cut | 
| 818 |  |  |  |  |  |  |  | 
| 819 |  |  |  |  |  |  | # Local Variables: | 
| 820 |  |  |  |  |  |  | # mode: perl | 
| 821 |  |  |  |  |  |  | # End: | 
| 822 |  |  |  |  |  |  |  | 
| 823 |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  | # Local Variables: | 
| 825 |  |  |  |  |  |  | # mode: perl | 
| 826 |  |  |  |  |  |  | # End: |