Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

515
database/perl/vendor/lib/Imager/API.pod vendored Normal file
View File

@@ -0,0 +1,515 @@
=head1 NAME
Imager::API - Imager's C API - introduction.
=head1 SYNOPSIS
#include "imext.h"
#include "imperl.h"
DEFINE_IMAGER_CALLBACKS;
MODULE = Your::Module PACKAGE = Your::Module
...
BOOT:
/* any release with the API */
PERL_INITIALIZE_IMAGER_CALLBACKS;
/* preferred from Imager 0.91 */
PERL_INITIALIZE_IMAGER_CALLBACKS_NAME("My::Module");
=head1 DESCRIPTION
=for stopwords XS
The API allows you to access Imager functions at the C level from XS
and from C<Inline::C>.
The intent is to allow users to:
=over
=item *
write C code that does Imager operations the user might do from Perl,
but faster, for example, the L<Imager::CountColor> example.
=item *
write C code that implements an application specific version of some
core Imager object, for example, Imager::SDL.
=item *
write C code that hooks into Imager's existing methods, such as filter
or file format handlers.
=back
See L<Imager::Inline> for information on using Imager's Inline::C
support.
=head1 Beware
=over
=item *
don't return an object you received as a parameter - this will cause
the object to be freed twice.
=back
=head1 Types
The API makes the following types visible:
=over
=item *
L</i_img> - used to represent an image
=item *
L</i_color> - used to represent a color with up
to 8 bits per sample.
=item *
L</i_fcolor> - used to represent
a color with a double per sample.
=item *
L</i_fill_t> - fill objects>> - an abstract fill
=item *
L</im_context_t> - Imager's per-thread state.
=back
At this point there is no consolidated font object type, and hence the
font functions are not visible through Imager's API.
=head2 i_img
This contains the dimensions of the image (C<xsize>, C<ysize>,
C<channels>), image metadata (C<ch_mask>, C<bits>, C<type>,
C<virtual>), potentially image data (C<idata>) and a function table,
with pointers to functions to perform various low level image
operations.
The only time you should directly write to any value in this type is
if you're implementing your own image type.
The typemap includes type names Imager and Imager::ImgRaw as typedefs
for C<i_img *>.
For incoming parameters the typemap will accept either Imager or
Imager::ImgRaw objects.
For return values the typemap will produce a full Imager object for an
Imager return type and a raw image object for an Imager::ImgRaw return
type.
=head2 i_color
Represents an 8-bit per sample color. This is a union containing
several different structs for access to components of a color:
=over
=item *
C<gray> - single member C<gray_color>.
=item *
C<rgb> - C<r>, C<g>, C<b> members.
=item *
C<rgba> - C<r>, C<g>, C<b>, C<a> members.
=item *
C<channels> - array of channels.
=back
Use C<Imager::Color> for parameter and return value types.
=head2 i_fcolor
Similar to C<i_color> except that each component is a double instead of
an unsigned char.
Use Imager::Color::Float for parameter and return value types.
=head2 i_fill_t
Abstract type containing pointers called to perform low level fill
operations.
Unless you're defining your own fill objects you should treat this as
an opaque type.
Use Imager::FillHandle for parameter and return value types. At the
Perl level this is stored in the C<fill> member of the Perl level
Imager::Fill object.
=head2 i_io_glue_t
C<i_io_glue_t> is Imager's I/O abstraction.
Historically named C<io_glue>, and this name is available for backward
compatibility.
=head2 im_context_t
This new type is an opaque type that stores Imager's per-thread state,
including the error message stack, the current log file state and
image size file limits.
While Imager's internal typemap provides a C<T_PTROBJ> mapping and a
DESTROY method for this type you B<must> never return objects of this
type back to perl.
See L</Context objects> for more information.
=head2 i_polygon_t
Represents a single polygon supplied to i_poly_poly_aa() and
i_poly_poly_aa_cfill().
This is a structure with 3 members:
=over
=item *
C<x>, C<y> - pointers to the first elements of arrays of doubles that define
the vertices of the polygon.
=item *
C<count> - the number of values in each of the C<x> and C<y> arrays.
=back
=head2 i_poly_fill_mode_t
An enumerated type of the possible fill modes for polygons:
=over
=item *
C<i_pfm_evenodd> - if areas overlap an odd number of times, they
are filled, and are otherwise unfilled.
=item *
C<i_pfm_nonzero> - areas that have an unbalanced clockwise and
anti-clockwise boundary are filled. This is the same as
C<WindingRule> for X and C<WINDING> for Win32 GDI.
=back
=head1 Create an XS module using the Imager API
=head2 Foo.pm
Load Imager:
use Imager 0.48;
and bootstrap your XS code - see L<XSLoader> or L<DynaLoader>.
=head2 C<Foo.xs>
You'll need the following in your XS source:
=over
=item *
include the Imager external API header, and the perl interface header:
#include "imext.h"
#include "imperl.h"
=item *
create the variables used to hold the callback table:
DEFINE_IMAGER_CALLBACKS;
=item *
initialize the callback table in your C<BOOT> code:
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
From Imager 0.91 you can supply your module name to improve error
reporting:
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS_NAME("My::Module");
=back
=head2 foo.c
In any other source files where you want to access the Imager API,
you'll need to:
=over
=item *
include the Imager external API header:
#include "imext.h"
=back
=head2 C<Makefile.PL>
If you're creating an XS module that depends on Imager's API your
C<Makefile.PL> will need to do the following:
=over
=item *
C<use Imager::ExtUtils;>
=item *
include Imager's include directory in INC:
INC => Imager::ExtUtils->includes
=item *
use Imager's typemap:
TYPEMAPS => [ Imager::ExtUtils->typemap ]
=item *
include Imager 0.48 as a PREREQ_PM:
PREREQ_PM =>
{
Imager => 0.48,
},
=item *
Since you use Imager::ExtUtils in C<Makefile.PL> (or C<Build.PL>) you
should include Imager in your configure_requires:
META_MERGE =>
{
configure_requires => { Imager => "0.48" }
},
=back
=head1 Context objects
Starting with Imager 0.93, Imager keeps some state per-thread rather
than storing it in global (or static) variables. The intent is to
improve support for multi-threaded perl programs.
For the typical XS or Inline::C module using Imager's API this won't
matter - the changes are hidden behind macros and rebuilding your
module should require no source code changes.
Some operations will be slightly slower, these include:
=over
=item *
creating an image
=item *
reporting errors
=item *
creating I/O objects
=item *
setting/getting/testing image file limits
=item *
logging
=back
You can avoid this fairly minor overhead by adding a C<#define>:
#define IMAGER_NO_CONTEXT
before including any Imager header files, but you will need to manage
context objects yourself.
Some functions and macros that are available without
C<IMAGER_NO_CONTEXT> are not available with it defined, these are:
=over
=item *
mm_log() - to avoid using a different context object for the line
header and the line text you need to use im_log() instead, with a
context object visible in scope.
=back
=head2 C<aIMCTX>
With C<IMAGER_NO_CONTEXT> defined, C<aIMCTX> refers to the locally
defined context object, either via one the of the C<dIMCTX> macros or
as a parameter with the C<pIMCTX> macro.
Without C<IMAGER_NO_CONTEXT>, C<aIMCTX> is a call to
C<im_get_context()> which retrieves the context object for the current
thread.
There is no C<aIMCTX_> macro, any Imager function that can accept a
context parameter always accepts it.
=head2 C<pIMCTX>
This macro declares a variable of type L</im_context_t> that's
accessible via the C<aIMCTX> macro. This is intended for use as a
parameter declaration for functions:
void f(pIMCTX) {
... use aIMCTX here
}
void g(...) {
...
f(aIMCTX);
}
=head2 C<dIMCTX>
Defines a local context variable and initializes it via
L<im_get_context()|Imager::APIRef/im_get_context()>.
=head2 C<dIMCTXim>
Defines a local context variable and initializes it from the context
stored in an L<image object|/i_img>, eg:
void f(i_img *im) {
dIMCTXim(im);
...
}
=head2 C<dIMCTXio>
Defines a local context variable and initializes it from the context
stored in an L<< IE<47>O object|/i_io_glue_t >> object.
void f(i_io_glue_t *io) {
dIMCTXio(io);
...
}
=head2 C<dIMCTXctx>
Defines a local context variable accessible via C<aIMCTX> in terms of
an expression you supply:
void f(my_object *p) {
dIMCTXctx(p->context);
...
}
This can be used to define your own local context macro:
#define dIMCTXmine(mine) ((mine)->context)
void f(my_object *p) {
dIMCTXmine(p);
...
}
=head1 Mutex Functions
Since some libraries are not thread safe, Imager's API includes some
simple mutex functions.
To create a mutex:
i_mutex_t m = i_mutex_new();
To control or lock the mutex:
i_mutex_lock(m);
To release or unlock the mutex:
i_mutex_unlock(m);
To free any resources used by the mutex:
i_mutex_destroy(m);
I most cases where you'd use these functions, your code would create
the mutex in your BOOT section, then lock and unlock the mutex as
needed to control access to the library.
=head1 Context slots
=for stopwords
TLS APIs
To avoid abstracting the platform TLS and thread clean up handling,
Imager provides simple APIs for storing per-context information.
To allocate a slot:
im_slot_t slot = im_context_slot_new(callback)
where callback is a (possibly NULL) function pointer called when the
context object is destroyed.
By default, the stored value for a slot is NULL, whether for a new
context or for a cloned context.
To store a value:
im_context_slot_set(aIMCTX, slot, somevalue);
where C<somevalue> can be represented as a C<void *>.
To retrieve the value:
value = im_context_slot_get(aIMCTX, slot);
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::ExtUtils, Imager::APIRef, Imager::Inline
=cut

2640
database/perl/vendor/lib/Imager/APIRef.pod vendored Normal file

File diff suppressed because it is too large Load Diff

709
database/perl/vendor/lib/Imager/Color.pm vendored Normal file
View File

@@ -0,0 +1,709 @@
package Imager::Color;
use 5.006;
use Imager;
use strict;
our $VERSION = "1.013";
# It's just a front end to the XS creation functions.
# used in converting hsv to rgb
my @hsv_map =
(
'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn'
);
sub _hsv_to_rgb {
my ($hue, $sat, $val) = @_;
# HSV conversions from pages 401-403 "Procedural Elements for Computer
# Graphics", 1985, ISBN 0-07-053534-5.
my @result;
if ($sat <= 0) {
return ( 255 * $val, 255 * $val, 255 * $val );
}
else {
$val >= 0 or $val = 0;
$val <= 1 or $val = 1;
$sat <= 1 or $sat = 1;
$hue >= 360 and $hue %= 360;
$hue < 0 and $hue += 360;
$hue /= 60.0;
my $i = int($hue);
my $f = $hue - $i;
$val *= 255;
my $m = $val * (1.0 - $sat);
my $n = $val * (1.0 - $sat * $f);
my $k = $val * (1.0 - $sat * (1 - $f));
my $v = $val;
my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, );
return @fields{split //, $hsv_map[$i]};
}
}
# cache of loaded gimp files
# each key is a filename, under each key is a hashref with the following
# keys:
# mod_time => last mod_time of file
# colors => hashref name to arrayref of colors
my %gimp_cache;
# palette search locations
# this is pretty rude
# $HOME is replaced at runtime
my @gimp_search =
(
'$HOME/.gimp-1.2/palettes/Named_Colors',
'$HOME/.gimp-1.1/palettes/Named_Colors',
'$HOME/.gimp/palettes/Named_Colors',
'/usr/share/gimp/1.2/palettes/Named_Colors',
'/usr/share/gimp/1.1/palettes/Named_Colors',
'/usr/share/gimp/palettes/Named_Colors',
);
my $default_gimp_palette;
sub _load_gimp_palette {
my ($filename) = @_;
if (open PAL, "< $filename") {
my $hdr = <PAL>;
chomp $hdr;
unless ($hdr =~ /GIMP Palette/) {
close PAL;
$Imager::ERRSTR = "$filename is not a GIMP palette file";
return;
}
my $line;
my %pal;
my $mod_time = (stat PAL)[9];
while (defined($line = <PAL>)) {
next if $line =~ /^#/ || $line =~ /^\s*$/;
chomp $line;
my ($r,$g, $b, $name) = split ' ', $line, 4;
if ($name) {
$name =~ s/\s*\([\d\s]+\)\s*$//;
$pal{lc $name} = [ $r, $g, $b ];
}
}
close PAL;
$gimp_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal };
return 1;
}
else {
$Imager::ERRSTR = "Cannot open palette file $filename: $!";
return;
}
}
sub _get_gimp_color {
my %args = @_;
my $filename;
if ($args{palette}) {
$filename = $args{palette};
}
elsif (defined $default_gimp_palette) {
# don't search again and again and again ...
if (!length $default_gimp_palette
|| !-f $default_gimp_palette) {
$Imager::ERRSTR = "No GIMP palette found";
$default_gimp_palette = "";
return;
}
$filename = $default_gimp_palette;
}
else {
# try to make one up - this is intended to die if tainting is
# enabled and $ENV{HOME} is tainted. To avoid that untaint $ENV{HOME}
# or set the palette parameter
for my $attempt (@gimp_search) {
my $work = $attempt; # don't modify the source array
$work =~ /\$HOME/ && !defined $ENV{HOME}
and next;
$work =~ s/\$HOME/$ENV{HOME}/;
if (-e $work) {
$filename = $work;
last;
}
}
if (!$filename) {
$Imager::ERRSTR = "No GIMP palette found";
$default_gimp_palette = "";
return ();
}
$default_gimp_palette = $filename;
}
if ((!$gimp_cache{$filename}
|| (stat $filename)[9] != $gimp_cache{$filename})
&& !_load_gimp_palette($filename)) {
return ();
}
if (!$gimp_cache{$filename}{colors}{lc $args{name}}) {
$Imager::ERRSTR = "Color '$args{name}' isn't in $filename";
return ();
}
return @{$gimp_cache{$filename}{colors}{lc $args{name}}};
}
my @x_search =
(
'/usr/share/X11/rgb.txt', # newer Xorg X11 dists use this
'/usr/lib/X11/rgb.txt', # seems fairly standard
'/usr/local/lib/X11/rgb.txt', # seems possible
'/usr/X11R6/lib/X11/rgb.txt', # probably the same as the first
'/usr/openwin/lib/rgb.txt',
'/usr/openwin/lib/X11/rgb.txt',
);
my $default_x_rgb;
# called by the test code to check if we can test this stuff
sub _test_x_palettes {
@x_search;
}
# x rgb.txt cache
# same structure as %gimp_cache
my %x_cache;
sub _load_x_rgb {
my ($filename) = @_;
local *RGB;
if (open RGB, "< $filename") {
my $line;
my %pal;
my $mod_time = (stat RGB)[9];
while (defined($line = <RGB>)) {
# the version of rgb.txt supplied with GNU Emacs uses # for comments
next if $line =~ /^[!#]/ || $line =~ /^\s*$/;
chomp $line;
my ($r,$g, $b, $name) = split ' ', $line, 4;
if ($name) {
$pal{lc $name} = [ $r, $g, $b ];
}
}
close RGB;
$x_cache{$filename} = { mod_time=>$mod_time, colors=>\%pal };
return 1;
}
else {
$Imager::ERRSTR = "Cannot open palette file $filename: $!";
return;
}
}
sub _get_x_color {
my %args = @_;
my $filename;
if ($args{palette}) {
$filename = $args{palette};
}
elsif (defined $default_x_rgb) {
unless (length $default_x_rgb) {
$Imager::ERRSTR = "No X rgb.txt palette found";
return ();
}
$filename = $default_x_rgb;
}
else {
for my $attempt (@x_search) {
if (-e $attempt) {
$filename = $attempt;
last;
}
}
if (!$filename) {
$Imager::ERRSTR = "No X rgb.txt palette found";
$default_x_rgb = "";
return ();
}
}
if ((!$x_cache{$filename}
|| (stat $filename)[9] != $x_cache{$filename}{mod_time})
&& !_load_x_rgb($filename)) {
return ();
}
$default_x_rgb = $filename;
if (!$x_cache{$filename}{colors}{lc $args{name}}) {
$Imager::ERRSTR = "Color '$args{name}' isn't in $filename";
return ();
}
return @{$x_cache{$filename}{colors}{lc $args{name}}};
}
# Parse color spec into an a set of 4 colors
sub _pspec {
return (@_,255) if @_ == 3 && !grep /[^\d.+eE-]/, @_;
return (@_ ) if @_ == 4 && !grep /[^\d.+eE-]/, @_;
if ($_[0] =~
/^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
return (hex($1),hex($2),hex($3),hex($4));
}
if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
return (hex($1),hex($2),hex($3),255);
}
if ($_[0] =~ /^\#([\da-f])([\da-f])([\da-f])$/i) {
return (hex($1) * 17, hex($2) * 17, hex($3) * 17, 255);
}
my %args;
if (@_ == 1) {
# a named color
%args = ( name => @_ );
}
else {
%args = @_;
}
my @result;
if (exists $args{gray}) {
@result = $args{gray};
}
elsif (exists $args{grey}) {
@result = $args{grey};
}
elsif ((exists $args{red} || exists $args{r})
&& (exists $args{green} || exists $args{g})
&& (exists $args{blue} || exists $args{b})) {
@result = ( exists $args{red} ? $args{red} : $args{r},
exists $args{green} ? $args{green} : $args{g},
exists $args{blue} ? $args{blue} : $args{b} );
}
elsif ((exists $args{hue} || exists $args{h})
&& (exists $args{saturation} || exists $args{'s'})
&& (exists $args{value} || exists $args{v})) {
my $hue = exists $args{hue} ? $args{hue} : $args{h};
my $sat = exists $args{saturation} ? $args{saturation} : $args{'s'};
my $val = exists $args{value} ? $args{value} : $args{v};
@result = _hsv_to_rgb($hue, $sat, $val);
}
elsif (exists $args{web}) {
if ($args{web} =~ /^#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])$/i) {
@result = (hex($1),hex($2),hex($3));
}
elsif ($args{web} =~ /^#?([\da-f])([\da-f])([\da-f])$/i) {
@result = (hex($1) * 17, hex($2) * 17, hex($3) * 17);
}
}
elsif ($args{name}) {
unless (@result = _get_gimp_color(%args)) {
unless (@result = _get_x_color(%args)) {
require Imager::Color::Table;
unless (@result = Imager::Color::Table->get($args{name})) {
$Imager::ERRSTR = "No color named $args{name} found";
return ();
}
}
}
}
elsif ($args{gimp}) {
@result = _get_gimp_color(name=>$args{gimp}, %args);
}
elsif ($args{xname}) {
@result = _get_x_color(name=>$args{xname}, %args);
}
elsif ($args{builtin}) {
require Imager::Color::Table;
@result = Imager::Color::Table->get($args{builtin});
}
elsif ($args{rgb}) {
@result = @{$args{rgb}};
}
elsif ($args{rgba}) {
@result = @{$args{rgba}};
return @result if @result == 4;
}
elsif ($args{hsv}) {
@result = _hsv_to_rgb(@{$args{hsv}});
}
elsif ($args{channels}) {
my @ch = @{$args{channels}};
return ( @ch, (0) x (4 - @ch) );
}
elsif (exists $args{channel0} || $args{c0}) {
my $i = 0;
while (exists $args{"channel$i"} || exists $args{"c$i"}) {
push(@result,
exists $args{"channel$i"} ? $args{"channel$i"} : $args{"c$i"});
++$i;
}
}
else {
$Imager::ERRSTR = "No color specification found";
return ();
}
if (@result) {
if (exists $args{alpha} || exists $args{a}) {
push(@result, exists $args{alpha} ? $args{alpha} : $args{a});
}
while (@result < 4) {
push(@result, 255);
}
return @result;
}
return ();
}
sub new {
shift; # get rid of class name.
my @arg = _pspec(@_);
return @arg ? new_internal($arg[0],$arg[1],$arg[2],$arg[3]) : ();
}
sub set {
my $self = shift;
my @arg = _pspec(@_);
return @arg ? set_internal($self, $arg[0],$arg[1],$arg[2],$arg[3]) : ();
}
sub equals {
my ($self, %opts) = @_;
my $other = $opts{other}
or return Imager->_set_error("'other' parameter required");
my $ignore_alpha = $opts{ignore_alpha} || 0;
my @left = $self->rgba;
my @right = $other->rgba;
my $last_chan = $ignore_alpha ? 2 : 3;
for my $ch (0 .. $last_chan) {
$left[$ch] == $right[$ch]
or return;
}
return 1;
}
sub CLONE_SKIP { 1 }
# Lifted from Graphics::Color::RGB
# Thank you very much
sub hsv {
my( $self ) = @_;
my( $red, $green, $blue, $alpha ) = $self->rgba;
my $max = $red;
my $maxc = 'r';
my $min = $red;
if($green > $max) {
$max = $green;
$maxc = 'g';
}
if($blue > $max) {
$max = $blue;
$maxc = 'b';
}
if($green < $min) {
$min = $green;
}
if($blue < $min) {
$min = $blue;
}
my ($h, $s, $v);
if($max == $min) {
$h = 0;
}
elsif($maxc eq 'r') {
$h = 60 * (($green - $blue) / ($max - $min)) % 360;
}
elsif($maxc eq 'g') {
$h = (60 * (($blue - $red) / ($max - $min)) + 120);
}
elsif($maxc eq 'b') {
$h = (60 * (($red - $green) / ($max - $min)) + 240);
}
$v = $max/255;
if($max == 0) {
$s = 0;
}
else {
$s = 1 - ($min / $max);
}
return int($h), $s, $v, $alpha;
}
1;
__END__
=head1 NAME
Imager::Color - Color handling for Imager.
=head1 SYNOPSIS
use Imager;
$color = Imager::Color->new($red, $green, $blue);
$color = Imager::Color->new($red, $green, $blue, $alpha);
$color = Imager::Color->new("#C0C0FF"); # html color specification
$color->set($red, $green, $blue);
$color->set($red, $green, $blue, $alpha);
$color->set("#C0C0FF"); # html color specification
($red, $green, $blue, $alpha) = $color->rgba();
@hsv = $color->hsv();
$color->info();
if ($color->equals(other=>$other_color)) {
...
}
=head1 DESCRIPTION
This module handles creating color objects used by Imager. The idea
is that in the future this module will be able to handle color space
calculations as well.
An Imager color consists of up to four components, each in the range 0
to 255. Unfortunately the meaning of the components can change
depending on the type of image you're dealing with:
=over
=item *
for 3 or 4 channel images the color components are red, green, blue,
alpha.
=item *
for 1 or 2 channel images the color components are gray, alpha, with
the other two components ignored.
=back
An alpha value of zero is fully transparent, an alpha value of 255 is
fully opaque.
=head1 METHODS
=over 4
=item new
This creates a color object to pass to functions that need a color argument.
=item set
This changes an already defined color. Note that this does not affect any places
where the color has been used previously.
=item rgba()
This returns the red, green, blue and alpha channels of the color the
object contains.
=item info
Calling info merely dumps the relevant color to the log.
=item equals(other=>$other_color)
=item equals(other=>$other_color, ignore_alpha=>1)
Compares $self and color $other_color returning true if the color
components are the same.
Compares all four channels unless C<ignore_alpha> is set. If
C<ignore_alpha> is set only the first three channels are compared.
=back
You can specify colors in several different ways, you can just supply
simple values:
=over
=item *
simple numeric parameters - if you supply 3 or 4 numeric arguments, you get a color made up of those RGB (and possibly A) components.
=item *
a six hex digit web color, either C<RRGGBB> or C<#RRGGBB>
=item *
an eight hex digit web color, either C<RRGGBBAA> or C<#RRGGBBAA>.
=item *
a 3 hex digit web color, C<#RGB> - a value of F becomes 255.
=item *
a color name, from whichever of the gimp C<Named_Colors> file or X
C<rgb.txt> is found first. The same as using the C<name> keyword.
=back
You can supply named parameters:
=over
=item *
'red', 'green' and 'blue', optionally shortened to 'r', 'g' and 'b'.
The color components in the range 0 to 255.
# all of the following are equivalent
my $c1 = Imager::Color->new(red=>100, blue=>255, green=>0);
my $c2 = Imager::Color->new(r=>100, b=>255, g=>0);
my $c3 = Imager::Color->new(r=>100, blue=>255, g=>0);
=item *
C<hue>, C<saturation> and C<value>, optionally shortened to C<h>, C<s> and
C<v>, to specify a HSV color. 0 <= hue < 360, 0 <= s <= 1 and 0 <= v
<= 1.
# the same as RGB(127,255,127)
my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5);
my $c1 = Imager::Color->new(hue=>120, value=>1, saturation=>0.5);
=item *
C<web>, which can specify a 6 or 3 hex digit web color, in any of the
forms C<#RRGGBB>, C<#RGB>, C<RRGGBB> or C<RGB>.
my $c1 = Imager::Color->new(web=>'#FFC0C0'); # pale red
=item *
C<gray> or C<grey> which specifies a single channel, from 0 to 255.
# exactly the same
my $c1 = Imager::Color->new(gray=>128);
my $c1 = Imager::Color->new(grey=>128);
=item *
C<rgb> which takes a 3 member arrayref, containing each of the red,
green and blue values.
# the same
my $c1 = Imager::Color->new(rgb=>[255, 100, 0]);
my $c1 = Imager::Color->new(r=>255, g=>100, b=>0);
=item *
C<hsv> which takes a 3 member arrayref, containing each of hue,
saturation and value.
# the same
my $c1 = Imager::Color->new(hsv=>[120, 0.5, 1]);
my $c1 = Imager::Color->new(hue=>120, v=>1, s=>0.5);
=item *
C<gimp> which specifies a color from a GIMP palette file. You can
specify the file name of the palette file with the 'palette'
parameter, or let Imager::Color look in various places, typically
C<$HOME/gimp-1.x/palettes/Named_Colors> with and without the version
number, and in C</usr/share/gimp/palettes/>. The palette file must
have color names.
my $c1 = Imager::Color->new(gimp=>'snow');
my $c1 = Imager::Color->new(gimp=>'snow', palette=>'testimg/test_gimp_pal);
=item *
C<xname> which specifies a color from an X11 C<rgb.txt> file. You can
specify the file name of the C<rgb.txt> file with the C<palette>
parameter, or let Imager::Color look in various places, typically
C</usr/lib/X11/rgb.txt>.
my $c1 = Imager::Color->new(xname=>'blue') # usually RGB(0, 0, 255)
=item *
C<builtin> which specifies a color from the built-in color table in
Imager::Color::Table. The colors in this module are the same as the
default X11 C<rgb.txt> file.
my $c1 = Imager::Color->new(builtin=>'black') # always RGB(0, 0, 0)
=item *
C<name> which specifies a name from either a GIMP palette, an X
C<rgb.txt> file or the built-in color table, whichever is found first.
=item *
'channel0', 'channel1', etc, each of which specifies a single channel. These can be abbreviated to 'c0', 'c1' etc.
=item *
'channels' which takes an arrayref of the channel values.
=back
Optionally you can add an alpha channel to a color with the 'alpha' or
'a' parameter.
These color specifications can be used for both constructing new
colors with the new() method and modifying existing colors with the
set() method.
=head1 METHODS
=over
=item hsv()
my($h, $s, $v, $alpha) = $color->hsv();
Returns the color as a Hue/Saturation/Value/Alpha tuple.
=item red
=item green
=item blue
=item alpha
Returns the respective component as an integer from 0 to 255.
=back
=head1 AUTHOR
Arnar M. Hrafnkelsson, addi@umich.edu
And a great deal of help from others - see the C<README> for a complete
list.
=head1 SEE ALSO
Imager(3), Imager::Color
http://imager.perl.org/
=cut

View File

@@ -0,0 +1,139 @@
package Imager::Color::Float;
use 5.006;
use Imager;
use strict;
our $VERSION = "1.006";
# It's just a front end to the XS creation functions.
# Parse color spec into an a set of 4 colors
sub _pspec {
return (@_,1) if @_ == 3;
return (@_ ) if @_ == 4;
if ($_[0] =~
/^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
return (hex($1)/255,hex($2)/255,hex($3)/255,hex($4)/255);
}
if ($_[0] =~ /^\#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/i) {
return (hex($1)/255,hex($2)/255,hex($3)/255,1);
}
return ();
}
sub new {
shift; # get rid of class name.
my @arg = _pspec(@_);
return @arg ? new_internal($arg[0],$arg[1],$arg[2],$arg[3]) : ();
}
sub set {
my $self = shift;
my @arg = _pspec(@_);
return @arg ? set_internal($self, $arg[0],$arg[1],$arg[2],$arg[3]) : ();
}
sub CLONE_SKIP { 1 }
1;
__END__
=head1 NAME
Imager::Color::Float - Rough floating point sample color handling
=head1 SYNOPSIS
$color = Imager::Color->new($red, $green, $blue);
$color = Imager::Color->new($red, $green, $blue, $alpha);
$color = Imager::Color->new("#C0C0FF"); # html color specification
$color->set($red, $green, $blue);
$color->set($red, $green, $blue, $alpha);
$color->set("#C0C0FF"); # html color specification
($red, $green, $blue, $alpha) = $color->rgba();
@hsv = $color->hsv(); # not implemented but proposed
$color->info();
=head1 DESCRIPTION
This module handles creating color objects used by Imager. The idea
is that in the future this module will be able to handle color space
calculations as well.
A floating point Imager color consists of up to four components, each
in the range 0.0 to 1.0. Unfortunately the meaning of the components
can change depending on the type of image you're dealing with:
=over
=item *
for 3 or 4 channel images the color components are red, green, blue,
alpha.
=item *
for 1 or 2 channel images the color components are gray, alpha, with
the other two components ignored.
=back
An alpha value of zero is fully transparent, an alpha value of 1.0 is
fully opaque.
=head1 METHODS
=over 4
=item new
This creates a color object to pass to functions that need a color argument.
=item set
This changes an already defined color. Note that this does not affect any places
where the color has been used previously.
=item rgba()
This returns the red, green, blue and alpha channels of the color the
object contains.
=item info
Calling info merely dumps the relevant color to the log.
=item red
=item green
=item blue
=item alpha
Returns the respective component as a floating point value typically
from 0 to 1.0.
=back
=head1 AUTHOR
Arnar M. Hrafnkelsson, addi@umich.edu
And a great deal of help from others - see the C<README> for a complete
list.
=head1 SEE ALSO
Imager(3), Imager::Color.
http://imager.perl.org/
=cut

View File

@@ -0,0 +1,852 @@
package Imager::Color::Table;
use strict;
use 5.006;
our $VERSION = "1.004";
my %colors;
{
local $_;
while (<DATA>) {
next if /^#/ or !/\S/;
chomp;
my ($r, $g, $b, $name) = split ' ', $_, 4;
if ($name) {
$colors{lc $name} = [ $r, $g, $b ];
}
}
}
sub get {
my ($class, $name) = @_;
exists $colors{lc $name} or return;
return @{$colors{lc $name}};
}
1;
__DATA__
# This color data was extracted from the freedesktop.org CVS tree, and
# appears to be under the following license:
#
# Copyright (C) 2004 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
# X Window System is a trademark of X Consortium, Inc.
255 250 250 snow
248 248 255 ghost white
248 248 255 GhostWhite
245 245 245 white smoke
245 245 245 WhiteSmoke
220 220 220 gainsboro
255 250 240 floral white
255 250 240 FloralWhite
253 245 230 old lace
253 245 230 OldLace
250 240 230 linen
250 235 215 antique white
250 235 215 AntiqueWhite
255 239 213 papaya whip
255 239 213 PapayaWhip
255 235 205 blanched almond
255 235 205 BlanchedAlmond
255 228 196 bisque
255 218 185 peach puff
255 218 185 PeachPuff
255 222 173 navajo white
255 222 173 NavajoWhite
255 228 181 moccasin
255 248 220 cornsilk
255 255 240 ivory
255 250 205 lemon chiffon
255 250 205 LemonChiffon
255 245 238 seashell
240 255 240 honeydew
245 255 250 mint cream
245 255 250 MintCream
240 255 255 azure
240 248 255 alice blue
240 248 255 AliceBlue
230 230 250 lavender
255 240 245 lavender blush
255 240 245 LavenderBlush
255 228 225 misty rose
255 228 225 MistyRose
255 255 255 white
0 0 0 black
47 79 79 dark slate gray
47 79 79 DarkSlateGray
47 79 79 dark slate grey
47 79 79 DarkSlateGrey
105 105 105 dim gray
105 105 105 DimGray
105 105 105 dim grey
105 105 105 DimGrey
112 128 144 slate gray
112 128 144 SlateGray
112 128 144 slate grey
112 128 144 SlateGrey
119 136 153 light slate gray
119 136 153 LightSlateGray
119 136 153 light slate grey
119 136 153 LightSlateGrey
190 190 190 gray
190 190 190 grey
211 211 211 light grey
211 211 211 LightGrey
211 211 211 light gray
211 211 211 LightGray
25 25 112 midnight blue
25 25 112 MidnightBlue
0 0 128 navy
0 0 128 navy blue
0 0 128 NavyBlue
100 149 237 cornflower blue
100 149 237 CornflowerBlue
72 61 139 dark slate blue
72 61 139 DarkSlateBlue
106 90 205 slate blue
106 90 205 SlateBlue
123 104 238 medium slate blue
123 104 238 MediumSlateBlue
132 112 255 light slate blue
132 112 255 LightSlateBlue
0 0 205 medium blue
0 0 205 MediumBlue
65 105 225 royal blue
65 105 225 RoyalBlue
0 0 255 blue
30 144 255 dodger blue
30 144 255 DodgerBlue
0 191 255 deep sky blue
0 191 255 DeepSkyBlue
135 206 235 sky blue
135 206 235 SkyBlue
135 206 250 light sky blue
135 206 250 LightSkyBlue
70 130 180 steel blue
70 130 180 SteelBlue
176 196 222 light steel blue
176 196 222 LightSteelBlue
173 216 230 light blue
173 216 230 LightBlue
176 224 230 powder blue
176 224 230 PowderBlue
175 238 238 pale turquoise
175 238 238 PaleTurquoise
0 206 209 dark turquoise
0 206 209 DarkTurquoise
72 209 204 medium turquoise
72 209 204 MediumTurquoise
64 224 208 turquoise
0 255 255 cyan
224 255 255 light cyan
224 255 255 LightCyan
95 158 160 cadet blue
95 158 160 CadetBlue
102 205 170 medium aquamarine
102 205 170 MediumAquamarine
127 255 212 aquamarine
0 100 0 dark green
0 100 0 DarkGreen
85 107 47 dark olive green
85 107 47 DarkOliveGreen
143 188 143 dark sea green
143 188 143 DarkSeaGreen
46 139 87 sea green
46 139 87 SeaGreen
60 179 113 medium sea green
60 179 113 MediumSeaGreen
32 178 170 light sea green
32 178 170 LightSeaGreen
152 251 152 pale green
152 251 152 PaleGreen
0 255 127 spring green
0 255 127 SpringGreen
124 252 0 lawn green
124 252 0 LawnGreen
0 255 0 green
127 255 0 chartreuse
0 250 154 medium spring green
0 250 154 MediumSpringGreen
173 255 47 green yellow
173 255 47 GreenYellow
50 205 50 lime green
50 205 50 LimeGreen
154 205 50 yellow green
154 205 50 YellowGreen
34 139 34 forest green
34 139 34 ForestGreen
107 142 35 olive drab
107 142 35 OliveDrab
189 183 107 dark khaki
189 183 107 DarkKhaki
240 230 140 khaki
238 232 170 pale goldenrod
238 232 170 PaleGoldenrod
250 250 210 light goldenrod yellow
250 250 210 LightGoldenrodYellow
255 255 224 light yellow
255 255 224 LightYellow
255 255 0 yellow
255 215 0 gold
238 221 130 light goldenrod
238 221 130 LightGoldenrod
218 165 32 goldenrod
184 134 11 dark goldenrod
184 134 11 DarkGoldenrod
188 143 143 rosy brown
188 143 143 RosyBrown
205 92 92 indian red
205 92 92 IndianRed
139 69 19 saddle brown
139 69 19 SaddleBrown
160 82 45 sienna
205 133 63 peru
222 184 135 burlywood
245 245 220 beige
245 222 179 wheat
244 164 96 sandy brown
244 164 96 SandyBrown
210 180 140 tan
210 105 30 chocolate
178 34 34 firebrick
165 42 42 brown
233 150 122 dark salmon
233 150 122 DarkSalmon
250 128 114 salmon
255 160 122 light salmon
255 160 122 LightSalmon
255 165 0 orange
255 140 0 dark orange
255 140 0 DarkOrange
255 127 80 coral
240 128 128 light coral
240 128 128 LightCoral
255 99 71 tomato
255 69 0 orange red
255 69 0 OrangeRed
255 0 0 red
255 105 180 hot pink
255 105 180 HotPink
255 20 147 deep pink
255 20 147 DeepPink
255 192 203 pink
255 182 193 light pink
255 182 193 LightPink
219 112 147 pale violet red
219 112 147 PaleVioletRed
176 48 96 maroon
199 21 133 medium violet red
199 21 133 MediumVioletRed
208 32 144 violet red
208 32 144 VioletRed
255 0 255 magenta
238 130 238 violet
221 160 221 plum
218 112 214 orchid
186 85 211 medium orchid
186 85 211 MediumOrchid
153 50 204 dark orchid
153 50 204 DarkOrchid
148 0 211 dark violet
148 0 211 DarkViolet
138 43 226 blue violet
138 43 226 BlueViolet
160 32 240 purple
147 112 219 medium purple
147 112 219 MediumPurple
216 191 216 thistle
255 250 250 snow1
238 233 233 snow2
205 201 201 snow3
139 137 137 snow4
255 245 238 seashell1
238 229 222 seashell2
205 197 191 seashell3
139 134 130 seashell4
255 239 219 AntiqueWhite1
238 223 204 AntiqueWhite2
205 192 176 AntiqueWhite3
139 131 120 AntiqueWhite4
255 228 196 bisque1
238 213 183 bisque2
205 183 158 bisque3
139 125 107 bisque4
255 218 185 PeachPuff1
238 203 173 PeachPuff2
205 175 149 PeachPuff3
139 119 101 PeachPuff4
255 222 173 NavajoWhite1
238 207 161 NavajoWhite2
205 179 139 NavajoWhite3
139 121 94 NavajoWhite4
255 250 205 LemonChiffon1
238 233 191 LemonChiffon2
205 201 165 LemonChiffon3
139 137 112 LemonChiffon4
255 248 220 cornsilk1
238 232 205 cornsilk2
205 200 177 cornsilk3
139 136 120 cornsilk4
255 255 240 ivory1
238 238 224 ivory2
205 205 193 ivory3
139 139 131 ivory4
240 255 240 honeydew1
224 238 224 honeydew2
193 205 193 honeydew3
131 139 131 honeydew4
255 240 245 LavenderBlush1
238 224 229 LavenderBlush2
205 193 197 LavenderBlush3
139 131 134 LavenderBlush4
255 228 225 MistyRose1
238 213 210 MistyRose2
205 183 181 MistyRose3
139 125 123 MistyRose4
240 255 255 azure1
224 238 238 azure2
193 205 205 azure3
131 139 139 azure4
131 111 255 SlateBlue1
122 103 238 SlateBlue2
105 89 205 SlateBlue3
71 60 139 SlateBlue4
72 118 255 RoyalBlue1
67 110 238 RoyalBlue2
58 95 205 RoyalBlue3
39 64 139 RoyalBlue4
0 0 255 blue1
0 0 238 blue2
0 0 205 blue3
0 0 139 blue4
30 144 255 DodgerBlue1
28 134 238 DodgerBlue2
24 116 205 DodgerBlue3
16 78 139 DodgerBlue4
99 184 255 SteelBlue1
92 172 238 SteelBlue2
79 148 205 SteelBlue3
54 100 139 SteelBlue4
0 191 255 DeepSkyBlue1
0 178 238 DeepSkyBlue2
0 154 205 DeepSkyBlue3
0 104 139 DeepSkyBlue4
135 206 255 SkyBlue1
126 192 238 SkyBlue2
108 166 205 SkyBlue3
74 112 139 SkyBlue4
176 226 255 LightSkyBlue1
164 211 238 LightSkyBlue2
141 182 205 LightSkyBlue3
96 123 139 LightSkyBlue4
198 226 255 SlateGray1
185 211 238 SlateGray2
159 182 205 SlateGray3
108 123 139 SlateGray4
202 225 255 LightSteelBlue1
188 210 238 LightSteelBlue2
162 181 205 LightSteelBlue3
110 123 139 LightSteelBlue4
191 239 255 LightBlue1
178 223 238 LightBlue2
154 192 205 LightBlue3
104 131 139 LightBlue4
224 255 255 LightCyan1
209 238 238 LightCyan2
180 205 205 LightCyan3
122 139 139 LightCyan4
187 255 255 PaleTurquoise1
174 238 238 PaleTurquoise2
150 205 205 PaleTurquoise3
102 139 139 PaleTurquoise4
152 245 255 CadetBlue1
142 229 238 CadetBlue2
122 197 205 CadetBlue3
83 134 139 CadetBlue4
0 245 255 turquoise1
0 229 238 turquoise2
0 197 205 turquoise3
0 134 139 turquoise4
0 255 255 cyan1
0 238 238 cyan2
0 205 205 cyan3
0 139 139 cyan4
151 255 255 DarkSlateGray1
141 238 238 DarkSlateGray2
121 205 205 DarkSlateGray3
82 139 139 DarkSlateGray4
127 255 212 aquamarine1
118 238 198 aquamarine2
102 205 170 aquamarine3
69 139 116 aquamarine4
193 255 193 DarkSeaGreen1
180 238 180 DarkSeaGreen2
155 205 155 DarkSeaGreen3
105 139 105 DarkSeaGreen4
84 255 159 SeaGreen1
78 238 148 SeaGreen2
67 205 128 SeaGreen3
46 139 87 SeaGreen4
154 255 154 PaleGreen1
144 238 144 PaleGreen2
124 205 124 PaleGreen3
84 139 84 PaleGreen4
0 255 127 SpringGreen1
0 238 118 SpringGreen2
0 205 102 SpringGreen3
0 139 69 SpringGreen4
0 255 0 green1
0 238 0 green2
0 205 0 green3
0 139 0 green4
127 255 0 chartreuse1
118 238 0 chartreuse2
102 205 0 chartreuse3
69 139 0 chartreuse4
192 255 62 OliveDrab1
179 238 58 OliveDrab2
154 205 50 OliveDrab3
105 139 34 OliveDrab4
202 255 112 DarkOliveGreen1
188 238 104 DarkOliveGreen2
162 205 90 DarkOliveGreen3
110 139 61 DarkOliveGreen4
255 246 143 khaki1
238 230 133 khaki2
205 198 115 khaki3
139 134 78 khaki4
255 236 139 LightGoldenrod1
238 220 130 LightGoldenrod2
205 190 112 LightGoldenrod3
139 129 76 LightGoldenrod4
255 255 224 LightYellow1
238 238 209 LightYellow2
205 205 180 LightYellow3
139 139 122 LightYellow4
255 255 0 yellow1
238 238 0 yellow2
205 205 0 yellow3
139 139 0 yellow4
255 215 0 gold1
238 201 0 gold2
205 173 0 gold3
139 117 0 gold4
255 193 37 goldenrod1
238 180 34 goldenrod2
205 155 29 goldenrod3
139 105 20 goldenrod4
255 185 15 DarkGoldenrod1
238 173 14 DarkGoldenrod2
205 149 12 DarkGoldenrod3
139 101 8 DarkGoldenrod4
255 193 193 RosyBrown1
238 180 180 RosyBrown2
205 155 155 RosyBrown3
139 105 105 RosyBrown4
255 106 106 IndianRed1
238 99 99 IndianRed2
205 85 85 IndianRed3
139 58 58 IndianRed4
255 130 71 sienna1
238 121 66 sienna2
205 104 57 sienna3
139 71 38 sienna4
255 211 155 burlywood1
238 197 145 burlywood2
205 170 125 burlywood3
139 115 85 burlywood4
255 231 186 wheat1
238 216 174 wheat2
205 186 150 wheat3
139 126 102 wheat4
255 165 79 tan1
238 154 73 tan2
205 133 63 tan3
139 90 43 tan4
255 127 36 chocolate1
238 118 33 chocolate2
205 102 29 chocolate3
139 69 19 chocolate4
255 48 48 firebrick1
238 44 44 firebrick2
205 38 38 firebrick3
139 26 26 firebrick4
255 64 64 brown1
238 59 59 brown2
205 51 51 brown3
139 35 35 brown4
255 140 105 salmon1
238 130 98 salmon2
205 112 84 salmon3
139 76 57 salmon4
255 160 122 LightSalmon1
238 149 114 LightSalmon2
205 129 98 LightSalmon3
139 87 66 LightSalmon4
255 165 0 orange1
238 154 0 orange2
205 133 0 orange3
139 90 0 orange4
255 127 0 DarkOrange1
238 118 0 DarkOrange2
205 102 0 DarkOrange3
139 69 0 DarkOrange4
255 114 86 coral1
238 106 80 coral2
205 91 69 coral3
139 62 47 coral4
255 99 71 tomato1
238 92 66 tomato2
205 79 57 tomato3
139 54 38 tomato4
255 69 0 OrangeRed1
238 64 0 OrangeRed2
205 55 0 OrangeRed3
139 37 0 OrangeRed4
255 0 0 red1
238 0 0 red2
205 0 0 red3
139 0 0 red4
255 20 147 DeepPink1
238 18 137 DeepPink2
205 16 118 DeepPink3
139 10 80 DeepPink4
255 110 180 HotPink1
238 106 167 HotPink2
205 96 144 HotPink3
139 58 98 HotPink4
255 181 197 pink1
238 169 184 pink2
205 145 158 pink3
139 99 108 pink4
255 174 185 LightPink1
238 162 173 LightPink2
205 140 149 LightPink3
139 95 101 LightPink4
255 130 171 PaleVioletRed1
238 121 159 PaleVioletRed2
205 104 137 PaleVioletRed3
139 71 93 PaleVioletRed4
255 52 179 maroon1
238 48 167 maroon2
205 41 144 maroon3
139 28 98 maroon4
255 62 150 VioletRed1
238 58 140 VioletRed2
205 50 120 VioletRed3
139 34 82 VioletRed4
255 0 255 magenta1
238 0 238 magenta2
205 0 205 magenta3
139 0 139 magenta4
255 131 250 orchid1
238 122 233 orchid2
205 105 201 orchid3
139 71 137 orchid4
255 187 255 plum1
238 174 238 plum2
205 150 205 plum3
139 102 139 plum4
224 102 255 MediumOrchid1
209 95 238 MediumOrchid2
180 82 205 MediumOrchid3
122 55 139 MediumOrchid4
191 62 255 DarkOrchid1
178 58 238 DarkOrchid2
154 50 205 DarkOrchid3
104 34 139 DarkOrchid4
155 48 255 purple1
145 44 238 purple2
125 38 205 purple3
85 26 139 purple4
171 130 255 MediumPurple1
159 121 238 MediumPurple2
137 104 205 MediumPurple3
93 71 139 MediumPurple4
255 225 255 thistle1
238 210 238 thistle2
205 181 205 thistle3
139 123 139 thistle4
0 0 0 gray0
0 0 0 grey0
3 3 3 gray1
3 3 3 grey1
5 5 5 gray2
5 5 5 grey2
8 8 8 gray3
8 8 8 grey3
10 10 10 gray4
10 10 10 grey4
13 13 13 gray5
13 13 13 grey5
15 15 15 gray6
15 15 15 grey6
18 18 18 gray7
18 18 18 grey7
20 20 20 gray8
20 20 20 grey8
23 23 23 gray9
23 23 23 grey9
26 26 26 gray10
26 26 26 grey10
28 28 28 gray11
28 28 28 grey11
31 31 31 gray12
31 31 31 grey12
33 33 33 gray13
33 33 33 grey13
36 36 36 gray14
36 36 36 grey14
38 38 38 gray15
38 38 38 grey15
41 41 41 gray16
41 41 41 grey16
43 43 43 gray17
43 43 43 grey17
46 46 46 gray18
46 46 46 grey18
48 48 48 gray19
48 48 48 grey19
51 51 51 gray20
51 51 51 grey20
54 54 54 gray21
54 54 54 grey21
56 56 56 gray22
56 56 56 grey22
59 59 59 gray23
59 59 59 grey23
61 61 61 gray24
61 61 61 grey24
64 64 64 gray25
64 64 64 grey25
66 66 66 gray26
66 66 66 grey26
69 69 69 gray27
69 69 69 grey27
71 71 71 gray28
71 71 71 grey28
74 74 74 gray29
74 74 74 grey29
77 77 77 gray30
77 77 77 grey30
79 79 79 gray31
79 79 79 grey31
82 82 82 gray32
82 82 82 grey32
84 84 84 gray33
84 84 84 grey33
87 87 87 gray34
87 87 87 grey34
89 89 89 gray35
89 89 89 grey35
92 92 92 gray36
92 92 92 grey36
94 94 94 gray37
94 94 94 grey37
97 97 97 gray38
97 97 97 grey38
99 99 99 gray39
99 99 99 grey39
102 102 102 gray40
102 102 102 grey40
105 105 105 gray41
105 105 105 grey41
107 107 107 gray42
107 107 107 grey42
110 110 110 gray43
110 110 110 grey43
112 112 112 gray44
112 112 112 grey44
115 115 115 gray45
115 115 115 grey45
117 117 117 gray46
117 117 117 grey46
120 120 120 gray47
120 120 120 grey47
122 122 122 gray48
122 122 122 grey48
125 125 125 gray49
125 125 125 grey49
127 127 127 gray50
127 127 127 grey50
130 130 130 gray51
130 130 130 grey51
133 133 133 gray52
133 133 133 grey52
135 135 135 gray53
135 135 135 grey53
138 138 138 gray54
138 138 138 grey54
140 140 140 gray55
140 140 140 grey55
143 143 143 gray56
143 143 143 grey56
145 145 145 gray57
145 145 145 grey57
148 148 148 gray58
148 148 148 grey58
150 150 150 gray59
150 150 150 grey59
153 153 153 gray60
153 153 153 grey60
156 156 156 gray61
156 156 156 grey61
158 158 158 gray62
158 158 158 grey62
161 161 161 gray63
161 161 161 grey63
163 163 163 gray64
163 163 163 grey64
166 166 166 gray65
166 166 166 grey65
168 168 168 gray66
168 168 168 grey66
171 171 171 gray67
171 171 171 grey67
173 173 173 gray68
173 173 173 grey68
176 176 176 gray69
176 176 176 grey69
179 179 179 gray70
179 179 179 grey70
181 181 181 gray71
181 181 181 grey71
184 184 184 gray72
184 184 184 grey72
186 186 186 gray73
186 186 186 grey73
189 189 189 gray74
189 189 189 grey74
191 191 191 gray75
191 191 191 grey75
194 194 194 gray76
194 194 194 grey76
196 196 196 gray77
196 196 196 grey77
199 199 199 gray78
199 199 199 grey78
201 201 201 gray79
201 201 201 grey79
204 204 204 gray80
204 204 204 grey80
207 207 207 gray81
207 207 207 grey81
209 209 209 gray82
209 209 209 grey82
212 212 212 gray83
212 212 212 grey83
214 214 214 gray84
214 214 214 grey84
217 217 217 gray85
217 217 217 grey85
219 219 219 gray86
219 219 219 grey86
222 222 222 gray87
222 222 222 grey87
224 224 224 gray88
224 224 224 grey88
227 227 227 gray89
227 227 227 grey89
229 229 229 gray90
229 229 229 grey90
232 232 232 gray91
232 232 232 grey91
235 235 235 gray92
235 235 235 grey92
237 237 237 gray93
237 237 237 grey93
240 240 240 gray94
240 240 240 grey94
242 242 242 gray95
242 242 242 grey95
245 245 245 gray96
245 245 245 grey96
247 247 247 gray97
247 247 247 grey97
250 250 250 gray98
250 250 250 grey98
252 252 252 gray99
252 252 252 grey99
255 255 255 gray100
255 255 255 grey100
169 169 169 dark grey
169 169 169 DarkGrey
169 169 169 dark gray
169 169 169 DarkGray
0 0 139 dark blue
0 0 139 DarkBlue
0 139 139 dark cyan
0 139 139 DarkCyan
139 0 139 dark magenta
139 0 139 DarkMagenta
139 0 0 dark red
139 0 0 DarkRed
144 238 144 light green
144 238 144 LightGreen
__END__
=head1 NAME
Imager::Color::Table - built-in Imager color table
=head1 SYNOPSIS
use Imager::Color::Table;
my @rgb = Imager::Color::Table->get($name)
or die "Color $name not found";
=head1 DESCRIPTION
This class provides a base color table for use in resolving color names.
The table contains the standard X11 C<rgb.txt> colors.
This table is not included as part of Imager::Color itself since it's
moderately large.
There is only one method:
=over
=item get
my @rgb = Imager::Color::Table->get('red')
or die "No red found";
Retrieves a color from Imager::Color::Tables built-in color table.
=back
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=cut

View File

@@ -0,0 +1,548 @@
=head1 NAME
Imager::Cookbook - recipes working with Imager
=head1 DESCRIPTION
Various simple and not so simple ways to do things with Imager.
=head1 FILES
This is described in detail in L<Imager::Files>.
=head2 Reading an image from a file
my $image = Imager->new;
$image->read(file=>$filename) or die $image->errstr;
Or:
my $image = Imager->new(file => $filename)
or die Imager->errstr;
See L<Imager::Files>.
=head2 Writing an image to a file
$image->write(file=>$filename) or die $image->errstr;
=head2 Write an animated GIF
# build an array of images to use in the gif
my @images;
# synthesize the images or read them from files, it doesn't matter
...
# write the gif
Imager->write_multi({ file=>$filename, type=>'gif' }, @images)
or die Imager->errstr;
See L<Imager::Files/"Writing an animated GIF"> for a more detailed
example.
=head2 Reading multiple images from one file
Some formats, like GIF and TIFF support multiple images per file. Use
the L<read_multi()|Imager::Files> method to read them:
my @images = Imager->read_multi(file=>$filename)
or die Imager->errstr;
=head2 Converting from one file format to another
This is as simple as reading the original file and writing the new
file, for single images:
my $image = Imager->new;
# Imager auto-detects the input file type
$image->read(file => $input_filename)
or die $image->errstr;
# Imager derives the output file format from the filename
$image->write(file => $output_filename)
or die $image->errstr;
# or you can supply a type parameter:
$image->write(file => $output_filename, type => 'gif')
or die $image->errstr;
The main issue that can occur with this is if the input file has
transparency and the output file format doesn't support that. This
can be a problem when converting from GIF files to JPEG files for
example.
By default, if the output format doesn't support transparency, Imager
will compose the image onto a black background. You can override that
by supplying an C<i_background> option to C<write()> or
C<write_multi()>:
$image->write(file => "foo.jpg", i_background => "#808080")
or die $image->errstr;
Some formats support multiple files, so if you want to convert from
say TIFF to JPEG, you'll need multiple output files:
my @images = Imager->read_multi(file => 'input.tif')
or die Imager->errstr;
my $index = 1;
for my $image (@images) {
$image->write(file => sprintf('output%02d.jpg', $index++))
or die $image->errstr;
}
=head2 Transparent PNG
To save to a transparent PNG (or GIF or TIFF) you need to start with
an image with transparency.
To make a transparent image, create an image object with 2 or 4
channels:
# RGB with alpha channel
my $rgba = Imager->new(xsize => $width, ysize => $height, channels => 4);
# Gray with alpha channel
my $graya = Imager->new(xsize => $width, ysize => $height, channels => 2);
By default, the created image will be transparent.
Otherwise, if you have an existing image file with transparency,
simply read it, and the transparency will be preserved.
=head1 IMAGE SYNTHESIS
=head2 Creating an image
To create a simple RGB image, supply the image width and height to the
new() method:
my $rgb = Imager->new(xsize=>$width, ysize=>$height);
If you also want an alpha channel:
my $rgb_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>4);
To make a gray-scale image:
my $gray = Imager->new(xsize=>$width, ysize=>$height, channels=>1);
and a gray-scale image with an alpha channel:
my $gray_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>2);
When a new image is created this way all samples are set to zero -
black for 1 or 3 channel images, transparent black for 2 or 4 channel
images.
You can also create paletted images and images with more than 8-bits
per channel, see L<Imager::ImageTypes> for more details.
=head2 Setting the background of a new image
To set the background of a new image to a solid color, use the box()
method with no limits, and C<< filled=>1 >>:
$image->box(filled=>1, color=>$color);
As always, a color can be specified as an L<Imager::Color> object:
my $white = Imager::Color->new(255, 255, 255);
$image->box(filled=>1, color=>$white);
or you supply any single scalar that Imager::Color's new() method
accepts as a color description:
$image->box(filled=>1, color=>'white');
$image->box(filled=>1, color=>'#FF0000');
$image->box(filled=>1, color=>[ 255, 255, 255 ]);
You can also fill the image with a fill object:
use Imager::Fill;
# create the fill object
my $fill = Imager::Fill->new(hatch=>'check1x1')
$image->box(fill=>$fill);
# let Imager create one automatically
$image->box(fill=>{ hatch=>'check1x1' });
See L<Imager::Fill> for information on Imager's fill objects.
=head1 WORLD WIDE WEB
As with any CGI script it's up to you to validate data and set limits
on any parameters supplied to Imager.
For example, if you allow the caller to set the size of an output
image you should limit the size to prevent the client from specifying
an image size that will consume all available memory.
This is beside any other controls you need over access to data.
See L<CGI> for a module useful for processing CGI submitted data.
=head2 Returning an image from a CGI script
This is similar to writing to a file, but you also need to supply the
information needed by the web browser to identify the file format:
my $img = ....; # create the image and generate the contents
++$|; # make sure the content type isn't buffered
print "Content-Type: image/png\n\n";
binmode STDOUT;
$img->write(fd=>fileno(STDOUT), type=>'png')
or die $img->errstr;
You need to set the Content-Type header depending on the file format
you send to the web browser.
If you want to supply a content-length header, write the image to a
scalar as a buffer:
my $img = ....; # create the image and generate the contents
my $data;
$img->write(type=>'png', data=>\$data)
or die $img->errstr;
print "Content-Type: image/png\n";
print "Content-Length: ",length($data),"\n\n";
binmode STDOUT;
print $data;
See C<samples/samp-scale.cgi> and C<samples/samp-image.cgi> for a
couple of simple examples of producing an image from CGI.
=head2 Inserting a CGI image in a page
There's occasionally confusion on how to display an image generated by
Imager in a page generated by a CGI.
Your web browser handles this process as two requests, one for the
HTML page, and another for the image itself.
Each request needs to perform validation since an attacker can control
the values supplied to both requests.
How you make the data available to the image generation code depends
on your application.
See C<samples/samp-form.cgi> and C<samples/samp-image.cgi> in the
Imager distribution for one approach. The POD in C<samp-form.cgi>
also discusses some of the issues involved.
=head2 Parsing an image posted via CGI
C<WARNING>: file format attacks have become a common attack vector,
make sure you have up to date image file format libraries, otherwise
trying to parse uploaded files, whether with Imager or some other
tool, may result in a remote attacker being able to run their own code
on your system.
If your HTML form uses the correct magic, it can upload files to your
CGI script, in particular, you need to use C< method="post" > and
C<enctype="multipart/form-data"> in the C<form> tag, and use
C<type="file"> in the C<input>, for example:
<form action="/cgi-bin/yourprogram" method="post"
enctype="multipart/form-data">
<input type="file" name="myimage" />
<input type="submit value="Upload Image" />
</form>
To process the form:
=over
=item 1.
first check that the user supplied a file
=item 2.
get the file handle
=item 3.
have Imager read the image
=back
# returns the client's name for the file, don't open this locally
my $cgi = CGI->new;
# 1. check the user supplied a file
my $filename = $cgi->param('myimage');
if ($filename) {
# 2. get the file handle
my $fh = $cgi->upload('myimage');
if ($fh) {
binmode $fh;
# 3. have Imager read the image
my $img = Imager->new;
if ($img->read(fh=>$fh)) {
# we can now process the image
}
}
# else, you probably have an incorrect form or input tag
}
# else, the user didn't select a file
See C<samples/samp-scale.cgi> and C<samples/samp-tags.cgi> in the
Imager distribution for example code.
You may also want to set limits on the size of the image read, using
Imager's C<set_file_limits> method, documented in
L<Imager::Files/set_file_limits()>. For example:
# limit to 10 million bytes of memory usage
Imager->set_file_limits(bytes => 10_000_000);
# limit to 1024 x 1024
Imager->set_file_limits(width => 1024, height => 1024);
=head1 DRAWING
=head2 Adding a border to an image
First make a new image with space for the border:
my $border_width = ...;
my $border_height = ...;
my $out = Imager->new(xsize => $source->getwidth() + 2 * $border_width,
ysize => $source->getheight() + 2 * $border_height,
bits => $source->bits,
channels => $source->getchannels);
Then paste the source image into the new image:
$out->paste(left => $border_width,
top => $border_height,
img => $source);
Whether you draw the border before or after pasting the original image
depends on whether you want the border to overlap the image, for
example a semi-transparent border drawn after pasting the source image
could overlap the edge without hiding it.
If you want a solid border you could just fill the image before
pasting the source for simplicity:
$out->box(filled=>1, color=>'red');
$out->paste(left => $border_width,
top => $border_height,
img => $source);
=head1 TEXT
=head2 Drawing text
=head2 Aligning text
=head2 Measuring text
=head2 Word wrapping text
=head2 Shearing (slanting) or Rotating text
This requires that you have Imager installed with FreeType 2.x support
installed, and that the font be created using the FreeType 2.x driver,
for example:
my $font = Imager::Font->new(file=>$fontfile, type=>'ft2');
First you need a transformation matrix, for shearing that could be:
my $angle_in_radians = ...;
my $tan_angle = sin($angle_rads) / cos($angle_rads);
# shear horizontally, supply this as y instead to do it vertically
my $matrix = Imager::Matrix2d->shear(x=>$tan_angle);
For rotation that would be:
my $matrix = Imager::Matrix2d->rotate(radians => $angle_in_radians);
or:
my $matrix = Imager::Matrix2d->rotate(degrees => $angle_in_degrees);
Feed that to the font object:
$font->transform(matrix => $matrix);
and draw the text as normal:
$image->string(string => $text,
x => $where_x,
y => $where_y,
color => $color,
font => $font);
See samples/slant_text.pl for a comprehensive example, including
calculating the transformed bounding box to create an image to fit the
transformed text into.
=head1 IMAGE TRANSFORMATION
=head2 Shearing an image
=head2 Convert to gray-scale
To convert an RGB image to a gray-scale image, use the convert method:
my $grey = $image->convert(preset => 'gray');
convert() returns a new image.
See: L<Imager::Transformations/"Color transformations">
=head1 METADATA
=head2 Image format
When Imager reads a file it does a magic number check to determine the
file type, so C<foo.png> could actually be a GIF image, and Imager
will read it anyway.
You can check the actual format of the image by looking at the
C<i_format> tag.
my $format = $image->tags(name=>'i_format');
=head2 Image spatial resolution
Most image file formats store information about the physical size of
the pixels, though in some cases that information isn't useful.
Imager stores this information in the tags C<i_xres> and C<i_yres>,
and this is always stored in dots per inch.
Some formats, including TIFF and JPEG allow you to change the units
spatial resolution information is stored in, if you set the tag that
changes this the Imager will convert C<i_xres> and C<i_yres> to those
units when it writes the file.
For example to set the resolution to 300 dpi:
$image->settag(name => 'i_xres', value => 300);
$image->settag(name => 'i_yres', value => 300);
If you want the file format to store the resolution in some other
unit, for example you can write a TIFF file that stores the resolution
in pixels per centimeter, you would do:
# 150 pixels/cm
$image->settag(name => 'i_xres', value => 150 * 2.54);
$image->settag(name => 'i_yres', value => 150 * 2.54);
$image->settag(name => 'tiff_resolutionunit', value => 3);
Keywords: DPI
=head1 IMAGE MANIPULATION
=head2 Replacing a color with transparency
X<replacing colors>
To replace a color with transparency you can use the
L<Imager::Filters/difference()> method.
# make a work image the same size as our input
my $work = Imager->new(xsize => $in->getwidth, ysize => $in->getheight,
channels => $in->getchannels);
# and fill it with the color we want transparent
$work->box(filled => 1, color => $color);
# get an image with that color replaced with transparent black
my $out = $work->difference(other => $in);
=head1 SPECIAL EFFECTS
=head2 Drop Shadows
X<drop shadow>X<effects, drop shadow>
This can be used for a glow effect as well.
First create a new image, either with an alpha channel (if you want
transparency behind the shadow) or without, if you want a background
color:
my $out = Imager->new
(
xsize => $shadow_size * 2 + $src->getwidth,
ysize => $shadow_size * 2 + $src->getheight,
channels => 4,
);
# fill it with your background color, if you want one
# $out->box(filled => 1, color => $back_color);
Make a work image to render the shadow on:
my $shadow_work = Imager->new
(
xsize => $back->getwidth,
ysize => $back->getheight,
channels => 1,
);
Extract the alpha channel from the source image, first the alpha version:
my $alpha = $src->convert(preset => "alpha");
and draw that on the work shadow:
$shadow_work->paste
(
src => $slpha,
left => $shadow_size,
top => $shadow_size,
);
otherwise just draw a box for the non-alpha source:
$shadow_work->box
(
filled => 1,
color => [ 255 ],
xmin => $shadow_size,
ymin => $shadow_size,
xmax => $shadow_size + $src->getwidth() - 1,
ymax => $shadow_size + $src->getheight() - 1,
);
Blur the work shadow:
$shadow_work->filter(type => "gaussian", stddev => $shadow_size);
Convert it to an RGB image with alpha:
$shadow_work = $shadow_work->convert
(
matrix => [ [ 0, $red / 255 ],
[ 0, $green / 255 ],
[ 0, $blue / 255 ],
[ 1 ] ]
);
Draw that on the output image:
$out->rubthrough(src => $shadow_work);
Draw our original image on the output image, perhaps with an offset:
$out->rubthrough
(
src => $src,
tx => $shadow_size + $x_offset,
ty => $shadow_size + $y_offset,
);
See F<samples/drop_shadow.pl> for an example of this recipe.
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 SEE ALSO
L<Imager>, L<Imager::Files>, L<Imager::Draw>.
=cut

View File

@@ -0,0 +1,50 @@
package Imager::CountColor;
use 5.006;
use strict;
use Imager;
require Exporter;
our @EXPORT_OK = 'count_color';
BEGIN {
our $VERSION = "0.03";
our @ISA = qw(Exporter);
require XSLoader;
XSLoader::load('Imager::CountColor', $VERSION);
}
1;
__END__
=head1 NAME
Imager::CountColor - demonstrates writing a simple function using Imager.
=head1 SYNOPSIS
use Imager;
use Imager::CountColor;
my $im = Imager->new(...); # some Imager image
...; # some sort of manipulation
print count_color($im, $color_object);
=head1 DESCRIPTION
This module is a simple demonstration of how to create an XS module
that works with Imager objects.
You may want to copy the source for this module as a start.
=head1 SEE ALSO
Imager, Imager::Filter::DynTest
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

1405
database/perl/vendor/lib/Imager/Draw.pod vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,577 @@
=head1 NAME
Imager::Engines - Programmable transformation operations
=head1 SYNOPSIS
use Imager;
my %opts;
my @imgs;
my $img;
...
my $newimg = $img->transform(
xexpr=>'x',
yexpr=>'y+10*sin((x+y)/10)')
or die $img->errstr;
my $newimg = Imager::transform2(\%opts, @imgs)
or die "transform2 failed: $Imager::ERRSTR";
my $newimg = $img->matrix_transform(
matrix=>[ -1, 0, $img->getwidth-1,
0, 1, 0,
0, 0, 1 ]);
=head1 DESCRIPTION
=head2 transform()
The C<transform()> function can be used to generate spatial warps and
rotations and such effects. It only operates on a single image and
its only function is to displace pixels.
It can be given the operations in postfix notation or the module
Affix::Infix2Postfix can be used to generate postfix code from infix
code. Look in the test case t/t55trans.t for an example.
C<transform()> needs expressions (or opcodes) that determine the
source pixel for each target pixel. Source expressions are infix
expressions using any of the +, -, *, / or ** binary operators, the -
unary operator, ( and ) for grouping and the C<sin()> and C<cos()>
functions. The target pixel is input as the variables x and y.
You specify the x and y expressions as C<xexpr> and C<yexpr> respectively.
You can also specify opcodes directly, but that's magic deep enough
that you can look at the source code.
Note: You can still use the transform() function, but the transform2()
function is just as fast and is more likely to be enhanced and
maintained.
$new_img=$img->transform(xexpr=>'x',yexpr=>'y+10*sin((x+y)/10)')
$new_img=$img->transform(xexpr=>'x+0.1*y+5*sin(y/10.0+1.57)',
yexpr=>'y+10*sin((x+y-0.785)/10)')
=head2 transform2()
Imager also supports a C<transform2()> class method which allows you
perform a more general set of operations, rather than just specifying
a spatial transformation as with the transform() method, you can also
perform color transformations, image synthesis and image
combinations from multiple source images.
C<transform2()> takes an reference to an options hash, and a list of
images to operate one (this list may be empty):
my %opts;
my @imgs;
...
my $img = Imager::transform2(\%opts, @imgs)
or die "transform2 failed: $Imager::ERRSTR";
The options hash may define a transformation function, and optionally:
=over
=item *
width - the width of the image in pixels. If this isn't supplied the
width of the first input image is used. If there are no input images
an error occurs.
=item *
height - the height of the image in pixels. If this isn't supplied
the height of the first input image is used. If there are no input
images an error occurs.
=item *
constants - a reference to hash of constants to define for the
expression engine. Some extra constants are defined by Imager
=item *
channels - the number of channels in the output image. If this isn't
supplied a 3 channel image will be created.
=back
The transformation function is specified using either the C<expr> or
C<rpnexpr> member of the options.
=head3 Infix expressions
You can supply infix expressions to transform 2 with the C<expr> keyword.
$opts{expr} = 'return getp1(w-x, h-y)'
The 'expression' supplied follows this general grammar:
( identifier '=' expr ';' )* 'return' expr
This allows you to simplify your expressions using variables.
A more complex example might be:
$opts{expr} = 'pix = getp1(x,y); return if(value(pix)>0.8,pix*0.8,pix)'
Currently to use infix expressions you must have the L<Parse::RecDescent>
module installed (available from CPAN). There is also what might be a
significant delay the first time you run the infix expression parser
due to the compilation of the expression grammar.
=head3 Postfix expressions
You can supply postfix or reverse-polish notation expressions to
transform2() through the C<rpnexpr> keyword.
The parser for C<rpnexpr> emulates a stack machine, so operators will
expect to see their parameters on top of the stack. A stack machine
isn't actually used during the image transformation itself.
You can store the value at the top of the stack in a variable called
C<foo> using C<!foo> and retrieve that value again using @foo. The !foo
notation will pop the value from the stack.
An example equivalent to the infix expression above:
$opts{rpnexpr} = 'x y getp1 !pix @pix value 0.8 gt @pix 0.8 * @pix ifp'
At the end of the expression there should be a single pixel value left
on the stack, which is used as the output pixel.
=head3 Operators
transform2() has a fairly rich range of operators.
Each entry below includes the usage with C<rpnexpr>, formatted as:
=over
I<operand> I<operand> ... B<I<operator>> -- I<result>
=back
If the operand or result begins with "N" it is a numeric value, if it
begins with "C" it is a color or pixel value.
=over
=item +, *, -, /, %, **
multiplication, addition, subtraction, division, remainder and
exponentiation. Multiplication, addition and subtraction can be used
on color values too - though you need to be careful - adding 2 white
values together and multiplying by 0.5 will give you gray, not white.
Division by zero (or a small number) just results in a large number.
Modulo zero (or a small number) results in zero. % is implemented
using fmod() so you can use this to take a value mod a floating point
value.
=for stopwords N1 N2 N uminus
C<rpnexpr> usage:
=over
I<N1> I<N2> B<+> -- I<N>
I<N1> I<N2> B<*> -- I<N>
I<N1> I<N2> B<-> -- I<N>
I<N1> I<N2> B</> -- I<N>
I<N1> I<N2> B<**> -- I<N>
I<N1> B<uminus> -- I<N>
=back
=item sin(N), cos(N), atan2(y,x)
Some basic trig functions. They work in radians, so you can't just
use the hue values.
=for stopwords Ny Nx atan2
C<rpnexpr> usage:
=over
I<N> B<sin> -- I<N>
I<N> B<cos> -- I<N>
I<Ny> I<Nx> B<atan2> -- I<N>
=back
=item distance(x1, y1, x2, y2)
Find the distance between two points. This is handy (along with
atan2()) for producing circular effects.
=for stopwords Nx1 Ny1 Nx2 Ny2
C<rpnexpr> usage:
=over
I<Nx1> I<Ny1> I<Nx2> I<Ny2> B<distance> -- I<N>
=back
=item sqrt(n)
Find the square root. I haven't had much use for this since adding
the distance() function.
C<rpnexpr> usage:
=over
I<N> B<sqrt> -- I<N>
=back
=item abs(n)
Find the absolute value.
C<rpnexpr> usage:
=over
I<N> B<abs> -- I<N>
=back
=item getp1(x,y), getp2(x,y), getp3(x, y)
Get the pixel at position (x,y) from the first, second or third image
respectively. I may add a getpn() function at some point, but this
prevents static checking of the instructions against the number of
images actually passed in.
=for stopwords getp1 getp2 getp3
C<rpnexpr> usage:
=over
I<Nx> I<Ny> B<getp1> -- I<C>
I<Nx> I<Ny> B<getp2> -- I<C>
I<Nx> I<Ny> B<getp3> -- I<C>
=back
=item value(c), hue(c), sat(c), hsv(h,s,v), hsva(h,s,v,alpha)
Separates a color value into it's value (brightness), hue (color)
and saturation elements. Use hsv() to put them back together (after
suitable manipulation), or hsva() to include a transparency value.
=for stopwords Nh Ns Nv hsv hsva Nr Ng Nb rgb rgba
C<rpnexpr> usage:
=over
I<C> B<value> -- I<N>
I<C> B<hue> -- I<N>
I<C> B<sat> -- I<N>
I<Nh> I<Ns> I<Nv> B<hsv> -- I<C>
I<Nh> I<Ns> I<Nv> I<Na> B<hsva> -- I<C>
=back
=item red(c), green(c), blue(c), rgb(r,g,b), rgba(r,g,b,a)
Separates a color value into it's red, green and blue colors. Use
rgb(r,g,b) to put it back together, or rgba() to include a
transparency value.
C<rpnexpr> usage:
=over
I<C> B<red> -- I<N>
I<C> B<green> -- I<N>
I<C> B<blue> -- I<N>
I<Nr> I<Ng> I<Nb> B<rgb> -- I<C>
I<Nr> I<Ng> I<Nb> I<Na> B<rgba> -- I<C>
=back
=item alpha(c)
Retrieve the alpha value from a color.
C<rpnexpr> usage:
=over
I<C> B<alpha> -- I<N>
=back
=item int(n)
Convert a value to an integer. Uses a C int cast, so it may break on
large values.
C<rpnexpr> usage:
=over
I<N> B<int> -- I<N>
=back
=item if(cond,ntrue,nfalse), if(cond,ctrue,cfalse)
A simple (and inefficient) if function.
=for stopwords Ncond ifp
C<rpnexpr> usage:
=over
I<Ncond> I<N-true-result> I<N-false-result> B<if> -- I<N>
I<Ncond> I<C-true-result> I<C-false-result> B<if> -- I<C>
I<Ncond> I<C-true-result> I<C-false-result> B<ifp> -- I<C>
=back
=item <=,<,==,>=,>,!=
Relational operators (typically used with if()). Since we're working
with floating point values the equalities are 'near equalities' - an
epsilon value is used.
=over
I<N1> I<N2> B<< <= >> -- I<N>
I<N1> I<N2> B<< < >> -- I<N>
I<N1> I<N2> B<< >= >> -- I<N>
I<N1> I<N2> B<< > >> -- I<N>
I<N1> I<N2> B<< == >> -- I<N>
I<N1> I<N2> B<< != >> -- I<N>
=back
=item &&, ||, not(n)
Basic logical operators.
C<rpnexpr> usage:
=over
I<N1> I<N2> B<and> -- I<N>
I<N1> I<N2> B<or> -- I<N>
I<N> B<not> -- I<N>
=back
=item log(n), exp(n)
Natural logarithm and exponential.
C<rpnexpr> usage:
=over
I<N> B<log> -- I<N>
I<N> B<exp> -- I<N>
=back
=item det(a, b, c, d)
Calculate the determinant of the 2 x 2 matrix;
a b
c d
=for stopwords Na Nv Nc Nd det
C<rpnexpr> usage:
=over
I<Na> I<Nb> I<Nc> I<Nd> B<det> -- I<N>
=back
=back
=head3 Constants
transform2() defines the following constants:
=over
=item C<pi>
The classical constant.
=item C<w>
=item C<h>
The width and height of the output image.
=item C<cx>
=item C<cy>
The center of the output image.
=item C<w>I<image number>
=item C<h>I<image number>
The width and height of each of the input images, C<w1> is the width
of the first input image and so on.
=item C<cx>I<image number>
=item C<cy>I<image number>
The center of each of the input images, (C<cx1>, C<cy1>) is the center
of the first input image and so on.
=back
A few examples:
=over
rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat x y getp1 !pix @pix sat 0.7 gt @pat @pix ifp'
tiles a smaller version of the input image over itself where the
color has a saturation over 0.7.
rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat y 360 / !rat x y getp1 1 @rat - pmult @pat @rat pmult padd'
tiles the input image over itself so that at the top of the image the
full-size image is at full strength and at the bottom the tiling is
most visible.
rpnexpr=>'x y getp1 !pix @pix value 0.96 gt @pix sat 0.1 lt and 128 128 255 rgb @pix ifp'
replace pixels that are white or almost white with a palish blue
rpnexpr=>'x 35 % 10 * y 45 % 8 * getp1 !pat x y getp1 !pix @pix sat 0.2 lt @pix value 0.9 gt and @pix @pat @pix value 2 / 0.5 + pmult ifp'
Tiles the input image over it self where the image isn't white or almost
white.
rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv'
Produces a spiral.
rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv'
A spiral built on top of a color wheel.
=back
For details on expression parsing see L<Imager::Expr>. For details on
the virtual machine used to transform the images, see
L<Imager::regmach>.
# generate a colorful spiral
# requires that Parse::RecDescent be installed
my $newimg = Imager::transform2({
width => 160, height=>160,
expr => <<EOS
dist = distance(x, y, w/2, h/2);
angle = atan2(y-h/2, x-w/2);
angle2 = (dist / 10 + angle) % ( 2 * pi );
return hsv(angle*180/pi, 1, (sin(angle2)+1)/2);
EOS
});
# replace green portions of an image with another image
my $newimg = Imager::transform2({
rpnexpr => <<EOS
x y getp2 !pat # used to replace green portions
x y getp1 !pix # source with "green screen"
@pix red 10 lt @pix blue 10 lt && # low blue and red
@pix green 254 gt && # and high green
@pat @pix ifp
EOS
}, $source, $background);
=head2 Matrix Transformations
=over
=item matrix_transform()
Rather than having to write code in a little language, you can use a
matrix to perform affine transformations, using the matrix_transform()
method:
my $newimg = $img->matrix_transform(matrix=>[ -1, 0, $img->getwidth-1,
0, 1, 0,
0, 0, 1 ]);
By default the output image will be the same size as the input image,
but you can supply the C<xsize> and C<ysize> parameters to change the
size.
Rather than building matrices by hand you can use the Imager::Matrix2d
module to build the matrices. This class has methods to allow you to
scale, shear, rotate, translate and reflect, and you can combine these
with an overloaded multiplication operator.
WARNING: the matrix you provide in the matrix operator transforms the
co-ordinates within the B<destination> image to the co-ordinates
within the I<source> image. This can be confusing.
You can also supply a C<back> argument which acts as a background
color for the areas of the image with no samples available (outside
the rectangle of the source image.) This can be either an
Imager::Color or Imager::Color::Float object. This is B<not> mixed
transparent pixels in the middle of the source image, it is B<only>
used for pixels where there is no corresponding pixel in the source
image.
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

703
database/perl/vendor/lib/Imager/Expr.pm vendored Normal file
View File

@@ -0,0 +1,703 @@
package Imager::Expr;
use 5.006;
use Imager::Regops;
use strict;
our $VERSION = "1.008";
my %expr_types;
my $error;
sub error {
shift if UNIVERSAL::isa($_[0], 'Imager::Expr');
if (@_) {
$error = "@_";
}
else {
return $error;
}
}
# what else?
my %default_constants =
(
# too many digits, better than too few
pi=>3.14159265358979323846264338327950288419716939937510582097494
);
sub new {
my ($class, $opts) = @_;
# possibly this is a very bad idea
my ($type) = grep exists $expr_types{$_}, keys %$opts;
die "Imager::Expr: No known expression type"
if !defined $type;
my $self = bless {}, $expr_types{$type};
$self->{variables} = [ @{$opts->{variables}} ];
$self->{constants} = { %default_constants, %{$opts->{constants} || {}} };
$self->{ops} = $self->compile($opts->{$type}, $opts)
or return;
$self->optimize()
or return;
$self->{code} = $self->assemble()
or return;
$self;
}
sub register_type {
my ($pack, $name) = @_;
$expr_types{$name} = $pack;
}
sub type_registered {
my ($class, $name) = @_;
$expr_types{$name};
}
sub _variables {
return @{$_[0]->{variables}};
}
sub code {
return $_[0]->{code};
}
sub nregs {
return $_[0]->{nregs};
}
sub cregs {
return $_[0]->{cregs};
}
my $numre = '[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?';
sub numre {
$numre;
}
# optimize the code
sub optimize {
my ($self) = @_;
my @ops = @{$self->{ops}};
# this function cannot current handle code with jumps
return 1 if grep $_->[0] =~ /^jump/, @ops;
# optimization - common sub-expression elimination
# it's possible to fold this into the code generation - but it will wait
my $max_opr = $Imager::Regops::MaxOperands;
my $attr = \%Imager::Regops::Attr;
my $foundops = 1;
while ($foundops) {
$foundops = 0;
my %seen;
my $index;
my @out;
while (@ops) {
my $op = shift @ops;
my $desc = join(",", @{$op}[0..$max_opr]);
if ($seen{$desc}) {
push(@out, @ops);
my $old = $op->[-1];
my $new = $seen{$desc};
for $op (@out) {
for my $reg (@{$op}[1..$max_opr]) {
$reg = $new if $reg eq $old;
}
}
$foundops=1;
last;
}
$seen{$desc} = $op->[-1];
push(@out, $op);
}
@ops = @out;
}
# strength reduction
for my $op (@ops) {
# reduce division by a constant to multiplication by a constant
if ($op->[0] eq 'div' && $op->[2] =~ /^r(\d+)/
&& defined($self->{"nregs"}[$1])) {
my $newreg = @{$self->{"nregs"}};
push(@{$self->{"nregs"}}, 1.0/$self->{"nregs"}[$1]);
$op->[0] = 'mult';
$op->[2] = 'r'.$newreg;
}
}
$self->{ops} = \@ops;
1;
}
sub assemble {
my ($self) = @_;
my $attr = \%Imager::Regops::Attr;
my $max_opr = $Imager::Regops::MaxOperands;
my @ops = @{$self->{ops}};
for my $op (@ops) {
$op->[0] = $attr->{$op->[0]}{opcode};
for (@{$op}[1..$max_opr+1]) { s/^[rpj]// }
}
my $pack = $Imager::Regops::PackCode x (2+$Imager::Regops::MaxOperands);
return join("", ,map { pack($pack, @$_, ) } @ops);
}
# converts stack code to register code
sub stack_to_reg {
my ($self, @st_ops) = @_;
my @regstack;
my %nregs;
my @vars = $self->_variables();
my @nregs = (0) x scalar(@vars);
my @cregs;
my $attr = \%Imager::Regops::Attr;
my %vars;
my %names;
my $max_opr = $Imager::Regops::MaxOperands;
@vars{@vars} = map { "r$_" } 0..$#vars;
my @ops;
for (@st_ops) {
if (/^$numre$/) {
# combining constants makes the optimization below work
if (exists $nregs{$_}) {
push(@regstack, $nregs{$_});
}
else {
$nregs{$_} = "r".@nregs;
push(@regstack,"r".@nregs);
push(@nregs, $_);
}
}
elsif (exists $vars{$_}) {
push(@regstack, $vars{$_});
}
elsif (exists $attr->{$_} && length $attr->{$_}{types}) {
if (@regstack < $attr->{$_}{parms}) {
error("Imager::transform2: stack underflow on $_");
return;
}
my @parms = splice(@regstack, -$attr->{$_}{parms});
my $types = join("", map {substr($_,0,1)} @parms);
if ($types ne $attr->{$_}{types}) {
if (exists $attr->{$_.'p'} && $types eq $attr->{$_.'p'}{types}) {
$_ .= 'p';
}
else {
error("Imager::transform2: Call to $_ with incorrect types");
return;
}
}
my $result;
if ($attr->{$_}{result} eq 'r') {
$result = "r".@nregs;
push(@nregs, undef);
}
else {
$result = "p".@cregs;
push(@cregs, -1);
}
push(@regstack, $result);
push(@parms, "0") while @parms < $max_opr;
push(@ops, [ $_, @parms, $result ]);
#print "$result <- $_ @parms\n";
}
elsif (/^!(\w+)$/) {
if (!@regstack) {
error("Imager::transform2: stack underflow with $_");
return;
}
$names{$1} = pop(@regstack);
}
elsif (/^\@(\w+)$/) {
if (exists $names{$1}) {
push(@regstack, $names{$1});
}
else {
error("Imager::Expr: unknown storage \@$1");
return;
}
}
else {
error("Imager::Expr: unknown operator $_");
return;
}
}
if (@regstack != 1) {
error("stack must have only one item at end");
return;
}
if ($regstack[0] !~ /^p/) {
error("you must have a color value at the top of the stack at end");
return;
}
push(@ops, [ "ret", $regstack[0], (-1) x $max_opr ]);
$self->{"nregs"} = \@nregs;
$self->{"cregs"} = \@cregs;
return \@ops;
}
sub dumpops {
my $result = '';
for my $op (@{$_[0]->{ops}}) {
$result .= "@{$op}\n";
}
$result;
}
# unassembles the compiled code
sub dumpcode {
my ($self) = @_;
my $code = $self->{"code"};
my $attr = \%Imager::Regops::Attr;
my @code = unpack("${Imager::Regops::PackCode}*", $code);
my %names = map { $attr->{$_}{opcode}, $_ } keys %Imager::Regops::Attr;
my @vars = $self->_variables();
my $result = '';
my $index = 0;
while (my @op = splice(@code, 0, 2+$Imager::Regops::MaxOperands)) {
my $opcode = shift @op;
my $name = $names{$opcode};
if ($name) {
$result .= "j$index: $name($opcode)";
my @types = split //, $attr->{$name}{types};
for my $parm (@types) {
my $reg = shift @op;
$result .= " $parm$reg";
if ($parm eq 'r') {
if ($reg < @vars) {
$result.= "($vars[$reg])";
}
elsif (defined $self->{"nregs"}[$reg]) {
$result .= "($self->{\"nregs\"}[$reg])";
}
}
}
$result .= " -> $attr->{$name}{result}$op[-1]"
if $attr->{$name}{result};
$result .= "\n";
}
else {
$result .= "unknown($opcode) @op\n";
}
++$index;
}
$result;
}
package Imager::Expr::Postfix;
our @ISA = qw(Imager::Expr);
Imager::Expr::Postfix->register_type('rpnexpr');
my %op_names = ( '+'=>'add', '-'=>'subtract', '*'=>'mult', '/' => 'div',
'%'=>'mod', '**'=>'pow' );
sub compile {
my ($self, $expr, $opts) = @_;
$expr =~ s/#.*//; # remove comments
my @st_ops = split ' ', $expr;
for (@st_ops) {
$_ = $op_names{$_} if exists $op_names{$_};
$_ = $self->{constants}{$_} if exists $self->{constants}{$_};
}
return $self->stack_to_reg(@st_ops);
}
package Imager::Expr::Infix;
our @ISA = qw(Imager::Expr);
use Imager::Regops qw(%Attr $MaxOperands);
{
local @INC = @INC;
pop @INC if $INC[-1] eq '.';
eval "use Parse::RecDescent;";
__PACKAGE__->register_type('expr') if !$@;
}
# I really prefer bottom-up parsers
my $grammar = <<'GRAMMAR';
code : assigns 'return' expr
{ $return = [ @item[1,3] ] }
assigns : assign(s?) { $return = [ @{$item[1]} ] }
assign : identifier '=' expr ';'
{ $return = [ @item[1,3] ] }
expr : relation
relation : addition (relstuff)(s?)
{
$return = $item[1];
for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
1;
}
relstuff : relop addition { $return = [ @item[1,2] ] }
relop : '<=' { $return = 'le' }
| '<' { $return = 'lt' }
| '==' { $return = 'eq' }
| '>=' { $return = 'ge' }
| '>' { $return = 'gt' }
| '!=' { $return = 'ne' }
addition : multiply (addstuff)(s?)
{
$return = $item[1];
# for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; }
for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
1;
}
addstuff : addop multiply { $return = [ @item[1,2] ] }
addop : '+' { $return = 'add' }
| '-' { $return = 'subtract' }
multiply : power mulstuff(s?)
{ $return = $item[1];
# for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; }
for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
1;
}
mulstuff : mulop power { $return = [ @item[1,2] ] }
mulop : '*' { $return = 'mult' }
| '/' { $return = 'div' }
| '%' { $return = 'mod' }
power : powstuff(s?) atom
{
$return = $item[2];
for my $op(reverse @{$item[1]}) { $return = [ @{$op}[1,0], $return ] }
1;
}
| atom
powstuff : atom powop { $return = [ @item[1,2] ] }
powop : '**' { $return = 'pow' }
atom: '(' expr ')' { $return = $item[2] }
| '-' atom { $return = [ uminus=>$item[2] ] }
| number
| funccall
| identifier
number : /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/
exprlist : expr ',' exprlist { $return = [ $item[1], @{$item[3]} ] }
| expr { $return = [ $item[1] ] }
funccall : identifier '(' exprlist ')'
{ $return = [ $item[1], @{$item[3]} ] }
identifier : /[^\W\d]\w*/ { $return = $item[1] }
GRAMMAR
my $parser;
sub init_parser {
if (!$parser) {
$parser = Parse::RecDescent->new($grammar);
}
}
sub compile {
my ($self, $expr, $opts) = @_;
if (!$parser) {
$parser = Parse::RecDescent->new($grammar);
}
my $optree = $parser->code($expr);
if (!$optree) {
$self->error("Error in $expr\n");
return;
}
@{$self->{inputs}}{$self->_variables} = ();
$self->{varregs} = {};
@{$self->{varregs}}{$self->_variables} = map { "r$_" } 0..$self->_variables-1;
$self->{"nregs"} = [ (undef) x $self->_variables ];
$self->{"cregs"} = [];
$self->{"lits"} = {};
eval {
# generate code for the assignments
for my $assign (@{$optree->[0]}) {
my ($varname, $tree) = @$assign;
if (exists $self->{inputs}{$varname}) {
$self->error("$varname is an input - you can't assign to it");
return;
}
$self->{varregs}{$varname} = $self->gencode($tree);
}
# generate the final result
my $result = $self->gencode($optree->[1]);
if ($result !~ /^p\d+$/) {
$self->error("You must return a color value");
return;
}
push(@{$self->{genops}}, [ 'ret', $result, (0) x $MaxOperands ])
};
if ($@) {
$self->error($@);
return;
}
return $self->{genops};
}
sub gencode {
my ($self, $tree) = @_;
if (ref $tree) {
my ($op, @parms) = @$tree;
if (!exists $Attr{$op}) {
die "Unknown operator or function $op";
}
for my $subtree (@parms) {
$subtree = $self->gencode($subtree);
}
my $types = join("", map {substr($_,0,1)} @parms);
if (length($types) < length($Attr{$op}{types})) {
die "Too few parameters in call to $op";
}
if ($types ne $Attr{$op}{types}) {
# some alternate operators have the same name followed by p
my $opp = $op."p";
if (exists $Attr{$opp} &&
$types eq $Attr{$opp}{types}) {
$op = $opp;
}
else {
die "Call to $_ with incorrect types";
}
}
my $result;
if ($Attr{$op}{result} eq 'r') {
$result = "r".@{$self->{nregs}};
push(@{$self->{nregs}}, undef);
}
else {
$result = "p".@{$self->{cregs}};
push(@{$self->{cregs}}, undef);
}
push(@parms, "0") while @parms < $MaxOperands;
push(@{$self->{genops}}, [ $op, @parms, $result]);
return $result;
}
elsif (exists $self->{varregs}{$tree}) {
return $self->{varregs}{$tree};
}
elsif ($tree =~ /^$numre$/ || exists $self->{constants}{$tree}) {
$tree = $self->{constants}{$tree} if exists $self->{constants}{$tree};
if (exists $self->{lits}{$tree}) {
return $self->{lits}{$tree};
}
my $reg = "r".@{$self->{nregs}};
push(@{$self->{nregs}}, $tree);
$self->{lits}{$tree} = $reg;
return $reg;
}
}
1;
__END__
=head1 NAME
Imager::Expr - implements expression parsing and compilation for the
expression evaluation engine used by Imager::transform2()
=head1 SYNOPSIS
my $code = Imager::Expr->new({rpnexpr=>$someexpr})
or die "Cannot compile $someexpr: ",Imager::Expr::error();
=head1 DESCRIPTION
This module is used internally by the Imager::transform2() function.
You shouldn't have much need to use it directly, but you may want to
extend it.
To create a new Imager::Expr object, call:
my %options;
my $expr = Imager::Expr->new(\%options)
or die Imager::Expr::error();
You will need to set an expression value and you may set any of the
following:
=over
=item *
constants
A hashref defining extra constants for expression parsing. The names
of the constants must be valid identifiers (/[^\W\d]\w*/) and the
values must be valid numeric constants (that Perl recognizes in
scalars).
Imager::Expr may define it's own constants (currently just pi.)
=item *
variables
A reference to an array of variable names. These are allocated
numeric registers starting from register zero.
=back
=for stopwords RPN
By default you can define a C<rpnexpr> key (which emulates RPN) or
C<expr> (an infix expression). It's also possible to write other
expression parsers that will use other keys. Only one expression key
should be defined.
=head2 Instance methods
The Imager::Expr::error() method is used to retrieve the error if the
expression object cannot be created.
=head2 Methods
Imager::Expr provides only a few simple methods meant for external use:
=for stopwords VM
=over
=item Imager::Expr->type_registered($keyword)
Returns true if the given expression type is available. The parameter
is the key supplied to the new() method.
if (Imager::Expr->type_registered('expr')) {
# use infix expressions
}
=item $expr->code()
Returns the compiled code.
=item $expr->nregs()
Returns a reference to the array of numeric registers.
=item $expr->cregs()
Returns a reference to the array of color registers.
=item $expr->dumpops()
Returns a string with the generated VM "machine code".
=item $expr->dumpcode()
Returns a string with the disassembled VM "machine code".
=back
=head2 Creating a new parser
I'll write this one day.
Methods used by parsers:
=over
=item compile
This is the main method you'll need to implement in a parser. See the
existing parsers for a guide.
It's supplied the following parameters:
=over
=item *
$expr - the expression to be parsed
=item *
$options - the options hash supplied to transform2.
=back
Return an array ref of array refs containing opcodes and operands.
=item @vars = $self->_variables()
A list (not a reference) of the input variables. This should be used
to allocate as many registers as there are variable as input
registers.
=item $self->error($message)
Set the return value of Imager::Expr::error()
=item @ops = $self->stack_to_reg(@stack_ops)
Converts marginally parsed RPN to register code.
=item assemble()
Called to convert op codes into byte code.
=item numre()
Returns a regular expression that matches floating point numbers.
=item optimize()
Optimizes the assembly code, including attempting common subexpression
elimination and strength reducing division by a constant into
multiplication by a constant.
=item register_type()
Called by a new expression parser implementation to register itself,
call as:
YourClassName->register_type('type code');
where type code is the parameter that will accept the expression.
=back
=head2 Future compatibility
Try to avoid doing your own optimization beyond literal folding - if
we add some sort of jump, the existing optimizer will need to be
rewritten, and any optimization you perform may well be broken too
(well, your code generation will probably be broken anyway <sigh>).
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

View File

@@ -0,0 +1,279 @@
package Imager::Expr::Assem;
use 5.006;
use strict;
use Imager::Expr;
use Imager::Regops;
our $VERSION = "1.004";
our @ISA = qw(Imager::Expr);
__PACKAGE__->register_type('assem');
sub compile {
my ($self, $expr, $opts) = @_;
my %nregs;
my @vars = $self->_variables();
my @nregs = (0) x @vars;
my @cregs;
my %vars;
@vars{@vars} = map { "r$_" } 0..$#vars;
my %labels;
my @ops;
my @msgs;
my $attr = \%Imager::Regops::Attr;
# initially produce [ $linenum, $result, $opcode, @parms ]
my $lineno = 0;
while ($expr =~ s/^([^\n]+)(?:\n|$)//) {
++$lineno;
my $line = $1;
$line =~ s/#.*//;
next if $line =~ /^\s*$/;
for my $op (split /;/, $line) {
if (my ($name, $type) = $op =~ /^\s*var\s+([^:]+):(\S+)\s*$/) {
if (exists $vars{$name}) {
push(@msgs, "$lineno: duplicate variable name '$name'");
next;
}
if ($type eq 'num' || $type eq 'n') {
$vars{$name} = 'r'.@nregs;
push(@nregs, undef);
next;
}
elsif ($type eq 'pixel' || $type eq 'p' || $type eq 'c') {
$vars{$name} = 'p'.@cregs;
push(@cregs, undef);
next;
}
push(@msgs, "$lineno: unknown variable type $type");
next;
}
# any statement can have a label
if ($op =~ s/^\s*(\w+):\s*//) {
if ($labels{$1}) {
push(@msgs,
"$lineno: duplicate label $1 (previous on $labels{$1}[1])");
next;
}
$labels{$1} = [ scalar @ops, $lineno ];
}
next if $op =~ /^\s*$/;
# jumps have special operand handling
if ($op =~ /^\s*jump\s+(\w+)\s*$/) {
push(@ops, [$lineno, "", "jump", $1]);
}
elsif (my ($code, $reg, $targ) =
($op =~ /^\s*(jumpz|jumpnz)\s+(\S+)\s+(\S+)\s*$/)) {
push(@ops, [$lineno, "", $code, $reg, $targ]);
}
elsif ($op =~ /^\s*print\s+(\S+)\s*/) {
push(@ops, [$lineno, "", 'print', $1 ]);
}
elsif ($op =~ /^\s*ret\s+(\S+)\s*/) {
push(@ops, [$lineno, "", 'ret', $1]);
}
elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*$//) {
# simple assignment
push(@ops, [$lineno, $1, "set", $2]);
}
elsif ($op =~ s/\s*(\S+)\s*=\s*(\S+)\s*//) {
# some normal ops finally
my ($result, $opcode) = ($1, $2);
unless ($attr->{$opcode}) {
push(@msgs, "$lineno: unknown operator $opcode");
next;
}
my @oper;
while ($op =~ s/(\S+)\s*//) {
push(@oper, $1);
}
push(@ops, [$lineno, $result, $opcode, @oper]);
}
else {
push(@msgs, "$lineno: invalid statement '$op'");
}
}
}
my $max_opr = $Imager::Regops::MaxOperands;
my $numre = $self->numre;
my $trans =
sub {
# translate a name/number to a <type><digits>
my ($name) = @_;
$name = $self->{constants}{$name}
if exists $self->{constants}{$name};
if ($vars{$name}) {
return $vars{$name};
}
elsif ($name =~ /^$numre$/) {
$vars{$name} = 'r'.@nregs;
push(@nregs, $name);
return $vars{$name};
}
else {
push(@msgs, "$lineno: undefined variable $name");
return '';
}
};
# now to translate symbols and so on
OP: for my $op (@ops) {
$lineno = shift @$op;
if ($op->[1] eq 'jump') {
unless (exists $labels{$op->[2]}) {
push(@msgs, "$lineno: unknown label $op->[2]");
next;
}
$op = [ 'jump', "j$labels{$op->[2]}[0]", (0) x $max_opr ];
}
elsif ($op->[1] =~ /^jump/) {
unless (exists $labels{$op->[3]}) {
push(@msgs, "$lineno: unknown label $op->[2]");
next;
}
$op = [ $op->[1], $trans->($op->[2]), "j$labels{$op->[3]}[0]",
(0) x ($max_opr-1) ];
}
elsif ($op->[1] eq 'print') {
$op = [ $op->[1], $trans->($op->[2]), (0) x $max_opr ];
}
elsif ($op->[1] eq 'ret') {
$op = [ 'ret', $trans->($op->[2]), (0) x $max_opr ];
}
else {
# a normal operator
my ($result, $name, @parms) = @$op;
if ($result =~ /^$numre$/) {
push(@msgs, "$lineno: target of operator cannot be a constant");
next;
}
$result = $trans->($result);
for my $parm (@parms) {
$parm = $trans->($parm);
}
push(@parms, (0) x ($max_opr-@parms));
$op = [ $op->[1], @parms, $result ];
}
}
# more validation than a real assembler
# not trying to solve the halting problem...
if (@ops && $ops[-1][0] ne 'ret' && $ops[-1][0] ne 'jump') {
push(@msgs, ": the last instruction must be ret or jump");
}
$self->{nregs} = \@nregs;
$self->{cregs} = \@cregs;
if (@msgs) {
$self->error(join("\n", @msgs));
return 0;
}
return \@ops;
}
1;
__END__
=head1 NAME
Imager::Expr::Assem - an assembler for producing code for the Imager
register machine
=head1 SYNOPSIS
use Imager::Expr::Assem;
my $expr = Imager::Expr->new(assem=>'...', ...)
=head1 DESCRIPTION
This module is a simple Imager::Expr compiler that compiles a
low-level language that has a nearly 1-to-1 relationship to the
internal representation used for compiled register machine code.
=head2 Syntax
Each line can contain multiple statements separated by semi-colons.
Anything after '#' in a line is ignored.
Types of statements:
=over 4
=item variable definition
=over 4
C<var> I<name>:I<type>
=back
defines variable I<name> to have I<type>, which can be any of C<n> or
C<num> for a numeric type or C<pixel>, C<p> or C<c> for a pixel or
color type.
Variable names cannot include white-space.
=item operators
Operators can be split into 3 basic types, those that have a result
value, those that don't and the null operator, eg. jump has no value.
The format for operators that return a value is typically:
=over 4
I<result> = I<operator> I<operand> ...
=back
and for those that don't return a value:
=over 4
I<operator> I<operand>
=back
where operator is any valid register machine operator, result is any
variable defined with C<var>, and operands are variables, constants or
literals, or for jump operators, labels.
The set operator can be simplified to:
=over 4
I<result> = I<operator>
=back
All operators maybe preceded by a label, which is any non-white-space
text immediately followed by a colon (':').
=back
=head1 BUGS
Note that the current optimizer may produce incorrect optimization for
your code, fortunately the optimizer will disable itself if you
include any jump operator in your code. A single jump to anywhere
after your final C<ret> operator can be used to disable the optimizer
without slowing down your code.
There's currently no high-level code generation that can generate code
with loops or real conditions.
=head1 SEE ALSO
Imager(3), F<transform.perl>, F<regmach.c>
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=cut

View File

@@ -0,0 +1,134 @@
package Imager::ExtUtils;
use 5.006;
use strict;
use File::Spec;
our $VERSION = "1.003";
=head1 NAME
Imager::ExtUtils - functions handy in writing Imager extensions
=head1 SYNOPSIS
# make Imager easier to use with Inline
# perldoc Imager::Inline
use Inline with => 'Imager';
=head1 DESCRIPTION
=over
=item base_dir
Returns the base directory where Imager is installed.
=cut
# figure out where Imager is installed
sub base_dir {
for my $inc_dir (@INC) {
if (-e "$inc_dir/Imager.pm") {
my $base_dir = $inc_dir;
unless (File::Spec->file_name_is_absolute($base_dir)) {
$base_dir = File::Spec->rel2abs($base_dir);
}
return $base_dir;
}
}
die "Cannot locate an installed Imager!";
}
=item inline_config
Implements Imager's Inline::C C<with> hook.
=cut
sub inline_config {
my ($class) = @_;
my $base = base_dir();
return
{
INC => $class->includes,
TYPEMAPS => $class->typemap,
AUTO_INCLUDE => <<CODE,
/* Inserted by Imager $Imager::VERSION */
#include "imext.h"
#include "imperl.h"
DEFINE_IMAGER_CALLBACKS;
CODE
BOOT => 'PERL_INITIALIZE_IMAGER_CALLBACKS;',
FILTERS => \&_inline_filter,
};
}
my @inline_replace =
qw(
Imager::ImgRaw
Imager::Color::Float
Imager::Color
Imager::IO
);
my %inline_replace =
map { (my $tmp = $_) =~ s/::/__/g; $_ => $tmp } @inline_replace;
my $inline_replace_re = "\\b(" . join('|', @inline_replace) . ")\\b";
sub _inline_filter {
my $code = shift;
$code =~ s/$inline_replace_re/$inline_replace{$1}/g;
$code;
}
=item includes
Returns -I options suitable for use with ExtUtils::MakeMaker's INC
option.
=cut
sub includes {
my $class = shift;
my $base = $class->base_dir();
"-I" . $base . '/Imager/include',
}
=item typemap
Returns the full path to Imager's installed typemap.
=cut
sub typemap {
my $class = shift;
my $base = $class->base_dir();
$base . '/Imager/typemap';
}
1;
__END__
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 REVISION
$Revision$
=head1 SEE ALSO
Imager, Imager::API, Imager::Inline, Imager::APIRef.
=cut

View File

@@ -0,0 +1,9 @@
package Imager::File::CUR;
use 5.006;
use strict;
our $VERSION = "1.000";
# all the work is done by Imager::File::ICO
use Imager::File::ICO;
1;

View File

@@ -0,0 +1,122 @@
package Imager::File::GIF;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.96";
require XSLoader;
XSLoader::load('Imager::File::GIF', $VERSION);
}
Imager->register_reader
(
type=>'gif',
single =>
sub {
my ($im, $io, %hsh) = @_;
if ($hsh{gif_consolidate}) {
if ($hsh{colors}) {
my $colors;
($im->{IMG}, $colors) =i_readgif_wiol( $io );
if ($colors) {
${ $hsh{colors} } = [ map { NC(@$_) } @$colors ];
}
}
else {
$im->{IMG} =i_readgif_wiol( $io );
}
}
else {
my $page = $hsh{page};
defined $page or $page = 0;
$im->{IMG} = i_readgif_single_wiol($io, $page);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
if ($hsh{colors}) {
${ $hsh{colors} } = [ $im->getcolors ];
}
return $im;
}
},
multiple =>
sub {
my ($io, %hsh) = @_;
my @imgs = i_readgif_multi_wiol($io);
unless (@imgs) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return map bless({ IMG => $_, ERRSTR => undef }, "Imager"), @imgs;
},
);
Imager->register_writer
(
type=>'gif',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->_set_opts(\%hsh, "i_", $im);
$im->_set_opts(\%hsh, "gif_", $im);
unless (i_writegif_wiol($io, \%hsh, $im->{IMG})) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($class, $io, $opts, @ims) = @_;
Imager->_set_opts($opts, "gif_", @ims);
my @work = map $_->{IMG}, @ims;
unless (i_writegif_wiol($io, $opts, @work)) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return 1;
},
);
__END__
=head1 NAME
Imager::File::GIF - read and write GIF files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.gif")
or die $img->errstr;
$img->write(file => "foo.gif")
or die $img->errstr;
=head1 DESCRIPTION
Imager's GIF support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

View File

@@ -0,0 +1,176 @@
package Imager::File::ICO;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.07";
require XSLoader;
XSLoader::load('Imager::File::ICO', $VERSION);
}
Imager->register_reader
(
type=>'ico',
single =>
sub {
my ($im, $io, %hsh) = @_;
my $masked =
exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
my $alpha_masked =
exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0;
$im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked,
$alpha_masked);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($io, %hsh) = @_;
my $masked =
exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
my @imgs = i_readico_multi($io, $masked);
unless (@imgs) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return map {
bless { IMG => $_, DEBUG => $Imager::DEBUG, ERRSTR => undef }, 'Imager'
} @imgs;
},
);
# the readers can read CUR files too
Imager->register_reader
(
type=>'cur',
single =>
sub {
my ($im, $io, %hsh) = @_;
my $masked =
exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
my $alpha_masked =
exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0;
$im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked,
$alpha_masked);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($io, %hsh) = @_;
my $masked =
exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
my @imgs = i_readico_multi($io, $masked);
unless (@imgs) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return map {
bless { IMG => $_, DEBUG => $Imager::DEBUG, ERRSTR => undef }, 'Imager'
} @imgs;
},
);
Imager->register_writer
(
type=>'ico',
single =>
sub {
my ($im, $io, %hsh) = @_;
unless (i_writeico_wiol($io, $im->{IMG})) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($class, $io, $opts, @images) = @_;
if (!i_writeico_multi_wiol($io, map $_->{IMG}, @images)) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return 1;
},
);
Imager->register_writer
(
type=>'cur',
single =>
sub {
my ($im, $io, %hsh) = @_;
unless (i_writecur_wiol($io, $im->{IMG})) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($class, $io, $opts, @images) = @_;
if (!i_writecur_multi_wiol($io, map $_->{IMG}, @images)) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return 1;
},
);
1;
__END__
=head1 NAME
Imager::File::ICO - read MS Icon files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.ico")
or die $img->errstr;
my @imgs = Imager->read_multi(file => "foo.ico")
or die Imager->errstr;
$img->write(file => "foo.ico")
or die $img->errstr;
Imager->write_multi({ file => "foo.ico" }, @imgs)
or die Imager->errstr;
=head1 DESCRIPTION
Imager's MS Icon support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

View File

@@ -0,0 +1,82 @@
package Imager::File::JPEG;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.94";
require XSLoader;
XSLoader::load('Imager::File::JPEG', $VERSION);
}
Imager->register_reader
(
type=>'jpeg',
single =>
sub {
my ($im, $io, %hsh) = @_;
($im->{IMG},$im->{IPTCRAW}) = i_readjpeg_wiol( $io );
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
Imager->register_writer
(
type=>'jpeg',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->_set_opts(\%hsh, "i_", $im);
$im->_set_opts(\%hsh, "jpeg_", $im);
$im->_set_opts(\%hsh, "exif_", $im);
my $quality = $hsh{jpegquality};
defined $quality or $quality = 75;
if ( !i_writejpeg_wiol($im->{IMG}, $io, $quality)) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
__END__
=head1 NAME
Imager::File::JPEG - read and write JPEG files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.jpg")
or die $img->errstr;
$img->write(file => "foo.jpg")
or die $img->errstr;
=head1 DESCRIPTION
Imager's JPEG support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

View File

@@ -0,0 +1,79 @@
package Imager::File::PNG;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.95";
require XSLoader;
XSLoader::load('Imager::File::PNG', $VERSION);
}
Imager->register_reader
(
type=>'png',
single =>
sub {
my ($im, $io, %hsh) = @_;
my $flags = 0;
$hsh{png_ignore_benign_errors}
and $flags |= IMPNG_READ_IGNORE_BENIGN_ERRORS;
$im->{IMG} = i_readpng_wiol($io, $flags);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
Imager->register_writer
(
type=>'png',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->_set_opts(\%hsh, "i_", $im);
$im->_set_opts(\%hsh, "png_", $im);
unless (i_writepng_wiol($im->{IMG}, $io)) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
__END__
=head1 NAME
Imager::File::PNG - read and write PNG files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.png")
or die $img->errstr;
$img->write(file => "foo.png")
or die $img->errstr;
=head1 DESCRIPTION
Imager's PNG support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

View File

@@ -0,0 +1,82 @@
package Imager::File::SGI;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.05";
require XSLoader;
XSLoader::load('Imager::File::SGI', $VERSION);
}
Imager->register_reader
(
type=>'sgi',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->{IMG} = i_readsgi_wiol($io, $hsh{page} || 0);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
Imager->register_writer
(
type=>'sgi',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->_set_opts(\%hsh, "i_", $im);
$im->_set_opts(\%hsh, "sgi_", $im);
unless (i_writesgi_wiol($io, $im->{IMG})) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
);
__END__
=head1 NAME
Imager::File::ICO - read MS Icon files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.ico")
or die $img->errstr;
my @imgs = Imager->read_multi(file => "foo.ico")
or die Imager->errstr;
$img->write(file => "foo.ico")
or die $img->errstr;
Imager->write_multi({ file => "foo.ico" }, @imgs)
or die Imager->errstr;
=head1 DESCRIPTION
Imager's MS Icon support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

View File

@@ -0,0 +1,133 @@
package Imager::File::TIFF;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.92";
require XSLoader;
XSLoader::load('Imager::File::TIFF', $VERSION);
}
Imager->register_reader
(
type=>'tiff',
single =>
sub {
my ($im, $io, %hsh) = @_;
my $allow_incomplete = $hsh{allow_incomplete};
defined $allow_incomplete or $allow_incomplete = 0;
my $page = $hsh{page};
defined $page or $page = 0;
$im->{IMG} = i_readtiff_wiol($io, $allow_incomplete, $page);
unless ($im->{IMG}) {
$im->_set_error(Imager->_error_as_msg);
return;
}
return $im;
},
multiple =>
sub {
my ($io, %hsh) = @_;
my @imgs = i_readtiff_multi_wiol($io);
unless (@imgs) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return map bless({ IMG => $_, ERRSTR => undef }, "Imager"), @imgs;
},
);
Imager->register_writer
(
type=>'tiff',
single =>
sub {
my ($im, $io, %hsh) = @_;
$im->_set_opts(\%hsh, "i_", $im);
$im->_set_opts(\%hsh, "tiff_", $im);
$im->_set_opts(\%hsh, "exif_", $im);
if (defined $hsh{class} && $hsh{class} eq "fax") {
my $fax_fine = $hsh{fax_fine};
defined $fax_fine or $fax_fine = 1;
if (!i_writetiff_wiol_faxable($im->{IMG}, $io, $fax_fine)) {
$im->{ERRSTR} = Imager->_error_as_msg();
return undef;
}
}
else {
unless (i_writetiff_wiol($im->{IMG}, $io)) {
$im->_set_error(Imager->_error_as_msg);
return;
}
}
return $im;
},
multiple =>
sub {
my ($class, $io, $opts, @ims) = @_;
Imager->_set_opts($opts, "tiff_", @ims);
Imager->_set_opts($opts, "exif_", @ims);
my @work = map $_->{IMG}, @ims;
my $tiff_class = $opts->{class};
defined $tiff_class or $tiff_class = "";
my $result;
if ($tiff_class eq "fax") {
my $fax_fine = $opts->{fax_fine};
defined $fax_fine or $fax_fine = 1;
$result = i_writetiff_multi_wiol_faxable($io, $fax_fine, @work);
}
else {
$result = i_writetiff_multi_wiol($io, @work);
}
unless ($result) {
$class->_set_error($class->_error_as_msg);
return;
}
return 1;
},
);
__END__
=head1 NAME
Imager::File::TIFF - read and write TIFF files
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
$img->read(file=>"foo.tiff")
or die $img->errstr;
$img->write(file => "foo.tif")
or die $img->errstr;
=head1 DESCRIPTION
Imager's TIFF support is documented in L<Imager::Files>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files.
=cut

2076
database/perl/vendor/lib/Imager/Files.pod vendored Normal file

File diff suppressed because it is too large Load Diff

494
database/perl/vendor/lib/Imager/Fill.pm vendored Normal file
View File

@@ -0,0 +1,494 @@
package Imager::Fill;
use 5.006;
use strict;
our $VERSION = "1.013";
# this needs to be kept in sync with the array of hatches in fills.c
my @hatch_types =
qw/check1x1 check2x2 check4x4 vline1 vline2 vline4
hline1 hline2 hline4 slash1 slosh1 slash2 slosh2
grid1 grid2 grid4 dots1 dots4 dots16 stipple weave cross1 cross2
vlozenge hlozenge scalesdown scalesup scalesleft scalesright stipple2
tile_L stipple3/;
my %hatch_types;
@hatch_types{@hatch_types} = 0..$#hatch_types;
*_color = \&Imager::_color;
sub new {
my ($class, %hsh) = @_;
my $self = bless { }, $class;
$hsh{combine} = Imager->_combine($hsh{combine}, 0);
if ($hsh{solid}) {
my $solid = _color($hsh{solid});
if (UNIVERSAL::isa($solid, 'Imager::Color')) {
$self->{fill} =
Imager::i_new_fill_solid($solid, $hsh{combine});
}
elsif (UNIVERSAL::isa($solid, 'Imager::Color::Float')) {
$self->{fill} =
Imager::i_new_fill_solidf($solid, $hsh{combine});
}
else {
$Imager::ERRSTR = "solid isn't a color";
return undef;
}
}
elsif (defined $hsh{hatch}) {
$hsh{dx} ||= 0;
$hsh{dy} ||= 0;
$hsh{fg} ||= Imager::Color->new(0, 0, 0);
if (ref $hsh{hatch}) {
$hsh{cust_hatch} = pack("C8", @{$hsh{hatch}});
$hsh{hatch} = 0;
}
elsif ($hsh{hatch} =~ /\D/) {
unless (exists($hatch_types{$hsh{hatch}})) {
$Imager::ERRSTR = "Unknown hatch type $hsh{hatch}";
return undef;
}
$hsh{hatch} = $hatch_types{$hsh{hatch}};
}
my $fg = _color($hsh{fg});
if (UNIVERSAL::isa($fg, 'Imager::Color')) {
my $bg = _color($hsh{bg} || Imager::Color->new(255, 255, 255));
$self->{fill} =
Imager::i_new_fill_hatch($fg, $bg, $hsh{combine},
$hsh{hatch}, $hsh{cust_hatch},
$hsh{dx}, $hsh{dy});
}
elsif (UNIVERSAL::isa($fg, 'Imager::Color::Float')) {
my $bg = _color($hsh{bg} || Imager::Color::Float->new(1, 1, 1));
$self->{fill} =
Imager::i_new_fill_hatchf($fg, $bg, $hsh{combine},
$hsh{hatch}, $hsh{cust_hatch},
$hsh{dx}, $hsh{dy});
}
else {
$Imager::ERRSTR = "fg isn't a color";
return undef;
}
}
elsif (defined $hsh{fountain}) {
# make sure we track the filter's defaults
my $fount = $Imager::filters{fountain};
my $def = $fount->{defaults};
my $names = $fount->{names};
$hsh{ftype} = $hsh{fountain};
# process names of values
for my $name (keys %$names) {
if (defined $hsh{$name} && exists $names->{$name}{$hsh{$name}}) {
$hsh{$name} = $names->{$name}{$hsh{$name}};
}
}
# process defaults
%hsh = (%$def, %hsh);
my @parms = @{$fount->{callseq}};
shift @parms;
for my $name (@parms) {
unless (defined $hsh{$name}) {
$Imager::ERRSTR =
"required parameter '$name' not set for fountain fill";
return undef;
}
}
# check that the segments supplied is an array ref
unless (ref $hsh{segments} && $hsh{segments} =~ /ARRAY/) {
$Imager::ERRSTR =
"segments must be an array reference or Imager::Fountain object";
return;
}
# make sure the segments are specified with colors
my @segments;
for my $segment (@{$hsh{segments}}) {
my @new_segment = @$segment;
$_ = _color($_) or return for @new_segment[3,4];
push @segments, \@new_segment;
}
$self->{fill} =
Imager::i_new_fill_fount($hsh{xa}, $hsh{ya}, $hsh{xb}, $hsh{yb},
$hsh{ftype}, $hsh{repeat}, $hsh{combine}, $hsh{super_sample},
$hsh{ssample_param}, \@segments);
}
elsif (defined $hsh{image}) {
$hsh{xoff} ||= 0;
$hsh{yoff} ||= 0;
$self->{fill} =
Imager::i_new_fill_image($hsh{image}{IMG}, $hsh{matrix}, $hsh{xoff},
$hsh{yoff}, $hsh{combine});
$self->{DEPS} = [ $hsh{image}{IMG} ];
}
elsif (defined $hsh{type} && $hsh{type} eq "opacity") {
my $other_fill = delete $hsh{other};
unless (defined $other_fill) {
Imager->_set_error("'other' parameter required to create opacity fill");
return;
}
unless (ref $other_fill &&
eval { $other_fill->isa("Imager::Fill") }) {
# try to auto convert to a fill object
if (ref $other_fill && $other_fill =~ /HASH/) {
$other_fill = Imager::Fill->new(%$other_fill)
or return;
}
else {
undef $other_fill;
}
unless ($other_fill) {
Imager->_set_error("'other' parameter must be an Imager::Fill object to create an opacity fill");
return;
}
}
my $raw_fill = $other_fill->{fill};
my $opacity = delete $hsh{opacity};
defined $opacity or $opacity = 0.5; # some sort of default
$self->{fill} =
Imager::i_new_fill_opacity($raw_fill, $opacity);
$self->{DEPS} = [ $other_fill ]; # keep reference to old fill and its deps
}
else {
$Imager::ERRSTR = "No fill type specified";
warn "No fill type!";
return undef;
}
$self;
}
sub hatches {
return @hatch_types;
}
sub combines {
return Imager->combines;
}
1;
=head1 NAME
Imager::Fill - general fill types
=head1 SYNOPSIS
use Imager;
use Imager::Fill;
my $fill1 = Imager::Fill->new(solid=>$color, combine=>$combine);
my $fill2 = Imager::Fill->new(hatch=>'vline2', fg=>$color1, bg=>$color2,
dx=>$dx, dy=>$dy);
my $fill3 = Imager::Fill->new(fountain=>$type, ...);
my $fill4 = Imager::Fill->new(image=>$img, ...);
my $fill5 = Imager::Fill->new(type => "opacity", other => $fill,
opacity => ...);
=head1 DESCRIPTION
Creates fill objects for use by most filled area drawing functions.
All fills are created with the new method.
=over
=item new
my $fill = Imager::Fill->new(...);
The parameters depend on the type of fill being created. See below
for details.
=back
The currently available fills are:
=over
=item *
solid
=item *
hatch
=item *
fountain (similar to gradients in paint software)
=item *
image - fill with an image, possibly transformed
=item *
opacity - a lower opacity version of some other fill
=back
=head1 Common options
=over
=item combine
The way in which the fill data is combined with the underlying image.
See L<Imager::Draw/"Combine Types">.
=back
In general colors can be specified as L<Imager::Color> or
L<Imager::Color::Float> objects. The fill object will typically store
both types and convert from one to the other. If a fill takes 2 color
objects they should have the same type.
=head2 Solid fills
my $fill = Imager::Fill->new(solid=>$color, combine =>$combine)
Creates a solid fill, the only required parameter is C<solid> which
should be the color to fill with.
A translucent red fill:
my $red = Imager::Fill->new(solid => "FF000080", combine => "normal");
=head2 Hatched fills
my $fill = Imager::Fill->new(hatch=>$type, fg=>$fgcolor, bg=>$bgcolor,
dx=>$dx, $dy=>$dy);
Creates a hatched fill. You can specify the following keywords:
=over
=item *
C<hatch> - The type of hatch to perform, this can either be the
numeric index of the hatch (not recommended), the symbolic name of the
hatch, or an array of 8 integers which specify the pattern of the
hatch.
Hatches are represented as cells 8x8 arrays of bits, which limits their
complexity.
Current hatch names are:
=over
=item *
C<check1x1>, C<check2x2>, C<check4x4> - checkerboards at various sizes
=item *
C<vline1>, C<vline2>, C<vline4> - 1, 2, or 4 vertical lines per cell
=item *
C<hline1>, C<hline2>, C<hline4> - 1, 2, or 4 horizontal lines per cell
=item *
C<slash1>, C<slash2> - 1 or 2 / lines per cell.
=item *
C<slosh1>, C<slosh2> - 1 or 2 \ lines per cell
=item *
C<grid1>, C<grid2>, C<grid4> - 1, 2, or 4 vertical and horizontal
lines per cell
=item *
C<dots1>, C<dots4>, C<dots16> - 1, 4 or 16 dots per cell
=item *
C<stipple>, C<stipple2> - see the samples
=item *
C<weave> - I hope this one is obvious.
=item *
C<cross1>, C<cross2> - 2 densities of crosshatch
=item *
C<vlozenge>, C<hlozenge> - something like lozenge tiles
=item *
C<scalesdown>, C<scalesup>, C<scalesleft>, C<scalesright> - Vaguely
like fish scales in each direction.
=item *
C<tile_L> - L-shaped tiles
=back
=item *
C<fg>, C<bg> - The C<fg> color is rendered where bits are set in the
hatch, and the C<bg> where they are clear. If you use a transparent
C<fg> or C<bg>, and set combine, you can overlay the hatch onto an
existing image.
C<fg> defaults to black, C<bg> to white.
=item *
C<dx>, C<dy> - An offset into the hatch cell. Both default to zero.
=back
A blue and white 4-pixel check pattern:
my $fill = Imager::Fill->new(hatch => "check2x2", fg => "blue");
You can call Imager::Fill->hatches for a list of hatch names.
=head2 Fountain fills
my $fill = Imager::Fill->new(fountain=>$ftype,
xa=>$xa, ya=>$ya, xb=>$xb, yb=>$yb,
segments=>$segments, repeat=>$repeat, combine=>$combine,
super_sample=>$super_sample, ssample_param=>$ssample_param);
This fills the given region with a fountain fill. This is exactly the
same fill as the C<fountain> filter, but is restricted to the shape
you are drawing, and the fountain parameter supplies the fill type,
and is required.
A radial fill from white to transparent centered on (50, 50) with a 50
pixel radius:
use Imager::Fountain;
my $segs = Imager::Fountain->simple(colors => [ "FFFFFF", "FFFFFF00" ],
positions => [ 0, 1 ]);
my $fill = Imager::Fill->new(fountain => "radial", segments => $segs,
xa => 50, ya => 50, xb => 0, yb => 50,
combine => "normal");
=head2 Image Fills
my $fill = Imager::Fill->new(image=>$src, xoff=>$xoff, yoff=>$yoff,
matrix=>$matrix, combine => $combine);
Fills the given image with a tiled version of the given image. The
first non-zero value of C<xoff> or C<yoff> will provide an offset
along the given axis between rows or columns of tiles respectively.
The matrix parameter performs a co-ordinate transformation from the
co-ordinates in the target image to the fill image co-ordinates.
Linear interpolation is used to determine the fill pixel. You can use
the L<Imager::Matrix2d> class to create transformation matrices.
The matrix parameter will significantly slow down the fill.
# some image to act as a texture
my $txim = Imager->new(...);
# simple tiling
my $fill = Imager::Fill->new(image => $txim);
# tile with a vertical offset
my $fill = Imager::Fill->new(image => $txim, yoff => 10);
# tile with a horizontal offset
my $fill = Imager::Fill->new(image => $txim, xoff => 10);
# rotated
use Imager::Matrix2d;
my $fill = Imager::Fill->new(image => $txim,
matrix => Imager::Matrix2d->rotate(degrees => 20));
=head2 Opacity modification fill
my $fill = Imager::Fill->new(type => "opacity",
other => $fill, opacity => 0.25);
This can be used to make a fill that is a more translucent or opaque
version of an existing fill. This is intended for use where you
receive a fill object as a parameter and need to change the opacity.
Parameters:
=over
=item *
type => "opacity" - Required
=item *
other - the fill to produce a modified version of. This must be an
Imager::Fill object. Required.
=item *
opacity - multiplier for the source fill opacity. Default: 0.5.
=back
The source fills combine mode is used.
my $hatch = Imager::Fill->new(hatch => "check4x4", combine => "normal");
my $fill = Imager::Fill->new(type => "opacity", other => $hatch);
=head1 OTHER METHODS
=over
=item Imager::Fill->hatches
A list of all defined hatch names.
=item Imager::Fill->combines
A list of all combine types.
=back
=head1 FUTURE PLANS
I'm planning on adding the following types of fills:
=over
=item *
C<checkerboard> - combines 2 other fills in a checkerboard
=item *
C<combine> - combines 2 other fills using the levels of an image
=item *
C<regmach> - uses the transform2() register machine to create fills
=back
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 SEE ALSO
Imager(3)
=cut

View File

@@ -0,0 +1,25 @@
package Imager::Filter::DynTest;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.03";
require XSLoader;
XSLoader::load('Imager::Filter::DynTest', $VERSION);
}
sub _lin_stretch {
my %hsh = @_;
lin_stretch($hsh{image}, $hsh{a}, $hsh{b});
}
Imager->register_filter(type=>'lin_stretch',
callsub => \&_lin_stretch,
defaults => { a => 0, b => 255 },
callseq => [ qw/image a b/ ]);
1;

View File

@@ -0,0 +1,50 @@
package Imager::Filter::Flines;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.04";
require XSLoader;
XSLoader::load('Imager::Filter::Flines', $VERSION);
}
Imager->register_filter(type=>'flines',
callsub => sub { my %hsh = @_; flines($hsh{image}) },
defaults => {},
callseq => [ 'image' ] );
1;
__END__
=head1 NAME
Imager::Filter::Flines - dim alternate lines to emulate a video display
=head1 SYNOPSIS
use Imager;
use Imager::Filter::Flines;
$img->filter(type=>'flines');
=head1 DESCRIPTION
This is an adaption of the C<flines> dynamically loadable filter
provided in dynfilt/ in previous releases of Imager.
This filter has no parameters.
=head1 AUTHOR
Original by Arnar M. Hrafnkelsson.
Adapted by Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Filters.
=cut

View File

@@ -0,0 +1,84 @@
package Imager::Filter::Mandelbrot;
use 5.006;
use strict;
use Imager;
BEGIN {
our $VERSION = "0.05";
require XSLoader;
XSLoader::load('Imager::Filter::Mandelbrot', $VERSION);
}
sub _mandelbrot {
my %hsh = @_;
mandelbrot($hsh{image}, $hsh{minx}, $hsh{miny}, $hsh{maxx}, $hsh{maxy}, $hsh{maxiter});
}
my %defaults =
(
minx => -2.5,
maxx => 1.5,
miny => -1.5,
maxy => 1.5,
maxiter => 256,
);
my @callseq = qw/image minx miny maxx maxy maxiter/;
Imager->register_filter(type=>'mandelbrot',
callsub => \&_mandelbrot,
defaults => \%defaults,
callseq => \@callseq);
1;
__END__
=head1 NAME
Imager::Filter::Mandelbrot - filter that renders the Mandelbrot set.
=head1 SYNOPSIS
use Imager;
use Imager::Filter::Mandelbrot;
$img->filter(type=>'mandelbrot', ...);
=head1 DESCRIPTION
This is a expansion of the C<mandelbrot> dynamically loadable filter
provided in C<dynfilt> in previous releases of Imager.
Valid filter parameters are:
=over
=item *
C<minx>, C<maxx> - the range of x values to render. Defaults: -2.5, 1.5.
=item *
C<miny>, C<maxy> - the range of y values to render. Defaults: -1.5, 1.5
=item *
C<maxiter> - the maximum number of iterations to perform when checking
if the sequence tend towards infinity.
=back
=head1 AUTHOR
Original by Arnar M. Hrafnkelsson.
Adapted and expanded by Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Filters.
=cut

View File

@@ -0,0 +1,823 @@
=head1 NAME
Imager::Filters - Entire Image Filtering Operations
=head1 SYNOPSIS
use Imager;
$img = ...;
$img->filter(type=>'autolevels');
$img->filter(type=>'autolevels', lsat=>0.2);
$img->filter(type=>'turbnoise')
# and lots of others
load_plugin("dynfilt/dyntest.so")
or die "unable to load plugin\n";
$img->filter(type=>'lin_stretch', a=>35, b=>200);
unload_plugin("dynfilt/dyntest.so")
or die "unable to load plugin\n";
$out = $img->difference(other=>$other_img);
=head1 DESCRIPTION
Filters are operations that have similar calling interface.
=over
=item filter()
Parameters:
=over
=item *
type - the type of filter, see L</Types of Filters>.
=item *
many other possible parameters, see L</Types of Filters> below.
=back
Returns the invocant (C<$self>) on success, returns a false value on
failure. You can call C<< $self->errstr >> to determine the cause of
the failure.
$self->filter(type => $type, ...)
or die $self->errstr;
=back
=head2 Types of Filters
Here is a list of the filters that are always available in Imager.
This list can be obtained by running the C<filterlist.perl> script
that comes with the module source.
Filter Arguments Default value
autolevels lsat 0.1
usat 0.1
autolevels_skew lsat 0.1
usat 0.1
skew 0
bumpmap bump lightx lighty
elevation 0
st 2
bumpmap_complex bump
channel 0
tx 0
ty 0
Lx 0.2
Ly 0.4
Lz -1
cd 1.0
cs 40.0
n 1.3
Ia (0 0 0)
Il (255 255 255)
Is (255 255 255)
contrast intensity
conv coef
fountain xa ya xb yb
ftype linear
repeat none
combine none
super_sample none
ssample_param 4
segments(see below)
gaussian stddev
gaussian2 stddevX
stddevY
gradgen xo yo colors
dist 0
hardinvert
hardinvertall
mosaic size 20
noise amount 3
subtype 0
postlevels levels 10
radnoise xo 100
yo 100
ascale 17.0
rscale 0.02
turbnoise xo 0.0
yo 0.0
scale 10.0
unsharpmask stddev 2.0
scale 1.0
watermark wmark
pixdiff 10
tx 0
ty 0
All parameters must have some value but if a parameter has a default
value it may be omitted when calling the filter function.
Every one of these filters modifies the image in place.
If none of the filters here do what you need, the
L<Imager::Engines/transform()> or L<Imager::Engines/transform2()>
function may be useful.
=for stopwords
autolevels bumpmap bumpmap_complex conv gaussian hardinvert hardinvertall
radnoise turbnoise unsharpmask gradgen postlevels
A reference of the filters follows:
=over
=item C<autolevels>
Scales the luminosity of the image so that the luminosity will cover
the possible range for the image. C<lsat> and C<usat> truncate the
range by the specified fraction at the top and bottom of the range
respectively.
# increase contrast, losing little detail
$img->filter(type=>"autolevels")
or die $img->errstr;
The method used here is typically called L<Histogram
Equalization|http://en.wikipedia.org/wiki/Histogram_equalization>.
=item C<autolevels_skew>
Scales the value of each channel so that the values in the image will
cover the whole possible range for the channel. C<lsat> and C<usat>
truncate the range by the specified fraction at the top and bottom of
the range respectively.
# increase contrast per channel, losing little detail
$img->filter(type=>"autolevels_skew")
or die $img->errstr;
# increase contrast, losing 20% of highlight at top and bottom range
$img->filter(type=>"autolevels", lsat=>0.2, usat=>0.2)
or die $img->errstr;
This filter was the original C<autolevels> filter, but it's typically
useless due to the significant color skew it can produce.
=item C<bumpmap>
uses the channel C<elevation> image C<bump> as a bump map on your
image, with the light at (C<lightx>, C<lightty>), with a shadow length
of C<st>.
$img->filter(type=>"bumpmap", bump=>$bumpmap_img,
lightx=>10, lighty=>10, st=>5)
or die $img->errstr;
=item C<bumpmap_complex>
uses the channel C<channel> image C<bump> as a bump map on your image.
If C<< Lz < 0 >> the three L parameters are considered to be the
direction of the light. If C<< Lz > 0 >> the L parameters are
considered to be the light position. C<Ia> is the ambient color,
C<Il> is the light color, C<Is> is the color of specular highlights.
C<cd> is the diffuse coefficient and C<cs> is the specular
coefficient. C<n> is the shininess of the surface.
$img->filter(type=>"bumpmap_complex", bump=>$bumpmap_img)
or die $img->errstr;
=item C<contrast>
scales each channel by C<intensity>. Values of C<intensity> < 1.0
will reduce the contrast.
# higher contrast
$img->filter(type=>"contrast", intensity=>1.3)
or die $img->errstr;
# lower contrast
$img->filter(type=>"contrast", intensity=>0.8)
or die $img->errstr;
=item C<conv>
performs 2 1-dimensional convolutions on the image using the values
from C<coef>. C<coef> should be have an odd length and the sum of the
coefficients must be non-zero.
# sharper
$img->filter(type=>"conv", coef=>[-0.5, 2, -0.5 ])
or die $img->errstr;
# blur
$img->filter(type=>"conv", coef=>[ 1, 2, 1 ])
or die $img->errstr;
# error
$img->filter(type=>"conv", coef=>[ -0.5, 1, -0.5 ])
or die $img->errstr;
=item C<fountain>
renders a fountain fill, similar to the gradient tool in most paint
software. The default fill is a linear fill from opaque black to
opaque white. The points C<A(Cxa, ya)> and C<B(xb, yb)> control the
way the fill is performed, depending on the C<ftype> parameter:
=for stopwords ramping
=over
=item C<linear>
the fill ramps from A through to B.
=item C<bilinear>
the fill ramps in both directions from A, where AB defines the length
of the gradient.
=item C<radial>
A is the center of a circle, and B is a point on it's circumference.
The fill ramps from the center out to the circumference.
=item C<radial_square>
A is the center of a square and B is the center of one of it's sides.
This can be used to rotate the square. The fill ramps out to the
edges of the square.
=item C<revolution>
A is the center of a circle and B is a point on its circumference. B
marks the 0 and 360 point on the circle, with the fill ramping
clockwise.
=item C<conical>
A is the center of a circle and B is a point on it's circumference. B
marks the 0 and point on the circle, with the fill ramping in both
directions to meet opposite.
=back
The C<repeat> option controls how the fill is repeated for some
C<ftype>s after it leaves the AB range:
=over
=item C<none>
no repeats, points outside of each range are treated as if they were
on the extreme end of that range.
=item C<sawtooth>
the fill simply repeats in the positive direction
=item C<triangle>
the fill repeats in reverse and then forward and so on, in the
positive direction
=item C<saw_both>
the fill repeats in both the positive and negative directions (only
meaningful for a linear fill).
=item C<tri_both>
as for triangle, but in the negative direction too (only meaningful
for a linear fill).
=back
By default the fill simply overwrites the whole image (unless you have
parts of the range 0 through 1 that aren't covered by a segment), if
any segments of your fill have any transparency, you can set the
I<combine> option to 'normal' to have the fill combined with the
existing pixels. See the description of I<combine> in L<Imager::Fill>.
If your fill has sharp edges, for example between steps if you use
repeat set to 'triangle', you may see some aliased or ragged edges.
You can enable super-sampling which will take extra samples within the
pixel in an attempt anti-alias the fill.
The possible values for the super_sample option are:
=over
=item C<none>
no super-sampling is done
=item C<grid>
a square grid of points are sampled. The number of points sampled is
the square of ceil(0.5 + sqrt(ssample_param)).
=item C<random>
a random set of points within the pixel are sampled. This looks
pretty bad for low ssample_param values.
=item C<circle>
the points on the radius of a circle within the pixel are sampled.
This seems to produce the best results, but is fairly slow (for now).
=back
You can control the level of sampling by setting the ssample_param
option. This is roughly the number of points sampled, but depends on
the type of sampling.
The segments option is an arrayref of segments. You really should use
the L<Imager::Fountain> class to build your fountain fill. Each
segment is an array ref containing:
=over
=item C<start>
a floating point number between 0 and 1, the start of the range of
fill parameters covered by this segment.
=item C<middle>
a floating point number between start and end which can be used to
push the color range towards one end of the segment.
=item C<end>
a floating point number between 0 and 1, the end of the range of fill
parameters covered by this segment. This should be greater than
start.
=item C<c0>
=item C<c1>
The colors at each end of the segment. These can be either
Imager::Color or Imager::Color::Float objects.
=item segment type
The type of segment, this controls the way the fill parameter varies
over the segment. 0 for linear, 1 for curved (unimplemented), 2 for
sine, 3 for sphere increasing, 4 for sphere decreasing.
=item color type
The way the color varies within the segment, 0 for simple RGB, 1 for
hue increasing and 2 for hue decreasing.
=back
Don't forget to use Imager::Fountain instead of building your own.
Really. It even loads GIMP gradient files.
# build the gradient the hard way - linear from black to white,
# then back again
my @simple =
(
[ 0, 0.25, 0.5, 'black', 'white', 0, 0 ],
[ 0.5. 0.75, 1.0, 'white', 'black', 0, 0 ],
);
# across
my $linear = $img->copy;
$linear->filter(type => "fountain",
ftype => 'linear',
repeat => 'sawtooth',
segments => \@simple,
xa => 0,
ya => $linear->getheight / 2,
xb => $linear->getwidth - 1,
yb => $linear->getheight / 2)
or die $linear->errstr;
# around
my $revolution = $img->copy;
$revolution->filter(type => "fountain",
ftype => 'revolution',
segments => \@simple,
xa => $revolution->getwidth / 2,
ya => $revolution->getheight / 2,
xb => $revolution->getwidth / 2,
yb => 0)
or die $revolution->errstr;
# out from the middle
my $radial = $img->copy;
$radial->filter(type => "fountain",
ftype => 'radial',
segments => \@simple,
xa => $im->getwidth / 2,
ya => $im->getheight / 2,
xb => $im->getwidth / 2,
yb => 0)
or die $radial->errstr;
=for stopwords Gaussian
=item C<gaussian>
performs a Gaussian blur of the image, using C<stddev> as the standard
deviation of the curve used to combine pixels, larger values give
bigger blurs. For a definition of Gaussian Blur, see:
http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node99.html
Values of C<stddev> around 0.5 provide a barely noticeable blur,
values around 5 provide a very strong blur.
# only slightly blurred
$img->filter(type=>"gaussian", stddev=>0.5)
or die $img->errstr;
# more strongly blurred
$img->filter(type=>"gaussian", stddev=>5)
or die $img->errstr;
=item C<gaussian2>
performs a Gaussian blur of the image, using C<stddevX>, C<stddevY> as the
standard deviation of the curve used to combine pixels on the X and Y axis,
respectively. Larger values give bigger blurs. For a definition of Gaussian
Blur, see:
http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node99.html
Values of C<stddevX> or C<stddevY> around 0.5 provide a barely noticeable blur,
values around 5 provide a very strong blur.
# only slightly blurred
$img->filter(type=>"gaussian2", stddevX=>0.5, stddevY=>0.5)
or die $img->errstr;
# blur an image in the Y axis
$img->filter(type=>"gaussian", stddevX=>0, stddevY=>5 )
or die $img->errstr;
=item C<gradgen>
renders a gradient, with the given I<colors> at the corresponding
points (x,y) in C<xo> and C<yo>. You can specify the way distance is
measured for color blending by setting C<dist> to 0 for Euclidean, 1
for Euclidean squared, and 2 for Manhattan distance.
$img->filter(type="gradgen",
xo=>[ 10, 50, 10 ],
yo=>[ 10, 50, 50 ],
colors=>[ qw(red blue green) ]);
=item C<hardinvert>
X<filters, hardinvert>X<hardinvert>
inverts the image, black to white, white to black. All color channels
are inverted, excluding the alpha channel if any.
$img->filter(type=>"hardinvert")
or die $img->errstr;
=item C<hardinvertall>
X<filters, hardinvertall>X<hardinvertall>
inverts the image, black to white, white to black. All channels are
inverted, including the alpha channel if any.
$img->filter(type=>"hardinvertall")
or die $img->errstr;
=item C<mosaic>
produces averaged tiles of the given C<size>.
$img->filter(type=>"mosaic", size=>5)
or die $img->errstr;
=item C<noise>
adds noise of the given C<amount> to the image. If C<subtype> is
zero, the noise is even to each channel, otherwise noise is added to
each channel independently.
# monochrome noise
$img->filter(type=>"noise", amount=>20, subtype=>0)
or die $img->errstr;
# color noise
$img->filter(type=>"noise", amount=>20, subtype=>1)
or die $img->errstr;
=for stopwords Perlin
=item C<radnoise>
renders radiant Perlin turbulent noise. The center of the noise is at
(C<xo>, C<yo>), C<ascale> controls the angular scale of the noise ,
and C<rscale> the radial scale, higher numbers give more detail.
$img->filter(type=>"radnoise", xo=>50, yo=>50,
ascale=>1, rscale=>0.02)
or die $img->errstr;
=item C<postlevels>
alters the image to have only C<levels> distinct level in each
channel.
$img->filter(type=>"postlevels", levels=>10)
or die $img->errstr;
=item C<turbnoise>
renders Perlin turbulent noise. (C<xo>, C<yo>) controls the origin of
the noise, and C<scale> the scale of the noise, with lower numbers
giving more detail.
$img->filter(type=>"turbnoise", xo=>10, yo=>10, scale=>10)
or die $img->errstr;
=for stopwords unsharp
=item C<unsharpmask>
performs an unsharp mask on the image. This increases the contrast of
edges in the image.
This is the result of subtracting a Gaussian blurred version of the
image from the original. C<stddev> controls the C<stddev> parameter
of the Gaussian blur. Each output pixel is:
in + scale * (in - blurred)
eg.
$img->filter(type=>"unsharpmask", stddev=>1, scale=>0.5)
or die $img->errstr;
C<unsharpmark> has the following parameters:
=for stopwords GIMP GIMP's
=over
=item *
C<stddev> - this is equivalent to the C<Radius> value in the GIMP's
unsharp mask filter. This controls the size of the contrast increase
around edges, larger values will remove fine detail. You should
probably experiment on the types of images you plan to work with.
Default: 2.0.
=item *
C<scale> - controls the strength of the edge enhancement, equivalent
to I<Amount> in the GIMP's unsharp mask filter. Default: 1.0.
=back
=item C<watermark>
applies C<wmark> as a watermark on the image with strength C<pixdiff>,
with an origin at (C<tx>, C<ty>)
$img->filter(type=>"watermark", tx=>10, ty=>50,
wmark=>$wmark_image, pixdiff=>50)
or die $img->errstr;
=back
A demonstration of most of the filters can be found at:
http://www.develop-help.com/imager/filters.html
=head2 External Filters
As of Imager 0.48 you can create perl or XS based filters and hook
them into Imager's filter() method:
=over
=item register_filter()
Registers a filter so it is visible via Imager's filter() method.
Imager->register_filter(type => 'your_filter',
defaults => { parm1 => 'default1' },
callseq => [ qw/image parm1/ ],
callsub => \&your_filter);
$img->filter(type=>'your_filter', parm1 => 'something');
The following parameters are needed:
=over
=item *
C<type> - the type value that will be supplied to filter() to use your
filter.
=item *
C<defaults> - a hash of defaults for the filter's parameters
=item *
C<callseq> - a reference to an array of required parameter names.
=item *
C<callsub> - a code reference called to execute your filter. The
parameters passed to filter() are supplied as a list of parameter
name, value ... which can be assigned to a hash.
The special parameters C<image> and C<imager> are supplied as the low
level image object from $self and $self itself respectively.
The function you supply must modify the image in place.
To indicate an error, die with an error message followed by a
newline. C<filter()> will store the error message as the C<errstr()>
for the invocant and return false to indicate failure.
sub my_filter {
my %opts = @_;
_is_valid($opts{myparam})
or die "myparam invalid!\n";
# actually do the filtering...
}
=back
See L<Imager::Filter::Mandelbrot> for an example.
=back
=for stopwords DSOs
=head2 Plug-ins
The plug in interface is deprecated. Please use the Imager API, see
L<Imager::API> and L</External Filters> for details
It is possible to add filters to the module without recompiling Imager
itself. This is done by using DSOs (Dynamic shared object) available
on most systems. This way you can maintain your own filters and not
have to have it added to Imager, or worse patch every new version of
Imager. Modules can be loaded AND UNLOADED at run time. This means
that you can have a server/daemon thingy that can do something like:
load_plugin("dynfilt/dyntest.so")
or die "unable to load plugin\n";
$img->filter(type=>'lin_stretch', a=>35, b=>200);
unload_plugin("dynfilt/dyntest.so")
or die "unable to load plugin\n";
Someone decides that the filter is not working as it should -
F<dyntest.c> can be modified and recompiled, and then reloaded:
load_plugin("dynfilt/dyntest.so")
or die "unable to load plugin\n";
$img->filter(%hsh);
=for stopwords Linux Solaris HPUX OpenBSD FreeBSD TRU64 OSF1 AIX Win32 OS X
Note: This has been tested successfully on the following systems:
Linux, Solaris, HPUX, OpenBSD, FreeBSD, TRU64/OSF1, AIX, Win32, OS X.
=over
=item load_plugin()
This is a function, not a method, exported by default. You should
import this function explicitly for future compatibility if you need
it.
Accepts a single parameter, the name of a shared library file to load.
Returns true on success. Check Imager->errstr on failure.
=item unload_plugin()
This is a function, not a method, which is exported by default. You
should import this function explicitly for future compatibility if you
need it.
Accepts a single parameter, the name of a shared library to unload.
This library must have been previously loaded by load_plugin().
Returns true on success. Check Imager->errstr on failure.
=back
A few example plug-ins are included and built (but not installed):
=over
=item *
F<plugins/dyntest.c> - provides the C<null> (no action) filter, and
C<lin_stretch> filters. C<lin_stretch> stretches sample values
between C<a> and C<b> out to the full sample range.
=item *
F<plugins/dt2.c> - provides the C<html_art> filter that writes the
image to the HTML fragment file supplied in C<fname> as a HTML table.
=item *
F<plugins/flines.c> - provides the C<flines> filter that dims
alternate lines to emulate an old CRT display.
L<Imager::Filter::Flines> provides the same functionality.
=item *
F<plugins/mandelbrot.c> - provides the C<mandelbrot> filter that
renders the Mandelbrot set within the given range of x [-2, 0.5) and y
[-1.25, 1,25). L<Imager::Filter::Mandelbrot> provides a more flexible
Mandelbrot set renderer.
=back
=head2 Image Difference
=over
=item difference()
You can create a new image that is the difference between 2 other images.
my $diff = $img->difference(other=>$other_img);
For each pixel in $img that is different to the pixel in $other_img,
the pixel from $other_img is given, otherwise the pixel is transparent
black.
This can be used for debugging image differences ("Where are they
different?"), and for optimizing animated GIFs.
Note that $img and $other_img must have the same number of channels.
The width and height of $diff will be the minimum of each of the width
and height of $img and $other_img.
Parameters:
=over
=item *
C<other> - the other image object to compare against
=item *
C<mindist> - the difference between corresponding samples must be
greater than C<mindist> for the pixel to be considered different. So
a value of zero returns all different pixels, not all pixels. Range:
0 to 255 inclusive. Default: 0.
For large sample images this is scaled down to the range 0 .. 1.
=back
=back
=head1 AUTHOR
Arnar M. Hrafnkelsson, Tony Cook <tonyc@cpan.org>.
=head1 SEE ALSO
Imager, Imager::Filter::Flines, Imager::Filter::Mandelbrot
=head1 REVISION
$Revision$
=cut

1097
database/perl/vendor/lib/Imager/Font.pm vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,282 @@
package Imager::Font::BBox;
use 5.006;
use strict;
our $VERSION = "1.007";
=head1 NAME
Imager::Font::BBox - objects representing the bounding box of a string.
=head1 SYNOPSIS
use Imager::Font;
# get the object
my $font = Imager::Font->new(...);
my $bbox = $font->bounding_box(string=>$text, size=>$size);
# methods
my $start = $bbox->start_offset;
my $left_bearing = $bbox->left_bearing;
my $right_bearing = $bbox->right_bearing;
my $end = $bbox->end_offset;
my $gdescent = $box->global_descent;
my $gascent = $bbox->global_ascent;
my $ascent = $bbox->ascent;
my $decent = $bbox->descent;
my $total_width = $bbox->total_width;
my $fheight = $bbox->font_height;
my $theight = $bbox->text_height;
my $display_width = $bbox->display_width;
=head1 DESCRIPTION
Objects of this class are returned by the Imager::Font bounding_box()
method when it is called in scalar context.
This will hopefully make the information from this method more
accessible.
=head1 METHODS
=over
=item start_offset()
=item neg_width
=item left_bearing
Returns the horizontal offset from the selected drawing location to
the left edge of the first character drawn. If this is positive, the
first glyph is to the right of the drawing location.
The alias neg_width() is present to match the bounding_box()
documentation for list context.
The alias left_bearing() is present to match font terminology.
=cut
sub start_offset {
return $_[0][0];
}
sub neg_width {
return $_[0][0];
}
sub left_bearing {
return $_[0][0];
}
=item advance_width()
The advance width of the string, if the driver supports that,
otherwise the same as end_offset.
=cut
sub advance_width {
my $self = shift;
@$self > 6 ? $self->[6] : $self->[2];
}
=item right_bearing
The distance from the right of the last glyph to the end of the advance
point.
If the glyph overflows the right side of the advance width this value
is negative.
=cut
sub right_bearing {
my $self = shift;
@$self >= 8 && return $self->[7]; # driver gives it to us
# otherwise the closest we have is the difference between the
# end_pos and advance_width
return $self->advance_width - $self->pos_width;
}
=item display_width
The distance from the left-most pixel of the left-most glyph to the
right-most pixel of the right-most glyph.
Equals advance_width - left_bearing - right_bearing (and implemented
that way.)
=cut
sub display_width {
my ($self) = @_;
$self->advance_width - $self->left_bearing - $self->right_bearing;
}
=item global_descent()
The lowest position relative to the font baseline that any character
in the font reaches in the character cell. Normally negative.
At least one font we've seen has reported a positive number for this.
=cut
sub global_descent {
return $_[0][1];
}
=item global_ascent()
The highest position relative to the font baseline that any character
in the font reaches in the character cell. Normally positive.
=cut
sub global_ascent {
return $_[0][3];
}
=item descent()
The lowest position relative to the font baseline that any character
in the supplied string reaches. Negative when any character's glyph
reaches below the baseline.
=cut
sub descent {
return $_[0][4];
}
=item ascent()
The highest position relative to the font baseline that any character
in the supplied string reaches. Positive if any character's glyph
reaches above the baseline.
=cut
sub ascent {
return $_[0][5];
}
=item font_height()
The maximum displayed height of any string using this font.
=cut
sub font_height {
my $self = shift;
$self->global_ascent - $self->global_descent;
}
=item text_height()
The displayed height of the supplied string.
=cut
sub text_height {
my $self = shift;
$self->ascent - $self->descent;
}
=back
=head1 OBSOLETE METHODS
These methods include bugs kept for backwards compatibility and
shouldn't be used in new code.
=over
=item total_width()
The total displayed width of the string.
New code should use display_width().
This depends on end_offset(), and is limited by it's backward
compatibility.
=cut
sub total_width {
my $self = shift;
$self->end_offset - $self->start_offset;
}
=item end_offset
=item pos_width
The offset from the selected drawing location to the right edge of the
last character drawn. Should always be positive.
You can use the alias pos_width() if you are used to the
bounding_box() documentation for list context.
For backwards compatibility this method returns the maximum of the
advance width and the offset of the right edge of the last glyph.
=cut
sub end_offset {
return $_[0][2];
}
sub pos_width {
return $_[0][2];
}
=back
=head1 INTERNAL FUNCTIONS
=over
=item new(...)
Called by Imager::Font->bounding_box() to create the object.
=cut
sub new {
my $class = shift;
return bless [ @_ ], $class;
}
=back
=head1 BUGS
Doesn't reproduce the functionality that you get using the x and y
parameters to Imager::Font->bounding_box(). I considered:
my ($left, $top, $right, $bottom) = $box->offset(x=>$x, y=>$y)
but this is about as clumsy as the original.
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 SEE ALSO
Imager(3), Imager::Font(3)
=cut
1;

View File

@@ -0,0 +1,307 @@
package Imager::Font::FT2;
use 5.006;
use strict;
use Imager;
use Scalar::Util ();
our @ISA = qw(Imager::Font);
our $VERSION;
BEGIN {
$VERSION = "0.98";
require XSLoader;
XSLoader::load('Imager::Font::FT2', $VERSION);
}
*_first = \&Imager::Font::_first;
sub new {
my $class = shift;
my %hsh=(color=>Imager::Color->new(255,0,0,255),
size=>15,
@_);
unless ($hsh{file}) {
$Imager::ERRSTR = "No font file specified";
return;
}
unless (-e $hsh{file}) {
$Imager::ERRSTR = "Font file $hsh{file} not found";
return;
}
unless ($Imager::formats{ft2}) {
$Imager::ERRSTR = "Freetype2 not supported in this build";
return;
}
my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0);
unless ($id) { # the low-level code may miss some error handling
$Imager::ERRSTR = Imager::_error_as_msg();
return;
}
return bless {
id => $id,
aa => $hsh{aa} || 0,
file => $hsh{file},
type => 't1',
size => $hsh{size},
color => $hsh{color},
utf8 => $hsh{utf8},
vlayout => $hsh{vlayout},
}, $class;
}
sub _draw {
my $self = shift;
$self->_valid
or return;
my %input = @_;
if (exists $input{channel}) {
i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'},
$input{channel}, $input{size}, $input{sizew} || 0,
$input{string}, , $input{align}, $input{aa}, $input{vlayout},
$input{utf8});
} else {
i_ft2_text($self->{id}, $input{image}{IMG},
$input{'x'}, $input{'y'},
$input{color}, $input{size}, $input{sizew} || 0,
$input{string}, $input{align}, $input{aa}, $input{vlayout},
$input{utf8});
}
}
sub _bounding_box {
my $self = shift;
my %input = @_;
$self->_valid
or return;
my @result = i_ft2_bbox($self->{id}, $input{size}, $input{sizew},
$input{string}, $input{utf8});
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
sub dpi {
my $self = shift;
$self->_valid
or return;
my @old = i_ft2_getdpi($self->{id});
if (@_) {
my %hsh = @_;
my $result;
unless ($hsh{xdpi} && $hsh{ydpi}) {
if ($hsh{dpi}) {
$hsh{xdpi} = $hsh{ydpi} = $hsh{dpi};
}
else {
$Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi";
return;
}
i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return;
}
}
return @old;
}
sub hinting {
my ($self, %opts) = @_;
$self->_valid
or return;
i_ft2_sethinting($self->{id}, $opts{hinting} || 0);
}
sub _transform {
my $self = shift;
$self->_valid
or return;
my %hsh = @_;
my $matrix = $hsh{matrix} or return undef;
return i_ft2_settransform($self->{id}, $matrix)
}
sub utf8 {
return 1;
}
# check if the font has the characters in the given string
sub has_chars {
my ($self, %hsh) = @_;
$self->_valid
or return;
unless (defined $hsh{string} && length $hsh{string}) {
$Imager::ERRSTR = "No string supplied to \$font->has_chars()";
return;
}
if (wantarray) {
my @result = i_ft2_has_chars($self->{id}, $hsh{string},
_first($hsh{'utf8'}, $self->{utf8}, 0));
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
else {
my $result = i_ft2_has_chars($self->{id}, $hsh{string},
_first($hsh{'utf8'}, $self->{utf8}, 0));
unless (defined $result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return $result;
}
}
sub face_name {
my ($self) = @_;
$self->_valid
or return;
i_ft2_face_name($self->{id});
}
sub can_glyph_names {
my ($self) = @_;
i_ft2_can_do_glyph_names()
or return;
if (ref $self) {
$self->_valid
or return;
i_ft2_face_has_glyph_names($self->{id})
or return;
}
return 1;
}
sub glyph_names {
my ($self, %input) = @_;
$self->_valid
or return;
my $string = $input{string};
defined $string
or return Imager->_set_error("no string parameter passed to glyph_names");
my $utf8 = _first($input{utf8}, 0);
my $reliable_only = _first($input{reliable_only}, 1);
my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only);
@names or return Imager->_set_error(Imager->_error_as_msg);
return @names if wantarray;
return pop @names;
}
sub is_mm {
my ($self) = @_;
$self->_valid
or return;
i_ft2_is_multiple_master($self->{id});
}
sub mm_axes {
my ($self) = @_;
$self->_valid
or return;
my ($num_axis, $num_design, @axes) =
i_ft2_get_multiple_masters($self->{id})
or return Imager->_set_error(Imager->_error_as_msg);
return @axes;
}
sub set_mm_coords {
my ($self, %opts) = @_;
$self->_valid
or return;
$opts{coords}
or return Imager->_set_error("Missing coords parameter");
ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/
or return Imager->_set_error("coords parameter must be an ARRAY ref");
i_ft2_set_mm_coords($self->{id}, @{$opts{coords}})
or return Imager->_set_error(Imager->_error_as_msg);
return 1;
}
# objects may be invalidated on thread creation (or Win32 fork emulation)
sub _valid {
my $self = shift;
unless ($self->{id} && Scalar::Util::blessed($self->{id})) {
Imager->_set_error("font object was created in another thread");
return;
}
return 1;
}
1;
__END__
=head1 NAME
Imager::Font::FT2 - font support using FreeType 2
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
my $font = Imager::Font->new(file => "foo.ttf", type => "ft2");
$img->string(... font => $font);
=head1 DESCRIPTION
This provides font support on FreeType 2.
=head1 CAVEATS
Unfortunately, older versions of Imager would install
C<Imager::Font::FreeType2> even if FreeType 2 wasn't available, and if
no font was created would succeed in loading the module. This means
that an existing C<FreeType2.pm> could cause a probe success for
supported font files, so I've renamed it.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Font.
=cut

View File

@@ -0,0 +1,71 @@
package Imager::Font::FreeType2;
use 5.006;
use strict;
use Imager::Font::FT2;
our @ISA = qw(Imager::Font::FT2);
our $VERSION = "1.021";
1;
__END__
=head1 NAME
Imager::Font::FreeType2 - low-level functions for FreeType2 text output
=head1 DESCRIPTION
Imager::Font creates a Imager::Font::FreeType2 object when asked to.
See Imager::Font to see how to use this type.
This class provides low-level functions that require the caller to
perform data validation.
This driver supports:
=over
=item transform()
=item dpi()
=item draw()
The following parameters:
=over
=item *
C<utf8>
=item *
C<vlayout>
=item *
C<sizew>
=back
=back
=head2 Special behaviors
If you call transform() to set a transformation matrix, hinting will
be switched off. This prevents sudden jumps in the size of the text
caused by the hinting when the transformation is the identity matrix.
If for some reason you want hinting enabled, use
$font->hinting(hinting=>1) to re-enable hinting. This will need to be
called after I<each> call to transform().
=head1 AUTHOR
Addi, Tony
=cut

View File

@@ -0,0 +1,168 @@
package Imager::Font::Image;
use 5.006;
use strict;
use Imager::Color;
use File::Basename;
use File::Spec;
our @ISA = qw(Imager::Font);
our $VERSION = "1.000";
sub NWIDTH () { 0 }
sub PWIDTH () { 2 }
sub GDESCENT () { 1 }
sub GASCENT () { 3 }
sub DESCENT () { 4 }
sub ASCENT () { 5 }
our %REQUIRED_FIELDS = (
Image_spec => 1,
Font_size => 1,
Global_ascent => 1,
Global_descent => 1,);
# Required fields
# Fontmetrics:
# Font global data:
# image name
# font size
# max glyph height
# max glyph width
#
# The per character data is:
# left edge (inclusive)
# right edge (exclusive)
# top edge (inclusive)
# bottom edge (exclusive)
# left adjustment
# forward shift
# baseline adjustment (from top)
#
# The left adjustment is the starting
# offset into the glyph, the forward shift
# is the actual forward movement of the
# imaginary cursor.
# To calculate the size of a string use:
# sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last
# example font spec file:
# IAGRFONT
# # This is an imager font definition file. This is a comment
# Image_spec = foo.png
# Font_size = 12
# Global_ascent = 10
# Global_descent = -2
# # Per character data
# FM_65 = 20 40 30 50 3 15
# # Code for 'A' left edge = 20, right = 40, top = 30, bottom 50, leading = 3, forward = 15.
# The left adjustment is the starting
# offset into the glyph, the forward shift
# is the actual forward movement of the
# imaginary cursor.
# To calculate the size of a string use:
# sum (forward_shift_i) + left_adjustment_0 + width_last - left_adjustment_last - forward_shift_last
sub parse_fontspec_file {
my ($self, $file) = @_;
local *FH;
return unless open(FH, "<$file");
my %req = %REQUIRED_FIELDS;
while(<FH>) {
next if m/^\#/;
if (m/^\s*?(\S+?)\s*=\s*(.+?)\s*$/) {
# Check for a required field:
my $char = $1;
my $metric = $2;
if ($req{$char}) {
$self->{$char} = $metric;
delete $req{$1};
} else {
next unless $char =~ s/^FM_(\d+)$/$1/;
next unless $metric =~ m/(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/;
$self->{fm}->{$char} = [$1, $2, $3, $4, $5, $6];
}
}
}
close(FH);
return $self;
}
sub new {
my $self = bless {}, shift;
my %opts = (color=>Imager::Color->new(255, 0, 0, 0), @_);
unless ($opts{file}) {
$Imager::ERRSTR = "No font file specified";
return;
}
unless ($self->parse_fontspec_file($opts{file})) {
$Imager::ERRSTR = "Font file $opts{file} not found or bad";
return;
}
my $img = Imager->new();
my $img_filename = File::Spec->catfile( dirname($opts{'file'}),
$self->{Image_spec} );
unless ($img->open(%opts, file=>$img_filename)) {
$Imager::ERRSTR = "Font IMAGE file $img_filename not found or bad: ".
$img->errstr();
return;
}
$self->{image} = $img;
$self->{size} = $self->{Font_size};
return $self;
}
sub get_glyph_data {
my ($self, $glyph_code) = @_;
return unless exists $self->{fm}->{$glyph_code};
return @{$self->{fm}->{$glyph_code}};
}
# copy_glyph
#
# $x, $y is left, baseline for glyphs.
#
sub copy_glyph {
my ($self, $glyph_code, $target_img, $x, $y) = @_;
my @gdata = $self->get_glyph_data($glyph_code) or return;
$target_img->rubthrough(src=>$self->{image},
tx => $x + $gdata[4],
ty => $y - $self->{Global_ascent},,
src_minx => $gdata[0],
src_maxx => $gdata[1],
src_miny => $gdata[2],
src_maxy => $gdata[3]);
}
sub _draw {
my ($self, %opts) = @_;
my $x = $opts{'x'};
my $y = $opts{'y'};
my @glyphs = unpack("C*", $opts{string});
my $img = $opts{image};
my $glyph;
for $glyph (@glyphs) {
my @gmetrics = $self->get_glyph_data($glyph) or next;
$self->copy_glyph($glyph, $img, $x, $y);
$x += $gmetrics[5];
}
}

View File

@@ -0,0 +1,313 @@
package Imager::Font::T1;
use 5.006;
use strict;
use Imager::Color;
our @ISA = qw(Imager::Font);
use Scalar::Util ();
BEGIN {
our $VERSION = "1.027";
require XSLoader;
XSLoader::load('Imager::Font::T1', $VERSION);
}
*_first = \&Imager::Font::_first;
my $t1aa = 2;
sub new {
my $class = shift;
my %hsh=(color=>Imager::Color->new(255,0,0,255),
size=>15,
@_);
unless ($hsh{file}) {
$Imager::ERRSTR = "No font file specified";
return;
}
unless (-e $hsh{file}) {
$Imager::ERRSTR = "Font file $hsh{file} not found";
return;
}
unless ($Imager::formats{t1}) {
$Imager::ERRSTR = "Type 1 fonts not supported in this build";
return;
}
# we want to avoid T1Lib's file search mechanism
unless ($hsh{file} =~ m!^/!
|| $hsh{file} =~ m!^\.\/?/!
|| $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
$hsh{file} = './' . $hsh{file};
}
if($hsh{afm}) {
unless (-e $hsh{afm}) {
$Imager::ERRSTR = "Afm file $hsh{afm} not found";
return;
}
unless ($hsh{afm} =~ m!^/!
|| $hsh{afm} =~ m!^\./!
|| $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
$hsh{file} = './' . $hsh{file};
}
} else {
$hsh{afm} = 0;
}
my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm});
unless ($font) { # the low-level code may miss some error handling
Imager->_set_error(Imager->_error_as_msg);
return;
}
return bless {
t1font => $font,
aa => $hsh{aa} || 0,
file => $hsh{file},
type => 't1',
size => $hsh{size},
color => $hsh{color},
t1aa => $t1aa,
}, $class;
}
sub _draw {
my $self = shift;
$self->_valid
or return;
my %input = @_;
my $flags = '';
$flags .= 'u' if $input{underline};
$flags .= 's' if $input{strikethrough};
$flags .= 'o' if $input{overline};
my $aa = $input{aa} ? $self->{t1aa} : 0;
if (exists $input{channel}) {
$self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'},
$input{channel}, $input{size},
$input{string}, $input{align},
$input{utf8}, $flags, $aa)
or return;
} else {
$self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'},
$input{color}, $input{size},
$input{string}, $input{align}, $input{utf8}, $flags, $aa)
or return;
}
return $self;
}
sub _bounding_box {
my $self = shift;
$self->_valid
or return;
my %input = @_;
my $flags = '';
$flags .= 'u' if $input{underline};
$flags .= 's' if $input{strikethrough};
$flags .= 'o' if $input{overline};
my @bbox = $self->{t1font}->bbox($input{size}, $input{string},
$input{utf8}, $flags);
unless (@bbox) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @bbox;
}
# check if the font has the characters in the given string
sub has_chars {
my ($self, %hsh) = @_;
$self->_valid
or return;
unless (defined $hsh{string}) {
$Imager::ERRSTR = "No string supplied to \$font->has_chars()";
return;
}
if (wantarray) {
my @result = $self->{t1font}
->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0));
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
else {
my $result = $self->{t1font}
->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0));
unless (defined $result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return $result;
}
}
sub utf8 {
1;
}
sub can_glyph_names {
1;
}
sub face_name {
my ($self) = @_;
$self->_valid
or return;
return $self->{t1font}->face_name();
}
sub glyph_names {
my ($self, %input) = @_;
$self->_valid
or return;
my $string = $input{string};
defined $string
or return Imager->_set_error("no string parameter passed to glyph_names");
my $utf8 = _first($input{utf8} || 0);
my @result = $self->{t1font}->glyph_names($string, $utf8);
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
sub set_aa_level {
my ($self, $new_t1aa) = @_;
if (!defined $new_t1aa ||
($new_t1aa != 1 && $new_t1aa != 2)) {
Imager->_set_error("set_aa_level: parameter must be 1 or 2");
return;
}
if (ref $self) {
$self->_valid
or return;
$self->{t1aa} = $new_t1aa;
}
else {
$t1aa = $new_t1aa;
}
return 1;
}
sub _valid {
my $self = shift;
unless ($self->{t1font} && Scalar::Util::blessed($self->{t1font})) {
Imager->_set_error("font object was created in another thread");
return;
}
return 1;
}
1;
__END__
=head1 NAME
Imager::Font::Type1 - low-level functions for Type1 fonts
=head1 DESCRIPTION
=for stopwords Freetype
Imager::Font::T1 is deprecated.
F<T1Lib> is unmaintained and has serious bugs when built on 64-bit
systems. Freetype 2 has Type 1 font support and is supported by
Imager via L<Imager::Font::FT2>.
L<Imager::Font> creates a C<Imager::Font::Type1 object> when asked to create
a font object based on a C<.pfb> file.
See Imager::Font to see how to use this type.
This class provides low-level functions that require the caller to
perform data validation
By default Imager no longer creates the F<t1lib.log> log file. You
can re-enable that by calling Imager::init() with the C<t1log> option:
Imager::init(t1log=>1);
This must be called before creating any fonts.
Currently specific to Imager::Font::Type1, you can use the following
flags when drawing text or calculating a bounding box:
=for stopwords overline strikethrough
=over
=item *
C<underline> - Draw the text with an underline.
=item *
C<overline> - Draw the text with an overline.
=item *
C<strikethrough> - Draw the text with a strikethrough.
=back
Obviously, if you're calculating the bounding box the size of the line
is included in the box, and the line isn't drawn :)
=head2 Anti-aliasing
T1Lib supports multiple levels of anti-aliasing, by default, if you
request anti-aliased output, Imager::Font::T1 will use the maximum
level.
You can override this with the set_t1_aa() method:
=over
=item set_aa_level()
Usage:
$font->set_aa_level(1);
Imager::Font::T1->set_aa_level(2);
Sets the T1Lib anti-aliasing level either for the specified font, or
for new font objects.
The only parameter must be 1 or 2.
Returns true on success.
=back
=head1 AUTHOR
Addi, Tony
=cut

View File

@@ -0,0 +1,95 @@
package Imager::Font::Test;
use 5.006;
use strict;
our $VERSION = "1.002";
use base 'Imager::Font';
sub new {
my ($class, %opts) = @_;
bless \%opts, shift;
}
sub _draw {
my ($self, %input) = @_;
my $text = $input{string};
my $ppn = int($input{size} * 0.5 + 0.5);
my $desc = int($input{size} * 0.3 + 0.5);
my $asc = $input{size} - $desc;
my $width = $ppn * length $text;
my $x = $input{x};
my $y = $input{'y'};
$input{align} and $y -= $asc;
$input{image}->box(color => $input{color}, xmin => $x, ymin => $y,
xmax => $x + $width-1, ymax => $y + $input{size} - 1);
return 1;
}
sub _bounding_box {
my ($self, %input) = @_;
my $text = $input{string};
my $ppn = int($input{size} * 0.5 + 0.5);
my $desc = int($input{size} * 0.3 + 0.5);
my $asc = $input{size} - $desc;
return ( 0, -$desc, $ppn * length $text, $asc, -$desc, $asc, $ppn * length $text, 0 );
}
sub has_chars {
my ($self, %input) = @_;
my $text = $input{string};
defined $text
or return Imager->_set_error("has_chars: No string parameter supplied");
return (1) x length $text;
}
sub face_name {
"test";
}
sub glyph_names {
my ($self, %input) = @_;
my $text = $input{string};
defined $text
or return Imager->_set_error("glyph_names: No string parameter supplied");
return (1) x length $text;
}
1;
=head1 NAME
Imager::Font::Test - font driver producing consistent output for tests.
=head1 SYNOPSIS
my $font = Imager::Font::Test->new;
# use $font where you use other fonts
=head1 DESCRIPTION
Imager::Font::Test is intended to produce consistent output without
being subject to the inconsistent output produced by different
versions of font libraries.
The output is simple box for the whole string.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

View File

@@ -0,0 +1,155 @@
package Imager::Font::Truetype;
use 5.006;
use strict;
our @ISA = qw(Imager::Font);
our $VERSION = "1.013";
*_first = \&Imager::Font::_first;
sub new {
my $class = shift;
my %hsh=(color=>Imager::Color->new(255,0,0,255),
size=>15,
@_);
unless ($hsh{file}) {
$Imager::ERRSTR = "No font file specified";
return;
}
unless (-e $hsh{file}) {
$Imager::ERRSTR = "Font file $hsh{file} not found";
return;
}
unless ($Imager::formats{tt}) {
$Imager::ERRSTR = "Type 1 fonts not supported in this build";
return;
}
my $id = Imager::i_tt_new($hsh{file});
unless ($id) { # the low-level code may miss some error handling
$Imager::ERRSTR = Imager::_error_as_msg();
return;
}
return bless {
id => $id,
aa => $hsh{aa} || 0,
file => $hsh{file},
type => 'tt',
size => $hsh{size},
color => $hsh{color},
}, $class;
}
sub _draw {
my $self = shift;
my %input = @_;
if ( exists $input{channel} ) {
Imager::i_tt_cp($self->{id},$input{image}{IMG},
$input{'x'}, $input{'y'}, $input{channel}, $input{size},
$input{string}, $input{aa},
$input{utf8}, $input{align});
} else {
Imager::i_tt_text($self->{id}, $input{image}{IMG},
$input{'x'}, $input{'y'}, $input{color},
$input{size}, $input{string},
$input{aa}, $input{utf8},
$input{align});
}
}
sub _bounding_box {
my $self = shift;
my %input = @_;
my @result =
Imager::i_tt_bbox($self->{id}, $input{size}, $input{string}, $input{utf8});
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
sub utf8 { 1 }
# check if the font has the characters in the given string
sub has_chars {
my ($self, %hsh) = @_;
unless (defined $hsh{string}) {
$Imager::ERRSTR = "No string supplied to \$font->has_chars()";
return;
}
if (wantarray) {
my @result = Imager::i_tt_has_chars($self->{id}, $hsh{string},
_first($hsh{'utf8'}, $self->{utf8}, 0));
unless (@result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @result;
}
else {
my $result = Imager::i_tt_has_chars($self->{id}, $hsh{string},
_first($hsh{'utf8'}, $self->{utf8}, 0));
unless (defined $result) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return $result;
}
}
sub face_name {
my ($self) = @_;
Imager::i_tt_face_name($self->{id});
}
sub can_glyph_names {
1;
}
sub glyph_names {
my ($self, %input) = @_;
my $string = $input{string};
defined $string
or return Imager->_set_error("no string parameter passed to glyph_names");
my $utf8 = _first($input{utf8} || 0);
my @names = Imager::i_tt_glyph_name($self->{id}, $string, $utf8);
unless (@names) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @names;
}
1;
__END__
=head1 NAME
Imager::Font::Truetype - low-level functions for Truetype fonts
=head1 DESCRIPTION
Imager::Font creates a Imager::Font::Truetype object when asked to
create a font object based on a F<.ttf> file.
See Imager::Font to see how to use this type.
This class provides low-level functions that require the caller to
perform data validation.
=head1 AUTHOR
Addi, Tony
=cut

View File

@@ -0,0 +1,27 @@
package Imager::Font::Type1;
use 5.006;
use strict;
use Imager::Font::T1;
our @ISA = qw(Imager::Font::T1);
our $VERSION = "1.013";
1;
__END__
=head1 NAME
Imager::Font::Type1 - low-level functions for T1Lib text output
=head1 DESCRIPTION
This is a simple wrapper around Imager::Font::T1 for backwards
compatibility.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

View File

@@ -0,0 +1,103 @@
package Imager::Font::W32;
use 5.006;
use strict;
use Imager;
our @ISA = qw(Imager::Font);
BEGIN {
our $VERSION = "0.91";
require XSLoader;
XSLoader::load('Imager::Font::W32', $VERSION);
}
# called by Imager::Font::new()
# since Win32's HFONTs include the size information this
# is just a stub
sub new {
my $class = shift;
my %opts =
(
color => Imager::Color->new(255, 0, 0),
size => 15,
@_,
);
return bless \%opts, $class;
}
sub _bounding_box {
my ($self, %opts) = @_;
my @bbox = i_wf_bbox($self->{face}, $opts{size}, $opts{string}, $opts{utf8});
unless (@bbox) {
Imager->_set_error(Imager->_error_as_msg);
return;
}
return @bbox;
}
sub _draw {
my $self = shift;
my %input = @_;
if (exists $input{channel}) {
return i_wf_cp($self->{face}, $input{image}{IMG}, $input{x}, $input{'y'},
$input{channel}, $input{size},
$input{string}, $input{align}, $input{aa}, $input{utf8});
}
else {
return i_wf_text($self->{face}, $input{image}{IMG}, $input{x},
$input{'y'}, $input{color}, $input{size},
$input{string}, $input{align}, $input{aa}, $input{utf8});
}
}
sub utf8 {
return 1;
}
sub can_glyph_names {
return;
}
1;
__END__
=head1 NAME
Imager::Font::W32 - font support using C<GDI> on Win32
=head1 SYNOPSIS
use Imager;
my $img = Imager->new;
my $font = Imager::Font->new(face => "Arial", type => "w32");
$img->string(... font => $font);
=head1 DESCRIPTION
This provides font support on Win32.
=head1 CAVEATS
Unfortunately, older versions of Imager would install
Imager::Font::Win32 even if Win32 wasn't available, and if no font was
created would succeed in loading the module. This means that an
existing Win32.pm could cause a probe success for Win32 fonts, so I've
renamed it.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Font.
=cut

View File

@@ -0,0 +1,32 @@
package Imager::Font::Win32;
use 5.006;
use strict;
our @ISA = qw(Imager::Font::W32);
our $VERSION = "1.000";
require Imager::Font::W32;
1;
__END__
=head1 NAME
=for stopwords GDI
Imager::Font::Win32 - uses Win32 GDI services for text output
=head1 SYNOPSIS
my $font = Imager::Font->new(face=>"Arial");
=head1 DESCRIPTION
This module is obsolete.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

View File

@@ -0,0 +1,387 @@
package Imager::Font::Wrap;
use 5.006;
use strict;
use Imager;
use Imager::Font;
our $VERSION = "1.005";
*_first = \&Imager::Font::_first;
# we can't accept the utf8 parameter, too hard at this level
# the %state contains:
# font - the font
# im - the image
# x - the left position
# w - the width
# justify - fill, left, right or center
sub _format_line {
my ($state, $spaces, $text, $fill) = @_;
$text =~ s/ +$//;
my $box = $state->{font}->bounding_box(string=>$text,
size=>$state->{size});
my $y = $state->{linepos} + $box->global_ascent;
if ($state->{bottom}
&& $state->{linepos} + $box->font_height > $state->{bottom}) {
$state->{full} = 1;
return 0;
}
if ($text =~ /\S/ && $state->{im}) {
my $justify = $fill ? $state->{justify} :
$state->{justify} eq 'fill' ? 'left' : $state->{justify};
if ($justify ne 'fill') {
my $x = $state->{x};
if ($justify eq 'right') {
$x += $state->{w} - $box->advance_width;
}
elsif ($justify eq 'center') {
$x += ($state->{w} - $box->advance_width) / 2;
}
$state->{font}->draw(image=>$state->{im}, string=>$text,
x=>$x, 'y'=>$y,
size=>$state->{size}, %{$state->{input}});
}
else {
(my $nospaces = $text) =~ tr/ //d;
my $nospace_bbox = $state->{font}->bounding_box(string=>$nospaces,
size=>$state->{size});
my $gap = $state->{w} - $nospace_bbox->advance_width;
my $x = $state->{x};
$spaces = $text =~ tr/ / /;
while (length $text) {
if ($text =~ s/^(\S+)//) {
my $word = $1;
my $bbox = $state->{font}->bounding_box(string=>$word,
size=>$state->{size});
$state->{font}->draw(image=>$state->{im}, string=>$1,
x=>$x, 'y'=>$y,
size=>$state->{size}, %{$state->{input}});
$x += $bbox->advance_width;
}
elsif ($text =~ s/^( +)//) {
my $sep = $1;
my $advance = int($gap * length($sep) / $spaces);
$spaces -= length $sep;
$gap -= $advance;
$x += $advance;
}
else {
die "This shouldn't happen\n";
}
}
}
}
$state->{linepos} += $box->font_height + $state->{linegap};
1;
}
sub wrap_text {
my $class = shift;
my %input = @_;
# try to get something useful
my $x = _first(delete $input{'x'}, 0);
my $y = _first(delete $input{'y'}, 0);
my $im = delete $input{image};
my $imerr = $im || 'Imager';
my $width = delete $input{width};
if (!defined $width) {
defined $im && $im->getwidth > $x
or return $imerr->_set_error("No width supplied and can't guess");
$width = $im->getwidth - $x;
}
my $font = delete $input{font}
or return $imerr->_set_error("No font parameter supplied");
my $size = _first(delete $input{size}, $font->{size});
defined $size
or return $imerr->_set_error("No font size supplied");
2 * $size < $width
or return $imerr->_set_error("Width too small for font size");
my $text = delete $input{string};
defined $text
or return $imerr->_set_error("No string parameter supplied");
my $justify = _first($input{justify}, "left");
my %state =
(
font => $font,
im => $im,
x => $x,
w => $width,
justify => $justify,
'y' => $y,
linepos=>$y,
size=>$size,
input => \%input,
linegap => delete $input{linegap} || 0,
);
$state{height} = delete $input{height};
if ($state{height}) {
$state{bottom} = $y + $state{height};
}
my $line = '';
my $spaces = 0;
my $charpos = 0;
my $linepos = 0;
pos($text) = 0; # avoid a warning
while (pos($text) < length($text)) {
#print pos($text), "\n";
if ($text =~ /\G( +)/gc) {
#print "spaces\n";
$line .= $1;
$spaces += length($1);
}
elsif ($text =~ /\G(?:\x0D\x0A?|\x0A\x0D?)/gc) {
#print "newline\n";
_format_line(\%state, $spaces, $line, 0)
or last;
$line = '';
$spaces = 0;
$linepos = pos($text);
}
elsif ($text =~ /\G(\S+)/gc) {
#print "word\n";
my $word = $1;
my $bbox = $font->bounding_box(string=>$line . $word, size=>$size);
if ($bbox->advance_width > $width) {
_format_line(\%state, $spaces, $line, 1)
or last;
$line = '';
$spaces = 0;
$linepos = pos($text) - length($word);
}
$line .= $word;
# check for long words
$bbox = $font->bounding_box(string=>$line, size=>$size);
while ($bbox->advance_width > $width) {
my $len = length($line) - 1;
$bbox = $font->bounding_box(string=>substr($line, 0, $len),
size=>$size);
while ($bbox->advance_width > $width) {
--$len;
$bbox = $font->bounding_box(string=>substr($line, 0, $len),
size=>$size);
}
_format_line(\%state, 0, substr($line, 0, $len), 0)
or last;
$line = substr($line, $len);
$bbox = $font->bounding_box(string=>$line, size=>$size);
$linepos = pos($text) - length($line);
}
}
elsif ($text =~ /\G\s/gc) {
# skip a single unrecognized whitespace char
#print "skip\n";
$linepos = pos($text);
}
}
if (length $line && !$state{full}) {
$linepos += length $line
if _format_line(\%state, 0, $line, 0);
}
if ($input{savepos}) {
${$input{savepos}} = $linepos;
}
return ($x, $y, $x+$width, $state{linepos});
}
1;
__END__
=head1 NAME
Imager::Font::Wrap - simple wrapped text output
=head1 SYNOPSIS
use Imager::Font::Wrap;
my $img = Imager->new(xsize=>$xsize, ysize=>$ysize);
my $font = Imager::Font->new(file=>$fontfile);
my $string = "..."; # text with or without newlines
Imager::Font::Wrap->wrap_text( image => $img,
font => $font,
string => $string,
x => $left,
y => $top,
width => $width,
.... );
=head1 DESCRIPTION
This is a simple text wrapper with options to control the layout of
text within the line.
You can control the position, width and height of the text with the
C<image>, C<x>, C<y>, C<width> and C<height> options.
You can simply calculate space usage by setting C<image> to C<undef>,
or set C<savepos> to see how much text can fit within the given
C<height>.
=over
=item wrap_text()
Draw word-wrapped text.
=over
=item *
C<x>, C<y> - The top-left corner of the rectangle the text is
formatted into. Defaults to (0, 0).
=item *
C<width> - The width of the formatted text in pixels. Defaults to the
horizontal gap between the top-left corner and the right edge of the
image. If no image is supplied then this is required.
=item *
C<height> - The maximum height of the formatted text in pixels. Not
required.
=item *
C<savepos> - The amount of text consumed (as a count of characters)
will be stored into the scalar this refers to.
my $pagenum = 1;
my $string = "...";
my $font = ...;
my $savepos;
while (length $string) {
my $img = Imager->new(xsize=>$xsize, ysize=>$ysize);
Imager::Font::Wrap->wrap_text(string=>$string, font=>$font,
image=>$img, savepos => \$savepos)
or die $img->errstr;
$savepos > 0
or die "Could not fit any text on page\n";
$string = substr($string, $savepos);
$img->write(file=>"page$pagenum.ppm");
}
=item *
C<image> - The image to render the text to. Can be supplied as
C<undef> or not provided to simply calculate the bounding box.
=item *
C<font> - The font used to render the text. Required.
=item *
C<size> - The size to render the font in. Defaults to the size stored
in the font object. Required if it isn't stored in the font object.
=item *
C<string> - The text to render. This can contain non-white-space,
blanks (ASCII 0x20), and newlines.
Newlines must match /(?:\x0A\x0D?|\x0D\x0A?)/. White-space other than
blanks and newlines are completely ignored.
=item *
C<justify>
The way text is formatted within each line. Possible values include:
=over
=item *
C<left> - left aligned against the left edge of the text box.
=item *
C<right> - right aligned against the right edge of the text box.
=item *
C<center> - centered horizontally in the text box.
=item *
fill - all but the final line of the paragraph has spaces expanded so
that the line fills from the left to the right edge of the text box.
=back
=item *
C<linegap> - Gap between lines of text in pixels. This is in addition
to the size from C<< $font->font_height >>. Can be positive or
negative. Default 0.
=back
Any other parameters are passed onto Imager::Font->draw().
Returns a list:
($left, $top, $right, $bottom)
which are the bounds of the space used to layout the text.
If C<height> is set then this is the space used within that height.
You can use this to calculate the space required to format the text
before doing it:
my ($left, $top, $right, $bottom) =
Imager::Font::Wrap->wrap_text(string => $string,
font => $font,
width => $xsize);
my $img = Imager->new(xsize=>$xsize, ysize=>$bottom);
Imager::Font::Wrap->wrap_text(string => $string,
font => $font,
width => $xsize,
image => $image);
=back
=head1 BUGS
Imager::Font can handle UTF-8 encoded text itself, but this module
doesn't support that (and probably won't). This could probably be
done with regex magic.
Currently ignores the C<sizew> parameter, if you supply one it will be
supplied to the draw() function and the text will be too short or too
long for the C<width>.
Uses a simplistic text model, which is why there's no hyphenation, and
no tabs.
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 SEE ALSO
Imager(3), Imager::Font(3)
=cut

View File

@@ -0,0 +1,437 @@
package Imager::Fountain;
use 5.006;
use strict;
use Imager::Color::Float;
our $VERSION = "1.008";
=head1 NAME
Imager::Fountain - a class for building fountain fills suitable for use by
the fountain filter.
=head1 SYNOPSIS
use Imager::Fountain;
my $f1 = Imager::Fountain->read(gimp=>$filename);
$f->write(gimp=>$filename);
my $f1 = Imager::Fountain->new;
$f1->add(start=>0, middle=>0.5, end=>1.0,
c0=>Imager::Color->new(...),
c1=>Imager::Color->new(...),
type=>$trans_type, color=>$color_trans_type);
=head1 DESCRIPTION
Provide an interface to build arrays suitable for use by the Imager
fountain filter. These can be loaded from or saved to a GIMP gradient
file or you can build them from scratch.
=over
=item read(gimp=>$filename)
=item read(gimp=>$filename, name=>\$name)
Loads a gradient from the given GIMP gradient file, and returns a
new Imager::Fountain object.
If the name parameter is supplied as a scalar reference then any name
field from newer GIMP gradient files will be returned in it.
my $gradient = Imager::Fountain->read(gimp=>'foo.ggr');
my $name;
my $gradient2 = Imager::Fountain->read(gimp=>'bar.ggr', name=>\$name);
=cut
sub read {
my ($class, %opts) = @_;
if ($opts{gimp}) {
my $fh;
$fh = ref($opts{gimp}) ? $opts{gimp} : IO::File->new($opts{gimp});
unless ($fh) {
$Imager::ERRSTR = "Cannot open $opts{gimp}: $!";
return;
}
my $trash_name;
my $name_ref = $opts{name} && ref $opts{name} ? $opts{name} : \$trash_name;
return $class->_load_gimp_gradient($fh, $opts{gimp}, $name_ref);
}
else {
warn "${class}::read: Nothing to do!";
return;
}
}
=item write(gimp=>$filename)
=item write(gimp=>$filename, name=>$name)
Save the gradient to a GIMP gradient file.
The second variant allows the gradient name to be set (for newer
versions of the GIMP).
$gradient->write(gimp=>'foo.ggr')
or die Imager->errstr;
$gradient->write(gimp=>'bar.ggr', name=>'the bar gradient')
or die Imager->errstr;
=cut
sub write {
my ($self, %opts) = @_;
if ($opts{gimp}) {
my $fh;
$fh = ref($opts{gimp}) ? $opts{gimp} : IO::File->new("> ".$opts{gimp});
unless ($fh) {
$Imager::ERRSTR = "Cannot open $opts{gimp}: $!";
return;
}
return $self->_save_gimp_gradient($fh, $opts{gimp}, $opts{name});
}
else {
warn "Nothing to do\n";
return;
}
}
=item new
Create an empty fountain fill description.
=cut
sub new {
my ($class) = @_;
return bless [], $class;
}
sub _first {
for (@_) {
return $_ if defined;
}
return undef;
}
=item add(start=>$start, middle=>$middle, end=>1.0, c0=>$start_color, c1=>$end_color, type=>$trans_type, color=>$color_trans_type)
Adds a new segment to the fountain fill, the possible options are:
=over
=item *
C<start> - the start position in the gradient where this segment takes
effect between 0 and 1. Default: 0.
=item *
C<middle> - the mid-point of the transition between the 2
colors, between 0 and 1. Default: average of C<start> and C<end>.
=item *
C<end> - the end of the gradient, from 0 to 1. Default: 1.
=item *
C<c0> - the color of the fountain fill where the fill parameter is
equal to I<start>. Default: opaque black.
=item *
C<c1> - the color of the fountain fill where the fill parameter is
equal to I<end>. Default: opaque black.
=item *
C<type> - the type of segment, controls the way in which the fill parameter
moves from 0 to 1. Default: linear.
This can take any of the following values:
=over
=item *
C<linear>
=item *
C<curved> - unimplemented so far.
=item *
C<sine>
=item *
C<sphereup>
=item *
C<spheredown>
=back
=item *
C<color> - the way in which the color transitions between C<c0> and C<c1>.
Default: direct.
This can take any of the following values:
=over
=item *
C<direct> - each channel is simple scaled between c0 and c1.
=item *
C<hueup> - the color is converted to a HSV value and the scaling is
done such that the hue increases as the fill parameter increases.
=item *
C<huedown> - the color is converted to a HSV value and the scaling is
done such that the hue decreases as the fill parameter increases.
=back
=back
In most cases you can ignore some of the arguments, eg.
# assuming $f is a new Imager::Fountain in each case here
use Imager ':handy';
# simple transition from red to blue
$f->add(c0=>NC('#FF0000'), c1=>NC('#0000FF'));
# simple 2 stages from red to green to blue
$f->add(end=>0.5, c0=>NC('#FF0000'), c1=>NC('#00FF00'))
$f->add(start=>0.5, c0=>NC('#00FF00'), c1=>NC('#0000FF'));
=cut
# used to translate segment types and color transition types to numbers
my %type_names =
(
linear => 0,
curved => 1,
sine => 2,
sphereup=> 3,
spheredown => 4,
);
my %color_names =
(
direct => 0,
hueup => 1,
huedown => 2
);
sub add {
my ($self, %opts) = @_;
my $start = _first($opts{start}, 0);
my $end = _first($opts{end}, 1);
my $middle = _first($opts{middle}, ($start+$end)/2);
my @row =
(
$start, $middle, $end,
_first($opts{c0}, Imager::Color::Float->new(0,0,0,1)),
_first($opts{c1}, Imager::Color::Float->new(1,1,1,0)),
_first($opts{type} && $type_names{$opts{type}}, $opts{type}, 0),
_first($opts{color} && $color_names{$opts{color}}, $opts{color}, 0)
);
push(@$self, \@row);
$self;
}
=item simple(positions=>[ ... ], colors=>[...])
Creates a simple fountain fill object consisting of linear segments.
The array references passed as positions and colors must have the same
number of elements. They must have at least 2 elements each.
colors must contain Imager::Color or Imager::Color::Float objects.
eg.
my $f = Imager::Fountain->simple(positions=>[0, 0.2, 1.0],
colors=>[ NC(255,0,0), NC(0,255,0),
NC(0,0,255) ]);
=cut
sub simple {
my ($class, %opts) = @_;
if ($opts{positions} && $opts{colors}) {
my $positions = $opts{positions};
my $colors = $opts{colors};
unless (@$positions == @$colors) {
$Imager::ERRSTR = "positions and colors must be the same size";
return;
}
unless (@$positions >= 2) {
$Imager::ERRSTR = "not enough segments";
return;
}
my $f = $class->new;
for my $i (0.. $#$colors-1) {
$f->add(start=>$positions->[$i], end=>$positions->[$i+1],
c0 => $colors->[$i], c1=>$colors->[$i+1]);
}
return $f;
}
else {
warn "Nothing to do";
return;
}
}
=back
=head2 Implementation Functions
Documented for internal use.
=over
=item _load_gimp_gradient($class, $fh, $name)
Does the work of loading a GIMP gradient file.
=cut
sub _load_gimp_gradient {
my ($class, $fh, $filename, $name) = @_;
my $head = <$fh>;
chomp $head;
unless ($head eq 'GIMP Gradient') {
$Imager::ERRSTR = "$filename is not a GIMP gradient file";
return;
}
my $count = <$fh>;
chomp $count;
if ($count =~ /^name:\s?(.*)/i) {
ref $name and $$name = $1;
$count = <$fh>; # try again
chomp $count;
}
unless ($count =~ /^\d+$/) {
$Imager::ERRSTR = "$filename is missing the segment count";
return;
}
my @result;
for my $i (1..$count) {
my $row = <$fh>;
chomp $row;
my @row = split ' ', $row;
unless (@row == 13) {
$Imager::ERRSTR = "Bad segment definition";
return;
}
my ($start, $middle, $end) = splice(@row, 0, 3);
my $c0 = Imager::Color::Float->new(splice(@row, 0, 4));
my $c1 = Imager::Color::Float->new(splice(@row, 0, 4));
my ($type, $color) = @row;
push(@result, [ $start, $middle, $end, $c0, $c1, $type, $color ]);
}
return bless \@result,
}
=item _save_gimp_gradient($self, $fh, $name)
Does the work of saving to a GIMP gradient file.
=cut
sub _save_gimp_gradient {
my ($self, $fh, $filename, $name) = @_;
print $fh "GIMP Gradient\n";
defined $name or $name = '';
$name =~ tr/ -~/ /cds;
if ($name) {
print $fh "Name: $name\n";
}
print $fh scalar(@$self),"\n";
for my $row (@$self) {
printf $fh "%.6f %.6f %.6f ",@{$row}[0..2];
for my $i (0, 1) {
for ($row->[3+$i]->rgba) {
printf $fh "%.6f ", $_/255.0;
}
}
print $fh "@{$row}[5,6]";
unless (print $fh "\n") {
$Imager::ERRSTR = "write error: $!";
return;
}
}
return 1;
}
=back
=head1 FILL PARAMETER
The add() documentation mentions a fill parameter in a few places,
this is as good a place as any to discuss it.
The process of deciding the color produced by the gradient works
through the following steps:
=over
=item 1.
calculate the base value, which is typically a distance or an angle of
some sort. This can be positive or occasionally negative, depending on
the type of fill being performed (linear, radial, etc).
=item 2.
clamp or convert the base value to the range 0 through 1, how this is
done depends on the repeat parameter. I'm calling this result the
fill parameter.
=item 3.
the appropriate segment is found. This is currently done with a
linear search, and the first matching segment is used. If there is no
matching segment the pixel is not touched.
=item 4.
the fill parameter is scaled from 0 to 1 depending on the segment type.
=item 5.
the color produced, depending on the segment color type.
=back
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 SEE ALSO
Imager(3)
=cut

View File

@@ -0,0 +1,57 @@
=head1 NAME
Imager::Handy - simple access to common functions
=head1 SYNOPSIS
use Imager ':handy';
my $color = NC(255, 0, 0);
my $font = NF(1.0, 0, 0);
=head1 DESCRIPTION
If you use Imager with the C<:handy> import tag, it will export a
number of functions that can shorter your code.
=over
=item NC()
=item newcolor()
=item newcolour()
Create a new Imager::Color object, supplying any parameters to the
new() method.
my $color = NC('red');
=item NF()
=item newfont()
Create a new Imager::Font object, supplying any parameters to the
new() method.
my $font = NF(file => 'foo.ttf');
=item NCF()
Create a new L<Imager::Color::Float> object, supplying any parameters
to the new() method.
my $colorf = NCF(1.0, 0, 0);
=back
=head1 BUGS
NC() can be mostly replaced by supplying the color name or other
description directly to the drawing method.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

376
database/perl/vendor/lib/Imager/IO.pod vendored Normal file
View File

@@ -0,0 +1,376 @@
=head1 NAME
Imager::IO - Imager's io_layer object.
=head1 SYNOPSIS
# Imager supplies Imager::IO objects to various callbacks
my $IO = ...;
my $count = $IO->write($data);
my $count = $IO->read($buffer, $max_count);
my $position = $IO->seek($offset, $whence);
my $status = $IO->close;
=head1 DESCRIPTION
Imager uses an abstraction when dealing with image files to allow the
same code to work with disk files, in memory data and callbacks.
If you're writing an Imager file handler your code will be passed an
Imager::IO object to write to or read from.
X<UTF-8>X<Unicode>Note that Imager::IO can only work with collections of bytes -
if you need to read UTF-8 data you will need to read the bytes and
decode them. If you want to write UTF-8 data you will need to encode
your characters to bytes and write the bytes.
=head1 CONSTRUCTORS
=over
=item new_fd($fd)
Create a new I/O layer based on a file descriptor.
my $io = Imager::IO->new(fileno($fh));
=item new_buffer($data)
Create a new I/O layer based on a memory buffer.
Buffer I/O layers are read only.
C<$data> can either a simple octet string, or a reference to an octet
string. If C<$data> contains characters with a code point above
C<0xFF> an exception will be thrown.
=item new_cb($writecb, $readcb, $seekcb, $closecb)
Create a new I/O layer based on callbacks. See
L<Imager::Files/"I/O Callbacks"> for details on the behavior of
the callbacks.
=item new_fh($fh)
Create a new I/O layer based on a perl file handle.
=item new_bufchain()
Create a new C<bufchain> based I/O layer. This accumulates the file
data as a chain of buffers starting from an empty stream.
Use the L</slurp()> method to retrieve the accumulated content into a
perl string.
=back
=head1 BUFFERED I/O METHODS
These methods use buffered I/O to improve performance unless you call
set_buffered() to disable buffering.
Prior to Imager 0.86 the write and read methods performed raw I/O.
=over
=item write($data)
Call to write to the file. Returns the number of bytes written. The
data provided may contain only characters \x00 to \xFF - characters
outside this range will cause this method to croak().
If you supply a UTF-8 flagged string it will be converted to a byte
string, which may have a performance impact.
Returns -1 on error, though in most cases if the result of the write
isn't the number of bytes supplied you'll want to treat it as an error
anyway.
=item read($buffer, $size)
my $buffer;
my $count = $io->read($buffer, $max_bytes);
Reads up to I<$max_bytes> bytes from the current position in the file
and stores them in I<$buffer>. Returns the number of bytes read on
success or an empty list on failure. Note that a read of zero bytes
is B<not> a failure, this indicates end of file.
=item read2($size)
my $buffer = $io->read2($max_bytes);
An alternative interface to read, that might be simpler to use in some
cases.
Returns the data read or an empty list. At end of file the data read
will be an empty string.
=item seek($offset, $whence)
my $new_position = $io->seek($offset, $whence);
Seek to a new position in the file. Possible values for I<$whence> are:
=over
=item *
C<SEEK_SET> - I<$offset> is the new position in the file.
=item *
C<SEEK_CUR> - I<$offset> is the offset from the current position in
the file.
=item *
C<SEEK_END> - I<$offset> is the offset relative to the end of the
file.
=back
Note that seeking past the end of the file may or may not result in an
error.
Any buffered output will be flushed, if flushing fails, seek() will
return -1.
Returns the new position in the file, or -1 on error.
=item getc()
Return the next byte from the stream.
Returns the ordinal of the byte or -1 on error or end of file.
while ((my $c = $io->getc) != -1) {
print chr($c);
}
=item nextc()
Discard the next byte from the stream.
Returns nothing.
=item gets()
=item gets($max_size)
=item gets($max_size, $end_of_line)
Returns the next line of input from the stream, as terminated by
C<end_of_line>.
The default C<max_size> is 8192.
The default C<end_of_line> is C<ord "\n">.
Returns nothing if the stream is in error or at end of file.
Returns the line as a string, including the line terminator (if one
was found) on success.
while (defined(my $line = $io->gets)) {
# do something with $line
}
=item peekc()
Return the buffered next character from the stream, loading the buffer
if necessary.
For an unbuffered stream a buffer will be setup and loaded with a
single character.
Returns the ordinal of the byte or -1 on error or end of file.
my $c = $io->peekc;
=item peekn($size)
Returns up to the next C<size> bytes from the file as a string.
Only up to the stream buffer size bytes (currently 8192) can be peeked.
This method ignores the buffering state of the stream.
Returns nothing on EOF.
my $s = $io->peekn(4);
if ($s =~ /^(II|MM)\*\0/) {
print "TIFF image";
}
=item putc($code)
Write a single character to the stream.
Returns C<code> on success, or -1 on failure.
=item close()
my $result = $io->close;
Call when you're done with the file. If the IO object is connected to
a file this won't close the file handle, but buffers may be flushed
(if any).
Returns 0 on success, -1 on failure.
=item eof()
$io->eof
Test if the stream is at end of file. No further read requests will
be passed to your read callback until you seek().
=item error()
Test if the stream has encountered a read or write error.
my $data = $io->read2(100);
$io->error
and die "Failed";
When the stream has the error flag set no further read or write
requests will be passed to your callbacks until you seek.
=item flush()
$io->flush
or die "Flush error";
Flush any buffered output. This will not call lower write layers when
the stream has it's error flag set.
Returns a true value on success.
=item is_buffered()
Test if buffering is enabled for this stream.
Returns a true value if the stream is buffered.
=item set_buffered($enabled)
If C<$enabled> is a non-zero integer, enable buffering, other disable
it.
Disabling buffering will flush any buffered output, but any buffered
input will be retained and consumed by input methods.
Returns true if any buffered output was flushed successfully, false if
there was an error flushing output.
=back
=head1 RAW I/O METHODS
These call the underlying I/O abstraction directly.
=over
=item raw_write()
Call to write to the file. Returns the number of bytes written. The
data provided may contain only characters \x00 to \xFF - characters
outside this range will cause this method to croak().
If you supply a UTF-8 flagged string it will be converted to a byte
string, which may have a performance impact.
Returns -1 on error, though in most cases if the result of the write
isn't the number of bytes supplied you'll want to treat it as an error
anyway.
=item raw_read()
my $buffer;
my $count = $io->raw_read($buffer, $max_bytes);
Reads up to I<$max_bytes> bytes from the current position in the file
and stores them in I<$buffer>. Returns the number of bytes read on
success or an empty list on failure. Note that a read of zero bytes
is B<not> a failure, this indicates end of file.
=item raw_read2()
my $buffer = $io->raw_read2($max_bytes);
An alternative interface to raw_read, that might be simpler to use in some
cases.
Returns the data read or an empty list.
=item raw_seek()
my $new_position = $io->raw_seek($offset, $whence);
Seek to a new position in the file. Possible values for I<$whence> are:
=over
=item *
C<SEEK_SET> - I<$offset> is the new position in the file.
=item *
C<SEEK_CUR> - I<$offset> is the offset from the current position in
the file.
=item *
C<SEEK_END> - I<$offset> is the offset relative to the end of the
file.
=back
Note that seeking past the end of the file may or may not result in an
error.
Returns the new position in the file, or -1 on error.
=item raw_close()
my $result = $io->raw_close;
Call when you're done with the file. If the IO object is connected to
a file this won't close the file handle.
Returns 0 on success, -1 on failure.
=back
=head1 UTILITY METHODS
=over
=item slurp()
Retrieve the data accumulated from an I/O layer object created with
the new_bufchain() method.
my $data = $io->slurp;
=item dump()
Dump the internal buffering state of the I/O object to C<stderr>.
$io->dump();
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 SEE ALSO
Imager, Imager::Files
=cut

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
=head1 NAME
Imager::Inline - using Imager with Inline::C.
=head1 SYNOPSIS
use Inline with => 'Imager';
use Inline C => <<'EOS';
Imager some_func(Imager::Color c, Imager::Fill f) {
Imager img = i_img_8_new(200, 200, 3);
/* fill with color */
i_box_filled(img, 0, 0, 199, 199, c);
/* inner area with fill */
i_box_cfill(img, 50, 50, 149, 149, f);
return img;
}
EOS
=head1 DESCRIPTION
=for stopwords inline Inline Inline's
Imager hooks into Inline's C<with> syntax to make it easier to write
Inline::C code that works with Imager, you can call Imager functions
without having to include headers or perform initialization.
Imager's Inline C<with> support does the following:
=over
=item *
add the installed Imager include directory to INC
=item *
add the Imager typemap to TYPEMAPS
=item *
include the headers needed by Imager C extension modules.
=item *
declare and initialize the Imager API function table pointer
=item *
filter the supplied code to replace Imager's class names with those
that Inline::C can handle.
=back
=head1 LIMITATIONS
The filtering mechanism is global, it will replace the class names
even inside string constants. If you need a string matching the name
of one of Imager's classes, like C<"Imager::Color"> you will need to
split it into 2 to use C's string pasting mechanism, for example:
C<"Imager:" ":Color">.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 REVISION
$Revision$
=head1 SEE ALSO
Imager, Imager::ExtUtils, Imager::API, Imager::APIRef,
samples/inline_replace_color.pl
=cut

View File

@@ -0,0 +1,433 @@
=for stopwords freetype MinGW dfont Redhat SDK IFD GDI TTF preprocessor Redhat-like
=head1 NAME
Imager::Install - installation notes for Imager
=head1 SYNOPSIS
perl Makefile.PL
make
make test
make install
=head1 DESCRIPTION
Assuming you have all of your required libraries in the places Imager
looks, you should be able to use the standard mantra:
perl Makefile.PL
make
make test
make install
to install Imager.
If you've installed libraries in places Imager doesn't look, you can
supply extra locations either with command-line options:
perl Makefile.PL --libpath=/home/tony/local/lib --incpath=/home/tony/local/include
or with environment variables:
export IM_LIBPATH=/home/tony/local/lib IM_INCPATH=/home/tony/local/include
perl Makefile.PL
Imager's F<Makefile.PL> produces an epilogue indicating which
libraries have and haven't been found, for example:
Libraries found:
FT2
GIF
JPEG
PNG
T1
TIFF
Libraries *not* found:
Win32
If a library you expect to be found isn't on this list, use the
C<--verbose> or C<-v> option to produce way too much information from
Imager's search for the libraries:
perl Makefile.PL -v
If you can't resolve this, then run
perl errep.perl
and include the (large) generated F<report.txt> in your email to:
bug-Imager@rt.cpan.org
There are other options used to configure how Imager is built:
=over
=item C<--nolog>
build Imager without logging support. This will speed up Imager a
little. You can also remove logging by setting the C<IMAGER_NOLOG>
environment variable to a true value.
=item C<--coverage>
used to build Imager for C<gcov> coverage testing. This is intended
for development and also requires options supplied to C<make>.
=item C<--assert>
build Imager with assertions enabled.
=item C<--tracecontext>
build Imager to trace context object management to C<stderr> for
debugging.
=back
=head2 Build time environment variables
X<build time environment variables>
=over
=item *
X<< C<IMAGER_NOLOG> >>C<IMAGER_NOLOG> - build Imager with logging disabled.
=item *
X<< C<IMAGER_DEBUG_MALLOC> >>C<IMAGER_DEBUG_MALLOC> - build Imager with it's
debug malloc wrappers. This is I<not> compatible with threaded code.
=item *
X<< C<IM_INCPATH> >>C<IM_INCPATH> - equivalent to C<--incpath>.
=item *
X<< C<IM_LIBPATH> >>C<IM_LIBPATH> - equivalent to C<--libpath>.
=item *
X<< C<IM_VERBOSE> >>C<IM_VERBOSE> - equivalent to C<--verbose>
=item *
X<< C<IM_CFLAGS> >>C<IM_CFLAGS> - extra C compiler flags.
=item *
X<< C<IM_LFLAGS> >>C<IM_LFLAGS> - extra linker flags.
=item *
X<< C<IM_DFLAGS> >>C<IM_DFLAGS> - extra preprocessor flags.
=back
=head1 EXTERNAL LIBRARIES
Some of the file format and font modules included with Imager use
external libraries, which should be installed before you try to
install Imager itself.
If you don't have the libraries installed then Imager itself will
install successfully, but the file format or font support module won't
be.
Preferably the latest version of each library should be used, simple
because it has the latest security fixes.
=head2 PNG - C<libpng>
X<< C<libpng> >>L<Imager::File::PNG> uses L<< C<libpng>
|http://www.libpng.org/pub/png/libpng.html >> for PNG image file
support.
Debian package: C<libpng-dev>
Redhat package: C<libpng-devel>
Cygwin: C<libpng-devel>
=head2 TIFF - C<libtiff>
X<< C<libtiff> >>L<Imager::File::TIFF> uses
L<< C<libtiff> |http://www.remotesensing.org/libtiff/ >> for GIF image file
support.
Version 3.6.0 or later is required to avoid an exploit with infinite
IFD loops, though it's possible some distributions have applied the
fix to older versions as a security fix.
Version 3.9.0 is rejected during the probe process due to a serious
bug, fixed in 3.9.1.
Debian package: C<libtiff4-dev>
Redhat package: C<libtiff-devel>
Cygwin: C<libtiff-devel>
=head2 GIF - C<libgif>
X<< C<libgif> >>L<Imager::File::GIF> uses
L<< C<libgif> |http://sourceforge.net/projects/giflib/ >> for GIF image file
support.
C<libgif> releases 4.2.0 and 5.0.0 are specifically not supported, due
to bugs in those versions.
Release 4.1.4 or later should be used.
C<giflib> 3 is no longer supported.
C<libungif> is no longer supported as an alternative.
Debian package: C<libgif-dev>
Redhat package: C<giflib-devel>
Cygwin: C<libgif-devel>
=head2 JPEG - C<libjpeg>
L<Imager::File::JPEG> uses L<< C<libjpeg> |http://www.ijg.org/ >> for JPEG
image file support.
You may also use
L<< C<libjpeg-turbo> |http://sourceforge.net/projects/libjpeg-turbo/ >>.
To install older releases of C<libjpeg> from source, you'll need to
run:
make install-lib
to install the libraries. C<make install> only installs the program
binaries.
Redhat package: C<libjpeg-devel>
Debian package: C<libjpeg-dev>
Cygwin: C<libjpeg-devel>
=head2 Freetype 2.x - C<libfreetype>
L<Imager::Font::FT2> uses L<< Freetype 2
(C<libfreetype>)|http://www.freetype.org/ >> for font support, supporting
too many font formats to mention here.
This is the recommended library to use for font support.
Debian package: C<libfreetype6-dev>
Redhat package: C<freetype-devel>
Cygwin: C<libfreetype-devel>
=head2 Win32 GDI fonts
L<Imager::Font::W32> uses L<Win32
GDI|http://msdn.microsoft.com/en-us/library/dd145203%28v=vs.85%29.aspx>
to render text using installed Windows fonts.
This requires Win32 SDK headers and libraries, and is only expected to
work on native Win32 or Cygwin.
For this to work under Cygwin, install the C<w32api-headers> and
C<w32api-runtime> packages.
=head2 C<t1lib>
L<Imager::Font::T1> uses L<< C<t1lib> |http://www.t1lib.org/ >> for
font support, supporting Postscript Type 1 fonts only.
=for stopwords
abandonware
T1Lib is abandonware, the latest released version has several bugs
that reliably crash on 64-bit systems.
Expect C<Imager::Font::T1> to be unbundled from the Imager
distribution at some point.
Debian package: C<libt1-dev>
Redhat package: C<t1lib-devel>
=head2 Freetype 1.x - C<libttf>
Imager uses L<< Freetype 1 (C<libttf>)|http://www.freetype.org/ >> if
available for font support, supporting TTF fonts only.
Freetype 1.x is essentially unsupported and shouldn't be used for new
code.
Expect Freetype 1 support to be removed from Imager at some point.
=head1 PLATFORM SPECIFICS
=head2 Linux
Several distributions include an Imager package, but they are
typically several releases behind due to the nature of release cycles.
Imager typically supports the external libraries as packaged with any
supported release of Linux.
=head3 Debian
To install the libraries used by Imager under Debian (or Ubuntu), run
as root (or with sudo):
apt-get install libgif-dev libjpeg8-dev libtiff4-dev libpng12-dev libfreetype6-dev
You may also need to install development tools:
apt-get install build-essential
=head3 Redhat
To install the libraries used by Imager under Redhat and related Linux
distributions, run as root (or sudo):
yum install giflib-devel libjpeg-devel libtiff-devel libpng-devel freetype-devel
To install the development tools needed:
yum install gcc
(which appears to be enough on a base Redhat-like install) or the more
commonly recommended recipe:
yum groupinstall "Development Tools"
which is massive overkill.
=head2 Mac OS X
=head3 Building libraries
The default perl build in Snow Leopard and Lion is a fat binary, and
default builds of C<giflib>, C<libpng> and C<libjpeg> (and maybe other
libraries) will produce link failures.
To avoid this you need to supply a C<CFLAGS> parameter to the
library's configure script, but since the C<-arch> flag conflicts with
the options used to build the dependency files, you need to supply
another flag to disable dependency tracking.
Snow Leopard fat binaries include C<i386>, C<x86_64> and C<PPC>
objects, hence you would run configure like:
./configure --disable-dependency-tracking CFLAGS='-arch x86_64 -arch i386 -arch ppc'
Lion doesn't support C<PPC>, so there you run configure like:
./configure --disable-dependency-tracking CFLAGS='-arch x86_64 -arch i386'
For C<libgif> you might also want to supply the C<--without-x> option:
./configure --disable-dependency-tracking --without-x CFLAGS='-arch x86_64 -arch i386'
If you copy library files into place manually, you may need to run
C<ranlib> on them in their new location:
ranlib /usr/local/lib/libgif.a
=head3 Macintosh C<dfont> and suitcase font support
Through Freetype 2.1, Imager can use Macintosh C<DFON> (C<.dfont>)
fonts and suitcase font files.
If you want to be able to use more than just the first face in the
font file though, you will need to configure C<freetype2> with the
--with-old-mac-fonts option:
./configure --with-old-mac-fonts
You can use the index option to get to the other font faces in the
file:
# get the second face from $file
my $font = Imager::Font->new(file=>$file, index=>1)
or die Imager->errstr;
If you're using a suitcase font, you will also need to force the use
of Freetype 2 with the type argument:
my $font = Imager::Font->new(file=>$suitcase, type=>'ft2', index=>$index)
or die Imager->errstr;
=head2 Microsoft Windows
The simplest way to install the libraries used by Imager is to install
L<Strawberry perl|http://strawberryperl.com/>.
You can then use either the bundled Imager, or install from CPAN.
If you get errors from your make tool, make sure you're using the same
make that was used to build your perl - C<nmake> for Visual C/C++ and
C<dmake> for MinGW, run:
perl -V:make
to see which make was used to build your perl.
=head2 Cygwin
To build Imager with as much library support as possible on Cygwin,
install the following packages:
libjpeg-devel libpng-devel libgif-devel libtiff-devel
libfreetype-devel t1lib-devel w32api-headers w32api-runtime
If you see an error under cygwin during testing along the lines of:
C:\cygwin\bin\perl.exe: *** unable to remap C:\cygwin\...some dll to the
same address as parent (0x...) != 0x....
you will need to install the cygwin C<rebase> package and run:
$ rebaseall -v
or possibly, just:
$ perlrebase
will fix the problem. 64-bit Cygwin significantly reduces occurrences
of this problem.
=head1 Other issues
=head2 Freetype 1.x vs Freetype 2.x
Freetype 1.x is no longer recommended, is no longer supported
upstream, and receives only limited updates in Imager.
These two libraries have some conflicting include file names, but as
long as you don't put the Freetype 2.x F<freetype.h> directory in the
include path it should all work.
Put the directory containing F<ft2build.h> in the include path, but
not the directory containing the freetype 2.x F<freetype.h>.
If you see compilation errors from font.c you've probably made the
mistake of putting the Freetype 2.x F<freetype.h> directory into the
include path.
To see which directories should be in the include path, try:
freetype-config --cflags
Ideally, C<freetype-config> should be in the PATH when building Imager
with freetype 2.x support, in which case L<Imager::Font::FT2> can
configure itself.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

View File

@@ -0,0 +1,115 @@
=head1 NAME
Imager::LargeSamples - track/document large sample support
=head1 SYNOPSIS
# make a large sample image
my $im = Imager->new(..., bits => 16);
# call some method
my $result = $im->$method(...);
# was the image modified at its full sample size
=head1 DESCRIPTION
Imager has had in-memory support for large samples for years now, but
many methods still don't work at the higher sample size when supplied
with a large sample image.
This document will track which methods support large samples and which
don't, for future improvements.
=head1 Support by method
Method Support Notes
------ ------- -----
arc Partial [1]
box Partial [2]
circle Partial [1]
convert Full
copy Full
crop Full
difference Full
filter Partial Depends on the filter.
flip Full
flood_fill Partial [1]
getpixel Full
getsamples Full
getscanline Full
map None
masked Full
matrix_transform
Full
paste Full
polygon Partial [1]
polyline None
read Partial See L<File format large sample support>
read_multi Partial See L<File format large sample support>
rotate Full
rubthrough Full
scale Partial Some qtypes support large samples
scaleX None
scaleY None
setpixel Full
setscanline Full
string Full Preserves large samples, but most font drivers
generate 8 or fewer bits of levels of coverage.
transform None
transform2 None
write Partial See L<File format large sample support>
write_multi Partial See L<File format large sample support>
[1] filling an area using the fill parameter works at the full depth
of the image, using filled => 1 and color works at 8-bits/sample
[2] box() will fill the area at the supplied color, but outline at
8-bits/sample.
=head1 File format large sample support
Format Format samples Imager support
------ -------------- --------------
BMP 8 8
GIF 8 8
ICO 8 8
JPEG 8, 12 8
PBM 1 1
PGM/PPM 1-16 read any, writes 8, 16
PNG 1, 2, 4, 8, 16 1, 2, 4, 8 paletted
1, 8, 16 gray (1 for is_monochrome() images)
8, 16 RGB
RAW 8
SGI 8, 16 8, 16
TGA 8 8
TIFF (many) read/write 8, 16, 32 contig rgb/grey images
read/write bi-level
read/write 4/8 paletted images
=head1 Filter larger sample support
Filter Large sample support
------ --------------------
autolevels No
bumpmap No
bumpmap_complex No
contrast No
conv Yes
fountain Yes
gaussian Yes
gradgen No
hardinvert Yes
mosaic No
postlevels No
radnoise No
turbnoise No
unsharpmask Yes
watermark No
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

View File

@@ -0,0 +1,525 @@
package Imager::Matrix2d;
use 5.006;
use strict;
use Scalar::Util qw(reftype looks_like_number);
use Carp qw(croak);
our $VERSION = "1.013";
=head1 NAME
Imager::Matrix2d - simple wrapper for matrix construction
=head1 SYNOPSIS
use Imager::Matrix2d;
$m1 = Imager::Matrix2d->identity;
$m2 = Imager::Matrix2d->rotate(radians=>$angle, x=>$cx, y=>$cy);
$m3 = Imager::Matrix2d->translate(x=>$dx, y=>$dy);
$m4 = Imager::Matrix2d->shear(x=>$sx, y=>$sy);
$m5 = Imager::Matrix2d->reflect(axis=>$axis);
$m6 = Imager::Matrix2d->scale(x=>$xratio, y=>$yratio);
$m8 = Imager::Matric2d->matrix($v11, $v12, $v13,
$v21, $v22, $v23,
$v31, $v32, $v33);
$m6 = $m1 * $m2;
$m7 = $m1 + $m2;
use Imager::Matrix2d qw(:handy);
# various m2d_* functions imported
# where m2d_(.*) calls Imager::Matrix2d->$1()
=head1 DESCRIPTION
This class provides a simple wrapper around a reference to an array of
9 coefficients, treated as a matrix:
[ 0, 1, 2,
3, 4, 5,
6, 7, 8 ]
Most of the methods in this class are constructors. The others are
overloaded operators.
Note that since Imager represents images with y increasing from top to
bottom, rotation angles are clockwise, rather than counter-clockwise.
=over
=cut
our @ISA = 'Exporter';
require Exporter;
our @EXPORT_OK = qw(m2d_rotate m2d_identity m2d_translate m2d_shear
m2d_reflect m2d_scale);
our %EXPORT_TAGS =
(
handy=> [ qw(m2d_rotate m2d_identity m2d_translate m2d_shear
m2d_reflect m2d_scale) ],
);
use overload
'*' => \&_mult,
'+' => \&_add,
'""'=>\&_string,
"eq" => \&_eq;
=item identity()
Returns the identity matrix.
=cut
sub identity {
return bless [ 1, 0, 0,
0, 1, 0,
0, 0, 1 ], $_[0];
}
=item rotate(radians=>$angle)
=item rotate(degrees=>$angle)
Creates a matrix that rotates around the origin, or around the point
(x,y) if the 'x' and 'y' parameters are provided.
=cut
sub rotate {
my ($class, %opts) = @_;
my $angle;
if (defined $opts{radians}) {
$angle = $opts{radians};
}
elsif (defined $opts{degrees}) {
$angle = $opts{degrees} * 3.1415926535 / 180;
}
else {
$Imager::ERRSTR = "degrees or radians parameter required";
return undef;
}
if ($opts{'x'} || $opts{'y'}) {
$opts{'x'} ||= 0;
$opts{'y'} ||= 0;
return $class->translate('x'=>$opts{'x'}, 'y'=>$opts{'y'})
* $class->rotate(radians=>$angle)
* $class->translate('x'=>-$opts{'x'}, 'y'=>-$opts{'y'});
}
else {
my $sin = sin($angle);
my $cos = cos($angle);
return bless [ $cos, -$sin, 0,
$sin, $cos, 0,
0, 0, 1 ], $class;
}
}
=item translate(x=>$dx, y=>$dy)
=item translate(x=>$dx)
=item translate(y=>$dy)
Translates by the specify amounts.
=cut
sub translate {
my ($class, %opts) = @_;
if (defined $opts{'x'} || defined $opts{'y'}) {
my $x = $opts{'x'} || 0;
my $y = $opts{'y'} || 0;
return bless [ 1, 0, $x,
0, 1, $y,
0, 0, 1 ], $class;
}
$Imager::ERRSTR = 'x or y parameter required';
return undef;
}
=item shear(x=>$sx, y=>$sy)
=item shear(x=>$sx)
=item shear(y=>$sy)
Shear by the given amounts.
=cut
sub shear {
my ($class, %opts) = @_;
if (defined $opts{'x'} || defined $opts{'y'}) {
return bless [ 1, $opts{'x'}||0, 0,
$opts{'y'}||0, 1, 0,
0, 0, 1 ], $class;
}
$Imager::ERRSTR = 'x and y parameters required';
return undef;
}
=item reflect(axis=>$axis)
Reflect around the given axis, either 'x' or 'y'.
=item reflect(radians=>$angle)
=item reflect(degrees=>$angle)
Reflect around a line drawn at the given angle from the origin.
=cut
sub reflect {
my ($class, %opts) = @_;
if (defined $opts{axis}) {
my $result = $class->identity;
if ($opts{axis} eq "y") {
$result->[0] = -$result->[0];
}
elsif ($opts{axis} eq "x") {
$result->[4] = -$result->[4];
}
else {
$Imager::ERRSTR = 'axis must be x or y';
return undef;
}
return $result;
}
my $angle;
if (defined $opts{radians}) {
$angle = $opts{radians};
}
elsif (defined $opts{degrees}) {
$angle = $opts{degrees} * 3.1415926535 / 180;
}
else {
$Imager::ERRSTR = 'axis, degrees or radians parameter required';
return undef;
}
# fun with matrices
return $class->rotate(radians=>-$angle) * $class->reflect(axis=>'x')
* $class->rotate(radians=>$angle);
}
=item scale(x=>$xratio, y=>$yratio)
Scales at the given ratios.
You can also specify a center for the scaling with the C<cx> and C<cy>
parameters.
=cut
sub scale {
my ($class, %opts) = @_;
if (defined $opts{'x'} || defined $opts{'y'}) {
$opts{'x'} = 1 unless defined $opts{'x'};
$opts{'y'} = 1 unless defined $opts{'y'};
if ($opts{cx} || $opts{cy}) {
return $class->translate('x'=>-$opts{cx}, 'y'=>-$opts{cy})
* $class->scale('x'=>$opts{'x'}, 'y'=>$opts{'y'})
* $class->translate('x'=>$opts{cx}, 'y'=>$opts{cy});
}
else {
return bless [ $opts{'x'}, 0, 0,
0, $opts{'y'}, 0,
0, 0, 1 ], $class;
}
}
else {
$Imager::ERRSTR = 'x or y parameter required';
return undef;
}
}
=item matrix($v11, $v12, $v13, $v21, $v22, $v23, $v31, $v32, $v33)
Create a matrix with custom coefficients.
=cut
sub matrix {
my ($class, @self) = @_;
if (@self == 9) {
return bless \@self, $class;
}
else {
$Imager::ERRSTR = "9 coefficients required";
return;
}
}
=item transform($x, $y)
Transform a point the same way matrix_transform does.
=cut
sub transform {
my ($self, $x, $y) = @_;
my $sz = $x * $self->[6] + $y * $self->[7] + $self->[8];
my ($sx, $sy);
if (abs($sz) > 0.000001) {
$sx = ($x * $self->[0] + $y * $self->[1] + $self->[2]) / $sz;
$sy = ($x * $self->[3] + $y * $self->[4] + $self->[5]) / $sz;
}
else {
$sx = $sy = 0;
}
return ($sx, $sy);
}
=item compose(matrix...)
Compose several matrices together for use in transformation.
For example, for three matrices:
my $out = Imager::Matrix2d->compose($m1, $m2, $m3);
is equivalent to:
my $out = $m3 * $m2 * $m1;
Returns the identity matrix if no parameters are supplied.
May return the supplied matrix if only one matrix is supplied.
=cut
sub compose {
my ($class, @in) = @_;
@in
or return $class->identity;
my $out = pop @in;
for my $m (reverse @in) {
$out = $out * $m;
}
return $out;
}
=item _mult()
Implements the overloaded '*' operator. Internal use.
Currently both the left and right-hand sides of the operator must be
an Imager::Matrix2d.
When composing a matrix for transformation you should multiply the
matrices in the reverse order of the transformations:
my $shear = Imager::Matrix2d->shear(x => 0.1);
my $rotate = Imager::Matrix2d->rotate(degrees => 45);
my $shear_then_rotate = $rotate * $shear;
or use the compose method:
my $shear_then_rotate = Imager::Matrix2d->compose($shear, $rotate);
=cut
sub _mult {
my ($left, $right, $order) = @_;
if (ref($right)) {
if (reftype($right) eq "ARRAY") {
@$right == 9
or croak "9 elements required in array ref";
if ($order) {
($left, $right) = ($right, $left);
}
my @result;
for my $i (0..2) {
for my $j (0..2) {
my $accum = 0;
for my $k (0..2) {
$accum += $left->[3*$i + $k] * $right->[3*$k + $j];
}
$result[3*$i+$j] = $accum;
}
}
return bless \@result, __PACKAGE__;
}
else {
croak "multiply by array ref or number";
}
}
elsif (defined $right && looks_like_number($right)) {
my @result = map $_ * $right, @$left;
return bless \@result, __PACKAGE__;
}
else {
# something we don't handle
croak "multiply by array ref or number";
}
}
=item _add()
Implements the overloaded binary '+' operator.
Currently both the left and right sides of the operator must be
Imager::Matrix2d objects.
=cut
sub _add {
my ($left, $right, $order) = @_;
if (ref($right) && UNIVERSAL::isa($right, __PACKAGE__)) {
my @result;
for (0..8) {
push @result, $left->[$_] + $right->[$_];
}
return bless \@result, __PACKAGE__;
}
else {
return undef;
}
}
=item _string()
Implements the overloaded stringification operator.
This returns a string containing 3 lines of text with no terminating
newline.
I tried to make it fairly nicely formatted. You might disagree :)
=cut
sub _string {
my ($m) = @_;
my $maxlen = 0;
for (@$m[0..8]) {
if (length() > $maxlen) {
$maxlen = length;
}
}
$maxlen <= 9 or $maxlen = 9;
my @left = ('[ ', ' ', ' ');
my @right = ("\n", "\n", ']');
my $out;
my $width = $maxlen+2;
for my $i (0..2) {
$out .= $left[$i];
for my $j (0..2) {
my $val = $m->[$i*3+$j];
if (length $val > 9) {
$val = sprintf("%9f", $val);
if ($val =~ /\./ && $val !~ /e/i) {
$val =~ s/0+$//;
$val =~ s/\.$//;
}
$val =~ s/^\s//;
}
$out .= sprintf("%-${width}s", "$val, ");
}
$out =~ s/ +\Z/ /;
$out .= $right[$i];
}
$out;
}
=item _eq
Implement the overloaded equality operator.
Provided for older perls that don't handle magic auto generation of eq
from "".
=cut
sub _eq {
my ($left, $right) = @_;
return $left . "" eq $right . "";
}
=back
The following functions are shortcuts to the various constructors.
These are not methods.
You can import these methods with:
use Imager::Matrix2d ':handy';
=over
=item m2d_identity
=item m2d_rotate()
=item m2d_translate()
=item m2d_shear()
=item m2d_reflect()
=item m2d_scale()
=back
=cut
sub m2d_identity {
return __PACKAGE__->identity;
}
sub m2d_rotate {
return __PACKAGE__->rotate(@_);
}
sub m2d_translate {
return __PACKAGE__->translate(@_);
}
sub m2d_shear {
return __PACKAGE__->shear(@_);
}
sub m2d_reflect {
return __PACKAGE__->reflect(@_);
}
sub m2d_scale {
return __PACKAGE__->scale(@_);
}
1;
=head1 AUTHOR
Tony Cook <tony@develop-help.com>
=head1 BUGS
Needs a way to invert a matrix.
=head1 SEE ALSO
Imager(3), Imager::Font(3)
http://imager.perl.org/
=cut

View File

@@ -0,0 +1,326 @@
package Imager::Preprocess;
use 5.006;
use strict;
require Exporter;
use Getopt::Long;
use Text::ParseWords;
our @EXPORT = qw(preprocess);
our @ISA = qw(Exporter);
our $VERSION = "1.002";
sub preprocess {
unshift @ARGV, grep /^-/, shellwords($ENV{IMAGER_PREPROCESS_OPTS})
if $ENV{IMAGER_PREPROCESS_OPTS};
my $skip_lines = 0;
GetOptions("l" => \$skip_lines)
or usage();
my $keep_lines = !$skip_lines;
my $src = shift @ARGV;
my $dest = shift @ARGV
or usage();
open SRC, "< $src"
or die "Cannot open $src: $!\n";
my $cond;
my $cond_line;
my $save_code;
my @code;
my $code_line;
my @out;
my $failed;
push @out,
"#define IM_ROUND_8(x) ((int)((x)+0.5))\n",
"#define IM_ROUND_double(x) (x)\n",
"#define IM_LIMIT_8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n",
"#define IM_LIMIT_double(x) ((x) < 0.0 ? 0.0 : (x) > 1.0 ? 1.0 : (x))\n";
push @out, "#line 1 \"$src\"\n" if $keep_lines;
while (defined(my $line = <SRC>)) {
if ($line =~ /^\#code\s+(\S.+)$/) {
$save_code
and do { warn "$src:$code_line:Unclosed #code block\n"; ++$failed; };
$cond = $1;
$cond_line = $.;
$code_line = $. + 1;
$save_code = 1;
}
elsif ($line =~ /^\#code\s*$/) {
$save_code
and do { warn "$src:$code_line:Unclosed #code block\n"; ++$failed; };
$cond = '';
$cond_line = 0;
$code_line = $. + 1;
$save_code = 1;
}
elsif ($line =~ /^\#\/code\s*$/) {
$save_code
or do { warn "$src:$.:#/code without #code\n"; ++$failed; next; };
if ($cond) {
push @out, "#line $cond_line \"$src\"\n" if $keep_lines;
push @out, " if ($cond) {\n";
}
push @out,
"#undef IM_EIGHT_BIT\n",
"#define IM_EIGHT_BIT 1\n",
"#undef IM_FILL_COMBINE\n",
"#define IM_FILL_COMBINE(fill) ((fill)->combine)\n",
"#undef IM_FILL_FILLER\n",
"#define IM_FILL_FILLER(fill) ((fill)->f_fill_with_color)\n";
push @out, "#line $code_line \"$src\"\n" if $keep_lines;
push @out, byte_samples(@code);
push @out, " }\n", " else {\n"
if $cond;
push @out,
"#undef IM_EIGHT_BIT\n",
"#undef IM_FILL_COMBINE\n",
"#define IM_FILL_COMBINE(fill) ((fill)->combinef)\n",
"#undef IM_FILL_FILLER\n",
"#define IM_FILL_FILLER(fill) ((fill)->f_fill_with_fcolor)\n";
push @out, "#line $code_line \"$src\"\n" if $keep_lines;
push @out, double_samples(@code);
push @out, " }\n"
if $cond;
push @out, "#line ",$.+1," \"$src\"\n" if $keep_lines;
@code = ();
$save_code = 0;
}
elsif ($save_code) {
push @code, $line;
}
else {
push @out, $line;
}
}
if ($save_code) {
warn "$src:$code_line:#code block not closed by EOF\n";
++$failed;
}
close SRC;
$failed
and die "Errors during parsing, aborting\n";
open DEST, "> $dest"
or die "Cannot open $dest: $!\n";
print DEST @out;
close DEST;
}
sub byte_samples {
# important we make a copy
my @lines = @_;
for (@lines) {
s/\bIM_GPIX\b/i_gpix/g;
s/\bIM_GLIN\b/i_glin/g;
s/\bIM_PPIX\b/i_ppix/g;
s/\bIM_PLIN\b/i_plin/g;
s/\bIM_GSAMP\b/i_gsamp/g;
s/\bIM_PSAMP\b/i_psamp/g;
s/\bIM_SAMPLE_MAX\b/255/g;
s/\bIM_SAMPLE_MAX2\b/65025/g;
s/\bIM_SAMPLE_T/i_sample_t/g;
s/\bIM_COLOR\b/i_color/g;
s/\bIM_WORK_T\b/int/g;
s/\bIM_Sf\b/"%d"/g;
s/\bIM_Wf\b/"%d"/g;
s/\bIM_SUFFIX\((\w+)\)/$1_8/g;
s/\bIM_ROUND\(/IM_ROUND_8(/g;
s/\bIM_ADAPT_COLORS\(/i_adapt_colors(/g;
s/\bIM_LIMIT\(/IM_LIMIT_8(/g;
s/\bIM_RENDER_LINE\(/i_render_line(/g;
s/\bIM_FILL_COMBINE_F\b/i_fill_combine_f/g;
}
@lines;
}
sub double_samples {
# important we make a copy
my @lines = @_;
for (@lines) {
s/\bIM_GPIX\b/i_gpixf/g;
s/\bIM_GLIN\b/i_glinf/g;
s/\bIM_PPIX\b/i_ppixf/g;
s/\bIM_PLIN\b/i_plinf/g;
s/\bIM_GSAMP\b/i_gsampf/g;
s/\bIM_PSAMP\b/i_psampf/g;
s/\bIM_SAMPLE_MAX\b/1.0/g;
s/\bIM_SAMPLE_MAX2\b/1.0/g;
s/\bIM_SAMPLE_T/i_fsample_t/g;
s/\bIM_COLOR\b/i_fcolor/g;
s/\bIM_WORK_T\b/double/g;
s/\bIM_Sf\b/"%f"/g;
s/\bIM_Wf\b/"%f"/g;
s/\bIM_SUFFIX\((\w+)\)/$1_double/g;
s/\bIM_ROUND\(/IM_ROUND_double(/g;
s/\bIM_ADAPT_COLORS\(/i_adapt_fcolors(/g;
s/\bIM_LIMIT\(/IM_LIMIT_double(/g;
s/\bIM_RENDER_LINE\(/i_render_linef(/g;
s/\bIM_FILL_COMBINE_F\b/i_fill_combinef_f/g;
}
@lines;
}
sub usage {
die <<EOS;
Usage: perl -MImager::Preprocess -epreprocess [-l] infile outfile
-l don't produce #line directives
infile - input file
outfile output file
See perldoc Imager::Preprocess for details.
EOS
}
1;
__END__
=head1 NAME
=for stopwords preprocessor
Imager::Preprocess - simple preprocessor for handling multiple sample sizes
=head1 SYNOPSIS
/* in the source: */
#code condition true to work with 8-bit samples
... code using preprocessor types/values ...
#/code
# process and make #line directives
perl -MImager::Preprocess -epreprocess foo.im foo.c
# process and no #line directives
perl -MImager::Preprocess -epreprocess -l foo.im foo.c
=head1 DESCRIPTION
This is a simple preprocessor that aims to reduce duplication of
source code when implementing an algorithm both for 8-bit samples and
double samples in Imager.
Imager's C<Makefile.PL> currently scans the F<MANIFEST> for F<.im>
files and adds Makefile files to convert these to F<.c> files.
The beginning of a sample-independent section of code is preceded by:
#code expression
where I<expression> should return true if processing should be done at
8-bits/sample.
You can also use a #code block around a function definition to produce
8-bit and double sample versions of a function. In this case #code
has no expression and you will need to use IM_SUFFIX() to produce
different function names.
The end of a sample-independent section of code is terminated by:
#/code
#code sections cannot be nested.
#/code without a starting #code is an error.
The following types and values are defined in a #code section:
=over
=item *
IM_GPIX(C<im>, C<x>, C<y>, C<&col>)
=item *
IM_GLIN(C<im>, C<l>, C<r>, C<y>, C<colors>)
=item *
IM_PPIX(C<im>, C<x>, C<y>, C<&col>)
=item *
IM_PLIN(C<im>, C<x>, C<y>, C<colors>)
=item *
IM_GSAMP(C<im>, C<l>, C<r>, C<y>, C<samples>, C<chans>, C<chan_count>)
These correspond to the appropriate image function, eg. IM_GPIX()
becomes i_gpix() or i_gpixf() as appropriate.
=item *
IM_ADAPT_COLORS(C<dest_channels>, C<src_channels>, C<colors>, C<count>)
Call i_adapt_colors() or i_adapt_fcolors().
=item *
IM_FILL_COMBINE(C<fill>) - retrieve the combine function from a fill
object.
=item *
IM_FILL_FILLER(C<fill>) - retrieve the fill_with_* function from a fill
object.
=item *
IM_SAMPLE_MAX - maximum value for a sample
=item *
IM_SAMPLE_MAX2 - maximum value for a sample, squared
=item *
IM_SAMPLE_T - type of a sample (i_sample_t or i_fsample_t)
=item *
IM_COLOR - color type, either i_color or i_fcolor.
=item *
IM_WORK_T - working sample type, either int or double.
=item *
IM_Sf - format string for the sample type, C<"%d"> or C<"%f">.
=item *
IM_Wf - format string for the work type, C<"%d"> or C<"%f">.
=item *
IM_SUFFIX(identifier) - adds _8 or _double onto the end of identifier.
=item *
IM_EIGHT_BIT - this is a macro defined only in 8-bit/sample code.
=back
Other types, functions and values may be added in the future.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

712
database/perl/vendor/lib/Imager/Probe.pm vendored Normal file
View File

@@ -0,0 +1,712 @@
package Imager::Probe;
use 5.006;
use strict;
use File::Spec;
use Config;
use Cwd ();
our $VERSION = "1.007";
my @alt_transfer = qw/altname incsuffix libbase/;
sub probe {
my ($class, $req) = @_;
$req->{verbose} ||= $ENV{IM_VERBOSE};
my $name = $req->{name};
my $result;
if ($req->{code}) {
$result = _probe_code($req);
}
if (!$result && $req->{pkg}) {
$result = _probe_pkg($req);
}
if (!$result && $req->{inccheck} && ($req->{libcheck} || $req->{libbase})) {
$req->{altname} ||= "main";
$result = _probe_check($req);
}
if ($result && $req->{testcode}) {
$result = _probe_test($req, $result);
}
if (!$result && $req->{alternatives}) {
ALTCHECK:
my $index = 1;
for my $alt (@{$req->{alternatives}}) {
$req->{altname} = $alt->{altname} || "alt $index";
$req->{verbose}
and print "$req->{name}: Trying alternative $index\n";
my %work = %$req;
for my $key (@alt_transfer) {
exists $alt->{$key} and $work{$key} = $alt->{$key};
}
$result = _probe_check(\%work);
if ($result && $req->{testcode}) {
$result = _probe_test(\%work, $result);
}
$result
and last;
++$index;
}
}
if (!$result && $req->{testcode}) {
$result = _probe_fake($req);
$result or return;
$result = _probe_test($req, $result);
}
$result or return;
return $result;
}
sub _probe_code {
my ($req) = @_;
my $code = $req->{code};
my @probes = ref $code eq "ARRAY" ? @$code : $code;
my $result;
for my $probe (@probes) {
$result = $probe->($req)
and return $result;
}
return;
}
sub is_exe {
my ($name) = @_;
my @exe_suffix = $Config{_exe};
if ($^O eq 'MSWin32') {
push @exe_suffix, qw/.bat .cmd/;
}
elsif ($^O eq 'cygwin') {
push @exe_suffix, "";
}
for my $dir (File::Spec->path) {
for my $suffix (@exe_suffix) {
-x File::Spec->catfile($dir, "$name$suffix")
and return 1;
}
}
return;
}
sub _probe_pkg {
my ($req) = @_;
# Setup pkg-config's environment variable to search non-standard paths
# which may be provided by --libdirs.
my @pkgcfg_paths = map { "$_/pkgconfig" } _lib_paths( $req );
push @pkgcfg_paths, $ENV{ 'PKG_CONFIG_PATH' } if $ENV{ 'PKG_CONFIG_PATH' };
local $ENV{ 'PKG_CONFIG_PATH' } = join $Config{path_sep}, @pkgcfg_paths;
is_exe('pkg-config') or return;
my $redir = $^O eq 'MSWin32' ? '' : '2>/dev/null';
my @pkgs = @{$req->{pkg}};
for my $pkg (@pkgs) {
if (!system("pkg-config $pkg --exists $redir")) {
# if we find it, but the following fail, then pkg-config is too
# broken to be useful
my $cflags = `pkg-config $pkg --cflags`
and !$? or return;
my $lflags = `pkg-config $pkg --libs`
and !$? or return;
my $defines = '';
$cflags =~ s/(-D\S+)/$defines .= " $1"; ''/ge;
chomp $cflags;
chomp $lflags;
print "$req->{name}: Found via pkg-config $pkg\n";
print <<EOS if $req->{verbose};
cflags: $cflags
defines: $defines
lflags: $lflags
EOS
# rt 75869
# if Win32 doesn't provide this information, too bad
if (!grep(/^-L/, split " ", $lflags)
&& $^O ne 'MSWin32') {
# pkg-config told us about the library, make sure it's
# somewhere EU::MM can find it
print "Checking if EU::MM can find $lflags\n" if $req->{verbose};
my ($extra, $bs_load, $ld_load, $ld_run_path) =
ExtUtils::Liblist->ext($lflags, $req->{verbose});
unless ($ld_run_path) {
# search our standard places
$lflags = _resolve_libs($req, $lflags);
}
}
return
{
INC => $cflags,
LIBS => $lflags,
DEFINE => $defines,
};
}
}
print "$req->{name}: Not found via pkg-config\n";
return;
}
sub _is_msvc {
return $Config{cc} eq "cl";
}
sub _lib_basename {
my ($base) = @_;
if (_is_msvc()) {
return $base;
}
else {
return "lib$base";
}
}
sub _lib_option {
my ($base) = @_;
if (_is_msvc()) {
return $base . $Config{_a};
}
else {
return "-l$base";
}
}
sub _quotearg {
my ($opt) = @_;
return $opt =~ /\s/ ? qq("$opt") : $opt;
}
sub _probe_check {
my ($req) = @_;
my @libcheck;
my @libbase;
if ($req->{libcheck}) {
if (ref $req->{libcheck} eq "ARRAY") {
push @libcheck, @{$req->{libcheck}};
}
else {
push @libcheck, $req->{libcheck};
}
}
elsif ($req->{libbase}) {
@libbase = ref $req->{libbase} ? @{$req->{libbase}} : $req->{libbase};
my $lext=$Config{'so'}; # Get extensions of libraries
my $aext=$Config{'_a'};
for my $libbase (@libbase) {
my $basename = _lib_basename($libbase);
push @libcheck, sub {
-e File::Spec->catfile($_[0], "$basename$aext")
|| -e File::Spec->catfile($_[0], "$basename.$lext")
};
}
}
else {
print "$req->{name}: No libcheck or libbase, nothing to search for\n"
if $req->{verbose};
return;
}
my @found_libpath;
my @lib_search = _lib_paths($req);
print "$req->{name}: Searching directories for libraries:\n"
if $req->{verbose};
for my $libcheck (@libcheck) {
for my $path (@lib_search) {
print "$req->{name}: $path\n" if $req->{verbose};
if ($libcheck->($path)) {
print "$req->{name}: Found!\n" if $req->{verbose};
push @found_libpath, $path;
last;
}
}
}
my $found_incpath;
my $inccheck = $req->{inccheck};
my @inc_search = _inc_paths($req);
print "$req->{name}: Searching directories for headers:\n"
if $req->{verbose};
for my $path (@inc_search) {
print "$req->{name}: $path\n" if $req->{verbose};
if ($inccheck->($path)) {
print "$req->{name}: Found!\n" if $req->{verbose};
$found_incpath = $path;
last;
}
}
my $alt = "";
if ($req->{altname}) {
$alt = " $req->{altname}:";
}
print "$req->{name}:$alt includes ", $found_incpath ? "" : "not ",
"found - libraries ", @found_libpath == @libcheck ? "" : "not ", "found\n";
@found_libpath == @libcheck && $found_incpath
or return;
my @libs = map "-L$_", @found_libpath;
if ($req->{libopts}) {
push @libs, $req->{libopts};
}
elsif (@libbase) {
push @libs, map _lib_option($_), @libbase;
}
else {
die "$req->{altname}: inccheck but no libbase or libopts";
}
return
{
INC => _quotearg("-I$found_incpath"),
LIBS => join(" ", map _quotearg($_), @libs),
DEFINE => "",
};
}
sub _probe_fake {
my ($req) = @_;
# the caller provided test code, and the compiler may look in
# places we don't, see Imager-Screenshot ticket 56793,
# so fake up a result so the test code can
my $lopts;
if ($req->{libopts}) {
$lopts = $req->{libopts};
}
elsif (defined $req->{libbase}) {
# might not need extra libraries, eg. Win32 perl already links
# everything
my @libs = $req->{libbase}
? ( ref $req->{libbase} ? @{$req->{libbase}} : $req->{libbase} )
: ();
$lopts = join " ", map _lib_option($_), @libs;
}
if (defined $lopts) {
print "$req->{name}: Checking if the compiler can find them on its own\n";
return
{
INC => "",
LIBS => $lopts,
DEFINE => "",
};
}
else {
print "$req->{name}: Can't fake it - no libbase or libopts\n"
if $req->{verbose};
return;
}
}
sub _probe_test {
my ($req, $result) = @_;
require Devel::CheckLib;
# setup LD_RUN_PATH to match link time
print "Asking liblist for LD_RUN_PATH:\n" if $req->{verbose};
my ($extra, $bs_load, $ld_load, $ld_run_path) =
ExtUtils::Liblist->ext($result->{LIBS}, $req->{verbose});
local $ENV{LD_RUN_PATH};
if ($ld_run_path) {
print "Setting LD_RUN_PATH=$ld_run_path for $req->{name} probe\n"
if $req->{verbose};
$ENV{LD_RUN_PATH} = $ld_run_path;
if ($Config{lddlflags} =~ /([^ ]*-(?:rpath|R)[,=]?)([^ ]+)/
&& -d $2) {
# hackety, hackety
# LD_RUN_PATH is ignored when there's already an -rpath option
# so provide one
my $prefix = $1;
$result->{LDDLFLAGS} = $Config{lddlflags} . " " .
join " ", map "$prefix$_", split $Config{path_sep}, $ld_run_path;
}
}
my $good =
Devel::CheckLib::check_lib
(
debug => $req->{verbose},
LIBS => [ $result->{LIBS} ],
INC => $result->{INC},
header => $req->{testcodeheaders},
function => $req->{testcode},
prologue => $req->{testcodeprologue},
);
unless ($good) {
print "$req->{name}: Test code failed: $@";
return;
}
print "$req->{name}: Passed code check\n";
return $result;
}
sub _resolve_libs {
my ($req, $lflags) = @_;
my @libs = grep /^-l/, split ' ', $lflags;
my %paths;
my @paths = _lib_paths($req);
my $so = $Config{so};
my $libext = $Config{_a};
for my $lib (@libs) {
$lib =~ s/^-l/lib/;
for my $path (@paths) {
if (-e "$path/$lib.$so" || -e "$path/$lib$libext") {
$paths{$path} = 1;
}
}
}
return join(" ", ( map "-L$_", keys %paths ), $lflags );
}
sub _lib_paths {
my ($req) = @_;
print "$req->{name} IM_LIBPATH: $ENV{IM_LIBPATH}\n"
if $req->{verbose} && defined $ENV{IM_LIBPATH};
print "$req->{name} LIB: $ENV{IM_LIBPATH}\n"
if $req->{verbose} && defined $ENV{LIB} && $^O eq "MSWin32";
my $lp = $req->{libpath};
print "$req->{name} libpath: ", ref $lp ? join($Config{path_sep}, @$lp) : $lp, "\n"
if $req->{verbose} && defined $lp;
return _paths
(
$ENV{IM_LIBPATH},
$req->{libpath},
(
map { split ' ' }
grep $_,
@Config{qw/loclibpth libpth libspath/}
),
$^O eq "MSWin32" ? $ENV{LIB} : "",
$^O eq "cygwin" ? "/usr/lib/w32api" : "",
"/usr/lib",
"/usr/local/lib",
_gcc_lib_paths(),
_dyn_lib_paths(),
);
}
sub _gcc_lib_paths {
$Config{gccversion}
or return;
my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
or return;
$base_version >= 4
or return;
local $ENV{LANG} = "C";
local $ENV{LC_ALL} = "C";
my ($lib_line) = grep /^libraries:/, `$Config{cc} -print-search-dirs`
or return;
$lib_line =~ s/^libraries: =//;
chomp $lib_line;
return grep !/gcc/ && -d, split /:/, $lib_line;
}
sub _dyn_lib_paths {
return map { defined() ? split /\Q$Config{path_sep}/ : () }
map $ENV{$_},
qw(LD_RUN_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH LIBRARY_PATH);
}
sub _inc_paths {
my ($req) = @_;
print "$req->{name} IM_INCPATH: $ENV{IM_INCPATH}\n"
if $req->{verbose} && defined $ENV{IM_INCPATH};
print "$req->{name} INCLUDE: $ENV{INCLUDE}\n"
if $req->{verbose} && defined $ENV{INCLUDE} && $^O eq "MSWin32";
my $ip = $req->{incpath};
print "$req->{name} incpath: ", ref $ip ? join($Config{path_sep}, @$ip) : $ip, "\n"
if $req->{verbose} && defined $req->{incpath};
my @paths = _paths
(
$ENV{IM_INCPATH},
$req->{incpath},
$^O eq "MSWin32" ? $ENV{INCLUDE} : "",
$^O eq "cygwin" ? "/usr/include/w32api" : "",
(
map { split ' ' }
grep $_,
@Config{qw/locincpth incpath/}
),
"/usr/include",
"/usr/local/include",
_gcc_inc_paths(),
_dyn_inc_paths(),
);
if ($req->{incsuffix}) {
@paths = map File::Spec->catdir($_, $req->{incsuffix}), @paths;
}
return @paths;
}
sub _gcc_inc_paths {
$Config{gccversion}
or return;
my ($base_version) = $Config{gccversion} =~ /^([0-9]+)/
or return;
$base_version >= 4
or return;
local $ENV{LANG} = "C";
local $ENV{LC_ALL} = "C";
my $devnull = File::Spec->devnull;
my @spam = `$Config{cc} -E -v - <$devnull 2>&1`;
# output includes lines like:
# ...
# ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../x86_64-linux-gnu/include"
# #include "..." search starts here:
# #include <...> search starts here:
# /usr/lib/gcc/x86_64-linux-gnu/4.9/include
# /usr/local/include
# /usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed
# /usr/include/x86_64-linux-gnu
# /usr/include
# End of search list.
# # 1 "<stdin>"
# # 1 "<built-in>"
# ...
while (@spam && $spam[0] !~ /^#include /) {
shift @spam;
}
my @inc;
while (@spam && $spam[0] !~ /^End of search/) {
my $line = shift @spam;
chomp $line;
next if $line =~ /^#include /;
next unless $line =~ s/^\s+//;
push @inc, $line;
}
return @inc;
}
sub _dyn_inc_paths {
return map {
my $tmp = $_;
$tmp =~ s/\blib$/include/ ? $tmp : ()
} _dyn_lib_paths();
}
sub _paths {
my (@in) = @_;
my @out;
# expand any array refs
@in = map { ref() ? @$_ : $_ } @in;
for my $path (@in) {
$path or next;
$path = _tilde_expand($path);
push @out, grep -d $_, split /\Q$Config{path_sep}/, $path;
}
@out = map Cwd::realpath($_), @out;
my %seen;
@out = grep !$seen{$_}++, @out;
return @out;
}
my $home;
sub _tilde_expand {
my ($path) = @_;
if ($path =~ m!^~[/\\]!) {
defined $home or $home = $ENV{HOME};
if (!defined $home && $^O eq 'MSWin32'
&& defined $ENV{HOMEDRIVE} && defined $ENV{HOMEPATH}) {
$home = $ENV{HOMEDRIVE} . $ENV{HOMEPATH};
}
unless (defined $home) {
$home = eval { (getpwuid($<))[7] };
}
defined $home or die "You supplied $path, but I can't find your home directory\n";
$path =~ s/^~//;
$path = File::Spec->catdir($home, $path);
}
return $path;
}
1;
__END__
=head1 NAME
Imager::Probe - hot needle of inquiry for libraries
=head1 SYNOPSIS
require Imager::Probe;
my %probe =
(
# short name of what we're looking for (displayed to user)
name => "FOO",
# pkg-config lookup
pkg => [ qw/name1 name2 name3/ ],
# perl subs that probe for the library
code => [ \&foo_probe1, \&foo_probe2 ],
# or just: code => \&foo_probe,
inccheck => sub { ... },
libcheck => sub { ... },
# search for this library if libcheck not supplied
libbase => "foo",
# library link time options, uses libbase to build options otherwise
libopts => "-lfoo",
# C code to check the library is sane
testcode => "...",
# header files needed
testcodeheaders => [ "stdio.h", "foo.h" ],
);
my $result = Imager::Probe->probe(\%probe)
or print "Foo library not found: ",Imager::Probe->error;
=head1 DESCRIPTION
Does the probes that were hidden in Imager's F<Makefile.PL>, pulled
out so the file format libraries can be externalized.
The return value is either nothing if the probe fails, or a hash
containing:
=over
=item *
C<INC> - C<-I> and other C options
=item *
C<LIBS> - C<-L>, C<-l> and other link-time options
=item *
C<DEFINE> - C<-D> options, if any.
=back
The possible values for the hash supplied to the probe() method are:
=over
=item *
C<pkg> - an array of F<pkg-config> names to probe for. If the
F<pkg-config> checks pass, C<inccheck> and C<libcheck> aren't used.
=item *
C<inccheck> - a code reference that checks if the supplied include
directory contains the required header files.
=item *
C<libcheck> - a code reference that checks if the supplied library
directory contains the required library files. Note: the
F<Makefile.PL> version of this was supplied all of the library file
names instead. C<libcheck> can also be an arrayref of library check
code references, all of which must find a match for the library to be
considered "found".
=item *
C<libbase> - if C<inccheck> is supplied, but C<libcheck> isn't, then a
C<libcheck> that checks for C<lib>I<libbase>I<$Config{_a}> and
C<lib>I<libbase>.I<$Config{so}> is created. If C<libopts> isn't
supplied then that can be synthesized as C<< -lI<libbase>
>>. C<libbase> can also be an arrayref of library base names to search
for, in which case all of the libraries mentioned must be found for
the probe to succeed.
=item *
C<libopts> - if the libraries are found via C<inccheck>/C<libcheck>,
these are the C<-l> options to supply during the link phase.
=item *
C<code> - a code reference to perform custom checks. Returns the
probe result directly. Can also be an array ref of functions to call.
=item *
C<testcode> - test C code that is run with Devel::CheckLib. You also
need to set C<testcodeheaders>.
=item *
C<testcodeprologue> - C code to insert between the headers and the
main function.
=item *
C<incpath> - C<$Config{path_sep}> separated list of header file
directories to check, or a reference to an array of such.
=item *
C<libpath> - C<$Config{path_sep}> separated list of library file
directories to check, or a reference to an array of such.
=item *
C<alternatives> - an optional array reference of alternate
configurations (as hash references) to test if the primary
configuration isn't successful. Each alternative should include an
C<altname> key describing the alternative. Any key not mentioned in
an alternative defaults to the value from the main configuration.
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

View File

@@ -0,0 +1,529 @@
# AUTOMATICALLY GENERATED BY regops.perl
package Imager::Regops;
use 5.006;
use strict;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(%Attr $MaxOperands $PackCode);
our $VERSION = "1.000";
use constant RBC_ADD => 0;
use constant RBC_SUBTRACT => 1;
use constant RBC_MULT => 2;
use constant RBC_DIV => 3;
use constant RBC_MOD => 4;
use constant RBC_POW => 5;
use constant RBC_UMINUS => 6;
use constant RBC_MULTP => 7;
use constant RBC_ADDP => 8;
use constant RBC_SUBTRACTP => 9;
use constant RBC_SIN => 10;
use constant RBC_COS => 11;
use constant RBC_ATAN2 => 12;
use constant RBC_SQRT => 13;
use constant RBC_DISTANCE => 14;
use constant RBC_GETP1 => 15;
use constant RBC_GETP2 => 16;
use constant RBC_GETP3 => 17;
use constant RBC_VALUE => 18;
use constant RBC_HUE => 19;
use constant RBC_SAT => 20;
use constant RBC_HSV => 21;
use constant RBC_RED => 22;
use constant RBC_GREEN => 23;
use constant RBC_BLUE => 24;
use constant RBC_RGB => 25;
use constant RBC_INT => 26;
use constant RBC_IF => 27;
use constant RBC_IFP => 28;
use constant RBC_LE => 29;
use constant RBC_LT => 30;
use constant RBC_GE => 31;
use constant RBC_GT => 32;
use constant RBC_EQ => 33;
use constant RBC_NE => 34;
use constant RBC_AND => 35;
use constant RBC_OR => 36;
use constant RBC_NOT => 37;
use constant RBC_ABS => 38;
use constant RBC_RET => 39;
use constant RBC_JUMP => 40;
use constant RBC_JUMPZ => 41;
use constant RBC_JUMPNZ => 42;
use constant RBC_SET => 43;
use constant RBC_SETP => 44;
use constant RBC_PRINT => 45;
use constant RBC_RGBA => 46;
use constant RBC_HSVA => 47;
use constant RBC_ALPHA => 48;
use constant RBC_LOG => 49;
use constant RBC_EXP => 50;
use constant RBC_DET => 51;
use constant RBC_OP_COUNT => 52;
our @EXPORT = qw(RBC_ADD RBC_SUBTRACT RBC_MULT RBC_DIV RBC_MOD RBC_POW RBC_UMINUS RBC_MULTP RBC_ADDP RBC_SUBTRACTP RBC_SIN RBC_COS RBC_ATAN2 RBC_SQRT RBC_DISTANCE RBC_GETP1 RBC_GETP2 RBC_GETP3 RBC_VALUE RBC_HUE RBC_SAT RBC_HSV RBC_RED RBC_GREEN RBC_BLUE RBC_RGB RBC_INT RBC_IF RBC_IFP RBC_LE RBC_LT RBC_GE RBC_GT RBC_EQ RBC_NE RBC_AND RBC_OR RBC_NOT RBC_ABS RBC_RET RBC_JUMP RBC_JUMPZ RBC_JUMPNZ RBC_SET RBC_SETP RBC_PRINT RBC_RGBA RBC_HSVA RBC_ALPHA RBC_LOG RBC_EXP RBC_DET RBC_OP_COUNT);
our %Attr =
(
'abs' =>
{
'func' => 1,
'opcode' => 38,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'add' =>
{
'func' => 0,
'opcode' => 0,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'addp' =>
{
'func' => 0,
'opcode' => 8,
'parms' => 2,
'result' => 'p',
'types' => 'pp',
},
'alpha' =>
{
'func' => 1,
'opcode' => 48,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'and' =>
{
'func' => 0,
'opcode' => 35,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'atan2' =>
{
'func' => 1,
'opcode' => 12,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'blue' =>
{
'func' => 1,
'opcode' => 24,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'cos' =>
{
'func' => 1,
'opcode' => 11,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'det' =>
{
'func' => 1,
'opcode' => 51,
'parms' => 4,
'result' => 'r',
'types' => 'rrrr',
},
'distance' =>
{
'func' => 1,
'opcode' => 14,
'parms' => 4,
'result' => 'r',
'types' => 'rrrr',
},
'div' =>
{
'func' => 0,
'opcode' => 3,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'eq' =>
{
'func' => 0,
'opcode' => 33,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'exp' =>
{
'func' => 1,
'opcode' => 50,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'ge' =>
{
'func' => 0,
'opcode' => 31,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'getp1' =>
{
'func' => 1,
'opcode' => 15,
'parms' => 2,
'result' => 'p',
'types' => 'rr',
},
'getp2' =>
{
'func' => 1,
'opcode' => 16,
'parms' => 2,
'result' => 'p',
'types' => 'rr',
},
'getp3' =>
{
'func' => 1,
'opcode' => 17,
'parms' => 2,
'result' => 'p',
'types' => 'rr',
},
'green' =>
{
'func' => 1,
'opcode' => 23,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'gt' =>
{
'func' => 0,
'opcode' => 32,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'hsv' =>
{
'func' => 1,
'opcode' => 21,
'parms' => 3,
'result' => 'p',
'types' => 'rrr',
},
'hsva' =>
{
'func' => 1,
'opcode' => 47,
'parms' => 4,
'result' => 'p',
'types' => 'rrrr',
},
'hue' =>
{
'func' => 1,
'opcode' => 19,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'if' =>
{
'func' => 1,
'opcode' => 27,
'parms' => 3,
'result' => 'r',
'types' => 'rrr',
},
'ifp' =>
{
'func' => 1,
'opcode' => 28,
'parms' => 3,
'result' => 'p',
'types' => 'rpp',
},
'int' =>
{
'func' => 1,
'opcode' => 26,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'jump' =>
{
'func' => 0,
'opcode' => 40,
'parms' => 0,
'result' => undef,
'types' => '',
},
'jumpnz' =>
{
'func' => 0,
'opcode' => 42,
'parms' => 1,
'result' => undef,
'types' => 'r',
},
'jumpz' =>
{
'func' => 0,
'opcode' => 41,
'parms' => 1,
'result' => undef,
'types' => 'r',
},
'le' =>
{
'func' => 0,
'opcode' => 29,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'log' =>
{
'func' => 1,
'opcode' => 49,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'lt' =>
{
'func' => 0,
'opcode' => 30,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'mod' =>
{
'func' => 0,
'opcode' => 4,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'mult' =>
{
'func' => 0,
'opcode' => 2,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'multp' =>
{
'func' => 0,
'opcode' => 7,
'parms' => 2,
'result' => 'p',
'types' => 'pr',
},
'ne' =>
{
'func' => 0,
'opcode' => 34,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'not' =>
{
'func' => 0,
'opcode' => 37,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'op_count' =>
{
'func' => 0,
'opcode' => 52,
'parms' => 0,
'result' => undef,
'types' => '',
},
'or' =>
{
'func' => 0,
'opcode' => 36,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'pow' =>
{
'func' => 0,
'opcode' => 5,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'print' =>
{
'func' => 1,
'opcode' => 45,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'red' =>
{
'func' => 1,
'opcode' => 22,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'ret' =>
{
'func' => 0,
'opcode' => 39,
'parms' => 1,
'result' => undef,
'types' => 'p',
},
'rgb' =>
{
'func' => 1,
'opcode' => 25,
'parms' => 3,
'result' => 'p',
'types' => 'rrr',
},
'rgba' =>
{
'func' => 1,
'opcode' => 46,
'parms' => 4,
'result' => 'p',
'types' => 'rrrr',
},
'sat' =>
{
'func' => 1,
'opcode' => 20,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
'set' =>
{
'func' => 0,
'opcode' => 43,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'setp' =>
{
'func' => 0,
'opcode' => 44,
'parms' => 1,
'result' => 'p',
'types' => 'p',
},
'sin' =>
{
'func' => 1,
'opcode' => 10,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'sqrt' =>
{
'func' => 1,
'opcode' => 13,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'subtract' =>
{
'func' => 0,
'opcode' => 1,
'parms' => 2,
'result' => 'r',
'types' => 'rr',
},
'subtractp' =>
{
'func' => 0,
'opcode' => 9,
'parms' => 2,
'result' => 'p',
'types' => 'pp',
},
'uminus' =>
{
'func' => 0,
'opcode' => 6,
'parms' => 1,
'result' => 'r',
'types' => 'r',
},
'value' =>
{
'func' => 1,
'opcode' => 18,
'parms' => 1,
'result' => 'r',
'types' => 'p',
},
);
our $MaxOperands = 4;
our $PackCode = "i";
1;
__END__
=head1 NAME
Imager::Regops - generated information about the register based virtual machine
=head1 SYNOPSIS
use Imager::Regops;
$Imager::Regops::Attr{$opname}->{opcode} # opcode for given operator
$Imager::Regops::Attr{$opname}->{parms} # number of parameters
$Imager::Regops::Attr{$opname}->{types} # types of parameters
$Imager::Regops::Attr{$opname}->{func} # operator is a function
$Imager::Regops::Attr{$opname}->{result} # r for numeric, p for pixel result
$Imager::Regops::MaxOperands; # maximum number of operands
=head1 DESCRIPTION
This module is generated automatically from F<regmach.h> so we don't need to
maintain the same information in at least one extra place.
At least that's the idea.
=head1 AUTHOR
Tony Cook, tony@develop-help.com
=head1 SEE ALSO
perl(1), Imager(3), http://imager.perl.org/
=cut

View File

@@ -0,0 +1,74 @@
=head1 NAME
Imager::Security - brief notes on security and image processing
=head1 SYNOPSIS
# keep abreast of security updates
apt-get update && apt-get upgrade
yum upgrade
pkgin update && pkgin upgrade
# or local equivalent
# limit memory use
use Imager;
# only images that use up to 10MB
Imager->set_file_limits(bytes => 10_000_000);
=head1 DESCRIPTION
There's two basic security considerations when dealing with images
from an unknown source:
=over
=item *
keeping your libraries up to date
=item *
limiting the amount of memory used to store images
=back
=head2 Keeping libraries up to date
Image file format libraries such as C<libpng> or C<libtiff> have
relatively frequent security updates, keeping your libraries up to
date is basic security.
If you're using user supplied fonts, you will need to keep your font
libraries up to date too.
=head2 Limiting memory used
With compression, and especially with pointer formats like TIFF, it's
possible to store very large images in a relatively small file.
If you're receiving image data from an untrusted source you should
limit the amount of memory that Imager can allocate for a read in
image file using the C<set_file_limits()> method.
Imager->set_file_limits(bytes => 10_000_000);
You may also want to limit the maximum width and height of images read
from files:
Imager->set_file_limits(width => 10_000, height => 10_000,
bytes => 10_000_000);
This has no effect on images created without a file:
# succeeds
my $image = Imager->new(xsize => 10_001, ysize => 10_001);
You can reset to the defaults with:
Imager->set_file_limits(reset => 1);
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

1105
database/perl/vendor/lib/Imager/Test.pm vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
=head1 NAME
Imager::Threads - Imager and threads
=head1 SYNOPSIS
use Imager;
use threads;
Imager->preload;
threads->create(...);
=head1 DESCRIPTION
Starting from version 0.94 Imager attempts to work safely with perl's
C<ithreads>.
Previous versions stored some state in global variables, in particular
the internal error stack.
However there are some limitations:
=over
=item *
Imager's debug malloc isn't thread safe and will never be. Imager's
debug malloc is disabled by default.
=item *
C<libtiff>, which Imager uses for TIFF file support is not thread
safe, C<Imager::File::TIFF> works around this by single-threading its
access to C<libtiff>.
=item *
C<giflib>, which Imager uses for GIF support is not thread safe before
version 5. C<Imager::File::GIF> works around this by single threading
its access to C<giflib>.
=item *
C<T1Lib>, used by one of Imager's font drivers, is not thread safe.
C<Imager::Font::T1> works around this by single threading access.
=item *
killing a thread reading or writing TIFF or GIF files, or using T1
fonts through C<Imager::Font::T1> may deadlock other threads when they
attempt to read or write TIFF or GIF files, or work with Type 1 fonts.
=item *
Fill, font, color or I/O layer objects created in one thread are not
valid for use in child threads. If you manage to duplicate such an
object in another thread, you get to keep both pieces when it breaks.
=back
Note that if you have another module using C<libtiff>, C<giflib> or
C<t1lib> it may interact with Imager's use of those libraries in a
threaded environment, since there's no way to co-ordinate access to
the global information C<libtiff>, C<giflib> and C<t1lib> maintain.
Imager currently doesn't use threads itself, except for testing its
threads support.
=head1 SEE ALSO
Imager, C<threads>
=head1 AUTHOR
Tony Cook <tony@cpan.org>
=cut

View File

@@ -0,0 +1,538 @@
package Imager::Transform;
use 5.006;
use strict;
use Imager;
use Imager::Expr::Assem;
our $VERSION = "1.007";
my %funcs =
(
mandel=>
{
desc=>"Mandelbrot set",
type=>'assem',
assem=><<EOS,
# x treated as in range minx..maxx
# y treated as in range miny..maxy
var nx:n ; var ny:n
var diffx:n ; var diffy:n
# conx/y are x/y adjusted to min..max ranges
var conx:n ; var cony:n
diffx = subtract maxx minx
conx = div x w
conx = mult conx diffx
conx = add conx minx
diffy = subtract maxy miny
cony = div y h
cony = mult cony diffy
cony = add cony miny
nx = 0
ny = 0
var count:n
count = 0
loop:
# calculate (nx,ny)**2 +(x,y)->
# (nx*nx-ny*ny+x, 2.nx.ny+y)
var wx:n ; var wy:n ; var work:n
wx = mult nx nx
wy = mult ny ny
wx = subtract wx wy
ny = mult ny nx
ny = mult ny 2
nx = wx
nx = add nx conx
ny = add ny cony
work = distance nx ny 0 0
work = gt work 2
jumpnz work docol
count = add count 1
work = lt count maxcount
jumpnz work loop
jumpnz insideangle doinang
var workp:p
workp = rgb 0 0 0
ret workp
doinang:
var ang:n
ang = atan2 ny nx
ang = mult ang 360
ang = div ang pi
workp = hsv ang 255 0.5
ret workp
docol:
var outvalue:n
outvalue = mult outsidevaluestep count
outvalue = add outvalue outsidevalue
outvalue = mod outvalue 1.01
jumpnz outsideangle do_outang
work = mult count huestep
work = add work huebase
work = mod work 360
workp = hsv work 1 outvalue
ret workp
do_outang:
ang = atan2 ny nx
ang = mult ang 360
ang = div ang pi
ang = add ang outsidebase
workp = hsv ang outsidesat outvalue
ret workp
EOS
constants=>
{
minx=>{ default=>-2, desc=>'Left of rendered area', },
miny=>{ default=>-1.5, desc=>'Top of rendered area', },
maxx=>{ default=>1, desc=>'Right of rendered area', },
maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
maxcount=>{ default=>100, desc=>'Maximum iterations', },
huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
insideangle=>
{
default=>0,
desc=>'Non-zero to use angle of final as hue for inside',
},
insidebase=>
{
default=>0,
desc=>'Base angle for inside colours if insideangle is non-zero',
},
outsideangle=>
{
default=>0,
desc=>'Non-zero to use angle of final as hue for outside',
},
outsidebase=>
{
default=>0,
desc=>'Base angle if outsideangle is true',
},
outsidevalue=>
{
default=>1,
desc=>'Brightness for outside pixels',
},
outsidevaluestep=>
{
default=>0,
desc=>'Brightness step for each count for outside pixels',
},
outsidesat=>
{
default=>1,
desc=>'Saturation for outside pixels',
},
},
inputs=>[],
},
julia=>
{
desc=>"Julia set",
type=>'assem',
assem=><<EOS,
# print x
# x treated as in range minx..maxx
# y treated as in range miny..maxy
var nx:n ; var ny:n
var diffx:n ; var diffy:n
# conx/y are x/y adjusted to min..max ranges
var conx:n ; var cony:n
diffx = subtract maxx minx
conx = div x w
conx = mult conx diffx
conx = add conx minx
diffy = subtract maxy miny
cony = div y h
cony = mult cony diffy
cony = add cony miny
nx = conx
ny = cony
var count:n
count = 0
loop:
# calculate (nx,ny)**2 +(x,y)->
# (nx*nx-ny*ny+x, 2.nx.ny+y)
var wx:n ; var wy:n ; var work:n
wx = mult nx nx
wy = mult ny ny
wx = subtract wx wy
ny = mult ny nx
ny = mult ny 2
nx = wx
nx = add nx zx
ny = add ny zy
work = distance nx ny 0 0
work = gt work 2
jumpnz work docol
count = add count 1
work = lt count maxcount
jumpnz work loop
jumpnz insideangle doinang
var workp:p
workp = rgb 0 0 0
ret workp
doinang:
var ang:n
ang = atan2 ny nx
ang = mult ang 360
ang = div ang pi
workp = hsv ang 255 0.5
ret workp
docol:
var outvalue:n
outvalue = mult outsidevaluestep count
outvalue = add outvalue outsidevalue
outvalue = mod outvalue 1.01
jumpnz outsideangle do_outang
work = mult count huestep
work = add work huebase
work = mod work 360
workp = hsv work 1 outvalue
ret workp
do_outang:
ang = atan2 ny nx
ang = mult ang 360
ang = div ang pi
ang = add ang outsidebase
workp = hsv ang outsidesat outvalue
ret workp
EOS
constants=>
{
zx=>{default=>0.7, desc=>'Real part of initial Z', },
zy=>{default=>0.2, desc=>'Imaginary part of initial Z', },
minx=>{ default=>-1.5, desc=>'Left of rendered area', },
miny=>{ default=>-1.5, desc=>'Top of rendered area', },
maxx=>{ default=>1.5, desc=>'Right of rendered area', },
maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
maxcount=>{ default=>100, desc=>'Maximum iterations', },
huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
insideangle=>
{
default=>0,
desc=>'Non-zero to use angle of final as hue for inside',
},
insidebase=>
{
default=>0,
desc=>'Base angle for inside colours if insideangle is non-zero',
},
outsideangle=>
{
default=>0,
desc=>'Non-zero to use angle of final as hue for outside',
},
outsidebase=>
{
default=>0,
desc=>'Base angle if outsideangle is true',
},
outsidevalue=>
{
default=>1,
desc=>'Brightness for outside pixels',
},
outsidevaluestep=>
{
default=>0,
desc=>'Brightness step for each count for outside pixels',
},
outsidesat=>
{
default=>1,
desc=>'Saturation for outside pixels',
},
},
inputs=>[],
},
circleripple=>
{
type=>'rpnexpr',
desc=>'Adds a circular ripple effect',
rpnexpr=><<'EOS',
x y cx cy distance !dist
@dist freq / sin !scale
@scale depth * @dist + !adj
y cy - x cx - atan2 !ang
cx @ang cos @adj * + cy @ang sin @adj * + getp1 @scale shadow + shadow 1 + / *
EOS
constants=>
{
freq=> { desc=>'Frequency of ripples', default=>5 },
depth=> { desc=>'Depth of ripples', default=>10 },
shadow=> { desc=>'Fraction of shadow', default=>20 },
},
inputs=>
[
{ desc=>'Image to ripple' }
],
},
spiral=>
{
type=>'rpnexpr',
desc=>'Render a colorful spiral',
rpnexpr=><<'EOS',
x y cx cy distance !d y cy - x cx - atan2 !a
@d spacing / @a + pi 2 * % !a2
@a 180 * pi / 1 @a2 sin 1 + 2 / hsv
EOS
constants=>
{
spacing=>{ desc=>'Spacing between arms', default=>10 },
},
inputs=>[],
},
diagripple=>
{
type=>'rpnexpr',
desc=>'Adds diagonal ripples to an image',
rpnexpr=><<'EOS',
x y + !dist @dist freq / sin !scale
@scale depth * !adj
x @adj + y @adj + getp1 @scale shadow + shadow 1 + / *
EOS
constants=>
{
freq=>{ desc=>'Frequency of ripples', default=>5, },
depth=>{desc=>'Depth of ripples', default=>3,},
shadow=>
{
desc=>'Fraction of brightness to remove for shadows',
default=>20,
},
},
inputs=>
[
{ desc=>'Image to add ripples to' }
],
},
twist=>
{
type=>'rpnexpr',
desc=>'Twist an image',
rpnexpr=><<'EOS',
x y cx cy distance !dist
y cy - x cx - atan2 @dist twist / + !ang
cx @ang cos @dist * + cy @ang sin @dist * + getp1
EOS
constants=>
{
twist=>{ desc=>'Amount of twist', default=>2.5, },
},
inputs=>
[
{ desc=>'Image to twist' },
],
},
# any other functions can wait until Imager::Expr::Infix supports
# jumps
);
sub new {
my ($class, $name) = @_;
exists $funcs{$name} or return;
bless { func=>$funcs{$name}, name=>$name }, $class;
}
sub inputs {
my ($self) = @_;
return @{$self->{func}{inputs}}
}
sub constants {
my $self = shift;
if (@_) {
return @{$self->{func}{constants}}{@_};
}
else {
return keys %{$self->{func}{constants}};
}
}
sub transform {
my ($self, $opts, $constants, @in) = @_;
my $func = $self->{func};
my %opts = %$opts;
$opts{$func->{type}} = $func->{$func->{type}};
my %con = %$constants;
for my $name (keys %{$func->{'constants'}}) {
unless (exists $con{$name}) {
if (exists $func->{'constants'}{$name}{default}) {
$con{$name} = $func->{'constants'}{$name}{default};
}
else {
$self->{error} = "No value or default for constant $name";
return;
}
}
}
$opts{'constants'} = \%con;
unless (@in == @{$func->{'inputs'}}) {
$self->{error} = @in." input images given, ".
@{$func->{'inputs'}}." supplied";
return;
}
my $out = Imager::transform2(\%opts, @in);
unless ($out) {
$self->{error} = $Imager::ERRSTR;
return;
}
return $out;
}
sub errstr {
return $_[0]{error};
}
sub list {
return keys %funcs;
}
sub describe {
my ($class, $name) = @_;
my $func;
if (ref $class && !$name) {
$func = $class->{func};
$name = $class->{name}
}
else {
$func = $funcs{$name}
or return undef;
}
my $desc = <<EOS;
Function : $name
Description: $func->{desc}
EOS
if ($func->{'inputs'} && @{$func->{'inputs'}}) {
$desc .= "Input images:\n";
my $i = 1;
for my $in (@{$func->{'inputs'}}) {
$desc .= " $i: $in->{desc}\n";
}
}
else {
$desc .= "There are no input images\n";
}
if ($func->{'constants'} && keys %{$func->{'constants'}}) {
$desc .= "Input constants:\n";
for my $key (keys %{$func->{'constants'}}) {
$desc .= " $key: $func->{'constants'}{$key}{desc}\n";
$desc .= " Default: $func->{'constants'}{$key}{default}\n";
}
}
else {
$desc .= "There are no constants\n";
}
return $desc;
}
1;
__END__
=head1 NAME
Imager::Transform - a library of register machine image transformations
=head1 SYNOPSIS
# get a list of transformations
my @funcs = Imager::Transform->list;
# create a transformation object
my $tran = Imager::Transform->new($name);
# describe it
print $tran->describe;
# a list of constant names
my @constants = $tran->constants;
# information about some of the constants
my @info = $tran->constants(@constants);
=head1 DESCRIPTION
This module provides a library of transformations that use the Imager
transform2() function.
The aim is to provide a place to collect these transformations.
At some point there might be an interface to add new functions, but
there's not a whole lot of point to that.
The interface is a little sparse as yet.
=head1 METHODS
=over 4
=item my @names = Imager::Transform->list
Returns a list of the transformations.
=item my $desc = Imager::Transform->describe($name);
=item my $desc = $tran->describe()
Describes a transformation specified either by name (as a class
method) or by reference (as an instance method).
The class method returns undef if there is no such transformation.
=item my $tran = Imager::Transform->new($name)
Create a new transformation object. Returns undef if there is no such
transformation.
=item my @inputs = $tran->inputs;
=item my $inputs = $tran->inputs;
Returns a list of input image descriptions, or the number of them,
depending on content.
The list contains hash references, which current contain only one
member, C<desc>, a description of the use of the input image.
=item $tran->constants
Returns a list of names of constants that can be set for the
transformation.
=item $tran->constants($name, $name, ...)
Returns a hashref for each named constant, which contains the default
in key C<default> and a description in key C<desc>.
=item my $out = $tran->transform(\%opts, \%constants, @imgs)
Perform the image transformation.
Returns the new image on success, or undef on failure, in which case
you can use $tran->errstr to get an error message.
=item $tran->errstr
The error message, if any from the last image transformation.
=back
=head1 BUGS
Needs more transformations.
=head1 SEE ALSO
Imager(3), F<transform.perl>
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=cut

View File

@@ -0,0 +1,973 @@
=head1 NAME
Imager::Transformations - Simple transformations of one image into another.
=head1 SYNOPSIS
use Imager;
$newimg = $img->copy();
$newimg = $img->scale(xpixels=>400, qtype => 'mixing');
$newimg = $img->scale(xpixels=>400, ypixels=>400);
$newimg = $img->scale(xpixels=>400, ypixels=>400, type=>'min');
$newimg = $img->scale(scalefactor=>0.25);
$newimg = $img->scaleX(pixels=>400);
$newimg = $img->scaleX(scalefactor=>0.25);
$newimg = $img->scaleY(pixels=>400);
$newimg = $img->scaleY(scalefactor=>0.25);
$newimg = $img->crop(left=>50, right=>100, top=>10, bottom=>100);
$newimg = $img->crop(left=>50, top=>10, width=>50, height=>90);
$dest->paste(left=>40,top=>20,img=>$logo);
$img->rubthrough(src=>$srcimage,tx=>30, ty=>50);
$img->rubthrough(src=>$srcimage,tx=>30, ty=>50,
src_minx=>20, src_miny=>30,
src_maxx=>20, src_maxy=>30);
$img->compose(src => $src, tx => 30, ty => 20, combine => 'color');
$img->compose(src => $src, tx => 30, ty => 20, combine => 'color');
mask => $mask, opacity => 0.5);
$img->flip(dir=>"h"); # horizontal flip
$img->flip(dir=>"vh"); # vertical and horizontal flip
$newimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically
my $rot20 = $img->rotate(degrees=>20);
my $rotpi4 = $img->rotate(radians=>3.14159265/4);
# Convert image to gray
$new = $img->convert(preset=>'grey');
# Swap red/green channel
$new = $img->convert(matrix=>[ [ 0, 1, 0 ],
[ 1, 0, 0 ],
[ 0, 0, 1 ] ]);
# build an image using channels from multiple input images
$new = $img->combine(src => [ $im1, $im2, $im3 ]);
$new = $img->combine(src => [ $im1, $im2, $im3 ],
channels => [ 2, 1, 0 ]);
# limit the range of red channel from 0..255 to 0..127
@map = map { int( $_/2 } 0..255;
$img->map( red=>\@map );
# Apply a Gamma of 1.4
my $gamma = 1.4;
my @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255;
$img->map(all=>\@map); # inplace conversion
=head1 DESCRIPTION
The methods described in Imager::Transformations fall into two categories.
Either they take an existing image and modify it in place, or they
return a modified copy.
Functions that modify inplace are C<flip()>, C<paste()>,
C<rubthrough()> and C<compose()>. If the original is to be left
intact it's possible to make a copy and alter the copy:
$flipped = $img->copy()->flip(dir=>'h');
=head2 Image copying/resizing/cropping/rotating
A list of the transformations that do not alter the source image follows:
=over
=item copy()
To create a copy of an image use the C<copy()> method. This is useful
if you want to keep an original after doing something that changes the image.
$newimg = $orig->copy();
=item scale()
X<scale>To scale an image so proportions are maintained use the
C<$img-E<gt>scale()> method. if you give either a C<xpixels> or
C<ypixels> parameter they will determine the width or height
respectively. If both are given the one resulting in a larger image
is used, unless you set the C<type> parameter to C<'min'>. example:
C<$img> is 700 pixels wide and 500 pixels tall.
$newimg = $img->scale(xpixels=>400); # 400x285
$newimg = $img->scale(ypixels=>400); # 560x400
$newimg = $img->scale(xpixels=>400,ypixels=>400); # 560x400
$newimg = $img->scale(xpixels=>400,ypixels=>400,type=>'min'); # 400x285
$newimg = $img->scale(xpixels=>400, ypixels=>400),type=>'nonprop'); # 400x400
$newimg = $img->scale(scalefactor=>0.25); 175x125
$newimg = $img->scale(); # 350x250
If you want to create low quality previews of images you can pass
C<qtype=E<gt>'preview'> to scale and it will use nearest neighbor
sampling instead of filtering. It is much faster but also generates
worse looking images - especially if the original has a lot of sharp
variations and the scaled image is by more than 3-5 times smaller than
the original.
=over
=item *
C<xpixels>, C<ypixels> - desired size of the scaled image. The
C<type> parameter controls whether the larger or smaller of the two
possible sizes is chosen, or if the image is scaled
non-proportionally.
=item *
C<constrain> - an Image::Math::Constrain object defining the way in
which the image size should be constrained.
=item *
C<scalefactor> - if none of C<xpixels>, C<ypixels>, C<xscalefactor>,
C<yscalefactor> or C<constrain> is supplied then this is used as the
ratio to scale by. Default: 0.5.
=item *
C<xscalefactor>, C<yscalefactor> - if both are supplied then the image is
scaled as per these parameters, whether this is proportionally or not.
New in Imager 0.54.
=item *
C<type> - controls whether the larger or smaller of the two possible
sizes is chosen, possible values are:
=over
=item *
C<min> - the smaller of the 2 sizes are chosen.
=item *
C<max> - the larger of the 2 sizes. This is the default.
=item *
C<nonprop> - non-proportional scaling. New in Imager 0.54.
=back
scale() will fail if C<type> is set to some other value.
For example, if the original image is 400 pixels wide by 200 pixels
high and C<xpixels> is set to 300, and C<ypixels> is set to 160. When
C<type> is C<'min'> the resulting image is 300 x 150, when C<type> is
C<'max'> the resulting image is 320 x 160.
C<type> is only used if both C<xpixels> and C<ypixels> are supplied.
=item *
C<qtype> - defines the quality of scaling performed. Possible values are:
=over
=item *
C<normal> - high quality scaling. This is the default.
=item *
C<preview> - lower quality. When scaling down this will skip input
pixels, eg. scaling by 0.5 will skip every other pixel. When scaling
up this will duplicate pixels.
=item *
C<mixing> - implements the mixing algorithm implemented by
F<pnmscale>. This retains more detail when scaling down than
C<normal>. When scaling down this proportionally accumulates sample
data from the pixels, resulting in a proportional mix of all of the
pixels. When scaling up this will mix pixels when the sampling grid
crosses a pixel boundary but will otherwise copy pixel values.
=back
scale() will fail if C<qtype> is set to some other value.
C<preview> is faster than C<mixing> which is much faster than C<normal>.
=back
To scale an image on a given axis without maintaining proportions, it
is best to call the scaleX() and scaleY() methods with the required
dimensions. eg.
my $scaled = $img->scaleX(pixels=>400)->scaleY(pixels=>200);
From Imager 0.54 you can scale without maintaining proportions either
by supplying both the C<xscalefactor> and C<yscalefactor> arguments:
my $scaled = $img->scale(xscalefactor => 0.5, yscalefactor => 0.67);
or by supplying C<xpixels> and C<ypixels> and setting C<type> to
<nonprop>:
my $scaled = $im->scale(xpixels => 200, ypixels => 200, type => 'nonprop');
Returns a new scaled image on success. The source image is not
modified.
Returns false on failure, check the errstr() method for the reason for
failure.
A mandatory warning is produced if scale() is called in void context.
# setup
my $image = Imager->new;
$image->read(file => 'somefile.jpg')
or die $image->errstr;
# all full quality unless indicated otherwise
# half the size:
my $half = $image->scale;
# double the size
my $double = $image->scale(scalefactor => 2.0);
# so a 400 x 400 box fits in the resulting image:
my $fit400x400inside = $image->scale(xpixels => 400, ypixels => 400);
my $fit400x400inside2 = $image->scale(xpixels => 400, ypixels => 400,
type=>'max');
# fit inside a 400 x 400 box
my $inside400x400 = $image->scale(xpixels => 400, ypixels => 400,
type=>'min');
# make it 400 pixels wide or high
my $width400 = $image->scale(xpixels => 400);
my $height400 = $image->scale(ypixels => 400);
# low quality scales:
# to half size
my $low = $image->scale(qtype => 'preview');
# mixing method scale
my $mixed = $image->scale(qtype => 'mixing', scalefactor => 0.1);
# using an Image::Math::Constrain object
use Image::Math::Constrain;
my $constrain = Image::Math::Constrain->new(800, 600);
my $scaled = $image->scale(constrain => $constrain);
# same as Image::Math::Constrain version
my $scaled2 = $image->scale(xpixels => 800, ypixels => 600, type => 'min');
=item scaleX()
scaleX() will scale along the X dimension, return a new image with the
new width:
my $newimg = $img->scaleX(pixels=>400); # 400x500
$newimg = $img->scaleX(scalefactor=>0.25) # 175x500
=over
=item *
C<scalefactor> - the amount to scale the X axis. Ignored if C<pixels> is
provided. Default: 0.5.
=item *
C<pixels> - the new width of the image.
=back
Returns a new scaled image on success. The source image is not
modified.
Returns false on failure, check the errstr() method for the reason for
failure.
A mandatory warning is produced if scaleX() is called in void context.
=item scaleY()
scaleY() will scale along the Y dimension, return a new image with the
new height:
$newimg = $img->scaleY(pixels=>400); # 700x400
$newimg = $img->scaleY(scalefactor=>0.25) # 700x125
=over
=item *
C<scalefactor> - the amount to scale the Y axis. Ignored if C<pixels> is
provided. Default: 0.5.
=item *
C<pixels> - the new height of the image.
=back
Returns a new scaled image on success. The source image is not
modified.
Returns false on failure, check the errstr() method for the reason for
failure.
A mandatory warning is produced if scaleY() is called in void context.
=item scale_calculate()
Performs the same calculations that the scale() method does to
calculate the scaling factors from the parameters you pass.
scale_calculate() can be called as an object method, or as a class
method.
Takes the following parameters over scale():
=over
=item *
C<width>, C<height> - the image width and height to base the scaling on.
Required if scale_calculate() is called as a class method. If called
as an object method these default to the image width and height
respectively.
=back
You might use scale_calculate() as a class method when generating an
HTML C<IMG> tag, for example.
Returns an empty list on failure.
Returns a list containing horizontal scale factor, vertical scale
factor, new width, new height, on success.
my ($x_scale, $y_scale, $new_width, $new_height) =
Imager->scale_calculate(width => 1024, height => 768,
ypixels => 180, type => 'min');
my ($x_scale, $y_scale, $new_width, $new_height) =
$img->scale_calculate(xpixels => 200, type => 'min');
=item crop()
=for stopwords resize
Another way to resize an image is to crop it. The parameters to
crop are the edges of the area that you want in the returned image,
where the right and bottom edges are non-inclusive. If a parameter is
omitted a default is used instead.
crop() returns the cropped image and does not modify the source image.
The possible parameters are:
=over
=item *
C<left> - the left edge of the area to be cropped. Default: 0
=item *
C<top> - the top edge of the area to be cropped. Default: 0
=item *
C<right> - the right edge of the area to be cropped. Default: right
edge of image.
=item *
C<bottom> - the bottom edge of the area to be cropped. Default:
bottom edge of image.
=item *
C<width> - width of the crop area. Ignored if both C<left> and C<right> are
supplied. Centered on the image if neither C<left> nor C<right> are
supplied.
=item *
C<height> - height of the crop area. Ignored if both C<top> and
C<bottom> are supplied. Centered on the image if neither C<top> nor
C<bottom> are supplied.
=back
For example:
# these produce the same image
$newimg = $img->crop(left=>50, right=>100, top=>10, bottom=>100);
$newimg = $img->crop(left=>50, top=>10, width=>50, height=>90);
$newimg = $img->crop(right=>100, bottom=>100, width=>50, height=>90);
# and the following produce the same image
$newimg = $img->crop(left=>50, right=>100);
$newimg = $img->crop(left=>50, right=>100, top=>0,
bottom=>$img->getheight);
# grab the top left corner of the image
$newimg = $img->crop(right=>50, bottom=>50);
You can also specify width and height parameters which will produce a
new image cropped from the center of the input image, with the given
width and height.
$newimg = $img->crop(width=>50, height=>50);
If you supply C<left>, C<width> and C<right> values, the C<right>
value will be ignored. If you supply C<top>, C<height> and C<bottom>
values, the C<bottom> value will be ignored.
The edges of the cropped area default to the edges of the source
image, for example:
# a vertical bar from the middle from top to bottom
$newimg = $img->crop(width=>50);
# the right half
$newimg = $img->crop(left=>$img->getwidth() / 2);
If the resulting image would have zero width or height then crop()
returns false and $img->errstr is an appropriate error message.
A mandatory warning is produced if crop() is called in void context.
=item rotate()
Use the rotate() method to rotate an image. This method will return a
new, rotated image.
To rotate by an exact amount in degrees or radians, use the 'degrees'
or 'radians' parameter:
my $rot20 = $img->rotate(degrees=>20);
my $rotpi4 = $img->rotate(radians=>3.14159265/4);
Exact image rotation uses the same underlying transformation engine as
the matrix_transform() method (see Imager::Engines).
You can also supply a C<back> argument which acts as a background
color for the areas of the image with no samples available (outside
the rectangle of the source image.) This can be either an
Imager::Color or Imager::Color::Float object. This is B<not> mixed
transparent pixels in the middle of the source image, it is B<only>
used for pixels where there is no corresponding pixel in the source
image.
To rotate in steps of 90 degrees, use the 'right' parameter:
my $rotated = $img->rotate(right=>270);
Rotations are clockwise for positive values.
Parameters:
=over
=item *
C<right> - rotate by an exact multiple of 90 degrees, specified in
degrees.
=item *
C<radians> - rotate by an angle specified in radians.
=item *
C<degrees> - rotate by an angle specified in degrees.
=item *
C<back> - for C<radians> and C<degrees> this is the color used for the
areas not covered by the original image. For example, the corners of
an image rotated by 45 degrees.
This can be either an Imager::Color object, an Imager::Color::Float
object or any parameter that Imager can convert to a color object, see
L<Imager::Draw/Color Parameters> for details.
This is B<not> mixed transparent pixels in the middle of the source
image, it is B<only> used for pixels where there is no corresponding
pixel in the source image.
Default: transparent black.
=back
# rotate 45 degrees clockwise,
my $rotated = $img->rotate(degrees => 45);
# rotate 10 degrees counter-clockwise
# set pixels not sourced from the original to red
my $rotated = $img->rotate(degrees => -10, back => 'red');
=back
=head2 Image pasting/flipping
A list of the transformations that alter the source image follows:
=over
=item paste()
X<paste>To copy an image to onto another image use the C<paste()>
method.
$dest->paste(left=>40, top=>20, src=>$logo);
That copies the entire C<$logo> image onto the C<$dest> image so that the
upper left corner of the C<$logo> image is at (40,20).
Parameters:
=over
=item *
C<src>, C<img> - the source image. C<src> added for compatibility with
rubthrough().
=item *
C<left>, C<top> - position in output of the top left of the pasted image.
Default: (0,0)
=item *
C<src_minx>, C<src_miny> - the top left corner in the source image to start
the paste from. Default: (0, 0)
=item *
C<src_maxx>, C<src_maxy> - the bottom right in the source image of the sub
image to paste. This position is B<non> inclusive. Default: bottom
right corner of the source image.
=item *
C<width>, C<height> - if the corresponding src_maxx or src_maxy is not
defined then width or height is used for the width or height of the
sub image to be pasted.
=back
# copy the 20x20 pixel image from (20,20) in $src_image to (10,10) in $img
$img->paste(src=>$src_image,
left => 10, top => 10,
src_minx => 20, src_miny => 20,
src_maxx => 40, src_maxx => 40);
If the source image has an alpha channel and the target doesn't, then
the source is treated as if composed onto a black background.
If the source image is color and the target is gray scale, the
source is treated as if run through C<< convert(preset=>'gray') >>.
=item rubthrough()
A more complicated way of blending images is where one image is
put 'over' the other with a certain amount of opaqueness. The
method that does this is rubthrough().
$img->rubthrough(src=>$overlay,
tx=>30, ty=>50,
src_minx=>20, src_miny=>30,
src_maxx=>20, src_maxy=>30);
That will take the sub image defined by I<$overlay> and
I<[src_minx,src_maxx)[src_miny,src_maxy)> and overlay it on top of
I<$img> with the upper left corner at (30,50). You can rub 2 or 4
channel images onto a 3 channel image, or a 2 channel image onto a 1
channel image. The last channel is used as an alpha channel. To add
an alpha channel to an image see I<convert()>.
Parameters:
=over
=item *
C<tx>, C<ty> - location in the target image ($self) to render the
top left corner of the source.
=item *
C<src_minx>, C<src_miny> - the top left corner in the source to transfer to
the target image. Default: (0, 0).
=item *
C<src_maxx>, C<src_maxy> - the bottom right in the source image of the sub
image to overlay. This position is B<non> inclusive. Default: bottom
right corner of the source image.
=back
# overlay all of $source onto $targ
$targ->rubthrough(tx => 20, ty => 25, src => $source);
# overlay the top left corner of $source onto $targ
$targ->rubthrough(tx => 20, ty => 25, src => $source,
src_maxx => 20, src_maxy => 20);
# overlay the bottom right corner of $source onto $targ
$targ->rubthrough(tx => 20, ty => 30, src => $src,
src_minx => $src->getwidth() - 20,
src_miny => $src->getheight() - 20);
rubthrough() returns true on success. On failure check
C<< $target->errstr >> for the reason for failure.
=item compose()
Draws the source image over the target image, with the source alpha
channel modified by the optional mask and the opacity.
$img->compose(src=>$overlay,
tx=>30, ty=>50,
src_minx=>20, src_miny=>30,
src_maxx=>20, src_maxy=>30,
mask => $mask, opacity => 0.5);
That will take the sub image defined by I<$overlay> and
I<[src_minx,src_maxx)[src_miny,src_maxy)> and overlay it on top of
I<$img> with the upper left corner at (30,50). You can rub 2 or 4
channel images onto a 3 channel image, or a 2 channel image onto a 1
channel image.
Parameters:
=over
=item *
C<src> - the source image to draw onto the target. Required.
=item *
C<tx>, C<ty> - location in the target image ($self) to render the top
left corner of the source. These can also be supplied as C<left> and
C<right>. Default: (0, 0).
=item *
C<src_minx>, C<src_miny> - the top left corner in the source to transfer to
the target image. Default: (0, 0).
=item *
C<src_maxx>, C<src_maxy> - the bottom right in the source image of the sub
image to overlay. This position is B<non> inclusive. Default: bottom
right corner of the source image.
=item *
C<mask> - a mask image. The first channel of this image is used to
modify the alpha channel of the source image. This can be used to
mask out portions of the source image. Where the first channel is
zero none of the source image will be used, where the first channel is
maximum the full alpha of the source image will be used, as further
modified by the opacity.
=item *
opacity - further modifies the alpha channel of the source image, in
the range 0.0 to 1.0. Default: 1.0.
=item *
combine - the method to combine the source pixels with the target.
See the combine option documentation in Imager::Fill. Default:
normal.
=back
Calling compose() with no mask, combine set to C<normal>, opacity set
to C<1.0> is equivalent to calling rubthrough().
compose() is intended to be produce similar effects to layers in
interactive paint software.
# overlay all of $source onto $targ
$targ->compose(tx => 20, ty => 25, src => $source);
# overlay the top left corner of $source onto $targ
$targ->compose(tx => 20, ty => 25, src => $source,
src_maxx => 20, src_maxy => 20);
# overlay the bottom right corner of $source onto $targ
$targ->compose(tx => 20, ty => 30, src => $src,
src_minx => $src->getwidth() - 20,
src_miny => $src->getheight() - 20);
compose() returns true on success. On failure check $target->errstr
for the reason for failure.
=item flip()
An inplace horizontal or vertical flip is possible by calling the
C<flip()> method. If the original is to be preserved it's possible to
make a copy first. The only parameter it takes is the C<dir>
parameter which can take the values C<h>, C<v>, C<vh> and C<hv>.
$img->flip(dir=>"h"); # horizontal flip
$img->flip(dir=>"vh"); # vertical and horizontal flip
$nimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically
flip() returns true on success. On failure check $img->errstr for the
reason for failure.
=back
=head2 Color transformations
=over
=item convert()
You can use the convert method to transform the color space of an
image using a matrix. For ease of use some presets are provided.
The convert method can be used to:
=over
=item *
convert an RGB or RGBA image to gray scale.
=item *
convert a gray scale image to RGB.
=item *
extract a single channel from an image.
=item *
set a given channel to a particular value (or from another channel)
=back
The currently defined presets are:
=over
=item *
C<gray>, C<grey> - converts an RGBA image into a gray scale image with
alpha channel, or an RGB image into a gray scale image without an
alpha channel.
This weights the RGB channels at 22.2%, 70.7% and 7.1% respectively.
=item *
C<noalpha> - removes the alpha channel from a 2 or 4 channel image.
An identity for other images. Warning: this removes the alpha channel
without applying it.
=item *
C<red>, C<channel0> - extracts the first channel of the image into a
single channel image
=item *
C<green>, C<channel1> - extracts the second channel of the image into
a single channel image
=item *
C<blue>, C<channel2> - extracts the third channel of the image into a
single channel image
=item *
C<alpha> - extracts the alpha channel of the image into a single
channel image.
If the image has 1 or 3 channels (assumed to be gray scale or RGB) then
the resulting image will be all white.
=item *
C<rgb>
converts a gray scale image to RGB, preserving the alpha channel if any
=item *
C<addalpha> - adds an alpha channel to a gray scale or RGB image.
Preserves an existing alpha channel for a 2 or 4 channel image.
=back
For example, to convert an RGB image into a gray scale image:
$new = $img->convert(preset=>'grey'); # or gray
or to convert a gray scale image to an RGB image:
$new = $img->convert(preset=>'rgb');
The presets aren't necessary simple constants in the code, some are
generated based on the number of channels in the input image.
If you want to perform some other color transformation, you can use
the 'matrix' parameter.
For each output pixel the following matrix multiplication is done:
| channel[0] | | $c00, ..., $c0k | | inchannel[0] |
| ... | = | ... | x | ... |
| channel[k] | | $ck0, ..., $ckk | | inchannel[k] |
1
Where C<k = $img-E<gt>getchannels()-1>.
So if you want to swap the red and green channels on a 3 channel image:
$new = $img->convert(matrix=>[ [ 0, 1, 0 ],
[ 1, 0, 0 ],
[ 0, 0, 1 ] ]);
or to convert a 3 channel image to gray scale using equal weightings:
$new = $img->convert(matrix=>[ [ 0.333, 0.333, 0.334 ] ])
Convert a 2 channel image (gray scale with alpha) to an RGBA image with
the gray converted to the specified RGB color:
# set (RGB) scaled on the grey scale portion and copy the alpha
# channel as is
my $colored = $gray->convert(matrix=>[ [ ($red/255), 0 ],
[ ($green/255), 0 ],
[ ($blue/255), 0 ],
[ 0, 1 ],
]);
To convert a 3 channel image to a 4 channel image with a 50 percent
alpha channel:
my $withalpha = $rgb->convert(matrix =>[ [ 1, 0, 0, 0 ],
[ 0, 1, 0, 0 ],
[ 0, 0, 1, 0 ],
[ 0, 0, 0, 0.5 ],
]);
=item combine()
X<combine>
Combine channels from one or more input images into a new image.
Parameters:
=over
=item *
C<src> - a reference to an array of input images. There must be at least
one input image. A given image may appear more than once in C<src>.
=item *
C<channels> - a reference to an array of channels corresponding to the
source images. If C<channels> is not supplied then the first channel
from each input image is used. If the array referenced by C<channels>
is shorter than that referenced by C<src> then the first channel is
used from the extra images.
=back
# make an rgb image from red, green, and blue images
my $rgb = Imager->combine(src => [ $red, $green, $blue ]);
# convert a BGR image into RGB
my $rgb = Imager->combine(src => [ $bgr, $bgr, $bgr ],
channels => [ 2, 1, 0 ]);
# add an alpha channel from another image
my $rgba = Imager->combine(src => [ $rgb, $rgb, $rgb, $alpha ],
channels => [ 0, 1, 2, 0 ]);
=back
=head2 Color Mappings
=over
=item map()
You can use the map method to map the values of each channel of an
image independently using a list of look-up tables. It's important to
realize that the modification is made inplace. The function simply
returns the input image again or undef on failure.
Each channel is mapped independently through a look-up table with 256
entries. The elements in the table should not be less than 0 and not
greater than 255. If they are out of the 0..255 range they are
clamped to the range. If a table does not contain 256 entries it is
silently ignored.
Single channels can mapped by specifying their name and the mapping
table. The channel names are C<red>, C<green>, C<blue>, C<alpha>.
@map = map { int( $_/2 } 0..255;
$img->map( red=>\@map );
It is also possible to specify a single map that is applied to all
channels, alpha channel included. For example this applies a gamma
correction with a gamma of 1.4 to the input image.
$gamma = 1.4;
@map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255;
$img->map(all=> \@map);
The C<all> map is used as a default channel, if no other map is
specified for a channel then the C<all> map is used instead. If we
had not wanted to apply gamma to the alpha channel we would have used:
$img->map(all=> \@map, alpha=>[]);
Since C<[]> contains fewer than 256 element the gamma channel is
unaffected.
It is also possible to simply specify an array of maps that are
applied to the images in the RGBA order. For example to apply
maps to the C<red> and C<blue> channels one would use:
$img->map(maps=>[\@redmap, [], \@bluemap]);
=back
=head1 SEE ALSO
L<Imager>, L<Imager::Engines>
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=head1 REVISION
$Revision$
=cut

View File

@@ -0,0 +1,182 @@
=head1 NAME
Imager::Tutorial - an introduction to Imager.
=head1 DESCRIPTION
=head2 Before you start
If you have the necessary knowledge, install the image format
libraries you want Imager image file support for, and Imager itself,
otherwise arrange to have it done.
=for stopwords Photoshop
You will also want some sort of image viewer tool, whether an image
editor like Photoshop or the GIMP, or a web browser.
=head2 Hello Boxes! - A Simple Start
As with any perl program it's useful to start with a #! line, and to
enable strict mode:
#!/usr/bin/perl -w
# you might to 'use warnings;' instead of the -w above
use strict;
These lines will be omitted in further examples.
As with any module, you need to load it:
use Imager;
Now create a image to draw on:
my $image = Imager->new(xsize => 100, ysize => 100);
and draw a couple of filled rectangles on it:
$image->box(xmin => 0, ymin => 0, xmax => 99, ymax => 99,
filled => 1, color => 'blue');
$image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79,
filled => 1, color => 'green');
Since the first box fills the whole image, it can be simplified to:
$image->box(filled => 1, color => 'blue');
and save it to a file:
$image->write(file=>'tutorial1.ppm')
or die 'Cannot save tutorial1.ppm: ', $image->errstr;
So our completed program is:
use Imager;
my $image = Imager->new(xsize => 100, ysize => 100);
$image->box(filled => 1, color => 'blue');
$image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79,
filled => 1, color => 'green');
$image->write(file=>'tutorial1.ppm')
or die 'Cannot save tutorial1.ppm: ', $image->errstr;
=head2 Adding some text
The first thing you need to draw text is a font object:
# use a different file, depending on the font support you have in
# your installed Imager.
my $font_filename = 'fontfiles/ImUgly.ttf';
my $font = Imager::Font->new(file=>$font_filename)
or die "Cannot load $font_filename: ", Imager->errstr;
If you're on Windows, you can supply a face name instead:
my $font = Imager::Font->new(face=>'Arial Bold')
or die "Cannot load 'Arial Bold: ", Imager->errstr;
and draw the text:
my $text = "Hello Boxes!";
my $text_size = 12;
$font->align(string => $text,
size => $text_size,
color => 'red',
x => $image->getwidth/2,
y => $image->getheight/2,
halign => 'center',
valign => 'center',
image => $image);
So inserting this into our existing code we have:
use Imager;
my $image = Imager->new(xsize => 100, ysize => 100);
$image->box(xmin => 0, ymin => 0, xmax => 99, ymax => 99,
filled => 1, color => 'blue');
$image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79,
filled => 1, color => 'green');
# use a different file, depending on the font support you have in
# your installed Imager.
my $font_filename = 'fontfiles/ImUgly.ttf';
my $font = Imager::Font->new(file=>$font_filename)
or die "Cannot load $font_filename: ", Imager->errstr;
my $text = "Hello Boxes!";
my $text_size = 12;
$font->align(string => $text,
size => $text_size,
color => 'red',
x => $image->getwidth/2,
y => $image->getheight/2,
halign => 'center',
valign => 'center',
image => $image);
$image->write(file=>'tutorial2.ppm')
or die 'Cannot save tutorial2.ppm: ', $image->errstr;
=head2 Using an existing image as a base
To load an image from a file, first create an empty image object:
my $read_image = Imager->new;
then call the read method:
my $image_source = shift; # from the command-line
$read_image->read(file=>$image_source)
or die "Cannot load $image_source: ", $image->errstr;
To keep to our working size, we'll scale the image:
# the scale() method always does a proportional scale, we don't want
# that here
my $scaled_image = $read_image->scaleX(pixels=>100)->scaleY(pixels=>100);
draw our inner box on that, and save the result:
$scaled_image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79,
filled => 1, color => 'green');
$scaled_image->write(file=>'tutorial3.ppm')
or die 'Cannot save tutorial3.ppm: ', $image->errstr;
so the complete program is:
use Imager;
my $read_image = Imager->new;
my $image_source = shift; # from the command-line
$read_image->read(file=>$image_source)
or die "Cannot load $image_source: ", $image->errstr;
# the scale() method always does a proportional scale, we don't want
# that here
my $scaled_image = $read_image->scaleX(pixels=>100)->scaleY(pixels=>100);
$scaled_image->box(xmin => 20, ymin => 20, xmax => 79, ymax => 79,
filled => 1, color => 'green');
$scaled_image->write(file=>'tutorial3.ppm')
or die 'Cannot save tutorial3.ppm: ', $image->errstr;
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>
=head1 REVISION
$Revision$
=cut

View File

@@ -0,0 +1,22 @@
#include "imager.h"
typedef struct {
i_img_dim min,max;
} minmax;
typedef struct {
minmax *data;
i_img_dim lines;
} i_mmarray;
/* FIXME: Merge this into datatypes.{c,h} */
void i_mmarray_cr(i_mmarray *ar,i_img_dim l);
void i_mmarray_dst(i_mmarray *ar);
void i_mmarray_add(i_mmarray *ar,i_img_dim x,i_img_dim y);
i_img_dim i_mmarray_gmin(i_mmarray *ar,i_img_dim y);
i_img_dim i_mmarray_getm(i_mmarray *ar,i_img_dim y);
void i_mmarray_info(i_mmarray *ar);
#if 0
void i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val);
#endif

View File

@@ -0,0 +1,58 @@
#ifndef _DYNALOAD_H_
#define _DYNALOAD_H_
#include "log.h"
#include "EXTERN.h"
#include "perl.h"
#include "ppport.h"
#include "ext.h"
typedef struct DSO_handle_tag DSO_handle;
typedef struct {
HV* hv;
char *key;
void *store;
} UTIL_args;
#if 0
int getobj(void *hv_t,char *key,char *type,void **store);
int getint(void *hv_t,char *key,int *store);
int getdouble(void *hv_t,char *key,double *store);
int getvoid(void *hv_t,char *key,void **store);
#endif
void *DSO_open(char* file,char** evalstring);
func_ptr *DSO_funclist(DSO_handle *handle);
int DSO_close(void *);
void DSO_call(DSO_handle *handle,int func_index,HV* hv);
#ifdef __EMX__ /* OS/2 */
# ifndef RTLD_LAZY
# define RTLD_LAZY 0
# endif /* RTLD_LAZY */
int dlclose(minthandle_t);
#endif /* __EMX__ */
#ifdef DLSYMUN
#define I_EVALSTR "_evalstr"
#define I_SYMBOL_TABLE "_symbol_table"
#define I_UTIL_TABLE "_util_table"
#define I_FUNCTION_LIST "_function_list"
#define I_INSTALL_TABLES "_install_tables"
#else
#define I_EVALSTR "evalstr"
#define I_SYMBOL_TABLE "symbol_table"
#define I_UTIL_TABLE "util_table"
#define I_FUNCTION_LIST "function_list"
#define I_INSTALL_TABLES "install_tables"
#endif
#endif /* _DYNALOAD_H_ */

View File

@@ -0,0 +1,50 @@
#include "imdatatypes.h"
#ifndef IMAGER_EXT_H
#define IMAGER_EXT_H
/* structures for passing data between Imager-plugin and the Imager-module */
typedef struct {
char *name;
void (*iptr)(void* ptr);
char *pcode;
} func_ptr;
typedef struct {
int (*getstr)(void *hv_t,char* key,char **store);
int (*getint)(void *hv_t,char *key,int *store);
int (*getdouble)(void *hv_t,char* key,double *store);
int (*getvoid)(void *hv_t,char* key,void **store);
int (*getobj)(void *hv_t,char* key,char* type,void **store);
} UTIL_table_t;
typedef struct {
undef_int (*i_has_format)(char *frmt);
i_color*(*ICL_set)(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a);
void (*ICL_info)(const i_color *cl);
im_context_t (*im_get_context_f)(void);
i_img*(*im_img_empty_ch_f)(im_context_t, i_img *im,i_img_dim x,i_img_dim y,int ch);
void(*i_img_exorcise_f)(i_img *im);
void(*i_img_info_f)(i_img *im,i_img_dim *info);
void(*i_img_setmask_f)(i_img *im,int ch_mask);
int (*i_img_getmask_f)(i_img *im);
/*
int (*i_ppix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
int (*i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
*/
void(*i_box)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val);
void(*i_line)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val,int endp);
void(*i_arc)(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val);
void(*i_copyto)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty);
void(*i_copyto_trans)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans);
int(*i_rubthru)(i_img *im,i_img *src,i_img_dim tx,i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
} symbol_table_t;
#endif

View File

@@ -0,0 +1,34 @@
#include "imager.h"
static char *i_format_list[]={
#ifdef HAVE_LIBJPEG
"jpeg",
#endif
#ifdef HAVE_LIBTIFF
"tiff",
#endif
#ifdef HAVE_LIBPNG
"png",
#endif
#ifdef HAVE_LIBGIF
"gif",
#endif
#ifdef HAVE_LIBT1
"t1",
#endif
#ifdef HAVE_LIBTT
"tt",
#endif
#ifdef HAVE_WIN32
"w32",
#endif
#ifdef HAVE_FT2
"ft2",
#endif
"raw",
"pnm",
"bmp",
"tga",
"ifs",
NULL};

View File

@@ -0,0 +1,420 @@
#ifndef _IMAGE_H_
#define _IMAGE_H_
#include "imconfig.h"
#include "immacros.h"
#include "imio.h"
#include "iolayer.h"
#include "stackmach.h"
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#ifdef SUNOS
#include <strings.h>
#endif
#ifndef PI
#define PI 3.14159265358979323846
#endif
#include "imdatatypes.h"
undef_int i_has_format(char *frmt);
/* constructors and destructors */
i_color *ICL_new_internal( unsigned char r,unsigned char g,unsigned char b,unsigned char a);
i_color *ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a);
void ICL_info (const i_color *cl);
void ICL_DESTROY (i_color *cl);
void ICL_add (i_color *dst, i_color *src, int ch);
extern i_fcolor *i_fcolor_new(double r, double g, double b, double a);
extern void i_fcolor_destroy(i_fcolor *cl);
extern void i_rgb_to_hsvf(i_fcolor *color);
extern void i_hsv_to_rgbf(i_fcolor *color);
extern void i_rgb_to_hsv(i_color *color);
extern void i_hsv_to_rgb(i_color *color);
i_img *im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch);
#define i_img_empty(im, x, y) i_img_empty_ch((im), (x), (y), 3)
i_img *im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch);
#define i_img_empty_ch(im, x, y, ch) im_img_empty_ch(aIMCTX, (im), (x), (y), (ch))
void i_img_exorcise(i_img *im);
void i_img_destroy(i_img *im);
i_img *im_img_alloc(pIMCTX);
void im_img_init(pIMCTX, i_img *im);
void i_img_info(i_img *im,i_img_dim *info);
extern i_img *i_sametype(i_img *im, i_img_dim xsize, i_img_dim ysize);
extern i_img *i_sametype_chans(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels);
/* Image feature settings */
void i_img_setmask (i_img *im,int ch_mask);
int i_img_getmask (i_img *im);
int i_img_getchannels(i_img *im);
i_img_dim i_img_get_width(i_img *im);
i_img_dim i_img_get_height(i_img *im);
i_color_model_t i_img_color_model(i_img *im);
int i_img_alpha_channel(i_img *im, int *channel);
int i_img_color_channels(i_img *im);
/* Base functions */
extern int (i_ppix)(i_img *im,i_img_dim x,i_img_dim y, const i_color *val);
extern int (i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
extern int (i_ppixf)(i_img *im,i_img_dim x,i_img_dim y, const i_fcolor *val);
extern int (i_gpixf)(i_img *im,i_img_dim x,i_img_dim y,i_fcolor *val);
extern i_img_dim (i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
const i_color *vals);
extern i_img_dim (i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
i_color *vals);
extern i_img_dim (i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
const i_fcolor *vals);
extern i_img_dim (i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
i_fcolor *vals);
extern i_img_dim (i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
i_sample_t *samp, const int *chans, int chan_count);
extern i_img_dim
(i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
const int *chans, int chan_count);
extern i_img_dim
(i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals);
extern i_img_dim
(i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals);
extern int (i_addcolors)(i_img *im, const i_color *colors, int count);
extern int (i_getcolors)(i_img *im, int i, i_color *, int count);
extern int (i_colorcount)(i_img *im);
extern int (i_maxcolors)(i_img *im);
extern int (i_findcolor)(i_img *im, const i_color *color, i_palidx *entry);
extern int (i_setcolors)(i_img *im, int index, const i_color *colors,
int count);
extern i_fill_t *i_new_fill_solidf(const i_fcolor *c, int combine);
extern i_fill_t *i_new_fill_solid(const i_color *c, int combine);
extern i_fill_t *
i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy);
extern i_fill_t *
i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy);
extern i_fill_t *
i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine);
extern i_fill_t *i_new_fill_opacity(i_fill_t *, double alpha_mult);
extern void i_fill_destroy(i_fill_t *fill);
float i_gpix_pch(i_img *im,i_img_dim x,i_img_dim y,int ch);
/* functions for drawing primitives */
void i_box (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val);
void i_box_filled (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val);
int i_box_filledf (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_fcolor *val);
void i_box_cfill(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_fill_t *fill);
void i_line (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val, int endp);
void i_line_aa (i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val, int endp);
void i_arc (i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val);
int i_arc_out(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,double d1,double d2,const i_color *val);
int i_arc_out_aa(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,double d1,double d2,const i_color *val);
void i_arc_aa (i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val);
void i_arc_cfill(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,i_fill_t *fill);
void i_arc_aa_cfill(i_img *im,double x,double y,double rad,double d1,double d2,i_fill_t *fill);
void i_circle_aa (i_img *im,double x, double y,double rad,const i_color *val);
void i_circle_aa_fill(i_img *im,double x, double y,double rad,i_fill_t *fill);
int i_circle_out (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val);
int i_circle_out_aa (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val);
void i_copyto (i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty);
void i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans);
i_img* i_copy (i_img *src);
int i_rubthru (i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
extern int
i_compose_mask(i_img *out, i_img *src, i_img *mask,
i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top,
i_img_dim mask_left, i_img_dim mask_top, i_img_dim width, i_img_dim height,
int combine, double opacity);
extern int
i_compose(i_img *out, i_img *src,
i_img_dim out_left, i_img_dim out_top, i_img_dim src_left, i_img_dim src_top,
i_img_dim width, i_img_dim height, int combine, double opacity);
extern i_img *
i_combine(i_img **src, const int *channels, int in_count);
undef_int i_flipxy (i_img *im, int direction);
extern i_img *i_rotate90(i_img *im, int degrees);
extern i_img *i_rotate_exact(i_img *im, double amount);
extern i_img *i_rotate_exact_bg(i_img *im, double amount, const i_color *backp, const i_fcolor *fbackp);
extern i_img *i_matrix_transform(i_img *im, i_img_dim xsize, i_img_dim ysize, const double *matrix);
extern i_img *i_matrix_transform_bg(i_img *im, i_img_dim xsize, i_img_dim ysize, const double *matrix, const i_color *backp, const i_fcolor *fbackp);
void i_bezier_multi(i_img *im,int l,const double *x,const double *y,const i_color *val);
int i_poly_aa (i_img *im,int l,const double *x,const double *y,const i_color *val);
int i_poly_aa_cfill(i_img *im,int l,const double *x,const double *y,i_fill_t *fill);
int i_poly_aa_m (i_img *im,int l,const double *x,const double *y, i_poly_fill_mode_t mode, const i_color *val);
int i_poly_aa_cfill_m(i_img *im,int l,const double *x,const double *y, i_poly_fill_mode_t mode, i_fill_t *fill);
extern int
i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys,
i_poly_fill_mode_t mode, const i_color *val);
extern int
i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys,
i_poly_fill_mode_t mode, i_fill_t *fill);
undef_int i_flood_fill (i_img *im,i_img_dim seedx,i_img_dim seedy, const i_color *dcol);
undef_int i_flood_cfill(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill);
undef_int i_flood_fill_border (i_img *im,i_img_dim seedx,i_img_dim seedy, const i_color *dcol, const i_color *border);
undef_int i_flood_cfill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border);
/* image processing functions */
int i_gaussian (i_img *im, double stddev);
int i_gaussian2 (i_img *im, double stddevX, double stddevY);
int i_conv (i_img *im,const double *coeff,int len);
void i_unsharp_mask(i_img *im, double stddev, double scale);
/* colour manipulation */
extern i_img *i_convert(i_img *src, const double *coeff, int outchan, int inchan);
extern void i_map(i_img *im, unsigned char (*maps)[256], unsigned int mask);
float i_img_diff (i_img *im1,i_img *im2);
double i_img_diffd(i_img *im1,i_img *im2);
int i_img_samef(i_img *im1,i_img *im2, double epsilon, const char *what);
/* font routines */
#ifdef HAVE_LIBTT
extern void i_tt_start(void);
TT_Fonthandle* i_tt_new(const char *fontname);
void i_tt_destroy( TT_Fonthandle *handle );
undef_int i_tt_cp( TT_Fonthandle *handle,i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char const* txt,size_t len,int smooth, int utf8, int align);
undef_int i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align);
undef_int i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8);
size_t i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8, char *out);
void i_tt_dump_names(TT_Fonthandle *handle);
size_t i_tt_face_name(TT_Fonthandle *handle, char *name_buf,
size_t name_buf_size);
size_t i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
size_t name_buf_size);
#endif /* End of freetype headers */
extern void i_quant_makemap(i_quantize *quant, i_img **imgs, int count);
extern i_palidx *i_quant_translate(i_quantize *quant, i_img *img);
extern void i_quant_transparent(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index);
i_img *im_img_pal_new(pIMCTX, i_img_dim x, i_img_dim y, int ch, int maxpal);
extern i_img *i_img_to_pal(i_img *src, i_quantize *quant);
extern i_img *i_img_to_rgb(i_img *src);
extern i_img *i_img_masked_new(i_img *targ, i_img *mask, i_img_dim x, i_img_dim y,
i_img_dim w, i_img_dim h);
extern i_img *im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch);
extern i_img *i_img_to_rgb16(i_img *im);
extern i_img *im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch);
extern i_img *i_img_to_drgb(i_img *im);
extern int i_img_is_monochrome(i_img *im, int *zero_is_white);
extern int i_get_file_background(i_img *im, i_color *bg);
extern int i_get_file_backgroundf(i_img *im, i_fcolor *bg);
const char * im_test_format_probe(im_context_t ctx, io_glue *data, int length);
#define i_test_format_probe(io, length) im_test_format_probe(aIMCTX, (io), (length))
/* file type magic to extend file detection */
extern int im_add_file_magic(im_context_t ctx, const char *name,
const unsigned char *bits, const unsigned char *mask,
size_t length);
#define i_add_file_magic(name, bits, mask, length) \
im_add_file_magic(aIMCTX, (name), (bits), (mask), (length))
i_img * i_readraw_wiol(io_glue *ig, i_img_dim x, i_img_dim y, int datachannels, int storechannels, int intrl);
undef_int i_writeraw_wiol(i_img* im, io_glue *ig);
i_img * i_readpnm_wiol(io_glue *ig, int allow_incomplete);
i_img ** i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete);
undef_int i_writeppm_wiol(i_img *im, io_glue *ig);
extern int i_writebmp_wiol(i_img *im, io_glue *ig);
extern i_img *i_readbmp_wiol(io_glue *ig, int allow_incomplete);
int tga_header_verify(unsigned char headbuf[18]);
i_img * i_readtga_wiol(io_glue *ig, int length);
undef_int i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen);
i_img * i_readrgb_wiol(io_glue *ig, int length);
undef_int i_writergb_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen);
i_img * i_scaleaxis(i_img *im, double Value, int Axis);
i_img * i_scale_nn(i_img *im, double scx, double scy);
i_img * i_scale_mixing(i_img *src, i_img_dim width, i_img_dim height);
i_img * i_haar(i_img *im);
int i_count_colors(i_img *im,int maxc);
int i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc);
i_img * i_transform(i_img *im, int *opx, int opxl, int *opy,int opyl,double parm[],int parmlen);
struct rm_op;
i_img * i_transform2(i_img_dim width, i_img_dim height, int channels,
struct rm_op *ops, int ops_count,
double *n_regs, int n_regs_count,
i_color *c_regs, int c_regs_count,
i_img **in_imgs, int in_imgs_count);
/* filters */
void i_contrast(i_img *im, float intensity);
void i_hardinvert(i_img *im);
void i_hardinvertall(i_img *im);
void i_noise(i_img *im, float amount, unsigned char type);
void i_bumpmap(i_img *im,i_img *bump,int channel,i_img_dim light_x,i_img_dim light_y,i_img_dim strength);
void i_bumpmap_complex(i_img *im, i_img *bump, int channel, i_img_dim tx, i_img_dim ty, double Lx, double Ly,
double Lz, float cd, float cs, float n, i_color *Ia, i_color *Il, i_color *Is);
void i_postlevels(i_img *im,int levels);
void i_mosaic(i_img *im,i_img_dim size);
void i_watermark(i_img *im,i_img *wmark,i_img_dim tx,i_img_dim ty,int pixdiff);
void i_autolevels(i_img *im,float lsat,float usat,float skew);
void i_autolevels_mono(i_img *im,float lsat,float usat);
void i_radnoise(i_img *im,i_img_dim xo,i_img_dim yo,double rscale,double ascale);
void i_turbnoise(i_img *im,double xo,double yo,double scale);
void i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure);
int i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure);
i_img *i_diff_image(i_img *im, i_img *im2, double mindist);
int
i_fountain(i_img *im, double xa, double ya, double xb, double yb,
i_fountain_type type, i_fountain_repeat repeat,
int combine, int super_sample, double ssample_param,
int count, i_fountain_seg *segs);
extern i_fill_t *
i_new_fill_fount(double xa, double ya, double xb, double yb,
i_fountain_type type, i_fountain_repeat repeat,
int combine, int super_sample, double ssample_param,
int count, i_fountain_seg *segs);
/* Debug only functions */
void malloc_state( void );
#include "imerror.h"
/* image tag processing */
extern void i_tags_new(i_img_tags *tags);
extern int i_tags_addn(i_img_tags *tags, char const *name, int code,
int idata);
extern int i_tags_add(i_img_tags *tags, char const *name, int code,
char const *data, int size, int idata);
extern int i_tags_set(i_img_tags *tags, char const *name,
char const *data, int size);
extern int i_tags_setn(i_img_tags *tags, char const *name, int idata);
extern void i_tags_destroy(i_img_tags *tags);
extern int i_tags_find(i_img_tags *tags, char const *name, int start,
int *entry);
extern int i_tags_findn(i_img_tags *tags, int code, int start, int *entry);
extern int i_tags_delete(i_img_tags *tags, int entry);
extern int i_tags_delbyname(i_img_tags *tags, char const *name);
extern int i_tags_delbycode(i_img_tags *tags, int code);
extern int i_tags_get_float(i_img_tags *tags, char const *name, int code,
double *value);
extern int i_tags_set_float(i_img_tags *tags, char const *name, int code,
double value);
extern int i_tags_set_float2(i_img_tags *tags, char const *name, int code,
double value, int places);
extern int i_tags_get_int(i_img_tags *tags, char const *name, int code,
int *value);
extern int i_tags_get_string(i_img_tags *tags, char const *name, int code,
char *value, size_t value_size);
extern int i_tags_get_color(i_img_tags *tags, char const *name, int code,
i_color *value);
extern int i_tags_set_color(i_img_tags *tags, char const *name, int code,
i_color const *value);
extern void i_tags_print(i_img_tags *tags);
/* image file limits */
extern int
im_set_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes);
extern int
im_get_image_file_limits(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes);
extern int
im_int_check_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size);
/* memory allocation */
void* mymalloc(size_t size);
void myfree(void *p);
void* myrealloc(void *p, size_t newsize);
void* mymalloc_file_line (size_t size, char* file, int line);
void myfree_file_line (void *p, char*file, int line);
void* myrealloc_file_line(void *p, size_t newsize, char* file,int line);
#ifdef IMAGER_DEBUG_MALLOC
#define mymalloc(x) (mymalloc_file_line((x), __FILE__, __LINE__))
#define myrealloc(x,y) (myrealloc_file_line((x),(y), __FILE__, __LINE__))
#define myfree(x) (myfree_file_line((x), __FILE__, __LINE__))
void malloc_state (void);
void bndcheck_all (void);
#else
void malloc_state(void);
#endif /* IMAGER_MALLOC_DEBUG */
#include "imrender.h"
extern void
i_adapt_colors(int dest_channels, int src_channels, i_color *colors,
size_t count);
extern void
i_adapt_fcolors(int dest_channels, int src_channels, i_fcolor *colors,
size_t count);
extern void
i_adapt_colors_bg(int dest_channels, int src_channels, i_color *colors,
size_t count, i_color const *bg);
extern void
i_adapt_fcolors_bg(int dest_channels, int src_channels, i_fcolor *colors,
size_t count, i_fcolor const *bg);
extern int
i_gsamp_bg(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samples,
int out_channels, i_color const *bg);
extern int
i_gsampf_bg(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samples,
int out_channels, i_fcolor const *bg);
/* context object management */
extern im_context_t im_context_new(void);
extern void im_context_refinc(im_context_t ctx, const char *where);
extern void im_context_refdec(im_context_t ctx, const char *where);
extern im_context_t im_context_clone(im_context_t ctx, const char *where);
extern im_slot_t im_context_slot_new(im_slot_destroy_t);
extern void *im_context_slot_get(im_context_t ctx, im_slot_t slot);
extern int im_context_slot_set(im_context_t ctx, im_slot_t slot, void *);
extern im_context_t (*im_get_context)(void);
/* mutex API */
extern i_mutex_t i_mutex_new(void);
extern void i_mutex_destroy(i_mutex_t m);
extern void i_mutex_lock(i_mutex_t m);
extern void i_mutex_unlock(i_mutex_t m);
#include "imio.h"
#endif

View File

@@ -0,0 +1,167 @@
/* Declares utility functions useful across various files which
aren't meant to be available externally
*/
#ifndef IMAGEI_H_
#define IMAGEI_H_
#include "imager.h"
#include <stddef.h>
/* wrapper functions that implement the floating point sample version of a
function in terms of the 8-bit sample version
*/
extern int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix);
extern int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix);
extern i_img_dim i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix);
extern i_img_dim i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix);
extern i_img_dim i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
int const *chans, int chan_count);
/* wrapper functions that forward palette calls to the underlying image,
assuming the underlying image is the first pointer in whatever
ext_data points at
*/
extern int i_addcolors_forward(i_img *im, const i_color *, int count);
extern int i_getcolors_forward(i_img *im, int i, i_color *, int count);
extern int i_colorcount_forward(i_img *im);
extern int i_maxcolors_forward(i_img *im);
extern int i_findcolor_forward(i_img *im, const i_color *color,
i_palidx *entry);
extern int i_setcolors_forward(i_img *im, int index, const i_color *colors,
int count);
/* fallback handler for gsamp_bits */
extern i_img_dim i_gsamp_bits_fb(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, unsigned *samp,
const int *chans, int chan_count, int bits);
#define SampleFTo16(num) ((int)((num) * 65535.0 + 0.5))
/* we add that little bit to avoid rounding issues */
#define Sample16ToF(num) ((num) / 65535.0)
#define SampleFTo8(num) ((int)((num) * 255.0 + 0.5))
#define Sample8ToF(num) ((num) / 255.0)
#define Sample16To8(num) (((num)+128) / 257)
#define Sample8To16(num) ((num) * 257)
extern void i_get_combine(int combine, i_fill_combine_f *, i_fill_combinef_f *);
#define im_min(a, b) ((a) < (b) ? (a) : (b))
#define im_max(a, b) ((a) > (b) ? (a) : (b))
#include "ext.h"
extern UTIL_table_t i_UTIL_table;
/* test if all channels are writable */
#define I_ALL_CHANNELS_WRITABLE(im) (((im)->ch_mask & 0xF) == 0xf)
typedef struct i_int_hline_seg_tag {
i_img_dim minx, x_limit;
} i_int_hline_seg;
typedef struct i_int_hline_entry_tag {
i_img_dim count;
size_t alloc;
i_int_hline_seg segs[1];
} i_int_hline_entry;
/* represents a set of horizontal line segments to be filled in later */
typedef struct i_int_hlines_tag {
i_img_dim start_y, limit_y;
i_img_dim start_x, limit_x;
i_int_hline_entry **entries;
} i_int_hlines;
extern void
i_int_init_hlines(
i_int_hlines *hlines,
i_img_dim start_y,
i_img_dim count_y,
i_img_dim start_x,
i_img_dim width_x
);
extern void i_int_init_hlines_img(i_int_hlines *hlines, i_img *img);
extern void i_int_hlines_add(i_int_hlines *hlines, i_img_dim y, i_img_dim minx, i_img_dim width);
extern void i_int_hlines_destroy(i_int_hlines *hlines);
extern void i_int_hlines_fill_color(i_img *im, i_int_hlines *hlines, const i_color *val);
extern void i_int_hlines_fill_fill(i_img *im, i_int_hlines *hlines, i_fill_t *fill);
#define I_LIMIT_8(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))
#define I_LIMIT_DOUBLE(x) ((x) < 0.0 ? 0.0 : (x) > 1.0 ? 1.0 : (x))
#define IM_STRING(x) #x
/* I considered using assert.h here, but perl does it's own thing with
assert() and the NDEBUG test is opposite to the direction I prefer */
#ifdef IM_ASSERT
extern void im_assert_fail(char const *, int, char const *);
#define im_assert(x) ((x) ? (void)(0) : im_assert_fail(__FILE__, __LINE__, IM_STRING(x)))
#else
#define im_assert(x) (void)(0)
#endif
i_img_dim i_minx(i_img_dim a, i_img_dim b);
i_img_dim i_maxx(i_img_dim x, i_img_dim y);
i_img_dim i_abs(i_img_dim x);
#define i_min(a, b) i_minx((a), (b))
#define i_max(a, b) i_maxx((a), (b))
#define color_to_grey(col) ((col)->rgb.r * 0.222 + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071)
struct file_magic_entry {
unsigned char *magic;
size_t magic_size;
char *name;
unsigned char *mask;
};
typedef struct im_file_magic im_file_magic;
struct im_file_magic {
struct file_magic_entry m;
/* more magic to check */
im_file_magic *next;
};
#define IM_ERROR_COUNT 20
typedef struct im_context_tag {
int error_sp;
size_t error_alloc[IM_ERROR_COUNT];
i_errmsg error_stack[IM_ERROR_COUNT];
#ifdef IMAGER_LOG
/* the log file and level for this context */
FILE *lg_file;
int log_level;
/* whether we own the lg_file, false for stderr and for cloned contexts */
int own_log;
/* values supplied by lhead */
const char *filename;
int line;
#endif
/* file size limits */
i_img_dim max_width, max_height;
size_t max_bytes;
/* per context storage */
size_t slot_alloc;
void **slots;
/* registered file type magic */
im_file_magic *file_magic;
ptrdiff_t refcount;
} im_context_struct;
#define DEF_BYTES_LIMIT 0x40000000
#define im_size_t_max (~(size_t)0)
#endif

View File

@@ -0,0 +1,34 @@
/* This file is automatically generated by Makefile.PL.
Don't edit this file, since any changes will be lost */
#ifndef IMAGER_IMCONFIG_H
#define IMAGER_IMCONFIG_H
/*
Logging system
*/
#define IMAGER_LOG 1
/*
Compiler supports the GCC __attribute__((format...)) syntax.
*/
#define IMAGER_FORMAT_ATTR 1
/* We can use snprintf() */
#define IMAGER_SNPRINTF 1
/* We can use vsnprintf() */
#define IMAGER_VSNPRINTF 1
/*
Type and format code for formatted output as with printf.
This is intended for formatting i_img_dim values.
*/
typedef long long i_dim_format_t;
#define i_DF "I64d"
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
#ifndef IMAGER_IMERROR_H
#define IMAGER_IMERROR_H
/* error handling
see error.c for documentation
the error information is currently global
*/
typedef void (*i_error_cb)(int code, char const *msg);
typedef void (*i_failed_cb)(i_errmsg *msgs);
extern i_error_cb i_set_error_cb(i_error_cb);
extern i_failed_cb i_set_failed_cb(i_failed_cb);
extern void i_set_argv0(char const *);
extern int i_set_errors_fatal(int new_fatal);
extern i_errmsg *im_errors(pIMCTX);
extern void im_push_error(pIMCTX, int code, char const *msg);
#ifndef IMAGER_NO_CONTEXT
extern void i_push_errorf(int code, char const *fmt, ...) I_FORMAT_ATTR(2, 3);
#endif
extern void im_push_errorf(pIMCTX, int code, char const *fmt, ...) I_FORMAT_ATTR(3, 4);
extern void im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list);
extern void im_clear_error(pIMCTX);
extern int i_failed(int code, char const *msg);
#endif

View File

@@ -0,0 +1,10 @@
/* imexif.h - interface to Exif handling */
#ifndef IMAGER_IMEXIF_H
#define IMAGER_IMEXIF_H
#include <stddef.h>
#include "imdatatypes.h"
extern int im_decode_exif(i_img *im, const unsigned char *data, size_t length);
#endif /* ifndef IMAGER_IMEXIF_H */

View File

@@ -0,0 +1,261 @@
#ifndef IMAGER_IMEXT_H_
#define IMAGER_IMEXT_H_
#include "imexttypes.h"
#include "immacros.h"
extern im_ext_funcs *imager_function_ext_table;
#define DEFINE_IMAGER_CALLBACKS im_ext_funcs *imager_function_ext_table
#ifndef IMAGER_MIN_API_LEVEL
#define IMAGER_MIN_API_LEVEL IMAGER_API_LEVEL
#endif
#define PERL_INITIALIZE_IMAGER_CALLBACKS_NAME(name) \
do { \
imager_function_ext_table = INT2PTR(im_ext_funcs *, SvIV(get_sv(PERL_FUNCTION_TABLE_NAME, 1))); \
if (!imager_function_ext_table) \
croak("Imager API function table not found!"); \
if (imager_function_ext_table->version != IMAGER_API_VERSION) { \
croak("Imager API version incorrect loaded %d vs expected %d in %s", \
imager_function_ext_table->version, IMAGER_API_VERSION, (name)); \
} \
if (imager_function_ext_table->level < IMAGER_MIN_API_LEVEL) \
croak("API level %d below minimum of %d in %s", imager_function_ext_table->level, IMAGER_MIN_API_LEVEL, (name)); \
} while (0)
#define PERL_INITIALIZE_IMAGER_CALLBACKS PERL_INITIALIZE_IMAGER_CALLBACKS_NAME(__FILE__)
/* just for use here */
#define im_extt imager_function_ext_table
#define im_get_context() ((im_extt->f_im_get_context)())
#define im_context_refinc(ctx, where) ((im_extt->f_im_context_refinc)((ctx), (where)))
#define im_context_refdec(ctx, where) ((im_extt->f_im_context_refdec)((ctx), (where)))
#ifdef IMAGER_DEBUG_MALLOC
#define mymalloc(size) ((im_extt->f_mymalloc_file_line)((size), __FILE__, __LINE__))
#define myrealloc(ptr, size) ((im_extt->f_myrealloc_file_line)((ptr), (size), __FILE__, __LINE__))
#define myfree(ptr) ((im_extt->f_myfree_file_line)((ptr), __FILE__, __LINE__))
#else
#define mymalloc(size) ((im_extt->f_mymalloc)(size))
#define myfree(size) ((im_extt->f_myfree)(size))
#define myrealloc(block, newsize) ((im_extt->f_myrealloc)((block), (newsize)))
#endif
#define im_img_8_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_8_new)((ctx), (xsize), (ysize), (channels)))
#define im_img_16_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_16_new)((ctx), (xsize), (ysize), (channels)))
#define im_img_double_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_double_new)((ctx), (xsize), (ysize), (channels)))
#define im_img_pal_new(ctx, xsize, ysize, channels, maxpal) ((im_extt->f_im_img_pal_new)((ctx), (xsize), (ysize), (channels), (maxpal)))
#define i_img_destroy(im) ((im_extt->f_i_img_destroy)(im))
#define i_sametype(im, xsize, ysize) ((im_extt->f_i_sametype)((im), (xsize), (ysize)))
#define i_sametype_chans(im, xsize, ysize, channels) ((im_extt->f_i_sametype_chans)((im), (xsize), (ysize), (channels)))
#define i_img_info(im, info) ((im_extt->f_i_img_info)((im), (info)))
#ifndef IMAGER_DIRECT_IMAGE_CALLS
#define IMAGER_DIRECT_IMAGE_CALLS 1
#endif
#if !IMAGER_DIRECT_IMAGE_CALLS
#define i_ppix(im, x, y, val) ((im_extt->f_i_ppix)((im), (x), (y), (val)))
#define i_gpix(im, x, y, val) ((im_extt->f_i_gpix)((im), (x), (y), (val)))
#define i_ppixf(im, x, y, val) ((im_extt->f_i_ppixf)((im), (x), (y), (val)))
#define i_gpixf(im, x, y, val) ((im_extt->f_i_gpixf)((im), (x), (y), (val)))
#define i_plin(im, l, r, y, val) ((im_extt->f_i_plin)((im), (l), (r), (y), (val)))
#define i_glin(im, l, r, y, val) ((im_extt->f_i_glin)((im), (l), (r), (y), (val)))
#define i_plinf(im, l, r, y, val) ((im_extt->f_i_plinf)((im), (l), (r), (y), (val)))
#define i_glinf(im, l, r, y, val) ((im_extt->f_i_glinf)((im), (l), (r), (y), (val)))
#define i_gsamp(im, l, r, y, samps, chans, count) \
((im_extt->f_i_gsamp)((im), (l), (r), (y), (samps), (chans), (count)))
#define i_gsampf(im, l, r, y, samps, chans, count) \
((im_extt->f_i_gsampf)((im), (l), (r), (y), (samps), (chans), (count)))
#endif
#define i_gsamp_bits(im, l, r, y, samps, chans, count, bits) \
(((im)->i_f_gsamp_bits) ? ((im)->i_f_gsamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
#define i_psamp_bits(im, l, r, y, samps, chans, count, bits) \
(((im)->i_f_psamp_bits) ? ((im)->i_f_psamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
#define i_new_fill_solid(c, combine) ((im_extt->f_i_new_fill_solid)((c), (combine)))
#define i_new_fill_solidf(c, combine) ((im_extt->f_i_new_fill_solidf)((c), (combine)))
#define i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) \
((im_extt->f_i_new_fill_hatch)((fg), (bg), (combine), (hatch), (cust_hatch), (dx), (dy)))
#define i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) \
((im_extt->f_i_new_fill_hatchf)((fg), (bg), (combine), (hatch), (cust_hatch), (dx), (dy)))
#define i_new_fill_image(im, matrix, xoff, yoff, combine) \
((im_extt->f_i_new_fill_image)((im), (matrix), (xoff), (yoff), (combine)))
#define i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) \
((im_extt->f_i_new_fill_fount)((xa), (ya), (xb), (yb), (type), (repeat), (combine), (super_sample), (ssample_param), (count), (segs)))
#define i_fill_destroy(fill) ((im_extt->f_i_fill_destroy)(fill))
#define i_quant_makemap(quant, imgs, count) \
((im_extt->f_i_quant_makemap)((quant), (imgs), (count)))
#define i_quant_translate(quant, img) \
((im_extt->f_i_quant_translate)((quant), (img)))
#define i_quant_transparent(quant, indices, img, trans_index) \
((im_extt->f_i_quant_transparent)((quant), (indices), (img), (trans_index)))
#define im_clear_error(ctx) ((im_extt->f_im_clear_error)(ctx))
#define im_push_error(ctx, code, msg) ((im_extt->f_im_push_error)((ctx), (code), (msg)))
#define i_push_errorf (im_extt->f_i_push_errorf)
#define im_push_errorvf(ctx, code, fmt, list) \
((im_extt->f_im_push_errorvf)((ctx), (code), (fmt), (list)))
#define i_tags_new(tags) ((im_extt->f_i_tags_new)(tags))
#define i_tags_set(tags, name, data, size) \
((im_extt->f_i_tags_set)((tags), (name), (data), (size)))
#define i_tags_setn(tags, name, idata) \
((im_extt->f_i_tags_setn)((tags), (name), (idata)))
#define i_tags_destroy(tags) ((im_extt->f_i_tags_destroy)(tags))
#define i_tags_find(tags, name, start, entry) \
((im_extt->f_i_tags_find)((tags), (name), (start), (entry)))
#define i_tags_findn(tags, code, start, entry) \
((im_extt->f_i_tags_findn)((tags), (code), (start), (entry)))
#define i_tags_delete(tags, entry) \
((im_extt->f_i_tags_delete)((tags), (entry)))
#define i_tags_delbyname(tags, name) \
((im_extt->f_i_tags_delbyname)((tags), (name)))
#define i_tags_delbycode(tags, code) \
((im_extt->f_i_tags_delbycode)((tags), (code)))
#define i_tags_get_float(tags, name, code, value) \
((im_extt->f_i_tags_get_float)((tags), (name), (code), (value)))
#define i_tags_set_float(tags, name, code, value) \
((im_extt->f_i_tags_set_float)((tags), (name), (code), (value)))
#define i_tags_set_float2(tags, name, code, value, places) \
((im_extt->f_i_tags_set_float2)((tags), (name), (code), (value), (places)))
#define i_tags_get_int(tags, name, code, value) \
((im_extt->f_i_tags_get_int)((tags), (name), (code), (value)))
#define i_tags_get_string(tags, name, code, value, value_size) \
((im_extt->f_i_tags_get_string)((tags), (name), (code), (value), (value_size)))
#define i_tags_get_color(tags, name, code, value) \
((im_extt->f_i_tags_get_color)((tags), (name), (code), (value)))
#define i_tags_set_color(tags, name, code, value) \
((im_extt->f_i_tags_set_color)((tags), (name), (code), (value)))
#define i_box(im, x1, y1, x2, y2, val) ((im_extt->f_i_box)((im), (x1), (y1), (x2), (y2), (val)))
#define i_box_filled(im, x1, y1, x2, y2, val) ((im_extt->f_i_box_filled)((im), (x1), (y1), (x2), (y2), (val)))
#define i_box_cfill(im, x1, y1, x2, y2, fill) ((im_extt->f_i_box_cfill)((im), (x1), (y1), (x2), (y2), (fill)))
#define i_line(im, x1, y1, x2, y2, val, endp) ((im_extt->f_i_line)((im), (x1), (y1), (x2), (y2), (val), (endp)))
#define i_line_aa(im, x1, y1, x2, y2, val, endp) ((im_extt->f_i_line_aa)((im), (x1), (y1), (x2), (y2), (val), (endp)))
#define i_arc(im, x, y, rad, d1, d2, val) ((im_extt->f_i_arc)((im), (x), (y), (rad), (d1), (d2), (val)))
#define i_arc_aa(im, x, y, rad, d1, d2, val) ((im_extt->f_i_arc_aa)((im), (x), (y), (rad), (d1), (d2), (val)))
#define i_arc_cfill(im, x, y, rad, d1, d2, fill) ((im_extt->f_i_arc_cfill)((im), (x), (y), (rad), (d1), (d2), (fill)))
#define i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) ((im_extt->f_i_arc_aa_cfill)((im), (x), (y), (rad), (d1), (d2), (fill)))
#define i_circle_aa(im, x, y, rad, val) ((im_extt->f_i_circle_aa)((im), (x), (y), (rad), (val)))
#define i_flood_fill(im, seedx, seedy, dcol) ((im_extt->f_i_flood_fill)((im), (seedx), (seedy), (dcol)))
#define i_flood_cfill(im, seedx, seedy, fill) ((im_extt->f_i_flood_cfill)((im), (seedx), (seedy), (fill)))
#define i_flood_fill_border(im, seedx, seedy, dcol, border) ((im_extt->f_i_flood_fill_border)((im), (seedx), (seedy), (dcol), (border)))
#define i_flood_cfill_border(im, seedx, seedy, fill, border) ((im_extt->f_i_flood_cfill_border)((im), (seedx), (seedy), (fill), (border)))
#define i_poly_aa_m(im, count, x, y, mode, c) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (c)))
#define i_poly_aa_cfill_m(im, count, x, y, mode, fill) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (fill)))
#define i_poly_poly_aa(im, count, polys, mode, c) ((im_extt->f_i_poly_poly_aa)((im), (count), (polys), (mode), (c)))
#define i_poly_poly_aa_cfill(im, count, polys, mode, fill) ((im_extt->f_i_poly_poly_aa_cfill)((im), (count), (polys), (mode), (fill)))
#define i_copyto(im, src, x1, y1, x2, y2, tx, ty) \
((im_extt->f_i_copyto)((im), (src), (x1), (y1), (x2), (y2), (tx), (ty)))
#define i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) \
((im_extt->f_i_copyto_trans)((im), (src), (x1), (y1), (x2), (y2), (tx), (ty), (trans)))
#define i_copy(im) ((im_extt->f_i_copy)(im))
#define i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy) \
((im_extt->f_i_rubthru)((im), (src), (tx), (ty), (src_minx), (src_miny), (src_maxx), (src_maxy)))
#define im_set_image_file_limits(ctx, max_width, max_height, max_bytes) \
((im_extt->f_im_set_image_file_limits)((max_width), (max_height), (max_bytes)))
#define im_get_image_file_limits(ctx, pmax_width, pmax_height, pmax_bytes) \
((im_extt->f_im_get_image_file_limits)((ctx), (pmax_width), (pmax_height), (pmax_bytes)))
#define im_int_check_image_file_limits(ctx, width, height, channels, sample_size) \
((im_extt->f_im_int_check_image_file_limits)((ctx), (width), (height), (channels), (sample_size)))
#define i_img_setmask(img, mask) ((im_extt->f_i_img_setmask)((img), (mask)))
#define i_img_getmask(img) ((im_extt->f_i_img_getmask)(img))
#define i_img_getchannels(img) ((im_extt->f_i_img_getchannels)(img))
#define i_img_get_width(img) ((im_extt->f_i_img_get_width)(img))
#define i_img_get_height(img) ((im_extt->f_i_img_get_height)(img))
#define i_lhead(file, line) ((im_extt->f_i_lhead)((file), (line)))
#define i_loog (im_extt->f_i_loog)
#define im_lhead(ctx, file, line) ((im_extt->f_im_lhead)((ctx), (file), (line)))
#define im_loog (im_extt->f_im_loog)
#define im_img_alloc(ctx) ((im_extt->f_im_img_alloc)(ctx))
#define im_img_init(ctx, img) ((im_extt->fm_i_img_init)((ctx), (img)))
#define i_img_is_monochrome(img, zero_is_white) ((im_extt->f_i_img_is_monochrome)((img), (zero_is_white)))
#define i_gsamp_bg(im, l, r, y, samples, out_channels, bg) \
((im_extt->f_i_gsamp_bg)((im), (l), (r), (y), (samples), (out_channels), (bg)))
#define i_gsampf_bg(im, l, r, y, samples, out_channels, bg) \
((im_extt->f_i_gsampf_bg)((im), (l), (r), (y), (samples), (out_channels), (bg)))
#define i_get_file_background(im, bg) \
((im_extt->f_i_get_file_background)((im), (bg)))
#define i_get_file_backgroundf(im, bg) \
((im_extt->f_i_get_file_backgroundf)((im), (bg)))
#define i_utf8_advance(p, s) ((im_extt->f_i_utf8_advance)((p), (s)))
#define i_render_new(im, width) ((im_extt->f_i_render_new)((im), (width)))
#define i_render_delete(r) ((im_extt->f_i_render_delete)(r))
#define i_render_color(r, x, y, width, src, color) \
((im_extt->f_i_render_color)((r), (x), (y), (width), (src), (color)))
#define i_render_fill(r, x, y, width, src, fill) \
((im_extt->f_i_render_fill)((r), (x), (y), (width), (src), (fill)))
#define i_render_line(r, x, y, width, src, line, combine) \
((im_extt->f_i_render_line)((r), (x), (y), (width), (src), (line), (combine)))
#define i_render_linef(r, x, y, width, src, line, combine) \
((im_extt->f_i_render_linef)((r), (x), (y), (width), (src), (line), (combine)))
#define i_io_getc_imp (im_extt->f_i_io_getc_imp)
#define i_io_peekc_imp (im_extt->f_i_io_peekc_imp)
#define i_io_peekn (im_extt->f_i_io_peekn)
#define i_io_putc_imp (im_extt->f_i_io_putc_imp)
#define i_io_read (im_extt->f_i_io_read)
#define i_io_write (im_extt->f_i_io_write)
#define i_io_seek (im_extt->f_i_io_seek)
#define i_io_flush (im_extt->f_i_io_flush)
#define i_io_close (im_extt->f_i_io_close)
#define i_io_set_buffered (im_extt->f_i_io_set_buffered)
#define i_io_gets (im_extt->f_i_io_gets)
#define im_io_new_fd(ctx, fd) ((im_extt->f_im_io_new_fd)(ctx, fd))
#define im_io_new_bufchain(ctx) ((im_extt->f_im_io_new_bufchain)(ctx))
#define im_io_new_buffer(ctx, data, len, closecb, closedata) \
((im_extt->f_im_io_new_buffer)((ctx), (data), (len), (closecb), (closedata)))
#define im_io_new_cb(ctx, p, readcb, writecb, seekcb, closecb, destroycb) \
((im_extt->f_im_io_new_cb)((ctx), (p), (readcb), (writecb), (seekcb), (closecb), (destroycb)))
#define io_slurp(ig, datap) ((im_extt->f_io_slurp)((ig), (datap)))
#define io_glue_destroy(ig) ((im_extt->f_io_glue_destroy)(ig))
#define i_mutex_new() ((im_extt->f_i_mutex_new)())
#define i_mutex_destroy(m) ((im_extt->f_i_mutex_destroy)(m))
#define i_mutex_lock(m) ((im_extt->f_i_mutex_lock)(m))
#define i_mutex_unlock(m) ((im_extt->f_i_mutex_unlock)(m))
#define im_context_slot_new(destructor) ((im_extt->f_im_context_slot_new)(destructor))
#define im_context_slot_get(ctx, slot) ((im_extt->f_im_context_slot_get)((ctx), (slot)))
#define im_context_slot_set(ctx, slot, value) ((im_extt->f_im_context_slot_set)((ctx), (slot), (value)))
#define im_push_errorf (im_extt->f_im_push_errorf)
#define i_img_alpha_channel(im, channel) ((im_extt->f_i_img_alpha_channel)((im), (channel)))
#define i_img_color_model(im) ((im_extt->f_i_img_color_model)((im)))
#define i_img_color_channels(im) ((im_extt->f_i_img_color_channels)((im)))
#define im_decode_exif(im, data, len) ((im_extt->f_im_decode_exif)((im), (data), (len)))
#ifdef IMAGER_LOG
#ifndef IMAGER_NO_CONTEXT
#define mm_log(x) { i_lhead(__FILE__,__LINE__); i_loog x; }
#endif
#define im_log(x) { im_lhead(aIMCTX, __FILE__,__LINE__); im_loog x; }
#else
#define mm_log(x)
#endif
#endif

View File

@@ -0,0 +1,11 @@
#ifndef IMAGER_IMEXTDEF_H
#define IMAGER_IMEXTDEF_H
#include "imexttypes.h"
extern im_ext_funcs imager_function_table;
#define PERL_SET_GLOBAL_CALLBACKS \
sv_setiv(get_sv(PERL_FUNCTION_TABLE_NAME, 1), PTR2IV(&imager_function_table));
#endif

View File

@@ -0,0 +1,33 @@
#ifndef IMAGER_IMEXTPL_H_
#define IMAGER_IMEXTPL_H_
#include "imextpltypes.h"
#include "immacros.h"
extern im_pl_ext_funcs *imager_perl_function_ext_table;
#define DEFINE_IMAGER_PERL_CALLBACKS im_pl_ext_funcs *imager_perl_function_ext_table
#ifndef IMAGER_MIN_PL_API_LEVEL
#define IMAGER_MIN_PL_API_LEVEL IMAGER_PL_API_LEVEL
#endif
#define PERL_INITIALIZE_IMAGER_PERL_CALLBACKS \
do { \
imager_perl_function_ext_table = INT2PTR(im_pl_ext_funcs *, SvIV(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1))); \
if (!imager_perl_function_ext_table) \
croak("Imager Perl API function table not found!"); \
if (imager_perl_function_ext_table->version != IMAGER_PL_API_VERSION) \
croak("Imager Perl API version incorrect"); \
if (imager_perl_function_ext_table->level < IMAGER_MIN_PL_API_LEVEL) \
croak("perl API level %d below minimum of %d", imager_perl_function_ext_table->level, IMAGER_MIN_PL_API_LEVEL); \
} while (0)
/* just for use here */
#define im_exttpl imager_perl_function_ext_table
#define ip_handle_quant_opts (im_exttpl->f_ip_handle_quant_opts)
#define ip_cleanup_quant_opts (im_exttpl->f_ip_cleanup_quant_opts)
#define ip_copy_colors_back (im_exttpl->f_ip_copy_colors_back)
#endif

View File

@@ -0,0 +1,33 @@
#ifndef IMAGER_IMEXTPLTYPES_H_
#define IMAGER_IMEXTPLTYPES_H_
#ifndef PERL_NO_GET_CONTEXT
#error Sorry, you need to build with PERL_NO_GET_CONTEXT
#endif
#define IMAGER_PL_API_VERSION 1
/* This file provides functions useful for external code in
interfacing with perl - these functions aren't part of the core
Imager API. */
#define IMAGER_PL_API_LEVEL 2
typedef struct {
int version;
int level;
/* IMAGER_PL_API_LEVEL 1 functions */
void (*f_ip_handle_quant_opts)(pTHX_ i_quantize *quant, HV *hv);
void (*f_ip_cleanup_quant_opts)(pTHX_ i_quantize *quant);
void (*f_ip_copy_colors_back)(pTHX_ HV *hv, i_quantize *quant);
/* IMAGER_PL_API_LEVEL 2 */
int (*f_ip_handle_quant_opts2)(pTHX_ i_quantize *quant, HV *hv);
/* IMAGER_PL_API_LEVEL 3 functions will go here */
} im_pl_ext_funcs;
#define PERL_PL_FUNCTION_TABLE_NAME "Imager::__ext_pl_func_table"
#endif

View File

@@ -0,0 +1,281 @@
#ifndef IMAGER_IMEXTTYPES_H_
#define IMAGER_IMEXTTYPES_H_
/* keep this file simple - apidocs.perl parses it. */
#include "imdatatypes.h"
#include <stdarg.h>
/*
IMAGER_API_VERSION is similar to the version number in the third and
fourth bytes of TIFF files - if it ever changes then the API has changed
too much for any application to remain compatible.
Version 2 changed the types of some parameters and pointers. A
simple recompile should be enough in most cases.
Version 3 changed the behaviour of some of the I/O layer functions,
and in some cases the initial seek position when calling file
readers. Switching away from calling readcb etc to i_io_read() etc
should fix your code.
Version 4 added i_psamp() and i_psampf() pointers to the i_img
structure.
Version 5 changed the return types of i_get_file_background() and
i_get_file_backgroundf() from void to int.
*/
#define IMAGER_API_VERSION 5
/*
IMAGER_API_LEVEL is the level of the structure. New function pointers
will always remain at the end (unless IMAGER_API_VERSION changes), and
will result in an increment of IMAGER_API_LEVEL.
*/
#define IMAGER_API_LEVEL 10
typedef struct {
int version;
int level;
/* IMAGER_API_LEVEL 1 functions */
void * (*f_mymalloc)(size_t size);
void (*f_myfree)(void *block);
void * (*f_myrealloc)(void *block, size_t newsize);
void* (*f_mymalloc_file_line)(size_t size, char* file, int line);
void (*f_myfree_file_line)(void *p, char*file, int line);
void* (*f_myrealloc_file_line)(void *p, size_t newsize, char* file,int line);
i_img *(*f_i_img_8_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */
i_img *(*f_i_img_16_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */
i_img *(*f_i_img_double_new)(i_img_dim xsize, i_img_dim ysize, int channels); /* SKIP */
i_img *(*f_i_img_pal_new)(i_img_dim xsize, i_img_dim ysize, int channels, int maxpal); /* SKIP */
void (*f_i_img_destroy)(i_img *im);
i_img *(*f_i_sametype)(i_img *im, i_img_dim xsize, i_img_dim ysize);
i_img *(*f_i_sametype_chans)(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels);
void (*f_i_img_info)(i_img *im, i_img_dim *info);
int (*f_i_ppix)(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
int (*f_i_gpix)(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
int (*f_i_ppixf)(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
int (*f_i_gpixf)(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
i_img_dim (*f_i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
i_img_dim (*f_i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
i_img_dim (*f_i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
i_img_dim (*f_i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
i_img_dim (*f_i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp,
const int *chans, int chan_count);
i_img_dim (*f_i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
const int *chans, int chan_count);
i_img_dim (*f_i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals);
i_img_dim (*f_i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals);
int (*f_i_addcolors)(i_img *im, const i_color *colors, int count);
int (*f_i_getcolors)(i_img *im, int i, i_color *, int count);
int (*f_i_colorcount)(i_img *im);
int (*f_i_maxcolors)(i_img *im);
int (*f_i_findcolor)(i_img *im, const i_color *color, i_palidx *entry);
int (*f_i_setcolors)(i_img *im, int index, const i_color *colors,
int count);
i_fill_t *(*f_i_new_fill_solid)(const i_color *c, int combine);
i_fill_t *(*f_i_new_fill_solidf)(const i_fcolor *c, int combine);
i_fill_t *(*f_i_new_fill_hatch)(const i_color *fg, const i_color *bg, int combine,
int hatch, const unsigned char *cust_hatch,
i_img_dim dx, i_img_dim dy);
i_fill_t *(*f_i_new_fill_hatchf)(const i_fcolor *fg, const i_fcolor *bg, int combine,
int hatch, const unsigned char *cust_hatch,
i_img_dim dx, i_img_dim dy);
i_fill_t *(*f_i_new_fill_image)(i_img *im, const double *matrix, i_img_dim xoff,
i_img_dim yoff, int combine);
i_fill_t *(*f_i_new_fill_fount)(double xa, double ya, double xb, double yb,
i_fountain_type type, i_fountain_repeat repeat,
int combine, int super_sample, double ssample_param,
int count, i_fountain_seg *segs);
void (*f_i_fill_destroy)(i_fill_t *fill);
void (*f_i_quant_makemap)(i_quantize *quant, i_img **imgs, int count);
i_palidx * (*f_i_quant_translate)(i_quantize *quant, i_img *img);
void (*f_i_quant_transparent)(i_quantize *quant, i_palidx *indices,
i_img *img, i_palidx trans_index);
void (*f_i_clear_error)(void); /* SKIP */
void (*f_i_push_error)(int code, char const *msg); /* SKIP */
void (*f_i_push_errorf)(int code, char const *fmt, ...) I_FORMAT_ATTR(2,3);
void (*f_i_push_errorvf)(int code, char const *fmt, va_list); /* SKIP */
void (*f_i_tags_new)(i_img_tags *tags);
int (*f_i_tags_set)(i_img_tags *tags, char const *name, char const *data,
int size);
int (*f_i_tags_setn)(i_img_tags *tags, char const *name, int idata);
void (*f_i_tags_destroy)(i_img_tags *tags);
int (*f_i_tags_find)(i_img_tags *tags, char const *name, int start,
int *entry);
int (*f_i_tags_findn)(i_img_tags *tags, int code, int start, int *entry);
int (*f_i_tags_delete)(i_img_tags *tags, int entry);
int (*f_i_tags_delbyname)(i_img_tags *tags, char const *name);
int (*f_i_tags_delbycode)(i_img_tags *tags, int code);
int (*f_i_tags_get_float)(i_img_tags *tags, char const *name, int code,
double *value);
int (*f_i_tags_set_float)(i_img_tags *tags, char const *name, int code,
double value);
int (*f_i_tags_set_float2)(i_img_tags *tags, char const *name, int code,
double value, int places);
int (*f_i_tags_get_int)(i_img_tags *tags, char const *name, int code,
int *value);
int (*f_i_tags_get_string)(i_img_tags *tags, char const *name, int code,
char *value, size_t value_size);
int (*f_i_tags_get_color)(i_img_tags *tags, char const *name, int code,
i_color *value);
int (*f_i_tags_set_color)(i_img_tags *tags, char const *name, int code,
i_color const *value);
void (*f_i_box)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val);
void (*f_i_box_filled)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val);
void (*f_i_box_cfill)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_fill_t *fill);
void (*f_i_line)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp);
void (*f_i_line_aa)(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp);
void (*f_i_arc)(i_img *im, i_img_dim x, i_img_dim y, double rad, double d1, double d2, const i_color *val);
void (*f_i_arc_aa)(i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val);
void (*f_i_arc_cfill)(i_img *im, i_img_dim x, i_img_dim y, double rad, double d1, double d2, i_fill_t *val);
void (*f_i_arc_aa_cfill)(i_img *im, double x, double y, double rad, double d1, double d2, i_fill_t *fill);
void (*f_i_circle_aa)(i_img *im, double x, double y, double rad, const i_color *val);
int (*f_i_flood_fill)(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol);
int (*f_i_flood_cfill)(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill);
void (*f_i_copyto)(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty);
void (*f_i_copyto_trans)(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty, const i_color *trans);
i_img *(*f_i_copy)(i_img *im);
int (*f_i_rubthru)(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
/* IMAGER_API_LEVEL 2 functions */
int (*f_i_set_image_file_limits)(i_img_dim width, i_img_dim height, size_t bytes); /* SKIP */
int (*f_i_get_image_file_limits)(i_img_dim *width, i_img_dim *height, size_t *bytes); /* SKIP */
int (*f_i_int_check_image_file_limits)(i_img_dim width, i_img_dim height, int channels, size_t sample_size); /* SKIP */
int (*f_i_flood_fill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol, const i_color *border);
int (*f_i_flood_cfill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border);
/* IMAGER_API_LEVEL 3 functions */
void (*f_i_img_setmask)(i_img *im, int ch_mask);
int (*f_i_img_getmask)(i_img *im);
int (*f_i_img_getchannels)(i_img *im);
i_img_dim (*f_i_img_get_width)(i_img *im);
i_img_dim (*f_i_img_get_height)(i_img *im);
void (*f_i_lhead)(const char *file, int line_number);
void (*f_i_loog)(int level, const char *msg, ...) I_FORMAT_ATTR(2,3);
/* IMAGER_API_LEVEL 4 functions will be added here */
i_img *(*f_i_img_alloc)(void); /* SKIP */
void (*f_i_img_init)(i_img *); /* SKIP */
/* IMAGER_API_LEVEL 5 functions will be added here */
/* added i_psampf?_bits macros */
int (*f_i_img_is_monochrome)(i_img *, int *zero_is_white);
int (*f_i_gsamp_bg)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samples,
int out_channels, i_color const * bg);
int (*f_i_gsampf_bg)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samples,
int out_channels, i_fcolor const * bg);
int (*f_i_get_file_background)(i_img *im, i_color *bg);
int (*f_i_get_file_backgroundf)(i_img *im, i_fcolor *bg);
unsigned long (*f_i_utf8_advance)(char const **p, size_t *len);
i_render *(*f_i_render_new)(i_img *im, i_img_dim width);
void (*f_i_render_delete)(i_render *r);
void (*f_i_render_color)(i_render *r, i_img_dim x, i_img_dim y,
i_img_dim width, unsigned char const *src,
i_color const *color);
void (*f_i_render_fill)(i_render *r, i_img_dim x, i_img_dim y,
i_img_dim width, unsigned char const *src,
i_fill_t *fill);
void (*f_i_render_line)(i_render *r, i_img_dim x, i_img_dim y,
i_img_dim width, const i_sample_t *src,
i_color *line, i_fill_combine_f combine);
void (*f_i_render_linef)(i_render *r, i_img_dim x, i_img_dim y,
i_img_dim width, const double *src,
i_fcolor *line, i_fill_combinef_f combine);
/* Level 6 lost to mis-numbering */
/* IMAGER_API_LEVEL 7 */
int (*f_i_io_getc_imp)(io_glue *ig);
int (*f_i_io_peekc_imp)(io_glue *ig);
ssize_t (*f_i_io_peekn)(io_glue *ig, void *buf, size_t size);
int (*f_i_io_putc_imp)(io_glue *ig, int c);
ssize_t (*f_i_io_read)(io_glue *, void *buf, size_t size);
ssize_t (*f_i_io_write)(io_glue *, const void *buf, size_t size);
off_t (*f_i_io_seek)(io_glue *, off_t offset, int whence);
int (*f_i_io_flush)(io_glue *ig);
int (*f_i_io_close)(io_glue *ig);
int (*f_i_io_set_buffered)(io_glue *ig, int buffered);
ssize_t (*f_i_io_gets)(io_glue *ig, char *, size_t, int);
i_io_glue_t *(*f_io_new_fd)(int fd); /* SKIP */
i_io_glue_t *(*f_io_new_bufchain)(void); /* SKIP */
i_io_glue_t *(*f_io_new_buffer)(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata); /* SKIP */
i_io_glue_t *(*f_io_new_cb)(void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb); /* SKIP */
size_t (*f_io_slurp)(i_io_glue_t *ig, unsigned char **c);
void (*f_io_glue_destroy)(i_io_glue_t *ig);
/* IMAGER_API_LEVEL 8 */
i_img *(*f_im_img_8_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
i_img *(*f_im_img_16_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
i_img *(*f_im_img_double_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
i_img *(*f_im_img_pal_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels, int maxpal);
void (*f_im_clear_error)(im_context_t ctx);
void (*f_im_push_error)(im_context_t ctx, int code, char const *msg);
void (*f_im_push_errorvf)(im_context_t ctx, int code, char const *fmt, va_list);
void (*f_im_push_errorf)(im_context_t , int code, char const *fmt, ...) I_FORMAT_ATTR(3,4);
int (*f_im_set_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes);
int (*f_im_get_image_file_limits)(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes);
int (*f_im_int_check_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size);
i_img *(*f_im_img_alloc)(im_context_t ctx);
void (*f_im_img_init)(im_context_t ctx, i_img *);
i_io_glue_t *(*f_im_io_new_fd)(im_context_t ctx, int fd);
i_io_glue_t *(*f_im_io_new_bufchain)(im_context_t ctx);
i_io_glue_t *(*f_im_io_new_buffer)(im_context_t ctx, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata);
i_io_glue_t *(*f_im_io_new_cb)(im_context_t ctx, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb);
im_context_t (*f_im_get_context)(void);
void (*f_im_lhead)( im_context_t, const char *file, int line );
void (*f_im_loog)(im_context_t, int level,const char *msg, ... ) I_FORMAT_ATTR(3,4);
void (*f_im_context_refinc)(im_context_t, const char *where);
void (*f_im_context_refdec)(im_context_t, const char *where);
i_errmsg *(*f_im_errors)(im_context_t);
i_mutex_t (*f_i_mutex_new)(void);
void (*f_i_mutex_destroy)(i_mutex_t m);
void (*f_i_mutex_lock)(i_mutex_t m);
void (*f_i_mutex_unlock)(i_mutex_t m);
im_slot_t (*f_im_context_slot_new)(im_slot_destroy_t);
int (*f_im_context_slot_set)(im_context_t, im_slot_t, void *);
void *(*f_im_context_slot_get)(im_context_t, im_slot_t);
/* IMAGER_API_LEVEL 9 */
int (*f_i_poly_poly_aa)(i_img *im, int count, const i_polygon_t *polys,
i_poly_fill_mode_t mode, const i_color *val);
int (*f_i_poly_poly_aa_cfill)(i_img *im, int count, const i_polygon_t *polys,
i_poly_fill_mode_t mode, i_fill_t *fill);
int (*f_i_poly_aa_m)(i_img *im, int l, const double *x, const double *y,
i_poly_fill_mode_t mode, const i_color *val);
int (*f_i_poly_aa_cfill_m)(i_img *im, int l, const double *x,
const double *y, i_poly_fill_mode_t mode,
i_fill_t *fill);
int (*f_i_img_alpha_channel)(i_img *im, int *channel);
i_color_model_t (*f_i_img_color_model)(i_img *im);
int (*f_i_img_color_channels)(i_img *im);
/* IMAGER_API_LEVEL 10 functions will be added here */
int (*f_im_decode_exif)(i_img *im, const unsigned char *data, size_t length);
/* IMAGER_API_LEVEL 11 functions will be added here */
} im_ext_funcs;
#define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table"
#endif

View File

@@ -0,0 +1,27 @@
#ifndef IMAGER_IMIO_H_
#define IMAGER_IMIO_H_
#include <stdio.h>
#include <sys/stat.h>
#include "imconfig.h"
#include "log.h"
typedef struct i_mempool {
void **p;
unsigned int alloc;
unsigned int used;
} i_mempool;
void i_mempool_init(i_mempool *mp);
void i_mempool_extend(i_mempool *mp);
void *i_mempool_alloc(i_mempool *mp, size_t size);
void i_mempool_destroy(i_mempool *mp);
#ifdef _MSC_VER
#undef min
#undef max
#endif
extern unsigned long i_utf8_advance(char const **p, size_t *len);
#endif

View File

@@ -0,0 +1,154 @@
/*
Imager "functions" implemented as macros
I suppose these could go in imdatatypes, but they aren't types.
*/
#ifndef IMAGER_IMMACROS_H_
#define IMAGER_IMMACROS_H_
/*
=item i_img_has_alpha(C<im>)
=category Image Information
Return true if the image has an alpha channel.
=cut
*/
#define i_img_has_alpha(im) (i_img_alpha_channel((im), NULL))
/*
=item i_psamp(im, left, right, y, samples, channels, channel_count)
=category Drawing
Writes sample values from C<samples> to C<im> for the horizontal line
(left, y) to (right-1, y) inclusive for the channels specified by
C<channels>, an array of C<int> with C<channel_count> elements.
If C<channels> is C<NULL> then the first C<channels_count> channels
are written to for each pixel.
Returns the number of samples written, which should be (right - left)
* channel_count. If a channel not in the image is in channels, left
is negative, left is outside the image or y is outside the image,
returns -1 and pushes an error.
=cut
*/
#define i_psamp(im, l, r, y, samps, chans, count) \
(((im)->i_f_psamp)((im), (l), (r), (y), (samps), (chans), (count)))
/*
=item i_psampf(im, left, right, y, samples, channels, channel_count)
=category Drawing
Writes floating point sample values from C<samples> to C<im> for the
horizontal line (left, y) to (right-1, y) inclusive for the channels
specified by C<channels>, an array of C<int> with C<channel_count>
elements.
If C<channels> is C<NULL> then the first C<channels_count> channels
are written to for each pixel.
Returns the number of samples written, which should be (right - left)
* channel_count. If a channel not in the image is in channels, left
is negative, left is outside the image or y is outside the image,
returns -1 and pushes an error.
=cut
*/
#define i_psampf(im, l, r, y, samps, chans, count) \
(((im)->i_f_psampf)((im), (l), (r), (y), (samps), (chans), (count)))
#ifndef IMAGER_DIRECT_IMAGE_CALLS
#define IMAGER_DIRECT_IMAGE_CALLS 1
#endif
#if IMAGER_DIRECT_IMAGE_CALLS
#define i_ppix(im, x, y, val) (((im)->i_f_ppix)((im), (x), (y), (val)))
#define i_gpix(im, x, y, val) (((im)->i_f_gpix)((im), (x), (y), (val)))
#define i_ppixf(im, x, y, val) (((im)->i_f_ppixf)((im), (x), (y), (val)))
#define i_gpixf(im, x, y, val) (((im)->i_f_gpixf)((im), (x), (y), (val)))
#define i_plin(im, l, r, y, val) (((im)->i_f_plin)(im, l, r, y, val))
#define i_glin(im, l, r, y, val) (((im)->i_f_glin)(im, l, r, y, val))
#define i_plinf(im, l, r, y, val) (((im)->i_f_plinf)(im, l, r, y, val))
#define i_glinf(im, l, r, y, val) (((im)->i_f_glinf)(im, l, r, y, val))
#define i_gsamp(im, l, r, y, samps, chans, count) \
(((im)->i_f_gsamp)((im), (l), (r), (y), (samps), (chans), (count)))
#define i_gsampf(im, l, r, y, samps, chans, count) \
(((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count)))
#endif
#define i_gsamp_bits(im, l, r, y, samps, chans, count, bits) \
(((im)->i_f_gsamp_bits) ? ((im)->i_f_gsamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
#define i_psamp_bits(im, l, r, y, samps, chans, count, bits) \
(((im)->i_f_psamp_bits) ? ((im)->i_f_psamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
#define i_findcolor(im, color, entry) \
(((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
#define i_gpal(im, l, r, y, vals) \
(((im)->i_f_gpal) ? ((im)->i_f_gpal)((im), (l), (r), (y), (vals)) : 0)
#define i_ppal(im, l, r, y, vals) \
(((im)->i_f_ppal) ? ((im)->i_f_ppal)((im), (l), (r), (y), (vals)) : 0)
#define i_addcolors(im, colors, count) \
(((im)->i_f_addcolors) ? ((im)->i_f_addcolors)((im), (colors), (count)) : -1)
#define i_getcolors(im, index, color, count) \
(((im)->i_f_getcolors) ? \
((im)->i_f_getcolors)((im), (index), (color), (count)) : 0)
#define i_setcolors(im, index, color, count) \
(((im)->i_f_setcolors) ? \
((im)->i_f_setcolors)((im), (index), (color), (count)) : 0)
#define i_colorcount(im) \
(((im)->i_f_colorcount) ? ((im)->i_f_colorcount)(im) : -1)
#define i_maxcolors(im) \
(((im)->i_f_maxcolors) ? ((im)->i_f_maxcolors)(im) : -1)
#define i_findcolor(im, color, entry) \
(((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
#define i_img_virtual(im) ((im)->virtual)
#define i_img_type(im) ((im)->type)
#define i_img_bits(im) ((im)->bits)
#define pIMCTX im_context_t my_im_ctx
#ifdef IMAGER_NO_CONTEXT
#define dIMCTXctx(ctx) pIMCTX = (ctx)
#define dIMCTX dIMCTXctx(im_get_context())
#define dIMCTXim(im) dIMCTXctx((im)->context)
#define dIMCTXio(io) dIMCTXctx((io)->context)
#define aIMCTX my_im_ctx
#else
#define aIMCTX im_get_context()
#endif
#define i_img_8_new(xsize, ysize, channels) im_img_8_new(aIMCTX, (xsize), (ysize), (channels))
#define i_img_16_new(xsize, ysize, channels) im_img_16_new(aIMCTX, (xsize), (ysize), (channels))
#define i_img_double_new(xsize, ysize, channels) im_img_double_new(aIMCTX, (xsize), (ysize), (channels))
#define i_img_pal_new(xsize, ysize, channels, maxpal) im_img_pal_new(aIMCTX, (xsize), (ysize), (channels), (maxpal))
#define i_img_alloc() im_img_alloc(aIMCTX)
#define i_img_init(im) im_img_init(aIMCTX, im)
#define i_set_image_file_limits(width, height, bytes) im_set_image_file_limits(aIMCTX, width, height, bytes)
#define i_get_image_file_limits(width, height, bytes) im_get_image_file_limits(aIMCTX, width, height, bytes)
#define i_int_check_image_file_limits(width, height, channels, sample_size) im_int_check_image_file_limits(aIMCTX, width, height, channels, sample_size)
#define i_clear_error() im_clear_error(aIMCTX)
#define i_push_errorvf(code, fmt, args) im_push_errorvf(aIMCTX, code, fmt, args)
#define i_push_error(code, msg) im_push_error(aIMCTX, code, msg)
#define i_errors() im_errors(aIMCTX)
#define io_new_fd(fd) im_io_new_fd(aIMCTX, (fd))
#define io_new_bufchain() im_io_new_bufchain(aIMCTX)
#define io_new_buffer(data, len, closecb, closectx) im_io_new_buffer(aIMCTX, (data), (len), (closecb), (closectx))
#define io_new_cb(p, readcb, writecb, seekcb, closecb, destroycb) \
im_io_new_cb(aIMCTX, (p), (readcb), (writecb), (seekcb), (closecb), (destroycb))
#endif

View File

@@ -0,0 +1,31 @@
/*
This header file defines types that Imager's typemap uses to convert to
perl types.
This is meant for use in XS code, not in normal C source.
*/
#ifndef IMAGER_IMPERL_H
#define IMAGER_IMPERL_H
#include "imdatatypes.h"
typedef i_color* Imager__Color;
typedef i_fcolor* Imager__Color__Float;
typedef i_img* Imager__ImgRaw;
typedef int undef_neg_int;
typedef i_img * Imager;
#ifdef HAVE_LIBTT
typedef TT_Fonthandle* Imager__Font__TT;
#endif
/* for the fill objects
Since a fill object may later have dependent images, (or fills!)
we need perl wrappers - oh well
*/
#define IFILL_DESTROY(fill) i_fill_destroy(fill);
typedef i_fill_t* Imager__FillHandle;
typedef io_glue *Imager__IO;
#endif

View File

@@ -0,0 +1,7 @@
#ifndef IMAGER_IMPERLIO_H
#define IMAGER_IMPERLIO_H
extern i_io_glue_t *
im_io_new_perlio(pTHX_ PerlIO *handle);
#endif

View File

@@ -0,0 +1,28 @@
#ifndef IMAGER_IMRENDER_H
#define IMAGER_IMRENDER_H
#include "rendert.h"
extern void
i_render_init(i_render *r, i_img *im, i_img_dim width);
extern void
i_render_done(i_render *r);
extern void
i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
unsigned char const *src, i_color const *color);
extern void
i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
unsigned char const *src, i_fill_t *fill);
extern void
i_render_line(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
const i_sample_t *src, i_color *line, i_fill_combine_f combine);
extern void
i_render_linef(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
const double *src, i_fcolor *line, i_fill_combinef_f combine);
extern i_render *
i_render_new(i_img *im, i_img_dim width);
extern void
i_render_delete(i_render *r);
#endif

View File

@@ -0,0 +1,47 @@
#ifndef _IOLAYER_H_
#define _IOLAYER_H_
/* How the IO layer works:
*
* Start by getting an io_glue object by calling the appropriate
* io_new...() function. After that data can be read via the
* io_glue->readcb() method.
*
*/
#include "iolayert.h"
/* #define BBSIZ 1096 */
#define BBSIZ 16384
#define IO_FAKE_SEEK 1<<0L
#define IO_TEMP_SEEK 1<<1L
void io_glue_gettypes (io_glue *ig, int reqmeth);
/* XS functions */
io_glue *im_io_new_fd(pIMCTX, int fd);
io_glue *im_io_new_bufchain(pIMCTX);
io_glue *im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata);
io_glue *im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb);
size_t io_slurp(io_glue *ig, unsigned char **c);
void io_glue_destroy(io_glue *ig);
void i_io_dump(io_glue *ig, int flags);
/* Buffered I/O */
extern int i_io_getc_imp(io_glue *ig);
extern int i_io_peekc_imp(io_glue *ig);
extern ssize_t i_io_peekn(io_glue *ig, void *buf, size_t size);
extern int i_io_putc_imp(io_glue *ig, int c);
extern ssize_t i_io_read(io_glue *ig, void *buf, size_t size);
extern ssize_t i_io_write(io_glue *ig, const void *buf, size_t size);
extern off_t i_io_seek(io_glue *ig, off_t offset, int whence);
extern int i_io_flush(io_glue *ig);
extern int i_io_close(io_glue *ig);
extern int i_io_set_buffered(io_glue *ig, int buffered);
extern ssize_t i_io_gets(io_glue *ig, char *, size_t, int);
#endif /* _IOLAYER_H_ */

View File

@@ -0,0 +1,110 @@
#ifndef IMAGER_IOLAYERT_H
#define IMAGER_IOLAYERT_H
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
typedef enum { FDSEEK, FDNOSEEK, BUFFER, CBSEEK, CBNOSEEK, BUFCHAIN } io_type;
#ifdef _MSC_VER
typedef int ssize_t;
#endif
typedef struct i_io_glue_t i_io_glue_t;
/* compatibility for now */
typedef i_io_glue_t io_glue;
/* Callbacks we give out */
typedef ssize_t(*i_io_readp_t) (io_glue *ig, void *buf, size_t count);
typedef ssize_t(*i_io_writep_t)(io_glue *ig, const void *buf, size_t count);
typedef off_t (*i_io_seekp_t) (io_glue *ig, off_t offset, int whence);
typedef int (*i_io_closep_t)(io_glue *ig);
typedef ssize_t(*i_io_sizep_t) (io_glue *ig);
typedef void (*i_io_closebufp_t)(void *p);
typedef void (*i_io_destroyp_t)(i_io_glue_t *ig);
/* Callbacks we get */
typedef ssize_t(*i_io_readl_t) (void *p, void *buf, size_t count);
typedef ssize_t(*i_io_writel_t)(void *p, const void *buf, size_t count);
typedef off_t (*i_io_seekl_t) (void *p, off_t offset, int whence);
typedef int (*i_io_closel_t)(void *p);
typedef void (*i_io_destroyl_t)(void *p);
typedef ssize_t(*i_io_sizel_t) (void *p);
extern char *io_type_names[];
/* Structures to describe data sources */
struct i_io_glue_t {
io_type type;
void *exdata;
i_io_readp_t readcb;
i_io_writep_t writecb;
i_io_seekp_t seekcb;
i_io_closep_t closecb;
i_io_sizep_t sizecb;
i_io_destroyp_t destroycb;
unsigned char *buffer;
unsigned char *read_ptr;
unsigned char *read_end;
unsigned char *write_ptr;
unsigned char *write_end;
size_t buf_size;
/* non-zero if we encountered EOF */
int buf_eof;
/* non-zero if we've seen an error */
int error;
/* if non-zero we do write buffering (enabled by default) */
int buffered;
im_context_t context;
};
#define I_IO_DUMP_CALLBACKS 1
#define I_IO_DUMP_BUFFER 2
#define I_IO_DUMP_STATUS 4
#define I_IO_DUMP_DEFAULT (I_IO_DUMP_BUFFER | I_IO_DUMP_STATUS)
#define i_io_type(ig) ((ig)->source.ig_type)
#define i_io_raw_read(ig, buf, size) ((ig)->readcb((ig), (buf), (size)))
#define i_io_raw_write(ig, data, size) ((ig)->writecb((ig), (data), (size)))
#define i_io_raw_seek(ig, offset, whence) ((ig)->seekcb((ig), (offset), (whence)))
#define i_io_raw_close(ig) ((ig)->closecb(ig))
#define i_io_is_buffered(ig) ((int)((ig)->buffered))
#define i_io_getc(ig) \
((ig)->read_ptr < (ig)->read_end ? \
*((ig)->read_ptr++) : \
i_io_getc_imp(ig))
#define i_io_nextc(ig) \
((void)((ig)->read_ptr < (ig)->read_end ? \
((ig)->read_ptr++, 0) : \
i_io_getc_imp(ig)))
#define i_io_peekc(ig) \
((ig)->read_ptr < (ig)->read_end ? \
*((ig)->read_ptr) : \
i_io_peekc_imp(ig))
#define i_io_putc(ig, c) \
((ig)->write_ptr < (ig)->write_end && !(ig)->error ? \
*(ig)->write_ptr++ = (c) : \
i_io_putc_imp(ig, (c)))
#define i_io_eof(ig) \
((ig)->read_ptr == (ig)->read_end && (ig)->buf_eof)
#define i_io_error(ig) \
((ig)->read_ptr == (ig)->read_end && (ig)->error)
#endif

View File

@@ -0,0 +1,56 @@
#ifndef _LOG_H_
#define _LOG_H_
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include "imdatatypes.h"
/*
input: name of file to log too
input: onoff, 0 means no logging
global: creates a global variable FILE* lg_file
*/
int im_init_log(pIMCTX, const char *name, int onoff );
#define i_init_log(name, onoff) im_init_log(aIMCTX, name, onoff)
#ifndef IMAGER_NO_CONTEXT
void i_fatal ( int exitcode,const char *fmt, ... );
#endif
void im_fatal (pIMCTX, int exitcode,const char *fmt, ... );
void im_lhead ( pIMCTX, const char *file, int line );
void i_lhead ( const char *file, int line );
void i_loog(int level,const char *msg, ... ) I_FORMAT_ATTR(2,3);
void im_loog(pIMCTX, int level,const char *msg, ... ) I_FORMAT_ATTR(3,4);
/*
=item im_log((aIMCTX, level, format, ...))
=category Logging
This is the main entry point to logging. Note that the extra set of
parentheses are required due to limitations in C89 macros.
This will format a string with the current file and line number to the
log file if logging is enabled.
This must be called with a context object defined by one of the
C<dIMCTX> macros in scope.
This can also be called as C<mm_log((level, format, args))> in which
case the currently active context is used and any in scope context is
ignored.
=cut
*/
#ifdef IMAGER_LOG
#ifndef IMAGER_NO_CONTEXT
#define mm_log(x) { i_lhead(__FILE__,__LINE__); i_loog x; }
#endif
#define im_log(x) { im_lhead(aIMCTX, __FILE__,__LINE__); im_loog x; }
#else
#define mm_log(x)
#define im_log(x)
#endif
#endif /* _LOG_H_ */

View File

@@ -0,0 +1,42 @@
#include "imdatatypes.h"
#include "immacros.h"
/* structures for passing data between Imager-plugin and the Imager-module */
#include "ext.h"
#define getINT(k,s) (util_table->getint(INP,k,s))
#define getDOUBLE(k,s) (util_table->getdouble(INP,k,s))
#define getVOID(k,s) (util_table->getvoid(INP,k,(void**)s))
#define getSTR(k,s) (util_table->getstr(INP,k,(char**)s))
#define getOBJ(k,t,s) (util_table->getobj(INP,k,t,(void**)s))
#define i_color_set(cl,r,g,b,a) (symbol_table->i_color_set(cl,r,g,b,a))
#define i_color_info(cl) (symbol_table->i_color_info(cl))
#define im_get_context() (symbol_table->im_get_context_f())
#define i_img_empty_ch(im,x,y,ch) ((symbol_table->i_img_empty_ch_f(im_get_context(), im,x,y,ch))
#define i_img_exorcise(im) (symbol_table->i_img_exorcise_f(im))
#define i_img_info(im,info) (symbol_table->i_img_info_f(im,info))
#define i_img_setmask(im,ch_mask) (symbol_table->i_img_setmask_f(im,ch_mask))
#define i_img_getmask(im) (symbol_table->i_img_getmask_f(im))
/*
Not needed? The i_gpix() macro in image.h will call the right function
directly.
#define i_ppix(im,x,y,val) (symbol_table->i_ppix(im,x,y,val))
#define i_gpix(im,x,y,val) (symbol_table->i_gpix(im,x,y,val))
*/
#define i_box(im, x1, y1, x2, y2,val) (symbol_table->i_box(im, x1, y1, x2, y2,val))
#define i_draw(im, x1, y1, x2, y2,val) (symbol_table->i_draw(im, x1, y1, x2, y2,val))
#define i_arc(im, x, y, rad, d1, d2,val) (symbol_table->i_arc(im, x, y, rad, d1, d2,val))
#define i_copyto(im,src, x1, y1, x2, y2, tx, ty,trans) (symbol_table->i_copyto(im,src, x1, y1, x2, y2, tx, ty,trans))
#define i_rubthru(im,src, tx, ty) (symbol_table->i_rubthru(im,src, tx, ty))
#ifdef WIN32
extern char __declspec(dllexport) evalstr[];
extern func_ptr __declspec(dllexport) function_list[];
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
#ifndef _REGMACH_H_
#define _REGMACH_H_
#include <stdio.h>
#include <math.h>
#include "imager.h"
enum rm_byte_codes {
rbc_add, /* ra + rb -> r*/
rbc_subtract, /* ra - rb -> r */
rbc_mult, /* ra * rb -> r */
rbc_div, /* ra / rb -> r */
rbc_mod, /* ra % rb -> r */
rbc_pow, /* ra ** rb -> r */
rbc_uminus, /* -ra -> r */
rbc_multp, /* pa ** rb -> p */
rbc_addp, /* pa + pb -> p */
rbc_subtractp, /* pa - pb -> p */
/* rbcParm, we just preload a register */
rbc_sin, /* sin(ra) -> r */
rbc_cos, /* cos(ra) -> r */
rbc_atan2, /* atan2(ra,rb) -> r */
rbc_sqrt, /* sqrt(ra) -> r */
rbc_distance, /* distance(rx, ry, rx, ry) -> r */
/* getp? codes must be in order */
rbc_getp1, /* getp1(ra, rb) -> p */
rbc_getp2, /* getp2(ra, rb) -> p */
rbc_getp3, /* getp3(ra, rb) -> p */
rbc_value, /* value(pa) -> r */
rbc_hue, /* hue(pa) -> r */
rbc_sat, /* sat(pa) -> r */
rbc_hsv, /* hsv(rh, rs, rv) -> p */
rbc_red, /* red(pa) -> r */
rbc_green, /* green(pa) -> r */
rbc_blue, /* blue(pa) -> r */
rbc_rgb, /* rgb(rr, rg, rb) -> p */
rbc_int, /* int(ra) -> r */
rbc_if, /* if(rc, rt, rf) -> r */
rbc_ifp, /* if(rc, pt, pf) -> p */
rbc_le, /* ra <= rb -> r */
rbc_lt, /* ra < rb -> r */
rbc_ge, /* ra >= rb -> r */
rbc_gt, /* ra > rb -> r */
rbc_eq, /* ra == rb -> r -- does approx equal */
rbc_ne, /* ra != rb -> r -- does approx equal */
rbc_and, /* ra && rb -> r */
rbc_or, /* ra || rb -> r */
rbc_not, /* !ra -> r */
rbc_abs, /* abs(ra) -> r */
rbc_ret, /* returns pa */
rbc_jump, /* jump to ja */
rbc_jumpz, /* jump if ra == 0 to jb */
rbc_jumpnz, /* jump if ra != 0 to jb */
rbc_set, /* ra -> r */
rbc_setp, /* pa -> p*/
rbc_print, /* print(ra) -> r -- prints, leaves on stack */
rbc_rgba, /* rgba(ra, rb, rc, rd) -> p */
rbc_hsva, /* hsva(ra, rb, rc, rd) -> p */
rbc_alpha, /* alpha(pa) -> r */
rbc_log, /* log(ra) -> r */
rbc_exp, /* exp(ra) -> r */
rbc_det, /* det(ra, rb, rc, rd) -> r */
rbc_op_count
};
/* rm_word was originally char, but even for some simpler expressions
I was getting close to running out of register numbers.
It should also simplify structure alignment issues. (I hope.)
*/
typedef int rm_word;
#define RM_WORD_PACK "i"
struct rm_op {
rm_word code; /* op code */
rm_word ra; /* first operand */
rm_word rb; /* possible second operand */
rm_word rc; /* possible third operand */
rm_word rd; /* possible fourth operand */
rm_word rout; /* output register */
};
i_color i_rm_run(struct rm_op codes[], size_t code_count,
double n_regs[], size_t n_regs_count,
i_color c_regs[], size_t c_regs_count,
i_img *images[], size_t image_count);
/* op_run(fx, sizeof(fx), parms, 2)) */
#endif /* _REGMACH_H_ */

View File

@@ -0,0 +1,19 @@
#ifndef IMAGER_RENDERT_H
#define IMAGER_RENDERT_H
#include "imdatatypes.h"
struct i_render_tag {
int magic;
i_img *im;
i_img_dim line_width;
i_color *line_8;
i_fcolor *line_double;
i_img_dim fill_width;
i_color *fill_line_8;
i_fcolor *fill_line_double;
};
#endif

View File

@@ -0,0 +1,25 @@
#ifndef _STACKMACH_H_
#define _STACKMACH_H_
#include <stdio.h>
#include <math.h>
enum ByteCodes {
bcAdd,
bcSubtract,
bcMult,
bcDiv,
bcParm,
bcSin,
bcCos
};
double i_op_run(int codes[], size_t code_size, double parms[], size_t parm_size);
/* op_run(fx, sizeof(fx), parms, 2)) */
#endif /* _STACKMACH_H_ */

View File

@@ -0,0 +1,352 @@
=head1 NAME
Imager::interface.pod - describes the C level virtual image interface
=head1 SYNOPSIS
=head1 DESCRIPTION
The Imager virtual interface aims to allow image types to be created
for special purposes, both to allow consistent access to images with
different sample sizes, and organizations, but also to allow creation
of synthesized or virtual images.
This is a C level interface rather than Perl.
=head2 Existing Images
As of this writing we have the following concrete image types:
=over
=item *
8-bit/sample direct images
=item *
16-bit/sample direct images
=item *
double/sample direct images
=item *
8-bit/sample 8-bit/index paletted images
=back
Currently there is only one virtual image type:
=over
=item *
masked images, where a mask image can control write access to an
underlying image.
=back
Other possible concrete images include:
=over
=item *
"bitmaps", 1 bit/sample images (perhaps limited to a single channel)
=item *
16-bit/index paletted images
=back
Some other possible virtual images:
=for stopwords GIMP Photoshop
=over
=item *
image alpha combining, where the combining function can be specified
(see the layer modes in graphical editors like the GIMP or Photoshop.
=back
=head1 THE INTERFACE
Each image type needs to define a number of functions which implement
the image operations.
The image structure includes information describes the image, which
can be used to determine the structure of the image:
=over
=item *
C<channels> - the number of samples kept for each pixel in the image.
For paletted images the samples are kept for each entry in the
palette.
=item *
C<xsize>, C<ysize> - the dimensions of the image in pixels.
=item *
C<bytes> - the number of bytes of data kept for the image. Zero for
virtual images. Does not include the space required for the palette
for paletted images.
=item *
C<ch_mask> - controls which samples will be written to for direct
images.
=item *
C<bits> - the number of bits kept for each sample. There are enum
values i_8_bits, i_16_bits and i_double_bits (64).
=item *
C<type> - the type of image, either i_direct_type or i_palette_type.
Direct images keep the samples for every pixel image, while
i_palette_type images keep an index into a color table for each pixel.
=item *
C<virtual> - whether the image keeps any pixel data. If this is
non-zero then C<idata> points to image data, otherwise it points to
implementation defined data, though C<ext_data> is more likely to be
used for that.
=item *
C<idata> - image data. If the image is 8-bit direct, non-virtual,
then this consists of each sample of the image stored one after
another, otherwise it is implementation defined.
=item *
C<tags> - will be used to store meta-data for an image, eg. tags from
a TIFF file, or animation information from a GIF file. This should be
initialized with a call to i_tags_new() in your image constructor if
creating a new image type.
=item *
C<ext_data> - for internal use of image types. This is not released
by the standard i_img_exorcise() function. If you create a new image
type and want to store a pointer to allocated memory here you should
point i_f_destroy at a function that will release the data.
=back
If a caller has no knowledge of the internal format of an image, the
caller must call the appropriate image function pointer. Imager
provides macros that wrap these functions, so it isn't necessary to
call them directly.
Many functions have a similar function with an 'f' suffix, these take
or return samples specified with floating point values rather than
8-bit integers (unsigned char). Floating point samples are returned
in the range 0 to 1 inclusive.
=over
=item i_f_ppix(im,x,y,color)
=item i_f_ppixf(im,x,y,fcolor)
stores the specified color at pixel (x,y) in the image. If the pixel
can be stored return 0, otherwise -1. An image type may choose to
return 0 under some circumstances, eg. writing to a masked area of an
image. The C<color> or C<fcolor> always contains the actual samples to be
written, rather than a palette index.
=item i_f_plin(im,l,r,y,colors)
=item i_f_plinf(im,l,r,y,fcolors)
stores (r-l) pixels at positions (l,y) ... (r-1, y) from the array
specified by C<colors> (or C<fcolors>). Returns the number of pixels
written to. If l is negative it will return 0. If C<< r > im->xsize
>> then only C<< (im->xsize - l) >> will be written.
=item i_f_gpix(im,x,y,color)
=item i_f_gpixf(im,x,y,fcolor)
retrieves a single pixel from position (x,y). This returns the
samples rather than the index for paletted images.
=item i_f_glin(im,l,r,y,colors)
=item i_f_glinf(im,l,r,y,fcolors)
retrieves (r-l) pixels from positions (l, y) through (r-1, y) into the
array specified by colors. Returns the number of pixels retrieved.
If l < 0 no pixels are retrieved. If C<< r > im->xsize >> then pixels
C<< (l, y) >> ... C<< (im->xsize-1, y) >> are retrieved. Retrieves
the samples rather than the color indexes for paletted images.
=item i_f_gsamp(im,l,r,y,samples,chans,chan_count)
=item i_f_gsampf(im,l,r,y,fsamples,chans,chan_count)
Retrieves samples from channels specified by C<chans> (for length
C<chan_count>) from pixels at positions (l,y) ... (r-1, y). If
C<chans> is NULL then samples from channels 0 ... C<chan_count-1> will
be retrieved. Returns the number of sample retrieved (I<not> the
number of channels). If a channel in C<chans> is not present in the
image or l < 0, returns 0. If C<< r > im->xsize >>, then the samples
from C<(l,y)> ... C<< (im->xsize-1, y) >> are returned.
=back
The following are for images where type == i_palette_type only.
=over
=item i_f_gpal(im,l,r,y,vals)
Retrieves color indexes from the image for pixels (l, y) ... (r-1, y)
into C<vals>. Returns the number of indexes retrieved.
=item i_f_ppal(im,l,r,y,vals)
Stores color indexes into the image for pixels (l, y) ... (r-1, y)
from C<vals>. Returns the number of indexes retrieved. If indexes are
outside the range of the images palette, then you may have problems
reading those pixels with i_gpix() or i_glin().
=item i_f_addcolors(im,colors,count)
Adds the count colors to the image's palette. Returns the index of
the first color added, or -1 if there is not enough space for count
colors.
=item i_f_getcolors(im,index,colors,count)
Retrieves count colors from the image's palette starting from entry
index in the palette. Returns non-zero on success.
=item i_f_colorcount(im)
Returns the number of colors in the image's palette. Returns -1 if
this is not a paletted image.
=item i_f_maxcolors(im)
Returns the maximum number of colors that can fit in the image's
palette. Returns -1 if this is not a paletted image.
=item i_f_findcolor(im,color,entry)
Searches the image's palette for the specified color, setting *entry
to the index and returning non-zero. Returns zero if the color is not
found.
=item i_f_setcolors_t(im,index,colors,count)
Sets count colors starting from index in the image from the array
colors. The colors to be set must already have entries in the image's
palette. Returns non-zero on success.
=back
Finally, the i_f_destroy function pointer can be set which is called
when the image is destroyed. This can be used to release memory
pointed to by ext_data or release any other resources.
When writing to a paletted image with i_ppix() or i_plin() and the
color you are writing doesn't exist in the image, then it's possible
that the image will be internally converted to a direct image with the
same number of channels.
=head1 TOOLS
Several functions have been written to simplify creating new image types.
These tools are available by including F<imagei.h>.
=head2 Floating point wrappers
These functions implement the floating point sample versions of each
interface function in terms of the integer sample version.
These are:
=over
=item i_ppixf_fp
=item i_gpixf_fp
=item i_plinf_fp
=item i_glinf_fp
=item i_gsampf_fp
=back
=head2 Forwarding functions
These functions are used in virtual images where the call should
simply be forwarded to the underlying image. The underlying image is
assumed to be the first pointer in a structure pointed at by ext_data.
If this is not the case then these functions will just crash :)
=over
=item i_addcolors_forward
=item i_getcolors_forward
=item i_colorcount_forward
=item i_maxcolors_forward
=item i_findcolor_forward
=item i_setcolors_forward
=back
=head2 Sample macros
C<imagei.h> defines several macros for converting samples between
different sizes.
Each macro is of the form C<Sample>I<size>C<To>I<size> where I<size> is one
of 8, 16, or F (for floating-point samples).
=over
=item SampleFTo16(sample)
=item Sample16ToF(sample)
=item SampleFTo8(sample)
=item Sample8ToF(sample)
=item Sample16To8(num)
=item Sample8To16(num)
=back
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

View File

@@ -0,0 +1,107 @@
=head1 NAME
Imager::regmach - documents the register virtual machine used by
Imager::transform2().
=head1 SYNOPSIS
The register machine is a complete rewrite of the stack machine
originally used by Imager::transform(), written for use by
Imager::transform2().
=head1 DESCRIPTION
(This document might be a little incoherent.)
The register machine is a fast implementation of a small instruction
set designed for evaluating an arithmetic expression to produce a
color for an image.
The machine takes as input:
=over 4
=item instructions
An array of instructions
=item numeric registers
An array of numeric registers. Some registers are initialized as
literals.
=item color registers
An array of color registers. Currently these registers aren't
initialized.
=item input images
An array of Imager i_img pointers. The C<getpn> operators read pixels
from these images.
=back
The instructions supplied each take up to 4 input numeric or color
registers with a single output numeric or color register. The
machine attempts to execute instructions as safely as possible,
assuming that correct instructions have been provided, eg. the machine
protects against divide by zero, but doesn't check register numbers
for validity.
The final instruction must be a C<ret> instruction, which returns the
result ;)
=head2 Adding new instructions
To add a new instruction:
=over 4
=item 1
Add a new opcode to the enumeration in F<regmach.h> - make sure to add
comment after the enum name giving the input registers (C<rX> for
numeric, C<pX> for color) that the instruction takes. These must be in
the order that the instruction expects to take the. Put a letter (r
or p) after -> to indicate the result type.
=item 2
Add a case to F<regmach.c> that executes the instruction.
=item 3
make
=back
The F<Makefile> should rebuild the F<Regops.pm> file, and your new
instruction will be added as a function.
If you want to add a single alternative instruction that might take
different argument types (it must take the same number of parameters),
create another instruction with that name followed by a p. The
current expression parsers explicitly look for such instruction names.
=head2 Future directions
Conditional and non-conditional jumps to implement iteration. This
will break the current optimizer in L<Imager::Expr> (and the compilers
for both expression compilers, for that matter.)
Complex arithmetic (Addi suggested this one). This would most likely
be a separate machine. Otherwise we'll have a very significant
performance loss.
=head1 WARNINGS
If you feed bad 'machine code' to the register machine, you have a
good chance of a C<SIGSEGV>.
=head1 AUTHOR
Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson
=cut

139
database/perl/vendor/lib/Imager/typemap vendored Normal file
View File

@@ -0,0 +1,139 @@
#i_img * T_PTR_NULL
Imager::Color T_PTROBJ
Imager::Color::Float T_PTROBJ
Imager::ImgRaw T_IMAGER_IMAGE
Imager::Font::TT T_PTROBJ
Imager::IO T_PTROBJ
Imager::FillHandle T_PTROBJ
const char * T_PV
im_float T_FLOAT
float* T_ARRAY
undef_int T_IV_U
undef_neg_int T_IV_NEGU
HASH T_HVREF
utf8_str T_UTF8_STR
i_img_dim T_IV_checked
im_double T_NV_checked
# these types are for use by Inline, which can't handle types containing ::
Imager__Color T_PTROBJ_INV
Imager__Color__Float T_PTROBJ_INV
Imager__ImgRaw T_IMAGER_IMAGE
Imager__FillHandle T_PTROBJ_INV
Imager__IO T_PTROBJ_INV
# mostly intended for non-Imager-core use
Imager T_IMAGER_FULL_IMAGE
#############################################################################
INPUT
T_PTR_NULL
if (SvOK($arg)) $var = INT2PTR($type,SvIV($arg));
else $var = NULL
# handles Imager objects rather than just raw objects
T_IMAGER_IMAGE
if (sv_derived_from($arg, \"Imager::ImgRaw\")) {
IV tmp = SvIV((SV*)SvRV($arg));
$var = INT2PTR($type,tmp);
}
else if (sv_derived_from($arg, \"Imager\") &&
SvTYPE(SvRV($arg)) == SVt_PVHV) {
HV *hv = (HV *)SvRV($arg);
SV **sv = hv_fetch(hv, \"IMG\", 3, 0);
if (sv && *sv && sv_derived_from(*sv, \"Imager::ImgRaw\")) {
IV tmp = SvIV((SV*)SvRV(*sv));
$var = INT2PTR($type,tmp);
}
else
Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\");
}
else
Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\");
T_IMAGER_FULL_IMAGE
if (sv_derived_from($arg, \"Imager\") &&
SvTYPE(SvRV($arg)) == SVt_PVHV) {
HV *hv = (HV *)SvRV($arg);
SV **sv = hv_fetch(hv, \"IMG\", 3, 0);
if (sv && *sv && sv_derived_from(*sv, \"Imager::ImgRaw\")) {
IV tmp = SvIV((SV*)SvRV(*sv));
$var = INT2PTR($type,tmp);
}
else
Perl_croak(aTHX_ \"$var is not of type Imager::ImgRaw\");
}
else
Perl_croak(aTHX_ \"$var is not of type Imager\");
# same as T_PTROBJ, but replace __ with ::, the opposite of the way
# xsubpp's processing works
# this is to compensate for Inline's problem with type names containing ::
T_PTROBJ_INV
if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\")) {
IV tmp = SvIV((SV*)SvRV($arg));
$var = INT2PTR($type,tmp);
}
else
croak(\"$var is not of type ${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\");
T_NV_checked
{
SvGETMAGIC($arg);
if (SvROK($arg) && !SvAMAGIC($arg)) {
croak(\"Numeric argument '$var' shouldn't be a reference\");
}
else {
$var = ($type)SvNV($arg);
}
}
T_IV_checked
{
SvGETMAGIC($arg);
if (SvROK($arg) && !SvAMAGIC($arg)) {
croak(\"Numeric argument '$var' shouldn't be a reference\");
}
else {
$var = ($type)SvIV($arg);
}
}
#############################################################################
OUTPUT
T_IV_U
if ($var == 0) $arg=&PL_sv_undef;
else sv_setiv($arg, (IV)$var);
T_IV_NEGU
if ($var < 0) $arg=&PL_sv_undef;
else sv_setiv($arg, (IV)$var);
T_PTR_NULL
sv_setiv($arg, (IV)$var);
# same as T_PTROBJ
T_IMAGER_IMAGE
sv_setref_pv($arg, \"Imager::ImgRaw\", (void*)$var);
T_PTROBJ_INV
sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\", (void*)$var);
# ugh, the things we do for ease of use
# this isn't suitable in some cases
T_IMAGER_FULL_IMAGE
if ($var) {
SV *imobj = NEWSV(0, 0);
HV *hv = newHV();
sv_setref_pv(imobj, \"Imager::ImgRaw\", $var);
hv_store(hv, "IMG", 3, imobj, 0);
$arg = sv_2mortal(sv_bless(newRV_noinc((SV*)hv), gv_stashpv("Imager", 1)));
}
else {
$arg = &PL_sv_undef;
}
T_IV_checked
sv_setiv($arg, (IV)$var);
T_NV_checked
sv_setnv($arg, (NV)$var);