newcolour
NC
NF
+ NCF
);
@EXPORT=qw(
newcolor
NF
NC
+ NCF
)],
all => [@EXPORT_OK],
default => [qw(
# modules we attempted to autoload
my %attempted_to_load;
+# library keys that are image file formats
+my %file_formats = map { $_ => 1 } qw/tiff pnm gif png jpeg raw bmp tga/;
+
BEGIN {
require Exporter;
@ISA = qw(Exporter);
- $VERSION = '0.56';
+ $VERSION = '0.61';
eval {
require XSLoader;
XSLoader::load(Imager => $VERSION);
# initlize Imager
# NOTE: this might be moved to an import override later on
-#sub import {
-# my $pack = shift;
-# (look through @_ for special tags, process, and remove them);
-# use Data::Dumper;
-# print Dumper($pack);
-# print Dumper(@_);
-#}
+sub import {
+ my $i = 1;
+ while ($i < @_) {
+ if ($_[$i] eq '-log-stderr') {
+ init_log(undef, 4);
+ splice(@_, $i, 1);
+ }
+ else {
+ ++$i;
+ }
+ }
+ goto &Exporter::import;
+}
sub init_log {
i_init_log($_[0],$_[1]);
$self->_set_error("resulting image would have no content");
return;
}
-
+ if( $r < $l or $b < $t ) {
+ $self->_set_error("attempting to crop outside of the image");
+ return;
+ }
my $dst = $self->_sametype(xsize=>$r-$l, ysize=>$b-$t);
i_copyto($dst->{IMG},$self->{IMG},$l,$t,$r,$b,0,0);
return $result;
}
+# convert a paletted (or any image) to an 8-bit/channel RGB images
+sub to_rgb16 {
+ my $self = shift;
+ my $result;
+
+ unless (defined wantarray) {
+ my @caller = caller;
+ warn "to_rgb16() called in void context - to_rgb8() returns the converted image at $caller[1] line $caller[2]\n";
+ return;
+ }
+
+ if ($self->{IMG}) {
+ $result = Imager->new;
+ $result->{IMG} = i_img_to_rgb16($self->{IMG})
+ or undef $result;
+ }
+
+ return $result;
+}
+
sub addcolors {
my $self = shift;
my %opts = (colors=>[], @_);
$self->{IMG} and i_img_virtual($self->{IMG});
}
+sub is_bilevel {
+ my ($self) = @_;
+
+ $self->{IMG} or return;
+
+ return i_img_is_monochrome($self->{IMG});
+}
+
sub tags {
my ($self, %opts) = @_;
}
unless ($formats{$input{'type'}}) {
- $self->_set_error("format '$input{'type'}' not supported");
+ my $read_types = join ', ', sort Imager->read_types();
+ $self->_set_error("format '$input{'type'}' not supported - formats $read_types available for reading");
return;
}
my $page = $input{'page'};
defined $page or $page = 0;
$self->{IMG} = i_readgif_single_wiol( $IO, $page );
- if ($input{colors}) {
+ if ($self->{IMG} && $input{colors}) {
${ $input{colors} } =
[ i_getcolors($self->{IMG}, 0, i_colorcount($self->{IMG})) ];
}
$self->{DEBUG} && print "loading a tga file\n";
}
- if ( $input{'type'} eq 'rgb' ) {
- $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
- if ( !defined($self->{IMG}) ) {
- $self->{ERRSTR}=$self->_error_as_msg();
- return undef;
- }
- $self->{DEBUG} && print "loading a tga file\n";
- }
-
-
if ( $input{'type'} eq 'raw' ) {
my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
return 1;
}
+sub read_types {
+ my %types =
+ (
+ map { $_ => 1 }
+ keys %readers,
+ grep($file_formats{$_}, keys %formats),
+ qw(ico sgi), # formats not handled directly, but supplied with Imager
+ );
+
+ return keys %types;
+}
+
+sub write_types {
+ my %types =
+ (
+ map { $_ => 1 }
+ keys %writers,
+ grep($file_formats{$_}, keys %formats),
+ qw(ico sgi), # formats not handled directly, but supplied with Imager
+ );
+
+ return keys %types;
+}
+
# probes for an Imager::File::whatever module
sub _reader_autoload {
my $type = shift;
}
else {
if (!$formats{$input{'type'}}) {
- $self->{ERRSTR}='format not supported';
+ my $write_types = join ', ', sort Imager->write_types();
+ $self->_set_error("format '$input{'type'}' not supported - formats $write_types available for writing");
return undef;
}
}
else {
if (!$formats{$type}) {
- $class->_set_error("format $type not supported");
+ my $write_types = join ', ', sort Imager->write_types();
+ $class->_set_error("format '$type' not supported - formats $write_types available for writing");
return undef;
}
if ($img->read(%opts, io => $IO, type => $type)) {
return ( $img );
}
+ Imager->_set_error($img->errstr);
}
- $ERRSTR = "Cannot read multiple images from $type files";
return;
}
if (ref $x && ref $y) {
unless (@$x == @$y) {
$self->{ERRSTR} = 'length of x and y mismatch';
- return undef;
+ return;
}
+ my $set = 0;
if ($color->isa('Imager::Color')) {
for my $i (0..$#{$opts{'x'}}) {
- i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color);
+ i_ppix($self->{IMG}, $x->[$i], $y->[$i], $color)
+ or ++$set;
}
}
else {
for my $i (0..$#{$opts{'x'}}) {
- i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color);
+ i_ppixf($self->{IMG}, $x->[$i], $y->[$i], $color)
+ or ++$set;
}
}
+ $set or return;
+ return $set;
}
else {
if ($color->isa('Imager::Color')) {
- i_ppix($self->{IMG}, $x, $y, $color);
+ i_ppix($self->{IMG}, $x, $y, $color)
+ and return;
}
else {
- i_ppixf($self->{IMG}, $x, $y, $color);
+ i_ppixf($self->{IMG}, $x, $y, $color)
+ and return;
}
}
sub getsamples {
my $self = shift;
- my %opts = ( type => '8bit', x=>0, @_);
+ my %opts = ( type => '8bit', x=>0, offset => 0, @_);
defined $opts{width} or $opts{width} = $self->getwidth - $opts{x};
$opts{channels} = [ 0 .. $self->getchannels()-1 ];
}
- if ($opts{type} eq '8bit') {
- return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
- $opts{y}, @{$opts{channels}});
- }
- elsif ($opts{type} eq 'float') {
- return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
- $opts{y}, @{$opts{channels}});
+ if ($opts{target}) {
+ my $target = $opts{target};
+ my $offset = $opts{offset};
+ if ($opts{type} eq '8bit') {
+ my @samples = i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, @{$opts{channels}})
+ or return;
+ @{$target}{$offset .. $offset + @samples - 1} = @samples;
+ return scalar(@samples);
+ }
+ elsif ($opts{type} eq 'float') {
+ my @samples = i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, @{$opts{channels}});
+ @{$target}{$offset .. $offset + @samples - 1} = @samples;
+ return scalar(@samples);
+ }
+ elsif ($opts{type} =~ /^(\d+)bit$/) {
+ my $bits = $1;
+
+ my @data;
+ my $count = i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, $bits, $target,
+ $offset, @{$opts{channels}});
+ unless (defined $count) {
+ $self->_set_error(Imager->_error_as_msg);
+ return;
+ }
+
+ return $count;
+ }
+ else {
+ $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+ return;
+ }
}
else {
- $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+ if ($opts{type} eq '8bit') {
+ return i_gsamp($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, @{$opts{channels}});
+ }
+ elsif ($opts{type} eq 'float') {
+ return i_gsampf($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, @{$opts{channels}});
+ }
+ elsif ($opts{type} =~ /^(\d+)bit$/) {
+ my $bits = $1;
+
+ my @data;
+ i_gsamp_bits($self->{IMG}, $opts{x}, $opts{x}+$opts{width},
+ $opts{y}, $bits, \@data, 0, @{$opts{channels}})
+ or return;
+ return @data;
+ }
+ else {
+ $self->_set_error("invalid type parameter - must be '8bit' or 'float'");
+ return;
+ }
+ }
+}
+
+sub setsamples {
+ my $self = shift;
+ my %opts = ( x => 0, offset => 0, @_ );
+
+ unless ($self->{IMG}) {
+ $self->_set_error('setsamples: empty input image');
return;
}
+
+ unless(defined $opts{data} && ref $opts{data}) {
+ $self->_set_error('setsamples: data parameter missing or invalid');
+ return;
+ }
+
+ unless ($opts{channels}) {
+ $opts{channels} = [ 0 .. $self->getchannels()-1 ];
+ }
+
+ unless ($opts{type} && $opts{type} =~ /^(\d+)bit$/) {
+ $self->_set_error('setsamples: type parameter missing or invalid');
+ return;
+ }
+ my $bits = $1;
+
+ unless (defined $opts{width}) {
+ $opts{width} = $self->getwidth() - $opts{x};
+ }
+
+ my $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits,
+ $opts{channels}, $opts{data}, $opts{offset},
+ $opts{width});
+ unless (defined $count) {
+ $self->_set_error(Imager->_error_as_msg);
+ return;
+ }
+
+ return $count;
}
# make an identity matrix of the given size
$matrix = $opts{matrix};
}
- my $new = Imager->new();
- $new->{IMG} = i_img_new();
- unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
+ my $new = Imager->new;
+ $new->{IMG} = i_convert($self->{IMG}, $matrix);
+ unless ($new->{IMG}) {
# most likely a bad matrix
$self->{ERRSTR} = _error_as_msg();
return undef;
return ($rc==-1? undef : $rc);
}
+# Returns a reference to a hash. The keys are colour named (packed) and the
+# values are the number of pixels in this colour.
+sub getcolorusagehash {
+ my $self = shift;
+
+ my %opts = ( maxcolors => 2**30, @_ );
+ my $max_colors = $opts{maxcolors};
+ unless (defined $max_colors && $max_colors > 0) {
+ $self->_set_error('maxcolors must be a positive integer');
+ return;
+ }
+
+ unless (defined $self->{IMG}) {
+ $self->_set_error('empty input image');
+ return;
+ }
+
+ my $channels= $self->getchannels;
+ # We don't want to look at the alpha channel, because some gifs using it
+ # doesn't define it for every colour (but only for some)
+ $channels -= 1 if $channels == 2 or $channels == 4;
+ my %color_use;
+ my $height = $self->getheight;
+ for my $y (0 .. $height - 1) {
+ my $colors = $self->getsamples('y' => $y, channels => [ 0 .. $channels - 1 ]);
+ while (length $colors) {
+ $color_use{ substr($colors, 0, $channels, '') }++;
+ }
+ keys %color_use > $max_colors
+ and return;
+ }
+ return \%color_use;
+}
+
+# This will return a ordered array of the colour usage. Kind of the sorted
+# version of the values of the hash returned by getcolorusagehash.
+# You might want to add safety checks and change the names, etc...
+sub getcolorusage {
+ my $self = shift;
+
+ my %opts = ( maxcolors => 2**30, @_ );
+ my $max_colors = $opts{maxcolors};
+ unless (defined $max_colors && $max_colors > 0) {
+ $self->_set_error('maxcolors must be a positive integer');
+ return;
+ }
+
+ unless (defined $self->{IMG}) {
+ $self->_set_error('empty input image');
+ return undef;
+ }
+
+ return i_get_anonymous_color_histo($self->{IMG}, $max_colors);
+}
+
# draw string to an image
sub string {
sub newcolor { Imager::Color->new(@_); }
sub newfont { Imager::Font->new(@_); }
+sub NCF { Imager::Color::Float->new(@_) }
*NC=*newcolour=*newcolor;
*NF=*newfont;
return 'png' if ($ext eq "png");
return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
return 'tga' if ($ext eq "tga");
- return 'rgb' if ($ext eq "rgb");
+ return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba");
return 'gif' if ($ext eq "gif");
return 'raw' if ($ext eq "raw");
return lc $ext; # best guess
getcolors() - L<Imager::ImageTypes/getcolors> - get colors from the image
palette, if it has one
+getcolorusage() - L<Imager::ImageTypes/getcolorusage>
+
+getcolorusagehash() - L<Imager::ImageTypes/getcolorusagehash>
+
get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
getheight() - L<Imager::ImageTypes/getwidth>
init() - L<Imager::ImageTypes/init>
+is_bilevel() - L<Imager::ImageTypes/is_bilevel>
+
line() - L<Imager::Draw/line>
load_plugin() - L<Imager::Filters/load_plugin>
NC() - L<Imager::Handy/NC>
+NCF() - L<Imager::Handy/NCF>
+
new() - L<Imager::ImageTypes/new>
newcolor() - L<Imager::Handy/newcolor>
read_multi() - L<Imager::Files> - read multiple images from an image
file
+read_types() - L<Imager::Files/read_types> - list image types Imager
+can read.
+
register_filter() - L<Imager::Filters/register_filter>
register_reader() - L<Imager::Filters/register_reader>
setpixel() - L<Imager::Draw/setpixel>
+setsamples() - L<Imager::Draw/setsamples>
+
setscanline() - L<Imager::Draw/setscanline>
settag() - L<Imager::ImageTypes/settag>
to_paletted() - L<Imager::ImageTypes/to_paletted>
+to_rgb16() - L<Imager::ImageTypes/to_rgb16>
+
to_rgb8() - L<Imager::ImageTypes/to_rgb8>
transform() - L<Imager::Engines/"transform">
write_multi() - L<Imager::Files> - write multiple image to an image
file.
+write_types() - L<Imager::Files/read_types> - list image types Imager
+can write.
+
=head1 CONCEPT INDEX
-animated GIF - L<Imager::File/"Writing an animated GIF">
+animated GIF - L<Imager::Files/"Writing an animated GIF">
aspect ratio - L<Imager::ImageTypes/i_xres>,
L<Imager::ImageTypes/i_yres>, L<Imager::ImageTypes/i_aspect_only>
cropping - L<Imager::Transformations/crop>
+CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
+
C<diff> images - L<Imager::Filter/"Image Difference">
dpi - L<Imager::ImageTypes/i_xres>,
L<Imager::Filters/fountain>, L<Imager::Fountain>,
L<Imager::Filters/gradgen>
+grayscale, convert image to - L<Imager::Transformations/convert>
+
guassian blur - L<Imager::Filter/guassian>
hatch fills - L<Imager::Fill/"Hatched fills">
+ICO files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
+
invert image - L<Imager::Filter/hardinvert>
JPEG - L<Imager::Files/"JPEG">
resizing an image - L<Imager::Transformations/scale>,
L<Imager::Transformations/crop>
+RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
+
saving an image - L<Imager::Files>
scaling - L<Imager::Transformations/scale>
+SGI files - L<Imager::Files/"SGI (RGB, BW)">
+
sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
size, image - L<Imager::ImageTypes/getwidth>,
=back
+or by sending an email to:
+
+=over
+
+bug-Imager@rt.cpan.org
+
+=back
+
Please remember to include the versions of Imager, perl, supporting
libraries, and any relevant code. If you have specific images that
cause the problems, please include those too.
-=head1 BUGS
+If you don't want to publish your email address on a mailing list you
+can use CPAN::Forum:
+
+ http://www.cpanforum.com/dist/Imager
+
+You will need to register to post.
+
+=head1 CONTRIBUTING TO IMAGER
+
+=head2 Feedback
+
+I like feedback.
-Bugs are listed individually for relevant pod pages.
+If you like or dislike Imager, you can add a public review of Imager
+at CPAN Ratings:
+
+ http://cpanratings.perl.org/dist/Imager
+
+This requires a Bitcard Account (http://www.bitcard.org).
+
+You can also send email to the maintainer below.
+
+If you send me a bug report via email, it will be copied to RT.
+
+=head2 Patches
+
+I accept patches, preferably against the main branch in subversion.
+You should include an explanation of the reason for why the patch is
+needed or useful.
+
+Your patch should include regression tests where possible, otherwise
+it will be delayed until I get a chance to write them.
=head1 AUTHOR
-Arnar M. Hrafnkelsson and Tony Cook (tony@imager.perl.org) among
-others. See the README for a complete list.
+Tony Cook <tony@imager.perl.org> is the current maintainer for Imager.
+
+Arnar M. Hrafnkelsson is the original author of Imager.
+
+Many others have contributed to Imager, please see the README for a
+complete list.
=head1 SEE ALSO