The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

# This file is just a list of exports and documentation. The source
# code for this file is in Libpng.xs in the top directory.

package Image::PNG::Libpng;
use warnings;
use strict;

require Exporter;
use Carp;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw/
	create_read_struct
	create_write_struct
	destroy_read_struct
	destroy_write_struct
	write_png
	init_io
	read_info
	read_update_info
	read_image
	read_png
	get_text
	set_text
	sig_cmp
	scalar_as_input
	read_from_scalar
	color_type_name
	text_compression_name
	get_libpng_ver
	access_version_number
	get_row_pointers
	get_rows
	get_rowbytes
	get_valid
	set_tRNS_pointer
	set_rows
	write_to_scalar
	set_filter
	set_verbosity
	set_unknown_chunks
	get_unknown_chunks
	libpng_supports
	set_keep_unknown_chunks
	get_tRNS_palette
	set_PLTE_pointer
	set_expand
	set_gray_to_rgb
	set_filler
	get_sRGB
	set_sRGB
	set_packing
	set_strip_16
	get_internals
	set_transforms
	copy_row_pointers
	get_bKGD
	set_bKGD
	get_cHRM
	set_cHRM
	get_gAMA
	set_gAMA
	get_hIST
	set_hIST
	get_iCCP
	set_iCCP
	get_IHDR
	set_IHDR
	get_oFFs
	set_oFFs
	get_pCAL
	set_pCAL
	get_pHYs
	set_pHYs
	get_PLTE
	set_PLTE
	get_sBIT
	set_sBIT
	get_sCAL
	set_sCAL
	get_sPLT
	set_sPLT
	get_tIME
	set_tIME
	get_tRNS
	set_tRNS
read_png_file
write_png_file
color_type_name
get_internals
copy_png
image_data_diff
png_compare
/;

our %EXPORT_TAGS = (
    all => \@EXPORT_OK,
);

require XSLoader;
our $VERSION = '0.44';

XSLoader::load('Image::PNG::Libpng', $VERSION);

use Image::PNG::Const ':all';

# Old undocumented function name

sub read_file
{
    goto & read_png_file;
}

# Old undocumented function name

sub write_file
{
    goto & write_png_file;
}

sub read_png_file
{
    my ($file_name, %options) = @_;
    my $png = create_read_struct ();
    if ($options{transforms}) {
	$png->set_transforms ($options{transforms});
    }
    if ($options{verbosity}) {
	$png->set_verbosity ($options{verbosity});
    }
    open my $in, "<:raw", $file_name
        or croak "Cannot open '$file_name' for reading: $!";
    $png->init_io ($in);
    $png->read_png ();
    close $in or croak $!;
    return $png;
}

sub write_png_file
{
    my ($png, $file_name) = @_;
    open my $in, ">:raw", $file_name
        or croak "Cannot open '$file_name' for writing: $!";
    $png->init_io ($in);
    $png->write_png ();
    close $in or croak $!;
}

my %known_chunks = (

bKGD => 1,

cHRM => 1,

gAMA => 1,

hIST => 1,



iCCP => 1,

IDAT => 1,





oFFs => 1,

pCAL => 1,

pHYs => 1,

PLTE => 1,

sBIT => 1,

sCAL => 1,

sPLT => 1,

sRGB => 1,



tIME => 1,

tRNS => 1,



);

sub get_chunk
{
    my ($png, $chunk) = @_;
    if ($chunk eq 'IDAT') {
	croak "Use get_rows";
    }
    if ($known_chunks{$chunk}) {
	no strict 'refs';
	my $sub = "get_$chunk";
	return &$sub ($png); 
    }
    return undef;
}

sub set_chunk
{
    my ($png, $chunk, $value) = @_;
    if ($chunk eq 'IDAT') {
	croak "Use get_rows";
    }
    if ($known_chunks{$chunk}) {
	no strict 'refs';
	my $sub = "set_$chunk";
	return &$sub ($png, $value); 
    }
    croak "Unknown chunk $chunk";
}

sub copy_png
{
    my ($png, %options) = @_;
    my $opng = create_write_struct ();
    if ($options{verbosity}) {
	$opng->set_verbosity ($options{verbosity});
    }
    my $strip = $options{strip};
    my $strip_all;
    if ($strip) {
	if ($strip eq 'all') {
	    $strip_all = 1;
	}
    }
    my $valid = $png->get_valid ();
    $opng->set_IHDR ($png->get_IHDR ());
    my $rows = $png->get_rows ();
    $opng->set_rows ($rows);

    # Set PLTE up first because hIST needs it to be set.
    if ($valid->{PLTE}) {
	$opng->set_chunk ('PLTE', $png->get_chunk ('PLTE'));
    }
    if (! $strip_all) {
	# Make a list of valid chunks excluding IHDR (header), IDAT
	# (image data), and PLTE (palette).
	my @valid = grep {!/IHDR|IDAT|PLTE/ && $valid->{$_}} sort keys %$valid;
	for my $chunk (@valid) {
	    $opng->set_chunk ($chunk, $png->get_chunk ($chunk));
	}
    }
    return $opng;
}


sub width
{
    goto & get_image_width;
}

sub height
{
    goto & get_image_height;
}


sub image_data_diff
{
    my ($file1, $file2, %options) = @_;
    my $png1 = read_png_file ($file1, transforms => PNG_TRANSFORM_EXPAND);
    my $png2 = read_png_file ($file2, transforms => PNG_TRANSFORM_EXPAND);
    my $ihdr1 = $png1->get_IHDR ();
    my $ihdr2 = $png2->get_IHDR ();
    my @fields = qw/height width/;
    for my $field (@fields) {
	if ($ihdr1->{$field} != $ihdr2->{$field}) {
	    return "$field differs: $file1: ".
	    "$ihdr1->{field}; $file2: $ihdr2->{field}";
	}
    }
    my $h = $ihdr1->{height};
    my $rows1 = $png1->get_rows ();
    my $rows2 = $png2->get_rows ();
    for my $r (0..$h - 1) {
 	my $row1 = $rows1->[$r];
	my $row2 = $rows2->[$r];
	if ($row1 ne $row2) {
	    if ($options{print_bytes}) {
		my @bytes1 = unpack "C*", $row1;
		my @bytes2 = unpack "C*", $row2;
		for my $byte (0..$#bytes1) {
		    printf ("%02X,%02X ", $bytes1[$byte], $bytes2[$byte]);
		}
		print "\n";
	    }
	    return "Row $r of image data differs";
	}
    }
    # No difference.
    return;
}

sub png_compare
{
    my ($file1, $file2, %options) = @_;
    my $png1 = read_png_file ($file1, transforms => PNG_TRANSFORM_EXPAND);
    my $png2 = read_png_file ($file2, transforms => PNG_TRANSFORM_EXPAND);
    my $ihdr1 = $png1->get_IHDR ();
    my $ihdr2 = $png2->get_IHDR ();
    my @fields = qw/height width/;
    for my $field (@fields) {
	if ($ihdr1->{$field} != $ihdr2->{$field}) {
	    return 1;
	}
    }
    my $h = $ihdr1->{height};
    my $rows1 = $png1->get_rows ();
    my $rows2 = $png2->get_rows ();
    for my $r (0..$h - 1) {
 	my $row1 = $rows1->[$r];
	my $row2 = $rows2->[$r];
	if ($row1 ne $row2) {
	    return 1;
	}
    }
    # No difference.
    return 0;
}

1;

# Local Variables:
# mode: perl
# End: