From 92bda6321b472bb18726d950da8833b950abf4ee Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 10 Jan 2006 03:09:58 +0000 Subject: [PATCH] - start of external Imager API access: - rename headers to avoid conflicts: - image.h to imager.h - imagei.h to imageri.h - datatypes.h to imdatatypes.h - config.h to imconfig.h (created by Makefile.PL) - moved all public types defined in imager.h to imdatatypes.h - supply the PM parameter to WriteMakefile(), to install headers under Imager/include, and the Imager typemap in Imager/typemap. We scan the MANIFEST for files to add to PM. - add "i_" prefix on some functions useful as public at the C level. - moved the typedefs that support the typemap from Imager.xs to imperl.h - set the global callbacks hook in the Imager.xs BOOT section - API cleanup: - define i_tags_set(), i_tags_setn() - we might not allow multiple values for a tag in the future - i_copy() now returns a new image instead of doing horrible inplace things to an existing image - provide actual functions for all of the macros we define in imager.h so we can put them in the global callbacks structure - define global functions structure (imexttypes.h) and initialize it (imext.c) - add API include header with macros to setup the define and initialize the local callbacks pointer, and macros to call the API functions. - build Imager::APIRef from C sources, including updating the sources to include documentation for each API function. - convert dyntest and mandelbrot dynfilts into XS modules (too easy) - simple Imager::CountColor example - support Inline::C : - typemap changes to accept Imager or Imager::ImgRaw objects as image parameters - define Imager output type for trivial cases of returning an i_img as a full Imager object - Inline WITH hook to filter Imager XS types into types Inline::C can accept, supply appropriate headers and initialization. - test script t/t82inline.t - try to use XSLoader instead of DynaLoader (but fallback if necessary) - paste() can now paste a subset of the source image. - paste() now has better tests - paste() should now be faster for larger pastes --- Changes | 42 ++ CountColor/CountColor.pm | 57 ++ CountColor/CountColor.xs | 51 ++ CountColor/Makefile.PL | 18 + CountColor/t/t00countcolor.t | 23 + DynTest/DynTest.pm | 32 + DynTest/DynTest.xs | 29 + DynTest/Makefile.PL | 18 + DynTest/linstretch.c | 49 ++ DynTest/t/t00dyntest.t | 20 + Imager.pm | 123 +++- Imager.xs | 35 +- MANIFEST | 35 +- MANIFEST.SKIP | 41 ++ Makefile.PL | 75 ++- Mandelbrot/Makefile.PL | 18 + Mandelbrot/Mandelbrot.pm | 42 ++ Mandelbrot/Mandelbrot.xs | 33 ++ Mandelbrot/mandel.c | 72 +++ Mandelbrot/t/t00mandel.t | 18 + apidocs.perl | 189 ++++++ bmp.c | 2 +- color.c | 2 +- conv.c | 2 +- convert.c | 2 +- datatypes.c | 2 +- draw.c | 128 +++- draw.h | 2 +- dynaload.c | 4 +- error.c | 15 +- ext.h | 2 +- feat.h | 2 +- fills.c | 22 +- filters.c | 40 +- font.c | 3 +- freetyp2.c | 2 +- gaussian.c | 2 +- gif.c | 24 +- hlines.c | 2 +- image.c | 89 ++- image.h => imager.h | 313 +--------- imagei.h => imageri.h | 2 +- datatypes.h => imdatatypes.h | 271 +++++++++ imexif.h | 4 +- imext.c | 454 ++++++++++++++ imext.h | 163 ++++++ imextdef.h | 11 + imexttypes.h | 119 ++++ img16.c | 18 +- imgdouble.c | 6 +- imperl.h | 33 ++ jpeg.c | 2 +- lib/Imager/API.pm | 211 +++++++ lib/Imager/APIRef.pm | 1007 ++++++++++++++++++++++++++++++++ lib/Imager/ExtUtils.pm | 125 ++++ lib/Imager/Inline.pod | 73 +++ lib/Imager/Transformations.pod | 44 +- limits.c | 2 +- map.c | 2 +- maskimg.c | 4 +- metafile.pl | 36 ++ palimg.c | 24 +- plug.h | 2 +- png.c | 2 +- pnm.c | 4 +- polygon.c | 2 +- quant.c | 54 +- raw.c | 2 +- regmach.h | 2 +- rgb.c | 2 +- rotate.c | 2 +- t/t022double.t | 2 +- t/t66paste.t | 86 ++- t/t82inline.t | 231 ++++++++ tags.c | 201 ++++++- tga.c | 2 +- tiff.c | 4 +- trans2.c | 2 +- typemap | 83 ++- win32.c | 2 +- 80 files changed, 4492 insertions(+), 484 deletions(-) create mode 100644 CountColor/CountColor.pm create mode 100644 CountColor/CountColor.xs create mode 100644 CountColor/Makefile.PL create mode 100644 CountColor/t/t00countcolor.t create mode 100644 DynTest/DynTest.pm create mode 100644 DynTest/DynTest.xs create mode 100644 DynTest/Makefile.PL create mode 100644 DynTest/linstretch.c create mode 100644 DynTest/t/t00dyntest.t create mode 100644 MANIFEST.SKIP create mode 100644 Mandelbrot/Makefile.PL create mode 100644 Mandelbrot/Mandelbrot.pm create mode 100644 Mandelbrot/Mandelbrot.xs create mode 100644 Mandelbrot/mandel.c create mode 100644 Mandelbrot/t/t00mandel.t create mode 100644 apidocs.perl rename image.h => imager.h (74%) rename imagei.h => imageri.h (99%) rename datatypes.h => imdatatypes.h (50%) create mode 100644 imext.c create mode 100644 imext.h create mode 100644 imextdef.h create mode 100644 imexttypes.h create mode 100644 imperl.h create mode 100644 lib/Imager/API.pm create mode 100644 lib/Imager/APIRef.pm create mode 100644 lib/Imager/ExtUtils.pm create mode 100644 lib/Imager/Inline.pod create mode 100644 metafile.pl create mode 100644 t/t82inline.t diff --git a/Changes b/Changes index 89d612a4..813a5feb 100644 --- a/Changes +++ b/Changes @@ -1248,6 +1248,48 @@ Revision history for Perl extension Imager. - extra concept index entries - Imager::Draw - align_string()'s valign parameter was invalid in the synopsis +- start of external Imager API access: + - rename headers to avoid conflicts: + - image.h to imager.h + - imagei.h to imageri.h + - datatypes.h to imdatatypes.h + - config.h to imconfig.h (created by Makefile.PL) + - moved all public types defined in imager.h to imdatatypes.h + - supply the PM parameter to WriteMakefile(), to install headers + under Imager/include, and the Imager typemap in Imager/typemap. + We scan the MANIFEST for files to add to PM. + - add "i_" prefix on some functions useful as public at the C level. + - moved the typedefs that support the typemap from Imager.xs to + imperl.h + - set the global callbacks hook in the Imager.xs BOOT section + - API cleanup: + - define i_tags_set(), i_tags_setn() - we might not allow multiple + values for a tag in the future + - i_copy() now returns a new image instead of doing horrible inplace + things to an existing image + - provide actual functions for all of the macros we define in imager.h + so we can put them in the global callbacks structure + - define global functions structure (imexttypes.h) + and initialize it (imext.c) + - add API include header with macros to setup the define and + initialize the local callbacks pointer, and macros to call the API + functions. + - build Imager::APIRef from C sources, including updating the sources + to include documentation for each API function. + - convert dyntest and mandelbrot dynfilts into XS modules (too easy) + - simple Imager::CountColor example +- support Inline::C : + - typemap changes to accept Imager or Imager::ImgRaw objects as + image parameters + - define Imager output type for trivial cases of returning an i_img as + a full Imager object + - Inline WITH hook to filter Imager XS types into types Inline::C can + accept, supply appropriate headers and initialization. + - test script t/t82inline.t +- try to use XSLoader instead of DynaLoader (but fallback if necessary) +- paste() can now paste a subset of the source image. +- paste() now has better tests +- paste() should now be faster for larger pastes ================================================================= diff --git a/CountColor/CountColor.pm b/CountColor/CountColor.pm new file mode 100644 index 00000000..514bc7f9 --- /dev/null +++ b/CountColor/CountColor.pm @@ -0,0 +1,57 @@ +package Imager::CountColor; +use strict; +use Imager; +use vars qw($VERSION @ISA @EXPORT_OK); +require Exporter; +@EXPORT_OK = 'count_color'; + +BEGIN { + $VERSION = "0.01"; + @ISA = qw(Exporter); + + eval { + require XSLoader; + XSLoader::load('Imager::CountColor', $VERSION); + 1; + } or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + bootstrap 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 + +=cut + + + diff --git a/CountColor/CountColor.xs b/CountColor/CountColor.xs new file mode 100644 index 00000000..df4cf1d8 --- /dev/null +++ b/CountColor/CountColor.xs @@ -0,0 +1,51 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" +#ifdef __cplusplus +} +#endif + +#include "imext.h" +#include "imperl.h" + +DEFINE_IMAGER_CALLBACKS; + +int +count_color(i_img *im, i_color *color) { + int x, y, chan; + i_color c; + int count = 0; + + for (x = 0; x < im->xsize; ++x) { + for (y = 0; y < im->ysize; ++y) { + i_gpix(im, x, y, &c); + int match = 1; + for (chan = 0; chan < im->channels; ++chan) { + if (c.channel[chan] != color->channel[chan]) { + match = 0; + break; + } + } + if (match) ++count; + } + } + + return count; +} + +MODULE = Imager::CountColor PACKAGE = Imager::CountColor + +PROTOTYPES: ENABLE + +int +count_color(im, color) + Imager::ImgRaw im + Imager::Color color + +BOOT: + PERL_INITIALIZE_IMAGER_CALLBACKS; + diff --git a/CountColor/Makefile.PL b/CountColor/Makefile.PL new file mode 100644 index 00000000..908937a6 --- /dev/null +++ b/CountColor/Makefile.PL @@ -0,0 +1,18 @@ +use ExtUtils::MakeMaker; +require "../metafile.pl"; + +my %opts = + ( + NAME => 'Imager::CountColor', + VERSION_FROM => 'CountColor.pm', + OBJECT => 'CountColor.o', + INC => '-I..', + ); +if ($ExtUtils::MakeMaker::VERSION > 6.06) { + $opts{AUTHOR} = 'Tony Cook '; + $opts{ABSTRACT} = 'Color Count an Imager image'; +} + +WriteMakefile(%opts); + + diff --git a/CountColor/t/t00countcolor.t b/CountColor/t/t00countcolor.t new file mode 100644 index 00000000..a51e971c --- /dev/null +++ b/CountColor/t/t00countcolor.t @@ -0,0 +1,23 @@ +#!perl -w +use strict; +use blib; +use lib '../t'; +use Imager; +use Test::More tests => 9; + +BEGIN { use_ok('Imager::CountColor' => 'count_color') } + +my $black = Imager::Color->new(0, 0, 0); +my $blue = Imager::Color->new(0, 0, 255); +my $red = Imager::Color->new(255, 0, 0); +my $im = Imager->new(xsize=>50, ysize=>50); +is(count_color($im, $black), 2500, "check black vs black image"); +is(count_color($im, $red), 0, "check red vs black image"); +$im->box(filled=>1, color=>$blue, xmin=>25); +is(count_color($im, $black), 1250, "check black vs black/blue image"); +is(count_color($im, $red), 0, "check red vs black/blue image"); +is(count_color($im, $blue), 1250, "check blue vs black/blue image"); +$im->box(filled=>1, color=>$red, ymin=>25); +is(count_color($im, $black), 625, "check black vs black/blue/red image"); +is(count_color($im, $blue), 625, "check black vs black/blue/red image"); +is(count_color($im, $red), 1250, "check black vs black/blue/red image"); diff --git a/DynTest/DynTest.pm b/DynTest/DynTest.pm new file mode 100644 index 00000000..05f04a1f --- /dev/null +++ b/DynTest/DynTest.pm @@ -0,0 +1,32 @@ +package Imager::Filter::DynTest; +use strict; +use Imager; +use vars qw($VERSION @ISA); + +BEGIN { + $VERSION = "0.01"; + + eval { + require XSLoader; + XSLoader::load('Imager::Filter::DynTest', $VERSION); + 1; + } or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + bootstrap 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; diff --git a/DynTest/DynTest.xs b/DynTest/DynTest.xs new file mode 100644 index 00000000..ca8ad27e --- /dev/null +++ b/DynTest/DynTest.xs @@ -0,0 +1,29 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" +#ifdef __cplusplus +} +#endif + +#include "imext.h" +#include "imperl.h" + +extern void lin_stretch(i_img *, int, int); + +DEFINE_IMAGER_CALLBACKS; + +MODULE = Imager::Filter::DynTest PACKAGE = Imager::Filter::DynTest + +void +lin_stretch(im, a, b) + Imager::ImgRaw im + int a + int b + +BOOT: + PERL_INITIALIZE_IMAGER_CALLBACKS; + diff --git a/DynTest/Makefile.PL b/DynTest/Makefile.PL new file mode 100644 index 00000000..1b2ec30f --- /dev/null +++ b/DynTest/Makefile.PL @@ -0,0 +1,18 @@ +use ExtUtils::MakeMaker; +require "../metafile.pl"; + +my %opts = + ( + NAME => 'Imager::Filter::DynTest', + VERSION_FROM => 'DynTest.pm', + OBJECT => 'DynTest.o linstretch.o', + INC => '-I..' + ); +if ($ExtUtils::MakeMaker::VERSION > 6.06) { + $opts{AUTHOR} = 'Tony Cook '; + $opts{ABSTRACT} = 'Demo Imager filter extension'; +} + +WriteMakefile(%opts); + + diff --git a/DynTest/linstretch.c b/DynTest/linstretch.c new file mode 100644 index 00000000..7d2d8faa --- /dev/null +++ b/DynTest/linstretch.c @@ -0,0 +1,49 @@ +#include "imext.h" + +char evalstr[]="Description string of plugin dyntest - kind of like"; + +void null_plug(void *ptr) { } + +/* Example dynamic filter - level stretch (linear) - note it only stretches and doesn't compress */ + +/* input parameters + a: the current black + b: the current white + + 0 <= a < b <= 255; + + output pixel value calculated by: o=((i-a)*255)/(b-a); + + note that since we do not have the needed functions to manipulate the data structures *** YET *** +*/ + + +unsigned char +static +saturate(int in) { + if (in>255) { return 255; } + else if (in>0) return in; + return 0; +} + +void lin_stretch(i_img *im, int a, int b) { + + i_color rcolor; + int i,bytes,x,y; + int info[4]; + + + /* fprintf(stderr,"parameters: (im 0x%x,a %d,b %d)\n",im,a,b);*/ + bytes=im->bytes; + + i_img_info(im,info); + + for(y=0;yysize;y++) for(x=0;xxsize;x++) { + i_gpix(im,x,y,&rcolor); + for(i=0;ichannels;i++) rcolor.channel[i]=saturate((255*(rcolor.channel[i]-a))/(b-a)); + i_ppix(im,x,y,&rcolor); + } + +} + + diff --git a/DynTest/t/t00dyntest.t b/DynTest/t/t00dyntest.t new file mode 100644 index 00000000..6402eeae --- /dev/null +++ b/DynTest/t/t00dyntest.t @@ -0,0 +1,20 @@ +#!perl -w +use strict; +use blib; +use lib '../t'; +use Imager; +use Test::More tests => 4; + +BEGIN { use_ok('Imager::Filter::DynTest') } + +my $im = Imager->new; +SKIP: +{ + ok($im->read(file => '../testout/t104.ppm'), "load source image") + or skip("couldn't load work image", 2); + ok($im->filter(type=>'lin_stretch', a => 50, b => 200), + "try filter") + or print "# ", $im->errstr, "\n"; + ok($im->write(file => '../testout/t00dyntest.ppm'), + "save result"); +} diff --git a/Imager.pm b/Imager.pm index 5027a5e4..fe0a874d 100644 --- a/Imager.pm +++ b/Imager.pm @@ -145,11 +145,17 @@ use Imager::Font; BEGIN { require Exporter; - require DynaLoader; - + @ISA = qw(Exporter); $VERSION = '0.47'; - @ISA = qw(Exporter DynaLoader); - bootstrap Imager $VERSION; + eval { + require XSLoader; + XSLoader::load(Imager => $VERSION); + 1; + } or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + bootstrap Imager $VERSION; + } } BEGIN { @@ -567,8 +573,7 @@ sub copy { } my $newcopy=Imager->new(); - $newcopy->{IMG}=i_img_new(); - i_copy($newcopy->{IMG},$self->{IMG}); + $newcopy->{IMG} = i_copy($self->{IMG}); return $newcopy; } @@ -576,19 +581,68 @@ sub copy { sub paste { my $self = shift; - unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; } - my %input=(left=>0, top=>0, @_); - unless($input{img}) { - $self->{ERRSTR}="no source image"; + + unless ($self->{IMG}) { + $self->_set_error('empty input image'); + return; + } + my %input=(left=>0, top=>0, src_minx => 0, src_miny => 0, @_); + my $src = $input{img} || $input{src}; + unless($src) { + $self->_set_error("no source image"); return; } $input{left}=0 if $input{left} <= 0; $input{top}=0 if $input{top} <= 0; - my $src=$input{img}; + my($r,$b)=i_img_info($src->{IMG}); + my ($src_left, $src_top) = @input{qw/src_minx src_miny/}; + my ($src_right, $src_bottom); + if ($input{src_coords}) { + ($src_left, $src_top, $src_right, $src_bottom) = @{$input{src_coords}} + } + else { + if (defined $input{src_maxx}) { + $src_right = $input{src_maxx}; + } + elsif (defined $input{width}) { + if ($input{width} <= 0) { + $self->_set_error("paste: width must me positive"); + return; + } + $src_right = $src_left + $input{width}; + } + else { + $src_right = $r; + } + if (defined $input{src_maxx}) { + $src_bottom = $input{src_maxy}; + } + elsif (defined $input{height}) { + if ($input{height} < 0) { + $self->_set_error("paste: height must be positive"); + return; + } + $src_bottom = $src_top + $input{height}; + } + else { + $src_bottom = $b; + } + } + + $src_right > $r and $src_right = $r; + $src_bottom > $r and $src_bottom = $b; + + if ($src_right <= $src_left + || $src_bottom < $src_top) { + $self->_set_error("nothing to paste"); + return; + } i_copyto($self->{IMG}, $src->{IMG}, - 0,0, $r, $b, $input{left}, $input{top}); + $src_left, $src_top, $src_right, $src_bottom, + $input{left}, $input{top}); + return $self; # What should go here?? } @@ -1655,6 +1709,25 @@ sub filter { return $self; } +sub register_filter { + my $class = shift; + my %hsh = ( defaults => {}, @_ ); + + defined $hsh{type} + or die "register_filter() with no type\n"; + defined $hsh{callsub} + or die "register_filter() with no callsub\n"; + defined $hsh{callseq} + or die "register_filter() with no callseq\n"; + + exists $filters{$hsh{type}} + and return; + + $filters{$hsh{type}} = \%hsh; + + return 1; +} + # Scale an image to requested size and return the scaled version sub scale { @@ -2953,7 +3026,15 @@ sub parseiptc { return (caption=>$caption,photogr=>$photogr,headln=>$headln,credit=>$credit); } -# Autoload methods go after =cut, and are processed by the autosplit program. +sub Inline { + my ($lang) = @_; + + $lang eq 'C' + or die "Only C language supported"; + + require Imager::ExtUtils; + return Imager::ExtUtils->inline_config; +} 1; __END__ @@ -3086,6 +3167,22 @@ L - Helper class for affine transformations. L - Helper for making gradient profiles. +=item * + +L - using Imager's C API + +=item * + +L - API function reference + +=item * + +L - using Imager's C API from Inline::C + +=item * + +L - tools to get access to Imager's C API. + =back =head2 Basic Overview diff --git a/Imager.xs b/Imager.xs index da982a9b..fd09d8c7 100644 --- a/Imager.xs +++ b/Imager.xs @@ -6,33 +6,24 @@ extern "C" { #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus - +} #endif #define i_int_hlines_testing() 1 -#include "image.h" +#include "imager.h" #include "feat.h" #include "dynaload.h" #include "regmach.h" - -#if i_int_hlines_testing() -#include "imagei.h" -#endif +#include "imextdef.h" typedef io_glue* Imager__IO; -typedef i_color* Imager__Color; -typedef i_fcolor* Imager__Color__Float; -typedef i_img* Imager__ImgRaw; -typedef int undef_neg_int; -#ifdef HAVE_LIBTT -typedef TT_Fonthandle* Imager__Font__TT; +#if i_int_hlines_testing() +#include "imageri.h" #endif -#ifdef HAVE_FT2 -typedef FT2_Fonthandle* Imager__Font__FT2; -#endif +#include "imperl.h" /* These functions are all shared - then comes platform dependant code */ static int getstr(void *hv_t,char *key,char **store) { @@ -816,12 +807,6 @@ load_fount_segs(AV *asegs, int *count) { #define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a)) #define ICLF_DESTROY(cl) i_fcolor_destroy(cl) -/* 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; /* the m_init_log() function was called init_log(), renamed to reduce potential naming conflicts */ @@ -1473,9 +1458,8 @@ i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans) int ty Imager::Color trans -void -i_copy(im,src) - Imager::ImgRaw im +Imager::ImgRaw +i_copy(src) Imager::ImgRaw src @@ -4560,3 +4544,6 @@ i_int_hlines_dump(hlines) Imager::Internal::Hlines hlines #endif + +BOOT: + PERL_SET_GLOBAL_CALLBACKS; diff --git a/MANIFEST b/MANIFEST index 0e29eeb1..841355f1 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,18 +1,33 @@ Changes +CountColor/CountColor.pm sample XS access to API +CountColor/CountColor.xs +CountColor/Makefile.PL +CountColor/t/t00countcolor.t +DynTest/DynTest.pm simple conversion of the dyntest sample from dynfilt/ +DynTest/DynTest.xs +DynTest/Makefile.PL +DynTest/linstretch.c +DynTest/t/t00dyntest.t Imager.pm Imager.xs MANIFEST +MANIFEST.SKIP META.yml Module meta-data +Mandelbrot/Makefile.PL more complex filter +Mandelbrot/Mandelbrot.pm +Mandelbrot/Mandelbrot.xs +Mandelbrot/mandel.c +Mandelbrot/t/t00mandel.t Makefile.PL README +apidocs.perl Build lib/Imager/APIRef.pm bigtest.perl Library selection tester bmp.c Reading and writing Windows BMP files color.c Color translation and handling conv.c convert.c -datatypes.c -datatypes.h doco.perl +datatypes.c draw.c draw.h dynaload.c @@ -51,23 +66,32 @@ gaussian.c gif.c hlines.c Manage sets of horizontal line segments image.c -image.h -imagei.h +imager.h +imageri.h +imdatatypes.h +imext.c Defines the function table +imext.h Included by external modules for API access +imextdef.h +imexttypes.h Define API function table type imexif.c Experimental JPEG EXIF decoding imexif.h img16.c imgdouble.c Implements double/sample images imio.h +imperl.h io.c iolayer.c iolayer.h jpeg.c +lib/Imager/API.pm +lib/Imager/APIRef.pm API function reference lib/Imager/Color.pm lib/Imager/Color/Float.pm lib/Imager/Color/Table.pm lib/Imager/Cookbook.pod lib/Imager/Draw.pod lib/Imager/Engines.pod +lib/Imager/ExtUtils.pm lib/Imager/Expr.pm lib/Imager/Expr/Assem.pm lib/Imager/Files.pod @@ -83,6 +107,7 @@ lib/Imager/Font/Win32.pm lib/Imager/Font/Wrap.pm lib/Imager/Fountain.pm lib/Imager/ImageTypes.pod +lib/Imager/Inline.pod Using Imager with Inline::C lib/Imager/Matrix2d.pm lib/Imager/Regops.pm lib/Imager/Transform.pm @@ -95,6 +120,7 @@ log.c log.h map.c maskimg.c +metafile.pl Common META.yml generation palimg.c plug.h png.c @@ -168,6 +194,7 @@ t/t70newgif.t t/t75polyaa.t t/t80texttools.t Test text wrapping t/t81hlines.t Test hlines.c +t/t82inline.t Test Inline::C integration t/t90cc.t t/t91pod.t Test POD with Test::Pod t/testtools.pl diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 00000000..f7ed5767 --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,41 @@ +# svn work files' +^\.svn\b +/\.svn\b + +# editor trash +~$ + +# stuff we don't distribute +^TODO$ +^STATUS$ +^\.cvsignore$ +/\.cvsignore$ +^announce/ +^bench/ +^design/ +^fileformatdocs/ +^extraimages/ +^fontfiles/.*\.sfd$ + +# might distribute one day +^tools/imager$ + +# trash left by Inline::C +^_Inline/ + +# build trash +Makefile$ +Makefile\.old +\bpm_to_blib$ +\.o$ +^testimg/ +^blib/ +^Imager\.c$ +^Mandelbrot/Mandelbrot\.c$ +^CountColor/CountColor\.c$ +^DynTest/DynTest\.c$ +^dynfilt/.*\.(so|dll)$ +\.bs$ +^meta\.tmp$ +/meta\.tmp$ +^imconfig\.h$ diff --git a/Makefile.PL b/Makefile.PL index 028f510e..e1334f0f 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -4,6 +4,9 @@ use Cwd; use Config; use File::Spec; use Getopt::Long; +use vars qw(%Recommends); +require "metafile.pl"; +use ExtUtils::Manifest qw(maniread); # # IM_INCPATH colon seperated list of paths to extra include paths @@ -128,7 +131,11 @@ if (defined $Config{'d_dlsymun'}) { $OSDEF .= ' -DDLSYMUN'; } filters.o dynaload.o stackmach.o datatypes.o regmach.o trans2.o quant.o error.o convert.o map.o tags.o palimg.o maskimg.o img16.o rotate.o - bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o hlines.o); + bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o hlines.o + imext.o); + +$Recommends{Imager} = + { 'Parse::RecDescent' => 0 }; %opts=( 'NAME' => 'Imager', @@ -138,6 +145,7 @@ if (defined $Config{'d_dlsymun'}) { $OSDEF .= ' -DDLSYMUN'; } 'INC' => "$lib_cflags $DFLAGS $F_INC", 'OBJECT' => join(' ', @objs, $F_OBJECT), clean => { FILES=>'testout meta.tmp' }, + PM => gen_PM(), ); if ($ExtUtils::MakeMaker::VERSION > 6.06) { @@ -162,36 +170,16 @@ dyntest.$(MYEXTLIB) : dynfilt/Makefile lib/Imager/Regops.pm : regmach.h regops.perl $(PERL) regops.perl regmach.h lib/Imager/Regops.pm -imconfig.h: Makefile.PL +imconfig.h : Makefile.PL $(ECHO) "imconfig.h out-of-date with respect to $?" $(PERLRUN) Makefile.PL $(ECHO) "==> Your Makefile has been rebuilt - re-run your make command <==" + +lib/Imager/APIRef.pm : $(C_FILES) apidocs.perl + $(PERLRUN) apidocs.perl lib/Imager/APIRef.pm + '; -} -sub MY::metafile { - my ($self) = @_; - - my $meta = <{VERSION} -version_from: $self->{VERSION_FROM} -author: $self->{AUTHOR} -abstract: $self->{ABSTRACT} -installdirs: $self->{INSTALLDIRS} -recommends: - Parse::RecDescent: 0 -license: perl -dynamic_config: 1 -distribution_type: module -generated_by: Imager version $self->{VERSION} -YAML - open META, "> meta.tmp" or die "Cannot create meta.tmp: $!"; - print META $meta; - close META; - - return sprintf "metafile :\n\t\$(CP) meta.tmp META.yml\n"; } # manual configuration of helper libraries @@ -687,3 +675,38 @@ EOS exit 1; } + +# generate the PM MM argument +# I'd prefer to modify the public version, but there doesn't seem to be +# a public API to do that +sub gen_PM { + my %pm; + my $instbase = '$(INST_LIBDIR)'; + + # first the basics, .pm and .pod files + $pm{"Imager.pm"} = "$instbase/Imager.pm"; + + my $mani = maniread(); + + for my $filename (keys %$mani) { + if ($filename =~ m!^lib/! && $filename =~ /\.(pm|pod)$/) { + (my $work = $filename) =~ s/^lib//; + $pm{$filename} = $instbase . $work; + } + } + + # need the typemap + $pm{typemap} = $instbase . '/Imager/typemap'; + + # and the core headers + for my $filename (keys %$mani) { + if ($filename =~ /^\w+\.h$/) { + $pm{$filename} = $instbase . '/Imager/include/' . $filename; + } + } + + # and the generated header + $pm{"imconfig.h"} = $instbase . '/Imager/include/imconfig.h'; + + \%pm; +} diff --git a/Mandelbrot/Makefile.PL b/Mandelbrot/Makefile.PL new file mode 100644 index 00000000..d0a60c48 --- /dev/null +++ b/Mandelbrot/Makefile.PL @@ -0,0 +1,18 @@ +use ExtUtils::MakeMaker; +require "../metafile.pl"; + +my %opts = + ( + NAME => 'Imager::Filter::Mandelbrot', + VERSION_FROM => 'Mandelbrot.pm', + OBJECT => 'Mandelbrot.o mandel.o', + INC => '-I..' + ); +if ($ExtUtils::MakeMaker::VERSION > 6.06) { + $opts{AUTHOR} = 'Tony Cook '; + $opts{ABSTRACT} = 'Mandelbrot Imager filter extension'; +} + +WriteMakefile(%opts); + + diff --git a/Mandelbrot/Mandelbrot.pm b/Mandelbrot/Mandelbrot.pm new file mode 100644 index 00000000..1a4c29fb --- /dev/null +++ b/Mandelbrot/Mandelbrot.pm @@ -0,0 +1,42 @@ +package Imager::Filter::Mandelbrot; +use strict; +use Imager; +use vars qw($VERSION @ISA); + +BEGIN { + $VERSION = "0.01"; + + eval { + require XSLoader; + XSLoader::load('Imager::Filter::Mandelbrot', $VERSION); + 1; + } or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + bootstrap 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; diff --git a/Mandelbrot/Mandelbrot.xs b/Mandelbrot/Mandelbrot.xs new file mode 100644 index 00000000..a6837ee5 --- /dev/null +++ b/Mandelbrot/Mandelbrot.xs @@ -0,0 +1,33 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" +#ifdef __cplusplus +} +#endif + +#include "imext.h" +#include "imperl.h" + +void +mandelbrot(i_img *im, double minx, double miny, double maxx, double maxy, int max_iter); + +DEFINE_IMAGER_CALLBACKS; + +MODULE = Imager::Filter::Mandelbrot PACKAGE = Imager::Filter::Mandelbrot + +void +mandelbrot(im, minx=-2.5, miny=-2.0, maxx=2.5, maxy=-2.0, max_iter=256) + Imager::ImgRaw im + double minx + double miny + double maxx + double maxy + int max_iter + +BOOT: + PERL_INITIALIZE_IMAGER_CALLBACKS; + diff --git a/Mandelbrot/mandel.c b/Mandelbrot/mandel.c new file mode 100644 index 00000000..299c0844 --- /dev/null +++ b/Mandelbrot/mandel.c @@ -0,0 +1,72 @@ +#include "imext.h" +#include + +char evalstr[]="Mandlebrot renderer"; + +/* Example Mandlebrot generator */ + +/* input parameters + image is the image object. +*/ + + +static +int +mandel(double x, double y, int max_iter) { + double xn, yn; + double xo, yo; + double dist; + int iter = 1; + /* Z(n+1) = Z(n) ^2 + c */ + + /* printf("(%.2f, %.2f) -> \n", x,y); */ + + xo = x; + yo = y; + + while( xo*xo+yo*yo <= 10 && iter < max_iter) { + xn = xo*xo-yo*yo + x; + yn = 2*xo*yo + y; + xo=xn; + yo=yn; + iter++; + } + return (iter == max_iter)?0:iter; +} + +void +mandelbrot(i_img *im, double minx, double miny, double maxx, double maxy, int max_iter) { + + i_color vl; + int i,bytes,x,y; + int idx; + double divx, divy; + + i_color icl[256]; + srand(12235); + for(i=1;i<256; i++) { + icl[i].rgb.r = 100+(int) (155.0*rand()/(RAND_MAX+1.0)); + icl[i].rgb.g = 100+(int) (155.0*rand()/(RAND_MAX+1.0)); + icl[i].rgb.g = 100+(int) (155.0*rand()/(RAND_MAX+1.0)); + } + + icl[0].rgb.r = 0; + icl[0].rgb.g = 0; + icl[0].rgb.g = 0; + + if (maxx <= minx) + maxx = minx + 1.0; + if (maxy <= miny) + maxy = miny + 1.0; + + divx = (maxx - minx) / im->xsize; + divy = (maxy - miny) / im->ysize; + + for(y = 0; y < im->ysize; y ++) { + for(x = 0; x < im->xsize; x ++ ) { + idx = mandel(minx + x*divx , miny + y*divy, max_iter); + idx = idx % 256; + i_ppix(im,x,y,&icl[idx]); + } + } +} diff --git a/Mandelbrot/t/t00mandel.t b/Mandelbrot/t/t00mandel.t new file mode 100644 index 00000000..c0dc9d3e --- /dev/null +++ b/Mandelbrot/t/t00mandel.t @@ -0,0 +1,18 @@ +#!perl -w +use strict; +use blib; +use lib '../t'; +use Imager; +use Test::More tests => 3; + +BEGIN { use_ok('Imager::Filter::Mandelbrot') } + +my $im = Imager->new(xsize=>100, ysize=>100); +SKIP: +{ + ok($im->filter(type=>'mandelbrot'), + "try filter") + or print "# ", $im->errstr, "\n"; + ok($im->write(file => '../testout/t00mandel.ppm'), + "save result"); +} diff --git a/apidocs.perl b/apidocs.perl new file mode 100644 index 00000000..366c425a --- /dev/null +++ b/apidocs.perl @@ -0,0 +1,189 @@ +#!perl -w +use strict; + +my $outname = shift || '-'; + + +my @funcs = make_func_list(); +my %funcs = map { $_ => 1 } @funcs; + +# look for files to parse + +my @files = grep $_ ne 'Imager.xs', glob '*.c'; + +# scan each file for =item \b +my $func; +my $start; +my %alldocs; +my @funcdocs; +my %from; +my $category; +my %funccats; +my %cats; +my $synopsis = ''; +my %funcsyns; +for my $file (@files) { + open SRC, "< $file" + or die "Cannot open $file for documentation: $!\n"; + while () { + if (/^=item (\w+)\b/ && $funcs{$1}) { + $func = $1; + $start = $.; + @funcdocs = $_; + } + elsif ($func && /^=(cut|head)/) { + if ($funcs{$func}) { # only save the API functions + $alldocs{$func} = [ @funcdocs ]; + $from{$func} = "Line $start in $file"; + if ($category) { + $funccats{$func} = $category; + push @{$cats{$category}}, $func; + } + if ($synopsis) { + $funcsyns{$func} = $synopsis; + } + } + undef $func; + undef $category; + $synopsis = ''; + } + elsif ($func) { + if (/^=category (.*)/) { + $category = $1; + } + elsif (/^=synopsis (.*)/) { + $synopsis .= "$1\n"; + } + else { + push @funcdocs, $_; + } + } + } + $func and + die "Documentation for $func not followed by =cut or =head in $file\n"; + + close SRC; +} + +open OUT, "> $outname" + or die "Cannot open $outname: $!"; + +print OUT <<'EOS'; +Do not edit this file, it is generated automatically by apidocs.perl +from Imager's source files. + +Each function description has a comment listing the source file and +line number where you can find the documentation. + +=head1 NAME + +Imager::APIRef - Imager's C API. + +=head1 SYNOPSIS + + i_color color; + color.rgba.red = 255; color.rgba.green = 0; color.rgba.blue = 255; + i_fill_t *fill = i_new_fill_...(...); + +EOS + +for my $cat (sort { lc $a cmp lc $b } keys %cats) { + print OUT "\n # $cat\n"; + for my $func (grep $funcsyns{$_}, sort @{$cats{$cat}}) { + my $syn = $funcsyns{$func}; + $syn =~ s/^/ /gm; + print OUT $syn; + } +} + +print OUT <<'EOS'; + + i_fill_destroy(fill); + +=head1 DESCRIPTION + +EOS + +my %undoc = %funcs; + +for my $cat (sort { lc $a cmp lc $b } keys %cats) { + print OUT "=head2 $cat\n\n=over\n\n"; + for my $func (sort @{$cats{$cat}}) { + print OUT @{$alldocs{$func}}, "\n"; + print OUT "=for comment\nFrom: $from{$func}\n\n"; + delete $undoc{$func}; + } + print OUT "\n=back\n\n"; +} + +# see if we have an uncategorized section +if (grep $alldocs{$_}, keys %undoc) { + print OUT "=head2 Uncategorized functions\n\n=over\n\n"; + for my $func (sort @funcs) { + if ($undoc{$func} && $alldocs{$func}) { + print OUT @{$alldocs{$func}}, "\n"; + print OUT "=for comment\nFrom: $from{$func}\n\n"; + delete $undoc{$func}; + } + } + print OUT "\n\n=back\n\n"; +} + +if (keys %undoc) { + print OUT <<'EOS'; + +=head1 UNDOCUMENTED + +The following API functions are undocumented so far, hopefully this +will change: + +=over + +EOS + + print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc; + + print OUT "\n\n=back\n\n"; +} + +print OUT <<'EOS'; + +=head1 AUTHOR + +Tony Cook + +=head1 SEE ALSO + +Imager, Imager::ExtUtils, Imager::Inline + +=cut +EOS + +close OUT; + + +sub make_func_list { + my $funcs; + open FUNCS, "< imexttypes.h" + or die "Cannot open imexttypes.h: $!\n"; + my $in_struct; + while () { + /^typedef struct/ && ++$in_struct; + if ($in_struct && /\(\*f_(i_\w+)/) { + push @funcs, $1; + } + if (/^\} im_ext_funcs;$/) { + $in_struct + or die "Found end of functions structure but not the start"; + + close FUNCS; + return @funcs; + } + } + if ($in_struct) { + die "Found start of the functions structure but not the end\n"; + } + else { + die "Found neither the start nor end of the functions structure\n"; + } +} diff --git a/bmp.c b/bmp.c index 8e1e4228..f2a15cd8 100644 --- a/bmp.c +++ b/bmp.c @@ -1,5 +1,5 @@ #include -#include "imagei.h" +#include "imageri.h" /* =head1 NAME diff --git a/color.c b/color.c index d83d8660..10376a35 100644 --- a/color.c +++ b/color.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include /* diff --git a/conv.c b/conv.c index 7e8513d0..3e560d30 100644 --- a/conv.c +++ b/conv.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" /* General convolution for 2d decoupled filters diff --git a/convert.c b/convert.c index 6d92fbb6..eb411e9f 100644 --- a/convert.c +++ b/convert.c @@ -17,7 +17,7 @@ converting from RGBA to greyscale and back. =cut */ -#include "image.h" +#include "imager.h" /* diff --git a/datatypes.c b/datatypes.c index cc930443..5a623ab7 100644 --- a/datatypes.c +++ b/datatypes.c @@ -1,5 +1,5 @@ #include "imio.h" -#include "datatypes.h" +#include "imdatatypes.h" #include #include #include diff --git a/draw.c b/draw.c index 6cca0a00..ec719f6c 100644 --- a/draw.c +++ b/draw.c @@ -1,7 +1,7 @@ -#include "image.h" +#include "imager.h" #include "draw.h" #include "log.h" -#include "imagei.h" +#include "imageri.h" #include @@ -201,6 +201,18 @@ i_arc_hlines(i_int_hlines *hlines,int x,int y,float rad,float d1,float d2) { } } +/* +=item i_arc(im, x, y, rad, d1, d2, color) + +=category Drawing +=synopsis i_arc(im, 50, 50, 20, 45, 135, &color); + +Fills an arc centered at (x,y) with radius I covering the range +of angles in degrees from d1 to d2, with the color. + +=cut +*/ + void i_arc(i_img *im,int x,int y,float rad,float d1,float d2,i_color *val) { i_int_hlines hlines; @@ -214,6 +226,18 @@ i_arc(i_img *im,int x,int y,float rad,float d1,float d2,i_color *val) { i_int_hlines_destroy(&hlines); } +/* +=item i_arc_cfill(im, x, y, rad, d1, d2, fill) + +=category Drawing +=synopsis i_arc_cfill(im, 50, 50, 35, 90, 135, fill); + +Fills an arc centered at (x,y) with radius I covering the range +of angles in degrees from d1 to d2, with the fill object. + +=cut +*/ + #define MIN_CIRCLE_STEPS 8 #define MAX_CIRCLE_STEPS 360 @@ -301,6 +325,18 @@ arc_poly(int *count, double **xvals, double **yvals, ++*count; } +/* +=item i_arc_aa(im, x, y, rad, d1, d2, color) + +=category Drawing +=synopsis i_arc_aa(im, 50, 50, 35, 90, 135, &color); + +Antialias fills an arc centered at (x,y) with radius I covering +the range of angles in degrees from d1 to d2, with the color. + +=cut +*/ + void i_arc_aa(i_img *im, double x, double y, double rad, double d1, double d2, i_color *val) { @@ -315,6 +351,18 @@ i_arc_aa(i_img *im, double x, double y, double rad, double d1, double d2, myfree(yvals); } +/* +=item i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) + +=category Drawing +=synopsis i_arc_aa_cfill(im, 50, 50, 35, 90, 135, fill); + +Antialias fills an arc centered at (x,y) with radius I covering +the range of angles in degrees from d1 to d2, with the fill object. + +=cut +*/ + void i_arc_aa_cfill(i_img *im, double x, double y, double rad, double d1, double d2, i_fill_t *fill) { @@ -425,6 +473,17 @@ i_pixel_coverage(i_mmarray *dot, int x, int y) { return cnt; } +/* +=item i_circle_aa(im, x, y, rad, color) + +=category Drawing +=synopsis i_circle_aa(im, 50, 50, 45, &color); + +Antialias fills a circle centered at (x,y) for radius I with +color. + +=cut +*/ void i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) { i_mmarray dot; @@ -468,10 +527,16 @@ i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) { i_mmarray_dst(&dot); } +/* +=item i_box(im, x1, y1, x2, y2, color) +=category Drawing +=synopsis i_box(im, 0, 0, im->xsize-1, im->ysize-1, &color). +Outlines the box from (x1,y1) to (x2,y2) inclusive with I. - +=cut +*/ void i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) { @@ -487,6 +552,17 @@ i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) { } } +/* +=item i_box_filled(im, x1, y1, x2, y2, color) + +=category Drawing +=synopsis i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &color); + +Fills the box from (x1,y1) to (x2,y2) inclusive with color. + +=cut +*/ + void i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) { int x,y; @@ -494,6 +570,17 @@ i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) { for(x=x1;xxsize-1, im->ysize-1, fill); + +Fills the box from (x1,y1) to (x2,y2) inclusive with fill. + +=cut +*/ + void i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) { mm_log((1,"i_box_cfill(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,fill 0x%x)\n",im,x1,y1,x2,y2,fill)); @@ -557,6 +644,8 @@ i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) { /* =item i_line(im, x1, y1, x2, y2, val, endp) +=category Drawing + Draw a line to image using bresenhams linedrawing algorithm im - image to draw to @@ -756,7 +845,17 @@ i_line_aa3(i_img *im,int x1,int y1,int x2,int y2,i_color *val) { } +/* +=item i_line_aa(im, x1, x2, y1, y2, color, endp) + +=category Drawing + +Antialias draws a line from (x1,y1) to (x2, y2) in color. +The point (x2, y2) is drawn only if endp is set. + +=cut +*/ void i_line_aa(i_img *im, int x1, int y1, int x2, int y2, i_color *val, int endp) { @@ -1192,8 +1291,19 @@ i_flood_fill_low(i_img *im,int seedx,int seedy, return btm; } +/* +=item i_flood_fill(im, seedx, seedy, color) + +=category Drawing +=synopsis i_flood_fill(im, 50, 50, &color); +Flood fills the 4-connected region starting from the point (seedx, +seedy) with I. +Returns false if (seedx, seedy) are outside the image. + +=cut +*/ undef_int i_flood_fill(i_img *im, int seedx, int seedy, i_color *dcol) { @@ -1218,7 +1328,19 @@ i_flood_fill(i_img *im, int seedx, int seedy, i_color *dcol) { return 1; } +/* +=item i_flood_cfill(im, seedx, seedy, fill) + +=category Drawing +=synopsis i_flood_cfill(im, 50, 50, fill); +Flood fills the 4-connected region starting from the point (seedx, +seedy) with I. + +Returns false if (seedx, seedy) are outside the image. + +=cut +*/ undef_int i_flood_cfill(i_img *im, int seedx, int seedy, i_fill_t *fill) { diff --git a/draw.h b/draw.h index 2fb33a95..c9dfdbc1 100644 --- a/draw.h +++ b/draw.h @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" typedef struct { int min,max; diff --git a/dynaload.c b/dynaload.c index 1d308fd7..b36df8ac 100644 --- a/dynaload.c +++ b/dynaload.c @@ -1,7 +1,7 @@ -#include "image.h" +#include "imager.h" #include "dynaload.h" /* #include "XSUB.h" so we can compile on threaded perls */ -#include "imagei.h" +#include "imageri.h" static symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info, i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise, diff --git a/error.c b/error.c index 9876ac67..3dcab3cd 100644 --- a/error.c +++ b/error.c @@ -61,7 +61,7 @@ C). The Perl level won't use all of this. =cut */ -#include "image.h" +#include "imager.h" #include #include @@ -184,9 +184,14 @@ the mark. =item i_clear_error() +=category Error handling + +Clears the error stack. + Called by any imager function before doing any other processing. -=cut */ +=cut +*/ void i_clear_error() { #ifdef IMAGER_DEBUG_MALLOC int i; @@ -205,6 +210,8 @@ void i_clear_error() { /* =item i_push_error(int code, char const *msg) +=category Error handling + Called by an imager function to push an error message onto the stack. No message is pushed if the stack is full (since this means someone @@ -241,6 +248,8 @@ void i_push_error(int code, char const *msg) { /* =item i_push_errorvf(int code, char const *fmt, va_list ap) +=category Error handling + Intended for use by higher level functions, takes a varargs pointer and a format to produce the finally pushed error message. @@ -263,6 +272,8 @@ void i_push_errorvf(int code, char const *fmt, va_list ap) { /* =item i_push_errorf(int code, char const *fmt, ...) +=category Error handling + A version of i_push_error() that does printf() like formating. =cut diff --git a/ext.h b/ext.h index 15cb3ffa..dd1cfbd8 100644 --- a/ext.h +++ b/ext.h @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #ifndef IMAGER_EXT_H #define IMAGER_EXT_H diff --git a/feat.h b/feat.h index bfcb4c00..1a7289d3 100644 --- a/feat.h +++ b/feat.h @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" static char *i_format_list[]={ #ifdef HAVE_LIBJPEG diff --git a/fills.c b/fills.c index e075c538..3bccde5c 100644 --- a/fills.c +++ b/fills.c @@ -1,5 +1,5 @@ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" /* =head1 NAME @@ -195,6 +195,8 @@ static i_fill_solid_t base_solid_fill_comb = /* =item i_fill_destroy(fill) +=category Fills + Call to destroy any fill object. =cut @@ -210,6 +212,8 @@ i_fill_destroy(i_fill_t *fill) { /* =item i_new_fill_solidf(color, combine) +=category Fills + Create a solid fill based on a float color. If combine is non-zero then alpha values will be combined. @@ -239,7 +243,9 @@ i_new_fill_solidf(i_fcolor *c, int combine) { /* =item i_new_fill_solid(color, combine) -Create a solid fill based. +=category Fills + +Create a solid fill based on an 8-bit color. If combine is non-zero then alpha values will be combined. @@ -420,6 +426,8 @@ i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg, /* =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) +=category Fills + Creates a new hatched fill with the fg color used for the 1 bits in the hatch and bg for the 0 bits. If combine is non-zero alpha values will be combined. @@ -443,6 +451,8 @@ i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch, /* =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) +=category Fills + Creates a new hatched fill with the fg color used for the 1 bits in the hatch and bg for the 0 bits. If combine is non-zero alpha values will be combined. @@ -478,8 +488,14 @@ struct i_fill_image_t { /* =item i_new_fill_image(im, matrix, xoff, yoff, combine) +=category Fills + Create an image based fill. +matrix is an array of 9 doubles representing a transformation matrix. + +xoff and yoff are the offset into the image to start filling from. + =cut */ i_fill_t * diff --git a/filters.c b/filters.c index dfd12cae..0efa89a3 100644 --- a/filters.c +++ b/filters.c @@ -1,5 +1,5 @@ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" #include #include @@ -109,21 +109,24 @@ i_hardinvert(i_img *im) { int x, y; unsigned char ch; - i_color rcolor; + i_color *row, *entry; - mm_log((1,"i_hardinvert(im %p)\n", im)); + mm_log((1,"i_hardinvert(im %p)\n", im)); + + row = mymalloc(sizeof(i_color) * im->xsize); for(y = 0; y < im->ysize; y++) { + i_glin(im, 0, im->xsize, y, row); + entry = row; for(x = 0; x < im->xsize; x++) { - i_gpix(im, x, y, &rcolor); - for(ch = 0; ch < im->channels; ch++) { - rcolor.channel[ch] = 255 - rcolor.channel[ch]; + entry->channel[ch] = 255 - entry->channel[ch]; } - - i_ppix(im, x, y, &rcolor); + ++entry; } + i_plin(im, 0, im->xsize, y, row); } + myfree(row); } @@ -1220,7 +1223,7 @@ image from double the original. =cut */ void i_unsharp_mask(i_img *im, double stddev, double scale) { - i_img copy; + i_img *copy; int x, y, ch; if (scale < 0) @@ -1229,14 +1232,14 @@ void i_unsharp_mask(i_img *im, double stddev, double scale) { if (scale > 100) scale = 100; - i_copy(©, im); - i_gaussian(©, stddev); + copy = i_copy(im); + i_gaussian(copy, stddev); if (im->bits == i_8_bits) { i_color *blur = mymalloc(im->xsize * sizeof(i_color) * 2); i_color *out = blur + im->xsize; for (y = 0; y < im->ysize; ++y) { - i_glin(©, 0, copy.xsize, y, blur); + i_glin(copy, 0, copy->xsize, y, blur); i_glin(im, 0, im->xsize, y, out); for (x = 0; x < im->xsize; ++x) { for (ch = 0; ch < im->channels; ++ch) { @@ -1260,7 +1263,7 @@ void i_unsharp_mask(i_img *im, double stddev, double scale) { i_fcolor *out = blur + im->xsize; for (y = 0; y < im->ysize; ++y) { - i_glinf(©, 0, copy.xsize, y, blur); + i_glinf(copy, 0, copy->xsize, y, blur); i_glinf(im, 0, im->xsize, y, out); for (x = 0; x < im->xsize; ++x) { for (ch = 0; ch < im->channels; ++ch) { @@ -1278,7 +1281,7 @@ void i_unsharp_mask(i_img *im, double stddev, double scale) { myfree(blur); } - i_img_exorcise(©); + i_img_destroy(copy); } /* @@ -1660,7 +1663,12 @@ static void fount_fill_destroy(i_fill_t *fill); /* -=item i_new_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) +=item i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) + +=category Fills +=synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, +=synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs); + Creates a new general fill which fills with a fountain fill. diff --git a/font.c b/font.c index 4dc1349a..d1fadf00 100644 --- a/font.c +++ b/font.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include #include @@ -1084,6 +1084,7 @@ i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) { bit->size = bit->rows * bit->cols; /* number of bytes in buffer */ } + /* rows can be 0 for some glyphs, for example ' ' */ if (bit->rows && bit->size / bit->rows != bit->cols) { m_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n", bit->width, bit->rows); diff --git a/freetyp2.c b/freetyp2.c index 687e2685..fed44110 100644 --- a/freetyp2.c +++ b/freetyp2.c @@ -34,7 +34,7 @@ Truetype, Type1 and Windows FNT. =cut */ -#include "image.h" +#include "imager.h" #include #include #include FT_FREETYPE_H diff --git a/gaussian.c b/gaussian.c index dee1f579..ce0c2958 100644 --- a/gaussian.c +++ b/gaussian.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" static float gauss(int x,float std) { diff --git a/gif.c b/gif.c index 8a538c4c..e300831d 100644 --- a/gif.c +++ b/gif.c @@ -1,4 +1,4 @@ -#include "imagei.h" +#include "imageri.h" #include #ifdef _MSCVER #include @@ -1721,7 +1721,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { } else { glob_paletted = 0; - quant_makemap(quant, glob_imgs, glob_img_count); + i_quant_makemap(quant, glob_imgs, glob_img_count); } glob_color_count = quant->mc_count; quant->mc_colors = orig_colors; @@ -1748,7 +1748,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { } else { colors_paletted = 0; - quant_makemap(quant, imgs, 1); + i_quant_makemap(quant, imgs, 1); } } if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) { @@ -1818,7 +1818,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { } else { colors_paletted = 0; - quant_makemap(quant, imgs, 1); + i_quant_makemap(quant, imgs, 1); } if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) { i_mempool_destroy(&mp); @@ -1838,7 +1838,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { if (colors_paletted) result = quant_paletted(quant, imgs[0]); else - result = quant_translate(quant, imgs[0]); + result = i_quant_translate(quant, imgs[0]); if (!result) { i_mempool_destroy(&mp); quant->mc_colors = orig_colors; @@ -1846,7 +1846,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { return 0; } if (want_trans) { - quant_transparent(quant, result, imgs[0], quant->mc_count); + i_quant_transparent(quant, result, imgs[0], quant->mc_count); trans_index = quant->mc_count; } @@ -1917,18 +1917,18 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { result = quant_paletted(quant, imgs[imgn]); } else { - quant_makemap(quant, imgs+imgn, 1); - result = quant_translate(quant, imgs[imgn]); + i_quant_makemap(quant, imgs+imgn, 1); + result = i_quant_translate(quant, imgs[imgn]); } if (!result) { i_mempool_destroy(&mp); quant->mc_colors = orig_colors; EGifCloseFile(gf); - mm_log((1, "error in quant_translate()")); + mm_log((1, "error in i_quant_translate()")); return 0; } if (want_trans) { - quant_transparent(quant, result, imgs[imgn], quant->mc_count); + i_quant_transparent(quant, result, imgs[imgn], quant->mc_count); trans_index = quant->mc_count; } @@ -1947,10 +1947,10 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) { if (glob_paletted) result = quant_paletted(quant, imgs[imgn]); else - result = quant_translate(quant, imgs[imgn]); + result = i_quant_translate(quant, imgs[imgn]); want_trans = glob_want_trans && imgs[imgn]->channels == 4; if (want_trans) { - quant_transparent(quant, result, imgs[imgn], quant->mc_count); + i_quant_transparent(quant, result, imgs[imgn], quant->mc_count); trans_index = quant->mc_count; } map = NULL; diff --git a/hlines.c b/hlines.c index aa5c15b2..e44c4e6e 100644 --- a/hlines.c +++ b/hlines.c @@ -1,4 +1,4 @@ -#include "imagei.h" +#include "imageri.h" #include #define OVERLAPPED(start1, end1, start2, end2) \ diff --git a/image.c b/image.c index eba037c5..19c9823a 100644 --- a/image.c +++ b/image.c @@ -1,5 +1,5 @@ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" /* =head1 NAME @@ -254,7 +254,12 @@ static i_img IIM_base_8bit_direct = /* =item IIM_new(x, y, ch) -Creates a new image object I pixels wide, and I pixels high with I channels. +=item i_img_8_new(x, y, ch) + +=category Image creation + +Creates a new image object I pixels wide, and I pixels high with +I channels. =cut */ @@ -279,8 +284,6 @@ IIM_DESTROY(i_img *im) { /* myfree(cl); */ } - - /* =item i_img_new() @@ -420,6 +423,8 @@ i_img_exorcise(i_img *im) { /* =item i_img_destroy(im) +=category Image + Destroy image and free data via exorcise. im - Image pointer @@ -437,6 +442,8 @@ i_img_destroy(i_img *im) { /* =item i_img_info(im, info) +=category Image + Return image information im - Image pointer @@ -507,6 +514,8 @@ i_img_getchannels(i_img *im) { return im->channels; } /* =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) +=category Image + (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates) (tx,ty) specifies the upper left corner for the target image. pass NULL in trans for non transparent i_colors. @@ -547,6 +556,8 @@ i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_ /* =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty) +=category Image + Copies image data from the area (x1,y1)-[x2,y2] in the source image to a rectangle the same size with it's top-left corner at (tx,ty) in the destination image. @@ -562,22 +573,39 @@ i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) if (x2= src->xsize || y1 >= src->ysize) + return; /* nothing to do */ + if (x2 > src->xsize) + x2 = src->xsize; + if (y2 > src->ysize) + y2 = src->ysize; + if (x1 == x2 || y1 == y2) + return; /* nothing to do */ + mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n", im, src, x1, y1, x2, y2, tx, ty)); if (im->bits == i_8_bits) { - i_color pv; + i_color *row = mymalloc(sizeof(i_color) * (x2-x1)); tty = ty; for(y=y1; y over the image I. +Returns: i_img * =cut */ -void -i_copy(i_img *im, i_img *src) { +i_img * +i_copy(i_img *src) { int y, y1, x1; + i_img *im = i_sametype(src, src->xsize, src->ysize); + + mm_log((1,"i_copy(src %p)\n", src)); - mm_log((1,"i_copy(im* %p,src %p)\n", im, src)); + if (!im) + return NULL; x1 = src->xsize; y1 = src->ysize; if (src->type == i_direct_type) { if (src->bits == i_8_bits) { i_color *pv; - i_img_empty_ch(im, x1, y1, src->channels); pv = mymalloc(sizeof(i_color) * x1); for (y = 0; y < y1; ++y) { @@ -624,14 +661,6 @@ i_copy(i_img *im, i_img *src) { } else { i_fcolor *pv; - if (src->bits == i_16_bits) - i_img_16_new_low(im, x1, y1, src->channels); - else if (src->bits == i_double_bits) - i_img_double_new_low(im, x1, y1, src->channels); - else { - fprintf(stderr, "i_copy(): Unknown image bit size %d\n", src->bits); - return; /* I dunno */ - } pv = mymalloc(sizeof(i_fcolor) * x1); for (y = 0; y < y1; ++y) { @@ -663,12 +692,16 @@ i_copy(i_img *im, i_img *src) { } myfree(vals); } + + return im; } /* =item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy ) +=category Image + Takes the sub image I and overlays it at (I,I) on the image object. @@ -1073,6 +1106,8 @@ i_scale_nn(i_img *im, float scx, float scy) { /* =item i_sametype(i_img *im, int xsize, int ysize) +=category Image creation + Returns an image of the same type (sample size, channels, paletted/direct). For paletted images the palette is copied from the source. @@ -1113,6 +1148,8 @@ i_img *i_sametype(i_img *src, int xsize, int ysize) { /* =item i_sametype_chans(i_img *im, int xsize, int ysize, int channels) +=category Image creation + Returns an image of the same type (sample size). For paletted images the equivalent direct type is returned. diff --git a/image.h b/imager.h similarity index 74% rename from image.h rename to imager.h index 20bfabf3..2fd775c5 100644 --- a/image.h +++ b/imager.h @@ -28,7 +28,7 @@ #define MAXINT 2147483647 #endif -#include "datatypes.h" +#include "imdatatypes.h" undef_int i_has_format(char *frmt); @@ -49,6 +49,7 @@ extern void i_rgb_to_hsv(i_color *color); extern void i_hsv_to_rgb(i_color *color); i_img *IIM_new(int x,int y,int ch); +#define i_img_8_new IIM_new void IIM_DESTROY(i_img *im); i_img *i_img_new( void ); i_img *i_img_empty(i_img *im,int x,int y); @@ -71,24 +72,33 @@ int i_img_getchannels(i_img *im); /* Base functions */ -#if 0 -int i_ppix(i_img *im,int x,int y,i_color *val); -int i_gpix(i_img *im,int x,int y,i_color *val); -int i_ppixf(i_img *im,int x,int y,i_color *val); -int i_gpixf(i_img *im,int x,int y,i_color *val); -#endif +extern int i_ppix(i_img *im,int x,int y,i_color *val); +extern int i_gpix(i_img *im,int x,int y,i_color *val); +extern int i_ppixf(i_img *im,int x,int y,i_fcolor *val); +extern int i_gpixf(i_img *im,int x,int y,i_fcolor *val); #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))) -#if 0 -int i_ppix_d(i_img *im,int x,int y,i_color *val); -int i_gpix_d(i_img *im,int x,int y,i_color *val); -int i_plin_d(i_img *im,int l, int r, int y, i_color *val); -int i_glin_d(i_img *im,int l, int r, int y, i_color *val); -#endif +extern int i_plin(i_img *im, int l, int r, int y, i_color *vals); +extern int i_glin(i_img *im, int l, int r, int y, i_color *vals); +extern int i_plinf(i_img *im, int l, int r, int y, i_fcolor *vals); +extern int i_glinf(i_img *im, int l, int r, int y, i_fcolor *vals); +extern int i_gsamp(i_img *im, int l, int r, int y, i_sample_t *samp, + const int *chans, int chan_count); +extern int i_gsampf(i_img *im, int l, int r, int y, i_fsample_t *samp, + const int *chans, int chan_count); +extern int i_gpal(i_img *im, int x, int r, int y, i_palidx *vals); +extern int i_ppal(i_img *im, int x, int r, int y, i_palidx *vals); +extern int i_addcolors(i_img *im, 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, i_color *color, i_palidx *entry); +extern int i_setcolors(i_img *im, int index, i_color *colors, + int count); #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)) @@ -100,14 +110,6 @@ int i_glin_d(i_img *im,int l, int r, int y, i_color *val); #define i_gsampf(im, l, r, y, samps, chans, count) \ (((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count))) -#define i_psamp(im, l, r, y, samps, chans, count) \ - (((im)->i_f_gsamp)((im), (l), (r), (y), (samps), (chans), (count))) -#define i_psampf(im, l, r, y, samps, chans, count) \ - (((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count))) - - - - #define i_findcolor(im, color, entry) \ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0) @@ -134,57 +136,6 @@ int i_glin_d(i_img *im,int l, int r, int y, i_color *val); #define i_img_type(im) ((im)->type) #define i_img_bits(im) ((im)->bits) -/* Generic fills */ -struct i_fill_tag; - -typedef void (*i_fill_with_color_f) - (struct i_fill_tag *fill, int x, int y, int width, int channels, - i_color *data); -typedef void (*i_fill_with_fcolor_f) - (struct i_fill_tag *fill, int x, int y, int width, int channels, - i_fcolor *data); -typedef void (*i_fill_destroy_f)(struct i_fill_tag *fill); -typedef void (*i_fill_combine_f)(i_color *out, i_color *in, int channels, - int count); -typedef void (*i_fill_combinef_f)(i_fcolor *out, i_fcolor *in, int channels, - int count); - - -typedef struct i_fill_tag -{ - /* called for 8-bit/sample image (and maybe lower) */ - /* this may be NULL, if so call fill_with_fcolor */ - i_fill_with_color_f fill_with_color; - - /* called for other sample sizes */ - /* this must be non-NULL */ - i_fill_with_fcolor_f fill_with_fcolor; - - /* called if non-NULL to release any extra resources */ - i_fill_destroy_f destroy; - - /* if non-zero the caller will fill data with the original data - from the image */ - i_fill_combine_f combine; - i_fill_combinef_f combinef; -} i_fill_t; - -typedef enum { - ic_none, - ic_normal, - ic_multiply, - ic_dissolve, - ic_add, - ic_subtract, - ic_diff, - ic_lighten, - ic_darken, - ic_hue, - ic_sat, - ic_value, - ic_color -} i_combine_t; - extern i_fill_t *i_new_fill_solidf(i_fcolor *c, int combine); extern i_fill_t *i_new_fill_solid(i_color *c, int combine); extern i_fill_t * @@ -213,7 +164,7 @@ void i_arc_aa_cfill(i_img *im,double x,double y,double rad,double d1,double d2,i void i_circle_aa (i_img *im,float x, float y,float rad,i_color *val); void i_copyto (i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty); void i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans); -void i_copy (i_img *im,i_img *src); +i_img* i_copy (i_img *src); int i_rubthru (i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny, int src_maxx, int src_maxy); @@ -248,30 +199,6 @@ float i_img_diff (i_img *im1,i_img *im2); undef_int i_init_fonts( int t1log ); -/* - describes an axis of a MM font. - Modelled on FT2's FT_MM_Axis. - It would be nice to have a default entry too, but FT2 - doesn't support it. -*/ -typedef struct i_font_mm_axis_tag { - char const *name; - int minimum; - int maximum; -} i_font_mm_axis; - -#define IM_FONT_MM_MAX_AXES 4 - -/* - multiple master information for a font, if any - modelled on FT2's FT_Multi_Master. -*/ -typedef struct i_font_mm_tag { - int num_axis; - int num_designs; /* provided but not necessarily useful */ - i_font_mm_axis axis[IM_FONT_MM_MAX_AXES]; -} i_font_mm; - #ifdef HAVE_LIBT1 undef_int i_init_t1( int t1log ); @@ -290,10 +217,6 @@ extern int i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf, #ifdef HAVE_LIBTT -struct TT_Fonthandle_; - -typedef struct TT_Fonthandle_ TT_Fonthandle; - undef_int i_init_tt( void ); TT_Fonthandle* i_tt_new(char *fontname); void i_tt_destroy( TT_Fonthandle *handle ); @@ -311,7 +234,6 @@ int i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, #ifdef HAVE_FT2 -typedef struct FT2_Fonthandle FT2_Fonthandle; extern int i_ft2_init(void); extern FT2_Fonthandle * i_ft2_new(char *name, int index); extern void i_ft2_destroy(FT2_Fonthandle *handle); @@ -413,144 +335,9 @@ extern int i_gen_writer(i_gen_write_data *info, char const *data, int size); extern i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, char *userdata, int maxlength); extern int i_free_gen_write_data(i_gen_write_data *, int flush); -/* transparency handling for quantized output */ -typedef enum i_transp_tag { - tr_none, /* ignore any alpha channel */ - tr_threshold, /* threshold the transparency - uses tr_threshold */ - tr_errdiff, /* error diffusion */ - tr_ordered /* an ordered dither */ -} i_transp; - -/* controls how we build the colour map */ -typedef enum i_make_colors_tag { - mc_none, /* user supplied colour map only */ - mc_web_map, /* Use the 216 colour web colour map */ - mc_addi, /* Addi's algorithm */ - mc_median_cut, /* median cut - similar to giflib, hopefully */ - mc_mask = 0xFF /* (mask for generator) */ -} i_make_colors; - -/* controls how we translate the colours */ -typedef enum i_translate_tag { - pt_giflib, /* get gif lib to do it (ignores make_colours) */ - pt_closest, /* just use the closest match within the hashbox */ - pt_perturb, /* randomly perturb the data - uses perturb_size*/ - pt_errdiff /* error diffusion dither - uses errdiff */ -} i_translate; - -/* Which error diffusion map to use */ -typedef enum i_errdiff_tag { - ed_floyd, /* floyd-steinberg */ - ed_jarvis, /* Jarvis, Judice and Ninke */ - ed_stucki, /* Stucki */ - ed_custom, /* the map found in ed_map|width|height|orig */ - ed_mask = 0xFF, /* mask to get the map */ - ed_bidir = 0x100 /* change direction for each row */ -} i_errdiff; - -/* which ordered dither map to use - currently only available for transparency - I don't know of a way to do ordered dither of an image against some - general palette - */ -typedef enum i_ord_dith_tag -{ - od_random, /* sort of random */ - od_dot8, /* large dot */ - od_dot4, - od_hline, - od_vline, - od_slashline, /* / line dither */ - od_backline, /* \ line dither */ - od_tiny, /* small checkerbox */ - od_custom /* custom 8x8 map */ -} i_ord_dith; - -typedef struct i_gif_pos_tag { - int x, y; -} i_gif_pos; - -/* passed into i_writegif_gen() to control quantization */ -typedef struct i_quantize_tag { - /* how to handle transparency */ - i_transp transp; - /* the threshold at which to make pixels opaque */ - int tr_threshold; - i_errdiff tr_errdiff; - i_ord_dith tr_orddith; - unsigned char tr_custom[64]; - - /* how to make the colour map */ - i_make_colors make_colors; - - /* any existing colours - mc_existing is an existing colour table - mc_count is the number of existing colours - mc_size is the total size of the array that mc_existing points - at - this must be at least 256 - */ - i_color *mc_colors; - int mc_size; - int mc_count; - - /* how we translate the colours */ - i_translate translate; - - /* the error diffusion map to use if translate is mc_errdiff */ - i_errdiff errdiff; - /* the following define the error diffusion values to use if - errdiff is ed_custom. ed_orig is the column on the top row that - represents the current - */ - int *ed_map; - int ed_width, ed_height, ed_orig; - - /* the amount of perturbation to use for translate is mc_perturb */ - int perturb; -} i_quantize; - -typedef struct i_gif_opts { - /* each image has a local color map */ - int each_palette; - - /* images are interlaced */ - int interlace; - - /* time for which image is displayed - (in 1/100 seconds) - default: 0 - */ - int delay_count; - int *delays; - - /* user input flags - default: 0 - */ - int user_input_count; - char *user_input_flags; - - /* disposal - default: 0 */ - int disposal_count; - char *disposal; - - /* this is added to the color table when we make an image transparent */ - i_color tran_color; - - /* image positions */ - int position_count; - i_gif_pos *positions; - - /* Netscape loop extension - number of loops */ - int loop_count; - - /* should be eliminate unused colors? */ - int eliminate_unused; -} i_gif_opts; - -extern void quant_makemap(i_quantize *quant, i_img **imgs, int count); -extern i_palidx *quant_translate(i_quantize *quant, i_img *img); -extern void quant_transparent(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index); +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); extern i_img *i_img_pal_new(int x, int y, int channels, int maxpal); extern i_img *i_img_pal_new_low(i_img *im, int x, int y, int channels, int maxpal); @@ -657,48 +444,6 @@ void i_turbnoise(i_img *im,float xo,float yo,float scale); void i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure); void i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure); i_img *i_diff_image(i_img *im, i_img *im2, int mindist); -typedef enum { - i_fst_linear, - i_fst_curved, - i_fst_sine, - i_fst_sphere_up, - i_fst_sphere_down, - i_fst_end -} i_fountain_seg_type; -typedef enum { - i_fc_direct, - i_fc_hue_up, - i_fc_hue_down, - i_fc_end -} i_fountain_color; -typedef struct { - double start, middle, end; - i_fcolor c[2]; - i_fountain_seg_type type; - i_fountain_color color; -} i_fountain_seg; -typedef enum { - i_fr_none, - i_fr_sawtooth, - i_fr_triangle, - i_fr_saw_both, - i_fr_tri_both -} i_fountain_repeat; -typedef enum { - i_ft_linear, - i_ft_bilinear, - i_ft_radial, - i_ft_radial_square, - i_ft_revolution, - i_ft_conical, - i_ft_end -} i_fountain_type; -typedef enum { - i_fts_none, - i_fts_grid, - i_fts_random, - i_fts_circle -} i_ft_supersample; void 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, @@ -772,6 +517,10 @@ 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); diff --git a/imagei.h b/imageri.h similarity index 99% rename from imagei.h rename to imageri.h index ce58e50a..99d62110 100644 --- a/imagei.h +++ b/imageri.h @@ -5,7 +5,7 @@ #ifndef IMAGEI_H_ #define IMAGEI_H_ -#include "image.h" +#include "imager.h" /* wrapper functions that implement the floating point sample version of a function in terms of the 8-bit sample version diff --git a/datatypes.h b/imdatatypes.h similarity index 50% rename from datatypes.h rename to imdatatypes.h index f4925651..774e9d9f 100644 --- a/datatypes.h +++ b/imdatatypes.h @@ -2,6 +2,7 @@ #define _DATATYPES_H_ #include "imio.h" +#include "imconfig.h" #define MAXCHANNELS 4 @@ -239,5 +240,275 @@ enum bounding_box_index_t { BOUNDING_BOX_COUNT }; +/* Generic fills */ +struct i_fill_tag; + +typedef void (*i_fill_with_color_f) + (struct i_fill_tag *fill, int x, int y, int width, int channels, + i_color *data); +typedef void (*i_fill_with_fcolor_f) + (struct i_fill_tag *fill, int x, int y, int width, int channels, + i_fcolor *data); +typedef void (*i_fill_destroy_f)(struct i_fill_tag *fill); +typedef void (*i_fill_combine_f)(i_color *out, i_color *in, int channels, + int count); +typedef void (*i_fill_combinef_f)(i_fcolor *out, i_fcolor *in, int channels, + int count); + +/* fountain fill types */ +typedef enum { + i_fst_linear, + i_fst_curved, + i_fst_sine, + i_fst_sphere_up, + i_fst_sphere_down, + i_fst_end +} i_fountain_seg_type; +typedef enum { + i_fc_direct, + i_fc_hue_up, + i_fc_hue_down, + i_fc_end +} i_fountain_color; +typedef struct { + double start, middle, end; + i_fcolor c[2]; + i_fountain_seg_type type; + i_fountain_color color; +} i_fountain_seg; +typedef enum { + i_fr_none, + i_fr_sawtooth, + i_fr_triangle, + i_fr_saw_both, + i_fr_tri_both +} i_fountain_repeat; +typedef enum { + i_ft_linear, + i_ft_bilinear, + i_ft_radial, + i_ft_radial_square, + i_ft_revolution, + i_ft_conical, + i_ft_end +} i_fountain_type; +typedef enum { + i_fts_none, + i_fts_grid, + i_fts_random, + i_fts_circle +} i_ft_supersample; + + +typedef struct i_fill_tag +{ + /* called for 8-bit/sample image (and maybe lower) */ + /* this may be NULL, if so call fill_with_fcolor */ + i_fill_with_color_f fill_with_color; + + /* called for other sample sizes */ + /* this must be non-NULL */ + i_fill_with_fcolor_f fill_with_fcolor; + + /* called if non-NULL to release any extra resources */ + i_fill_destroy_f destroy; + + /* if non-zero the caller will fill data with the original data + from the image */ + i_fill_combine_f combine; + i_fill_combinef_f combinef; +} i_fill_t; + +typedef enum { + ic_none, + ic_normal, + ic_multiply, + ic_dissolve, + ic_add, + ic_subtract, + ic_diff, + ic_lighten, + ic_darken, + ic_hue, + ic_sat, + ic_value, + ic_color +} i_combine_t; + +/* + describes an axis of a MM font. + Modelled on FT2's FT_MM_Axis. + It would be nice to have a default entry too, but FT2 + doesn't support it. +*/ +typedef struct i_font_mm_axis_tag { + char const *name; + int minimum; + int maximum; +} i_font_mm_axis; + +#define IM_FONT_MM_MAX_AXES 4 + +/* + multiple master information for a font, if any + modelled on FT2's FT_Multi_Master. +*/ +typedef struct i_font_mm_tag { + int num_axis; + int num_designs; /* provided but not necessarily useful */ + i_font_mm_axis axis[IM_FONT_MM_MAX_AXES]; +} i_font_mm; + +#ifdef HAVE_LIBTT + +struct TT_Fonthandle_; + +typedef struct TT_Fonthandle_ TT_Fonthandle; + +#endif + +#ifdef HAVE_FT2 + +typedef struct FT2_Fonthandle FT2_Fonthandle; + +#endif + +/* transparency handling for quantized output */ +typedef enum i_transp_tag { + tr_none, /* ignore any alpha channel */ + tr_threshold, /* threshold the transparency - uses tr_threshold */ + tr_errdiff, /* error diffusion */ + tr_ordered /* an ordered dither */ +} i_transp; + +/* controls how we build the colour map */ +typedef enum i_make_colors_tag { + mc_none, /* user supplied colour map only */ + mc_web_map, /* Use the 216 colour web colour map */ + mc_addi, /* Addi's algorithm */ + mc_median_cut, /* median cut - similar to giflib, hopefully */ + mc_mask = 0xFF /* (mask for generator) */ +} i_make_colors; + +/* controls how we translate the colours */ +typedef enum i_translate_tag { + pt_giflib, /* get gif lib to do it (ignores make_colours) */ + pt_closest, /* just use the closest match within the hashbox */ + pt_perturb, /* randomly perturb the data - uses perturb_size*/ + pt_errdiff /* error diffusion dither - uses errdiff */ +} i_translate; + +/* Which error diffusion map to use */ +typedef enum i_errdiff_tag { + ed_floyd, /* floyd-steinberg */ + ed_jarvis, /* Jarvis, Judice and Ninke */ + ed_stucki, /* Stucki */ + ed_custom, /* the map found in ed_map|width|height|orig */ + ed_mask = 0xFF, /* mask to get the map */ + ed_bidir = 0x100 /* change direction for each row */ +} i_errdiff; + +/* which ordered dither map to use + currently only available for transparency + I don't know of a way to do ordered dither of an image against some + general palette + */ +typedef enum i_ord_dith_tag +{ + od_random, /* sort of random */ + od_dot8, /* large dot */ + od_dot4, + od_hline, + od_vline, + od_slashline, /* / line dither */ + od_backline, /* \ line dither */ + od_tiny, /* small checkerbox */ + od_custom /* custom 8x8 map */ +} i_ord_dith; + +typedef struct i_gif_pos_tag { + int x, y; +} i_gif_pos; + +/* passed into i_writegif_gen() to control quantization */ +typedef struct i_quantize_tag { + /* how to handle transparency */ + i_transp transp; + /* the threshold at which to make pixels opaque */ + int tr_threshold; + i_errdiff tr_errdiff; + i_ord_dith tr_orddith; + unsigned char tr_custom[64]; + + /* how to make the colour map */ + i_make_colors make_colors; + + /* any existing colours + mc_existing is an existing colour table + mc_count is the number of existing colours + mc_size is the total size of the array that mc_existing points + at - this must be at least 256 + */ + i_color *mc_colors; + int mc_size; + int mc_count; + + /* how we translate the colours */ + i_translate translate; + + /* the error diffusion map to use if translate is mc_errdiff */ + i_errdiff errdiff; + /* the following define the error diffusion values to use if + errdiff is ed_custom. ed_orig is the column on the top row that + represents the current + */ + int *ed_map; + int ed_width, ed_height, ed_orig; + + /* the amount of perturbation to use for translate is mc_perturb */ + int perturb; +} i_quantize; + +typedef struct i_gif_opts { + /* each image has a local color map */ + int each_palette; + + /* images are interlaced */ + int interlace; + + /* time for which image is displayed + (in 1/100 seconds) + default: 0 + */ + int delay_count; + int *delays; + + /* user input flags + default: 0 + */ + int user_input_count; + char *user_input_flags; + + /* disposal + default: 0 */ + int disposal_count; + char *disposal; + + /* this is added to the color table when we make an image transparent */ + i_color tran_color; + + /* image positions */ + int position_count; + i_gif_pos *positions; + + /* Netscape loop extension - number of loops */ + int loop_count; + + /* should be eliminate unused colors? */ + int eliminate_unused; +} i_gif_opts; + + + #endif diff --git a/imexif.h b/imexif.h index 6221ab35..70a2b161 100644 --- a/imexif.h +++ b/imexif.h @@ -1,9 +1,9 @@ /* imexif.h - interface to Exif handling */ #ifndef IMAGER_IMEXIF_H -#define IMAGER_IMEXIT_H +#define IMAGER_IMEXIF_H #include -#include "imagei.h" +#include "imageri.h" extern int i_int_decode_exif(i_img *im, unsigned char *data, size_t length); diff --git a/imext.c b/imext.c new file mode 100644 index 00000000..fc7fce4e --- /dev/null +++ b/imext.c @@ -0,0 +1,454 @@ +#include "imexttypes.h" +#include "imager.h" + +/* + DON'T ADD CASTS TO THESE +*/ +im_ext_funcs imager_function_table = + { + mymalloc, + myfree, + myrealloc, + + i_img_8_new, + i_img_16_new, + i_img_double_new, + i_img_pal_new, + i_img_destroy, + i_sametype, + i_sametype_chans, + i_img_info, + + i_ppix, + i_gpix, + i_ppixf, + i_gpixf, + i_plin, + i_glin, + i_plinf, + i_glinf, + i_gsamp, + i_gsampf, + i_gpal, + i_ppal, + i_addcolors, + i_getcolors, + i_colorcount, + i_maxcolors, + i_findcolor, + i_setcolors, + + i_new_fill_solid, + i_new_fill_solidf, + i_new_fill_hatch, + i_new_fill_hatchf, + i_new_fill_image, + i_new_fill_fount, + i_fill_destroy, + + i_quant_makemap, + i_quant_translate, + i_quant_transparent, + + i_clear_error, + i_push_error, + i_push_errorf, + i_push_errorvf, + + i_tags_new, + i_tags_set, + i_tags_setn, + i_tags_destroy, + i_tags_find, + i_tags_findn, + i_tags_delete, + i_tags_delbyname, + i_tags_delbycode, + i_tags_get_float, + i_tags_set_float, + i_tags_set_float2, + i_tags_get_int, + i_tags_get_string, + i_tags_get_color, + i_tags_set_color, + + i_box, + i_box_filled, + i_box_cfill, + i_line, + i_line_aa, + i_arc, + i_arc_aa, + i_arc_cfill, + i_arc_aa_cfill, + i_circle_aa, + i_flood_fill, + i_flood_cfill, + + i_copyto, + i_copyto_trans, + i_copy, + i_rubthru, + }; + +/* in general these functions aren't called by Imager internally, but + only via the pointers above, since faster macros that call the + image vtable pointers are used. + + () are used around the function names to prevent macro replacement + on the function names. +*/ + +/* +=item i_ppix(im, x, y, color) + +=category Drawing + +Sets the pixel at (x,y) to I. + +Returns 0 if the pixel was drawn, or -1 if not. + +Does no alpha blending, just copies the channels from the supplied +color to the image. + +=cut +*/ + +int +(i_ppix)(i_img *im,int x,int y,i_color *val) { + return i_ppix(im, x, y, val); +} + +/* +=item i_gpix(im, x, y, color) + +=category Drawing + +Retrieves the I of the pixel (x,y). + +Returns 0 if the pixel was retrieved, or -1 if not. + +=cut +*/ + +int +(i_gpix)(i_img *im,int x,int y,i_color *val) { + return i_gpix(im, x, y, val); +} + +/* +=item i_ppixf(im, x, y, fcolor) + +=category Drawing + +Sets the pixel at (x,y) to the floating point color I. + +Returns 0 if the pixel was drawn, or -1 if not. + +Does no alpha blending, just copies the channels from the supplied +color to the image. + +=cut +*/ +int +(i_ppixf)(i_img *im,int x,int y,i_fcolor *val) { + return i_ppixf(im, x, y, val); +} + +/* +=item i_gpixf(im, x, y, fcolor) + +=category Drawing + +Retrieves the color of the pixel (x,y) as a floating point color into +I. + +Returns 0 if the pixel was retrieved, or -1 if not. + +=cut +*/ + +int +(i_gpixf)(i_img *im,int x,int y,i_fcolor *val) { + return i_gpixf(im, x, y, val); +} + +/* +=item i_plin(im, l, r, y, colors) + +=category Drawing + +Sets (r-l) pixels starting from (l,y) using (r-l) values from +I. + +Returns the number of pixels set. + +=cut +*/ + +int +(i_plin)(i_img *im, int l, int r, int y, i_color *vals) { + return i_plin(im, l, r, y, vals); +} + +/* +=item i_glin(im, l, r, y, colors) + +=category Drawing + +Retrieves (r-l) pixels starting from (l,y) into I. + +Returns the number of pixels retrieved. + +=cut +*/ + +int +(i_glin)(i_img *im, int l, int r, int y, i_color *vals) { + return i_glin(im, l, r, y, vals); +} + +/* +=item i_plinf(im, l, r, fcolors) + +=category Drawing + +Sets (r-l) pixels starting from (l,y) using (r-l) floating point +colors from I. + +Returns the number of pixels set. + +=cut +*/ + +int +(i_plinf)(i_img *im, int l, int r, int y, i_fcolor *vals) { + return i_plinf(im, l, r, y, vals); +} + +/* +=item i_glinf(im, l, r, y, colors) + +=category Drawing + +Retrieves (r-l) pixels starting from (l,y) into I as floating +point colors. + +Returns the number of pixels retrieved. + +=cut +*/ + +int +(i_glinf)(i_img *im, int l, int r, int y, i_fcolor *vals) { + return i_glinf(im, l, r, y, vals); +} + +/* +=item i_gsamp(im, l, r, y, samp, chans, chan_count) + +=category Drawing + +Reads sample values from im for the horizontal line (l, y) to (r-1,y) +for the channels specified by chans, an array of int with chan_count +elements. + +If chans is NULL then the first chan_count channels are retrieved for +each pixel. + +Returns the number of samples read (which should be (r-l) * +chan_count) + +=cut +*/ +int +(i_gsamp)(i_img *im, int l, int r, int y, i_sample_t *samp, + const int *chans, int chan_count) { + return i_gsamp(im, l, r, y, samp, chans, chan_count); +} + +/* +=item i_gsampf(im, l, r, y, samp, chans, chan_count) + +=category Drawing + +Reads floating point sample values from im for the horizontal line (l, +y) to (r-1,y) for the channels specified by chans, an array of int +with chan_count elements. + +If chans is NULL then the first chan_count channels are retrieved for +each pixel. + +Returns the number of samples read (which should be (r-l) * +chan_count) + +=cut +*/ +int +(i_gsampf)(i_img *im, int l, int r, int y, i_fsample_t *samp, + const int *chans, int chan_count) { + return i_gsampf(im, l, r, y, samp, chans, chan_count); +} + +/* +=item i_gpal(im, x, r, y, indexes) + +=category Drawing + +Reads palette indexes for the horizontal line (x, y) to (r-1, y) into +indexes. + +Returns the number of indexes read. + +Always returns 0 for direct color images. + +=cut +*/ +int +(i_gpal)(i_img *im, int x, int r, int y, i_palidx *vals) { + return i_gpal(im, x, r, y, vals); +} + +/* +=item i_ppal(im, x, r, y, indexes) + +=category Drawing + +Writes palette indexes for the horizontal line (x, y) to (r-1, y) from +indexes. + +Returns the number of indexes written. + +Always returns 0 for direct color images. + +=cut +*/ +int +(i_ppal)(i_img *im, int x, int r, int y, i_palidx *vals) { + return i_ppal(im, x, r, y, vals); +} + +/* +=item i_addcolors(im, colors, count) + +=category Paletted images + +Adds colors to the image's palette. + +On success returns the index of the lowest color added. + +On failure returns -1. + +Always fails for direct color images. + +=cut +*/ + +int +(i_addcolors)(i_img *im, i_color *colors, int count) { + return i_addcolors(im, colors, count); +} + +/* +=item i_getcolors(im, index, colors, count) + +=category Paletted images + +Retrieves I colors starting from I in the image's +palette. + +On success stores the colors into I and returns true. + +On failure returns false. + +Always fails for direct color images. + +Fails if there are less than I+I colors in the image's +palette. + +=cut +*/ + +int +(i_getcolors)(i_img *im, int i, i_color *colors, int count) { + return i_getcolors(im, i, colors, count); +} + +/* +=item i_colorcount(im) + +=category Paletted images + +Returns the number of colors in the image's palette. + +Returns -1 for direct images. + +=cut +*/ + +int +(i_colorcount)(i_img *im) { + return i_colorcount(im); +} + +/* +=item i_maxcolors(im) + +=category Paletted images + +Returns the maximum number of colors the palette can hold for the +image. + +Returns -1 for direct color images. + +=cut +*/ + +int +(i_maxcolors)(i_img *im) { + return i_maxcolors(im); +} + +/* +=item i_findcolor(im, color, &entry) + +=category Paletted images + +Searches the images palette for the given color. + +On success sets *I to the index of the color, and returns true. + +On failure returns false. + +Always fails on direct color images. + +=cut +*/ +int +(i_findcolor)(i_img *im, i_color *color, i_palidx *entry) { + return i_findcolor(im, color, entry); +} + +/* +=item i_setcolors(im, index, colors, count) + +=category Paletted images + +Sets I colors starting from I in the image's palette. + +On sucess returns true. + +On failure returns false. + +The image must have at least I+I colors in it's palette +for this to succeed. + +Always fails on direct color images. + +=cut +*/ +int +(i_setcolors)(i_img *im, int index, i_color *colors, int count) { + return i_setcolors(im, index, colors, count); +} + diff --git a/imext.h b/imext.h new file mode 100644 index 00000000..e5b7d989 --- /dev/null +++ b/imext.h @@ -0,0 +1,163 @@ +#ifndef IMAGER_IMEXT_H_ +#define IMAGER_IMEXT_H_ + +#include "imexttypes.h" + +extern im_ext_funcs *imager_function_ext_table; + +#define DEFINE_IMAGER_CALLBACKS im_ext_funcs *imager_function_ext_table + +#define PERL_INITIALIZE_IMAGER_CALLBACKS \ + imager_function_ext_table = INT2PTR(im_ext_funcs *, SvIV(get_sv(PERL_FUNCTION_TABLE_NAME, 1))) + +/* just for use here */ +#define im_extt imager_function_ext_table + +#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))) + +#define i_img_8_new(xsize, ysize, channels) ((im_extt->f_i_img_8_new)((xsize), (ysize), (channels))) +#define i_img_16_new(xsize, ysize, channels) ((im_extt->f_i_img_16_new)((xsize), (ysize), (channels))) +#define i_img_double_new(xsize, ysize, channels) ((im_extt->f_i_img_double_new)((xsize), (ysize), (channels))) +#define i_img_pal_new(xsize, ysize, channels, maxpal) ((im_extt->f_i_img_pal_new)((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)->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))) + +#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) +#else +#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_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 i_clear_error() ((im_extt->f_i_clear_error)()) +#define i_push_error(code, msg) ((im_extt->f_i_push_error)((code), (msg))) +#define i_push_errorf (im_extt->f_i_push_errorf) +#define i_push_errorvf(code, fmt, list) \ + ((im_extt->f_i_push_errorvf)((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_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))) + +#endif diff --git a/imextdef.h b/imextdef.h new file mode 100644 index 00000000..d1c5f50b --- /dev/null +++ b/imextdef.h @@ -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 diff --git a/imexttypes.h b/imexttypes.h new file mode 100644 index 00000000..4c4c5594 --- /dev/null +++ b/imexttypes.h @@ -0,0 +1,119 @@ +#ifndef IMAGER_IMEXTTYPES_H_ +#define IMAGER_IMEXTTYPES_H_ + +/* keep this file simple - apidocs.perl parses it. */ + +#include "imdatatypes.h" + +typedef struct { + void * (*f_mymalloc)(int size); + void (*f_myfree)(void *block); + void * (*f_myrealloc)(void *block, size_t newsize); + + i_img *(*f_i_img_8_new)(int xsize, int ysize, int channels); + i_img *(*f_i_img_16_new)(int xsize, int ysize, int channels); + i_img *(*f_i_img_double_new)(int xsize, int ysize, int channels); + i_img *(*f_i_img_pal_new)(int xsize, int ysize, int channels, int maxpal); + void (*f_i_img_destroy)(i_img *im); + i_img *(*f_i_sametype)(i_img *im, int xsize, int ysize); + i_img *(*f_i_sametype_chans)(i_img *im, int xsize, int ysize, int channels); + void (*f_i_img_info)(i_img *im, int *info); + + int (*f_i_ppix)(i_img *im, int x, int y, i_color *val); + int (*f_i_gpix)(i_img *im, int x, int y, i_color *val); + int (*f_i_ppixf)(i_img *im, int x, int y, i_fcolor *val); + int (*f_i_gpixf)(i_img *im, int x, int y, i_fcolor *val); + int (*f_i_plin)(i_img *im, int l, int r, int y, i_color *vals); + int (*f_i_glin)(i_img *im, int l, int r, int y, i_color *vals); + int (*f_i_plinf)(i_img *im, int l, int r, int y, i_fcolor *vals); + int (*f_i_glinf)(i_img *im, int l, int r, int y, i_fcolor *vals); + int (*f_i_gsamp)(i_img *im, int l, int r, int y, i_sample_t *samp, + const int *chans, int chan_count); + int (*f_i_gsampf)(i_img *im, int l, int r, int y, i_fsample_t *samp, + const int *chans, int chan_count); + int (*f_i_gpal)(i_img *im, int x, int r, int y, i_palidx *vals); + int (*f_i_ppal)(i_img *im, int x, int r, int y, i_palidx *vals); + int (*f_i_addcolors)(i_img *im, 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, i_color *color, i_palidx *entry); + int (*f_i_setcolors)(i_img *im, int index, i_color *colors, + int count); + + i_fill_t *(*f_i_new_fill_solid)(i_color *c, int combine); + i_fill_t *(*f_i_new_fill_solidf)(i_fcolor *c, int combine); + + i_fill_t *(*f_i_new_fill_hatch)(i_color *fg, i_color *bg, int combine, + int hatch, unsigned char *cust_hatch, + int dx, int dy); + i_fill_t *(*f_i_new_fill_hatchf)(i_fcolor *fg, i_fcolor *bg, int combine, + int hatch, unsigned char *cust_hatch, + int dx, int dy); + i_fill_t *(*f_i_new_fill_image)(i_img *im, double *matrix, int xoff, + int 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); + void (*f_i_push_error)(int code, char const *msg); + void (*f_i_push_errorf)(int code, char const *fmt, ...); + void (*f_i_push_errorvf)(int code, char const *fmt, va_list); + + 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, int x1, int y1, int x2, int y2, i_color *val); + void (*f_i_box_filled)(i_img *im, int x1, int y1, int x2, int y2, i_color *val); + void (*f_i_box_cfill)(i_img *im, int x1, int y1, int x2, int y2, i_fill_t *fill); + void (*f_i_line)(i_img *im, int x1, int y1, int x2, int y2, i_color *val, int endp); + void (*f_i_line_aa)(i_img *im, int x1, int y1, int x2, int y2, i_color *val, int endp); + void (*f_i_arc)(i_img *im, int x, int y, float rad, float d1, float d2, i_color *val); + void (*f_i_arc_aa)(i_img *im, double x, double y, double rad, double d1, double d2, i_color *val); + void (*f_i_arc_cfill)(i_img *im, int x, int y, float rad, float d1, float 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, float x, float y, float rad, i_color *val); + int (*f_i_flood_fill)(i_img *im, int seedx, int seedy, i_color *dcol); + int (*f_i_flood_cfill)(i_img *im, int seedx, int seedy, i_fill_t *fill); + + void (*f_i_copyto)(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty); + void (*f_i_copyto_trans)(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty, i_color *trans); + i_img *(*f_i_copy)(i_img *im); + int (*f_i_rubthru)(i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny, int src_maxx, int src_maxy); +} im_ext_funcs; + +#define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table" + +#endif diff --git a/img16.c b/img16.c index 5db81723..af477cef 100644 --- a/img16.c +++ b/img16.c @@ -20,8 +20,8 @@ sample image type to work with. =cut */ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" static int i_ppix_d16(i_img *im, int x, int y, i_color *val); static int i_gpix_d16(i_img *im, int x, int y, i_color *val); @@ -136,7 +136,7 @@ typedef unsigned short i_sample16_t; #endif /* -=item i_img_16_new(int x, int y, int ch) +=item i_img_16_new_low(int x, int y, int ch) Creates a new 16-bit per sample image. @@ -188,6 +188,18 @@ i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) { return im; } +/* +=item i_img_16_new(x, y, ch) + +=category Image creation + +Create a new 16-bit/sample image. + +Returns the image on success, or NULL on failure. + +=cut +*/ + i_img *i_img_16_new(int x, int y, int ch) { i_img *im; diff --git a/imgdouble.c b/imgdouble.c index 5f063a62..21d0b4c3 100644 --- a/imgdouble.c +++ b/imgdouble.c @@ -20,8 +20,8 @@ sample image type to work with. =cut */ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" static int i_ppix_ddoub(i_img *im, int x, int y, i_color *val); static int i_gpix_ddoub(i_img *im, int x, int y, i_color *val); @@ -81,6 +81,8 @@ static i_img IIM_base_double_direct = /* =item i_img_double_new(int x, int y, int ch) +=category Image creation + Creates a new double per sample image. =cut diff --git a/imperl.h b/imperl.h new file mode 100644 index 00000000..93db8379 --- /dev/null +++ b/imperl.h @@ -0,0 +1,33 @@ +/* + 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 + +#ifdef HAVE_FT2 +typedef FT2_Fonthandle* Imager__Font__FT2; +#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; + +#endif diff --git a/jpeg.c b/jpeg.c index 1ba75ac4..42535d5a 100644 --- a/jpeg.c +++ b/jpeg.c @@ -28,7 +28,7 @@ Reads and writes JPEG images #include #include "iolayer.h" -#include "imagei.h" +#include "imageri.h" #include "jpeglib.h" #include "jerror.h" #include diff --git a/lib/Imager/API.pm b/lib/Imager/API.pm new file mode 100644 index 00000000..acb63975 --- /dev/null +++ b/lib/Imager/API.pm @@ -0,0 +1,211 @@ +=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: + PERL_INITIALIZE_IMAGER_CALLBACKS; + + +=head1 DESCRIPTION + +The API allows you to access Imager functions at the C level from XS +and from 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 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 Imagers existing methods, such as filter +or file format handlers. + +=back + +See L for information on using Imager's Inline::C +support. + +=head1 Types + +The API makes the following types visible: + +=over + +=item * + +i_img - used to represent an image + +=item * + +i_color - used to represent a color with up to 8 bits per sample. + +=item * + +i_fcolor - used to represent a color with a double per sample. + +=item * + +i_fill_t - an abstract fill + +=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 - images + +This contains the dimensions of the image (xsize, ysize, channels), +image metadata (ch_mask, bits, type, virtual), potentially image data +(idata) and the 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. + +=head2 i_color - 8-bit 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 * + +gray - single member gray_color. + +=item * + +rgb - r, g, b members. + +=item * + +rgba - r, g, b, a members. + +=item * + +channels - array of channels. + +=back + +=head2 i_fcolor - floating point color + +Similar to i_fcolor except that each component is a double instead of +an unsigned char. + +=head2 i_fill_t - fill objects + +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. + +=head1 Create an XS module using the Imager API + +=head2 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 BOOT code: + + BOOT: + PERL_INITIALIZE_IMAGER_CALLBACKS; + +=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 Makefile.PL + +If you're creating an XS module that depends on Imager's API your +Makefile.PL will need to do the following: + +=over + +=item * + +C + +=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, + }, + +=back + +=head1 AUTHOR + +Tony Cook + +=head1 SEE ALSO + +Imager, Imager::ExtUtils, Imager::APIRef, Imager::Inline + +=cut diff --git a/lib/Imager/APIRef.pm b/lib/Imager/APIRef.pm new file mode 100644 index 00000000..1abc984c --- /dev/null +++ b/lib/Imager/APIRef.pm @@ -0,0 +1,1007 @@ +Do not edit this file, it is generated automatically by apidocs.perl +from Imager's source files. + +Each function description has a comment listing the source file and +line number where you can find the documentation. + +=head1 NAME + +Imager::APIRef - Imager's C API. + +=head1 SYNOPSIS + + i_color color; + color.rgba.red = 255; color.rgba.green = 0; color.rgba.blue = 255; + i_fill_t *fill = i_new_fill_...(...); + + + # Drawing + i_arc(im, 50, 50, 20, 45, 135, &color); + i_arc_aa(im, 50, 50, 35, 90, 135, &color); + i_arc_aa_cfill(im, 50, 50, 35, 90, 135, fill); + i_arc_cfill(im, 50, 50, 35, 90, 135, fill); + i_box(im, 0, 0, im->xsize-1, im->ysize-1, &color). + i_box_cfill(im, 0, 0, im->xsize-1, im->ysize-1, fill); + i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &color); + i_circle_aa(im, 50, 50, 45, &color); + i_flood_cfill(im, 50, 50, fill); + i_flood_fill(im, 50, 50, &color); + + # Error handling + + # Fills + fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, + i_fr_triangle, 0, i_fts_grid, 9, 1, segs); + + # Image + + # Image creation + + # Image quantization + + # Paletted images + + # Tags + + i_fill_destroy(fill); + +=head1 DESCRIPTION + +=head2 Drawing + +=over + +=item i_arc(im, x, y, rad, d1, d2, color) + + +Fills an arc centered at (x,y) with radius I covering the range +of angles in degrees from d1 to d2, with the color. + + +=for comment +From: Line 205 in draw.c + +=item i_arc_aa(im, x, y, rad, d1, d2, color) + + +Antialias fills an arc centered at (x,y) with radius I covering +the range of angles in degrees from d1 to d2, with the color. + + +=for comment +From: Line 329 in draw.c + +=item i_arc_aa_cfill(im, x, y, rad, d1, d2, fill) + + +Antialias fills an arc centered at (x,y) with radius I covering +the range of angles in degrees from d1 to d2, with the fill object. + + +=for comment +From: Line 355 in draw.c + +=item i_arc_cfill(im, x, y, rad, d1, d2, fill) + + +Fills an arc centered at (x,y) with radius I covering the range +of angles in degrees from d1 to d2, with the fill object. + + +=for comment +From: Line 230 in draw.c + +=item i_box(im, x1, y1, x2, y2, color) + + +Outlines the box from (x1,y1) to (x2,y2) inclusive with I. + + +=for comment +From: Line 531 in draw.c + +=item i_box_cfill(im, x1, y1, x2, y2, fill) + + +Fills the box from (x1,y1) to (x2,y2) inclusive with fill. + + +=for comment +From: Line 574 in draw.c + +=item i_box_filled(im, x1, y1, x2, y2, color) + + +Fills the box from (x1,y1) to (x2,y2) inclusive with color. + + +=for comment +From: Line 556 in draw.c + +=item i_circle_aa(im, x, y, rad, color) + + +Antialias fills a circle centered at (x,y) for radius I with +color. + + +=for comment +From: Line 477 in draw.c + +=item i_flood_cfill(im, seedx, seedy, fill) + + +Flood fills the 4-connected region starting from the point (seedx, +seedy) with I. + +Returns false if (seedx, seedy) are outside the image. + + +=for comment +From: Line 1332 in draw.c + +=item i_flood_fill(im, seedx, seedy, color) + + +Flood fills the 4-connected region starting from the point (seedx, +seedy) with I. + +Returns false if (seedx, seedy) are outside the image. + + +=for comment +From: Line 1295 in draw.c + +=item i_glin(im, l, r, y, colors) + + +Retrieves (r-l) pixels starting from (l,y) into I. + +Returns the number of pixels retrieved. + + +=for comment +From: Line 195 in imext.c + +=item i_glinf(im, l, r, y, colors) + + +Retrieves (r-l) pixels starting from (l,y) into I as floating +point colors. + +Returns the number of pixels retrieved. + + +=for comment +From: Line 230 in imext.c + +=item i_gpal(im, x, r, y, indexes) + + +Reads palette indexes for the horizontal line (x, y) to (r-1, y) into +indexes. + +Returns the number of indexes read. + +Always returns 0 for direct color images. + + +=for comment +From: Line 294 in imext.c + +=item i_gpix(im, x, y, color) + + +Retrieves the I of the pixel (x,y). + +Returns 0 if the pixel was retrieved, or -1 if not. + + +=for comment +From: Line 123 in imext.c + +=item i_gpixf(im, x, y, fcolor) + + +Retrieves the color of the pixel (x,y) as a floating point color into +I. + +Returns 0 if the pixel was retrieved, or -1 if not. + + +=for comment +From: Line 159 in imext.c + +=item i_gsamp(im, l, r, y, samp, chans, chan_count) + + +Reads sample values from im for the horizontal line (l, y) to (r-1,y) +for the channels specified by chans, an array of int with chan_count +elements. + +If chans is NULL then the first chan_count channels are retrieved for +each pixel. + +Returns the number of samples read (which should be (r-l) * +chan_count) + + +=for comment +From: Line 248 in imext.c + +=item i_gsampf(im, l, r, y, samp, chans, chan_count) + + +Reads floating point sample values from im for the horizontal line (l, +y) to (r-1,y) for the channels specified by chans, an array of int +with chan_count elements. + +If chans is NULL then the first chan_count channels are retrieved for +each pixel. + +Returns the number of samples read (which should be (r-l) * +chan_count) + + +=for comment +From: Line 271 in imext.c + +=item i_line(im, x1, y1, x2, y2, val, endp) + + +Draw a line to image using bresenhams linedrawing algorithm + + im - image to draw to + x1 - starting x coordinate + y1 - starting x coordinate + x2 - starting x coordinate + y2 - starting x coordinate + val - color to write to image + endp - endpoint flag (boolean) + + +=for comment +From: Line 645 in draw.c + +=item i_line_aa(im, x1, x2, y1, y2, color, endp) + + +Antialias draws a line from (x1,y1) to (x2, y2) in color. + +The point (x2, y2) is drawn only if endp is set. + + +=for comment +From: Line 849 in draw.c + +=item i_plin(im, l, r, y, colors) + + +Sets (r-l) pixels starting from (l,y) using (r-l) values from +I. + +Returns the number of pixels set. + + +=for comment +From: Line 177 in imext.c + +=item i_plinf(im, l, r, fcolors) + + +Sets (r-l) pixels starting from (l,y) using (r-l) floating point +colors from I. + +Returns the number of pixels set. + + +=for comment +From: Line 212 in imext.c + +=item i_ppal(im, x, r, y, indexes) + + +Writes palette indexes for the horizontal line (x, y) to (r-1, y) from +indexes. + +Returns the number of indexes written. + +Always returns 0 for direct color images. + + +=for comment +From: Line 313 in imext.c + +=item i_ppix(im, x, y, color) + + +Sets the pixel at (x,y) to I. + +Returns 0 if the pixel was drawn, or -1 if not. + +Does no alpha blending, just copies the channels from the supplied +color to the image. + + +=for comment +From: Line 103 in imext.c + +=item i_ppixf(im, x, y, fcolor) + + +Sets the pixel at (x,y) to the floating point color I. + +Returns 0 if the pixel was drawn, or -1 if not. + +Does no alpha blending, just copies the channels from the supplied +color to the image. + + +=for comment +From: Line 140 in imext.c + + +=back + +=head2 Error handling + +=over + +=item i_clear_error() + + +Clears the error stack. + +Called by any imager function before doing any other processing. + + +=for comment +From: Line 185 in error.c + +=item i_push_error(int code, char const *msg) + + +Called by an imager function to push an error message onto the stack. + +No message is pushed if the stack is full (since this means someone +forgot to call i_clear_error(), or that a function that doesn't do +error handling is calling function that does.). + + +=for comment +From: Line 211 in error.c + +=item i_push_errorf(int code, char const *fmt, ...) + + +A version of i_push_error() that does printf() like formating. + + +=for comment +From: Line 273 in error.c + +=item i_push_errorvf(int code, char const *fmt, va_list ap) + + +Intended for use by higher level functions, takes a varargs pointer +and a format to produce the finally pushed error message. + + +=for comment +From: Line 249 in error.c + + +=back + +=head2 Fills + +=over + +=item i_fill_destroy(fill) + + +Call to destroy any fill object. + + +=for comment +From: Line 196 in fills.c + +=item i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) + + + +Creates a new general fill which fills with a fountain fill. + + +=for comment +From: Line 1666 in filters.c + +=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) + + +Creates a new hatched fill with the fg color used for the 1 bits in +the hatch and bg for the 0 bits. If combine is non-zero alpha values +will be combined. + +If cust_hatch is non-NULL it should be a pointer to 8 bytes of the +hash definition, with the high-bits to the left. + +If cust_hatch is NULL then one of the standard hatches is used. + +(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area. + + +=for comment +From: Line 427 in fills.c + +=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) + + +Creates a new hatched fill with the fg color used for the 1 bits in +the hatch and bg for the 0 bits. If combine is non-zero alpha values +will be combined. + +If cust_hatch is non-NULL it should be a pointer to 8 bytes of the +hash definition, with the high-bits to the left. + +If cust_hatch is NULL then one of the standard hatches is used. + +(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area. + + +=for comment +From: Line 452 in fills.c + +=item i_new_fill_image(im, matrix, xoff, yoff, combine) + + +Create an image based fill. + +matrix is an array of 9 doubles representing a transformation matrix. + +xoff and yoff are the offset into the image to start filling from. + + +=for comment +From: Line 489 in fills.c + +=item i_new_fill_solid(color, combine) + + +Create a solid fill based on an 8-bit color. + +If combine is non-zero then alpha values will be combined. + + +=for comment +From: Line 244 in fills.c + +=item i_new_fill_solidf(color, combine) + + +Create a solid fill based on a float color. + +If combine is non-zero then alpha values will be combined. + + +=for comment +From: Line 213 in fills.c + + +=back + +=head2 Image + +=over + +=item i_copy(src) + + +Creates a new image that is a copy of src. + +Tags are not copied, only the image data. + +Returns: i_img * + + +=for comment +From: Line 626 in image.c + +=item i_copyto(dest, src, x1, y1, x2, y2, tx, ty) + + +Copies image data from the area (x1,y1)-[x2,y2] in the source image to +a rectangle the same size with it's top-left corner at (tx,ty) in the +destination image. + +If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped. + + +=for comment +From: Line 557 in image.c + +=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) + + +(x1,y1) (x2,y2) specifies the region to copy (in the source coordinates) +(tx,ty) specifies the upper left corner for the target image. +pass NULL in trans for non transparent i_colors. + + +=for comment +From: Line 515 in image.c + +=item i_img_destroy(im) + + +Destroy image and free data via exorcise. + + im - Image pointer + + +=for comment +From: Line 424 in image.c + +=item i_img_info(im, info) + + +Return image information + + im - Image pointer + info - pointer to array to return data + +info is an array of 4 integers with the following values: + + info[0] - width + info[1] - height + info[2] - channels + info[3] - channel mask + + +=for comment +From: Line 443 in image.c + +=item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy ) + + +Takes the sub image I and +overlays it at (I,I) on the image object. + +The alpha channel of each pixel in I is used to control how much +the existing colour in I is replaced, if it is 255 then the colour +is completely replaced, if it is 0 then the original colour is left +unmodified. + + +=for comment +From: Line 701 in image.c + + +=back + +=head2 Image creation + +=over + +=item i_img_16_new(x, y, ch) + + +Create a new 16-bit/sample image. + +Returns the image on success, or NULL on failure. + + +=for comment +From: Line 192 in img16.c + +=item i_img_8_new(x, y, ch) + + +Creates a new image object I pixels wide, and I pixels high with +I channels. + + +=for comment +From: Line 257 in image.c + +=item i_img_double_new(int x, int y, int ch) + + +Creates a new double per sample image. + + +=for comment +From: Line 82 in imgdouble.c + +=item i_img_pal_new(x, y, channels, maxpal) + + +Creates a new paletted image of the supplied dimensions. + +Returns a new image or NULL on failure. + + +=for comment +From: Line 136 in palimg.c + +=item i_sametype(i_img *im, int xsize, int ysize) + + +Returns an image of the same type (sample size, channels, paletted/direct). + +For paletted images the palette is copied from the source. + + +=for comment +From: Line 1107 in image.c + +=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels) + + +Returns an image of the same type (sample size). + +For paletted images the equivalent direct type is returned. + + +=for comment +From: Line 1149 in image.c + + +=back + +=head2 Image quantization + +=over + +=item i_quant_makemap(quant, imgs, count) + + +Analyzes the I images in I according to the rules in +I to build a color map (optimal or not depending on +quant->make_colors). + + +=for comment +From: Line 30 in quant.c + +=item i_quant_translate(quant, img) + + +Quantize the image given the palette in quant. + +On success returns a pointer to a memory block of img->xsize * +img->ysize i_palidx entries. + +On failure returns NULL. + +You should call myfree() on the returned block when you're done with +it. + +This function will fail if the supplied palette contains no colors. + + +=for comment +From: Line 86 in quant.c + +=item i_quant_transparent(quant, data, img, trans_index) + + +Dither the alpha channel on I into the palette indexes in +I. Pixels to be transparent are replaced with I. + +The method used depends on the tr_* members of quant. + + +=for comment +From: Line 1470 in quant.c + + +=back + +=head2 Paletted images + +=over + +=item i_addcolors(im, colors, count) + + +Adds colors to the image's palette. + +On success returns the index of the lowest color added. + +On failure returns -1. + +Always fails for direct color images. + + +=for comment +From: Line 332 in imext.c + +=item i_colorcount(im) + + +Returns the number of colors in the image's palette. + +Returns -1 for direct images. + + +=for comment +From: Line 378 in imext.c + +=item i_findcolor(im, color, &entry) + + +Searches the images palette for the given color. + +On success sets *I to the index of the color, and returns true. + +On failure returns false. + +Always fails on direct color images. + + +=for comment +From: Line 413 in imext.c + +=item i_getcolors(im, index, colors, count) + + +Retrieves I colors starting from I in the image's +palette. + +On success stores the colors into I and returns true. + +On failure returns false. + +Always fails for direct color images. + +Fails if there are less than I+I colors in the image's +palette. + + +=for comment +From: Line 353 in imext.c + +=item i_maxcolors(im) + + +Returns the maximum number of colors the palette can hold for the +image. + +Returns -1 for direct color images. + + +=for comment +From: Line 395 in imext.c + +=item i_setcolors(im, index, colors, count) + + +Sets I colors starting from I in the image's palette. + +On sucess returns true. + +On failure returns false. + +The image must have at least I+I colors in it's palette +for this to succeed. + +Always fails on direct color images. + + +=for comment +From: Line 433 in imext.c + + +=back + +=head2 Tags + +=over + +=item i_tags_delbycode(tags, code) + + +Delete any tags with the given code. + +Returns the number of tags deleted. + + +=for comment +From: Line 294 in tags.c + +=item i_tags_delbyname(tags, name) + + +Delete any tags with the given name. + +Returns the number of tags deleted. + + +=for comment +From: Line 264 in tags.c + +=item i_tags_delete(tags, index) + + +Delete a tag by index. + +Returns true on success. + + +=for comment +From: Line 235 in tags.c + +=item i_tags_destroy(tags) + + +Destroys the given tags structure. Called by i_img_destroy(). + + +=for comment +From: Line 158 in tags.c + +=item i_tags_find(tags, name, start, &entry) + + +Searchs for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + + +=for comment +From: Line 181 in tags.c + +=item i_tags_findn(tags, code, start, &entry) + + +Searchs for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + + +=for comment +From: Line 208 in tags.c + +=item i_tags_get_color(tags, name, code, &value) + + +Retrieve a tag specified by name or code as color. + +On success sets the i_color *I to the color and returns true. + +On failure returns false. + + +=for comment +From: Line 505 in tags.c + +=item i_tags_get_float(tags, name, code, value) + + +Retrieves a tag as a floating point value. + +If the tag has a string value then that is parsed as a floating point +number, otherwise the integer value of the tag is used. + +On success sets *I and returns true. + +On failure returns false. + + +=for comment +From: Line 320 in tags.c + +=item i_tags_get_int(tags, name, code, &value) + + +Retrieve a tag specified by name or code as an integer. + +On success sets the i_color *I to the color and returns true. + +On failure returns false. + + +=for comment +From: Line 406 in tags.c + +=item i_tags_get_string(tags, name, code, value, value_size) + + +Retrieves a tag by name or code as a string. + +On success copies the string to value for a max of value_size and +returns true. + +On failure returns false. + +value_size must be at least large enough for a string representation +of an integer. + +The copied value is always NUL terminated. + + +=for comment +From: Line 569 in tags.c + +=item i_tags_new(i_img_tags *tags) + + +Initialize a tags structure. Should not be used if the tags structure +has been previously used. + +This should be called tags member of an i_img object on creation (in +i_img_*_new() functions). + +To destroy the contents use i_tags_destroy() + + +=for comment +From: Line 61 in tags.c + +=item i_tags_set(tags, name, data, size) + + +Sets the given tag to the string I + + +=for comment +From: Line 617 in tags.c + +=item i_tags_set_color(tags, name, code, &value) + + +Stores the given color as a tag with the given name and code. + + +=for comment +From: Line 545 in tags.c + +=item i_tags_set_float(tags, name, code, value) + + +Equivalent to i_tags_set_float2(tags, name, code, value, 30). + + +=for comment +From: Line 359 in tags.c + +=item i_tags_set_float2(tags, name, code, value, places) + + +Sets the tag with the given name and code to the given floating point +value. + +Since tags are strings or ints, we convert the value to a string before +storage at the precision specified by C. + + +=for comment +From: Line 374 in tags.c + +=item i_tags_setn(tags, name, idata) + + +Sets the given tag to the integer I + + +=for comment +From: Line 634 in tags.c + + +=back + + +=head1 AUTHOR + +Tony Cook + +=head1 SEE ALSO + +Imager, Imager::ExtUtils, Imager::Inline + +=cut diff --git a/lib/Imager/ExtUtils.pm b/lib/Imager/ExtUtils.pm new file mode 100644 index 00000000..069dc9fb --- /dev/null +++ b/lib/Imager/ExtUtils.pm @@ -0,0 +1,125 @@ +package Imager::ExtUtils; +use strict; + +=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 $dir (@INC) { + if (-e "$dir/Imager.pm") { + return $dir; + } + } + + die "Cannot locate an installed Imager!"; +} + +=item inline_config + +Implements Imager's Inline::C C hook. + +=cut + +sub inline_config { + my ($class) = @_; + my $base = base_dir(); + + return + { + INC => $class->includes, + TYPEMAPS => $class->typemap, + AUTO_INCLUDE => <<'CODE', +#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 + +=head1 REVISION + +$Revision$ + +=head1 SEE ALSO + +Imager, Imager::API, Imager::Inline, Imager::APIRef. + +=cut diff --git a/lib/Imager/Inline.pod b/lib/Imager/Inline.pod new file mode 100644 index 00000000..a4d329a4 --- /dev/null +++ b/lib/Imager/Inline.pod @@ -0,0 +1,73 @@ +=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 + +Imager hooks into Inline's C 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 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 + +=head1 REVISION + +$Revision$ + +=head1 SEE ALSO + +Imager, Imager::ExtUtils, Imager::API, Imager::APIRef + +=cut diff --git a/lib/Imager/Transformations.pod b/lib/Imager/Transformations.pod index 10c112a8..78922574 100644 --- a/lib/Imager/Transformations.pod +++ b/lib/Imager/Transformations.pod @@ -301,15 +301,53 @@ A list of the transformations that alter the source image follows: =item paste +XTo copy an image to onto another image use the C +method. -To copy an image to onto another image use the C method. - - $dest->paste(left=>40,top=>20,img=>$logo); + $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 * + +src, img - the source image. I added for compatibility with +rubthrough(). + +=item * + +left, top - position in output of the top left of the pasted image. +Default: (0,0) + +=item * + +src_minx, src_miny - the top left corner in the source image to start +the paste from. Default: (0, 0) + +=item * + +src_maxx, src_maxy - the bottom right in the source image of the sub +image to paste. This position is B inclusive. Default: bottom +right corner of the source image. + +=item * + +width, 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); + =item rubthrough A more complicated way of blending images is where one image is diff --git a/limits.c b/limits.c index cc2b1194..de02ddd2 100644 --- a/limits.c +++ b/limits.c @@ -24,7 +24,7 @@ Setting a value of zero means that limit will be ignored. */ -#include "imagei.h" +#include "imageri.h" static int max_width, max_height; static int max_bytes; diff --git a/map.c b/map.c index 0e9c47db..e88dfcc4 100644 --- a/map.c +++ b/map.c @@ -17,7 +17,7 @@ converting from RGBA to greyscale and back. =cut */ -#include "image.h" +#include "imager.h" /* diff --git a/maskimg.c b/maskimg.c index aa8f5efb..67868500 100644 --- a/maskimg.c +++ b/maskimg.c @@ -11,8 +11,8 @@ maskimg.c - implements masked images/image subsets =cut */ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" #include /* diff --git a/metafile.pl b/metafile.pl new file mode 100644 index 00000000..ef24bdcf --- /dev/null +++ b/metafile.pl @@ -0,0 +1,36 @@ +# some versions of EU::MM have problems with recursive Makefile.PLs with +# this method defined. +undef &MY::metafile; + +sub MY::metafile { + my ($self) = @_; + + my $meta = <{NAME} +version: $self->{VERSION} +version_from: $self->{VERSION_FROM} +author: $self->{AUTHOR} +abstract: $self->{ABSTRACT} +installdirs: $self->{INSTALLDIRS} +YAML + if (keys %{$Recommends{$self->{NAME}}}) { + $meta .= "recommends:\n"; + while (my ($module, $version) = each %{$Recommends{$self->{NAME}}}) { + $meta .= "$module: $version\n"; + } + } + $meta .= <{NAME} version $self->{VERSION} +YAML + open META, "> meta.tmp" or die "Cannot create meta.tmp: $!"; + print META $meta; + close META; + + return sprintf "metafile :\n\t\$(CP) meta.tmp META.yml\n"; +} + +1; diff --git a/palimg.c b/palimg.c index f586f4ef..90ec29e7 100644 --- a/palimg.c +++ b/palimg.c @@ -18,8 +18,8 @@ Basic 8-bit/sample paletted image =cut */ -#include "image.h" -#include "imagei.h" +#include "imager.h" +#include "imageri.h" #define PALEXT(im) ((i_img_pal_ext*)((im)->ext_data)) static int i_ppix_p(i_img *im, int x, int y, i_color *val); @@ -74,7 +74,7 @@ static i_img IIM_base_8bit_pal = }; /* -=item i_img_pal_new_low(i_img *im, int x, int y, int channels, int maxpal) +=item i_img_pal_new_low(im, x, y, channels, maxpal) Creates a new paletted image. @@ -132,6 +132,18 @@ i_img *i_img_pal_new_low(i_img *im, int x, int y, int channels, int maxpal) { return im; } +/* +=item i_img_pal_new(x, y, channels, maxpal) + +=category Image creation + +Creates a new paletted image of the supplied dimensions. + +Returns a new image or NULL on failure. + +=cut +*/ + i_img *i_img_pal_new(int x, int y, int channels, int maxpal) { i_img *im; mm_log((1, "i_img_pal_new(x %d, y %d, channels %d, maxpal %d)\n", x, y, channels, maxpal)); @@ -210,8 +222,8 @@ i_img *i_img_to_pal(i_img *src, i_quantize *quant) { i_clear_error(); - quant_makemap(quant, &src, 1); - result = quant_translate(quant, src); + i_quant_makemap(quant, &src, 1); + result = i_quant_translate(quant, src); if (result) { @@ -289,7 +301,7 @@ static int i_ppix_p(i_img *im, int x, int y, i_color *val) { } /* -=item i_gpix(i_img *im, int x, int y, i_color *val) +=item i_gpix_p(i_img *im, int x, int y, i_color *val) Retrieve a pixel, converting from a palette index to a color. diff --git a/plug.h b/plug.h index 3e23b830..e3583fca 100644 --- a/plug.h +++ b/plug.h @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" /* structures for passing data between Imager-plugin and the Imager-module */ diff --git a/png.c b/png.c index 684d53f9..19af7e5a 100644 --- a/png.c +++ b/png.c @@ -1,5 +1,5 @@ #include "iolayer.h" -#include "imagei.h" +#include "imageri.h" #include "png.h" /* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() diff --git a/pnm.c b/pnm.c index eef17997..e5d30504 100644 --- a/pnm.c +++ b/pnm.c @@ -1,7 +1,7 @@ -#include "image.h" +#include "imager.h" #include "log.h" #include "iolayer.h" -#include "imagei.h" +#include "imageri.h" #include #include diff --git a/polygon.c b/polygon.c index 257713ca..d4802541 100644 --- a/polygon.c +++ b/polygon.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include "draw.h" #include "log.h" diff --git a/quant.c b/quant.c index 51524cd5..dc74bebd 100644 --- a/quant.c +++ b/quant.c @@ -2,7 +2,7 @@ currently only used by gif.c, but maybe we'll support producing 8-bit (or bigger indexed) png files at some point */ -#include "image.h" +#include "imager.h" static void makemap_addi(i_quantize *, i_img **imgs, int count); static void makemap_mediancut(i_quantize *, i_img **imgs, int count); @@ -26,8 +26,20 @@ setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char handle multiple colour maps. */ +/* +=item i_quant_makemap(quant, imgs, count) + +=category Image quantization + +Analyzes the I images in I according to the rules in +I to build a color map (optimal or not depending on +quant->make_colors). + +=cut +*/ + void -quant_makemap(i_quantize *quant, i_img **imgs, int count) { +i_quant_makemap(i_quantize *quant, i_img **imgs, int count) { if (quant->translate == pt_giflib) { /* giflib does it's own color table generation */ @@ -70,11 +82,27 @@ static void translate_closest(i_quantize *, i_img *, i_palidx *); static void translate_errdiff(i_quantize *, i_img *, i_palidx *); static void translate_addi(i_quantize *, i_img *, i_palidx *); -/* Quantize the image given the palette in quant. +/* +=item i_quant_translate(quant, img) + +=category Image quantization + +Quantize the image given the palette in quant. + +On success returns a pointer to a memory block of img->xsize * +img->ysize i_palidx entries. + +On failure returns NULL. - The giflib quantizer ignores the palette. +You should call myfree() on the returned block when you're done with +it. + +This function will fail if the supplied palette contains no colors. + +=cut */ -i_palidx *quant_translate(i_quantize *quant, i_img *img) { +i_palidx * +i_quant_translate(i_quantize *quant, i_img *img) { i_palidx *result; int bytes; @@ -1438,7 +1466,21 @@ static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx); static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx); static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx); -void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img, +/* +=item i_quant_transparent(quant, data, img, trans_index) + +=category Image quantization + +Dither the alpha channel on I into the palette indexes in +I. Pixels to be transparent are replaced with I. + +The method used depends on the tr_* members of quant. + +=cut +*/ + +void +i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { switch (quant->transp) { diff --git a/raw.c b/raw.c index 214bc21e..8b363d5a 100644 --- a/raw.c +++ b/raw.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include #include "iolayer.h" #ifndef _MSC_VER diff --git a/regmach.h b/regmach.h index 448ef7a9..e8df6ea2 100644 --- a/regmach.h +++ b/regmach.h @@ -3,7 +3,7 @@ #include #include -#include "image.h" +#include "imager.h" enum rm_byte_codes { rbc_add, /* ra + rb -> r*/ diff --git a/rgb.c b/rgb.c index 7559a06c..cb47a8c9 100644 --- a/rgb.c +++ b/rgb.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include "log.h" #include "iolayer.h" diff --git a/rotate.c b/rotate.c index cb2e3e58..457fea0f 100644 --- a/rotate.c +++ b/rotate.c @@ -16,7 +16,7 @@ Other rotations will be added as tuits become available. =cut */ -#include "image.h" +#include "imager.h" #include /* for floor() */ i_img *i_rotate90(i_img *src, int degrees) { diff --git a/t/t022double.t b/t/t022double.t index e809c86a..80d7823d 100644 --- a/t/t022double.t +++ b/t/t022double.t @@ -66,7 +66,7 @@ ok($ooimg->bits eq 'double', "oo didn't give double image"); # check that the image is copied correctly my $oocopy = $ooimg->copy; -ok($oocopy->bits eq 'double', "oo copy didn't give double image"); +is($oocopy->bits, 'double', "oo copy didn't give double image"); ok(!Imager->new(xsize=>0, ysize=>1, bits=>'double'), "fail making 0 width image"); diff --git a/t/t66paste.t b/t/t66paste.t index 5a6ef2ee..b55692f0 100644 --- a/t/t66paste.t +++ b/t/t66paste.t @@ -1,28 +1,86 @@ -BEGIN { $| = 1; print "1..4\n"; } -END {print "not ok 1\n" unless $loaded;} -use Imager; +#!perl -w +use strict; +use Test::More tests => 15; -$loaded = 1; +BEGIN { use_ok("Imager") } #$Imager::DEBUG=1; Imager::init('log'=>'testout/t66paste.log'); -$img=Imager->new() || die "unable to create image object\n"; +# the original smoke tests +my $img=Imager->new() || die "unable to create image object\n"; -print "ok 1\n"; +ok($img->open(file=>'testimg/scale.ppm',type=>'pnm'), "load test img"); -$img->open(file=>'testimg/scale.ppm',type=>'pnm'); +my $nimg=Imager->new() or die "Unable to create image object\n"; +ok($nimg->open(file=>'testimg/scale.ppm',type=>'pnm'), "load test img again"); -$nimg=Imager->new() or die "Unable to create image object\n"; -$nimg->open(file=>'testimg/scale.ppm',type=>'pnm'); -print "ok 2\n"; +ok($img->paste(img=>$nimg, top=>30, left=>30), "paste it") + or print "# ", $img->errstr, "\n";; -$img->paste(img=>$nimg, top=>30, left=>30) or die $img->{ERRSTR}; -print "ok 3\n"; +ok($img->write(type=>'pnm',file=>'testout/t66.ppm'), "save it") + or print "# ", $img->errstr, "\n"; +# more stringent tests +{ + my $src = Imager->new(xsize => 100, ysize => 100); + $src->box(filled=>1, color=>'FF0000'); -$img->write(type=>'pnm',file=>'testout/t66.ppm') || die "error in write()\n"; -print "ok 4\n"; + $src->box(filled=>1, color=>'0000FF', xmin => 20, ymin=>20, + xmax=>79, ymax=>79); + my $targ = Imager->new(xsize => 100, ysize => 100); + $targ->box(filled=>1, color=>'00FF00', xmin=>20, ymin=>20, xmax=>79, + ymax=>79); + my $work = $targ->copy; + ok($work->paste(src=>$src, left => 15, top => 10), "paste whole image"); + # build comparison image + my $cmp = $targ->copy; + $cmp->box(filled=>1, xmin=>15, ymin => 10, color=>'FF0000'); + $cmp->box(filled=>1, xmin=>35, ymin => 30, xmax=>94, ymax=>89, + color=>'0000FF'); + + is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, + "compare pasted and expected"); + + $work = $targ->copy; + ok($work->paste(src=>$src, left=>2, top=>7, src_minx => 10, src_miny => 15), + "paste from inside src"); + $cmp = $targ->copy; + $cmp->box(filled=>1, xmin=>2, ymin=>7, xmax=>91, ymax=>91, color=>'FF0000'); + $cmp->box(filled=>1, xmin=>12, ymin=>12, xmax=>71, ymax=>71, + color=>'0000FF'); + is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, + "compare pasted and expected"); + + # paste part source + $work = $targ->copy; + ok($work->paste(src=>$src, left=>15, top=>20, + src_minx=>10, src_miny=>15, src_maxx=>80, src_maxy =>70), + "paste src cropped all sides"); + $cmp = $targ->copy; + $cmp->box(filled=>1, xmin=>15, ymin=>20, xmax=>84, ymax=>74, + color=>'FF0000'); + $cmp->box(filled=>1, xmin=>25, ymin=>25, xmax=>84, ymax=>74, + color=>'0000FF'); + is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, + "compare pasted and expected"); + + # go by width instead + $work = $targ->copy; + ok($work->paste(src=>$src, left=>15, top=>20, + src_minx=>10, src_miny => 15, width => 70, height => 55), + "same but specify width/height instead"); + is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, + "compare pasted and expected"); + + # use src_coords + $work = $targ->copy; + ok($work->paste(src=>$src, left => 15, top => 20, + src_coords => [ 10, 15, 80, 70 ]), + "using src_coords"); + is(Imager::i_img_diff($work->{IMG}, $cmp->{IMG}), 0, + "compare pasted and expected"); +} diff --git a/t/t82inline.t b/t/t82inline.t new file mode 100644 index 00000000..177dc9ca --- /dev/null +++ b/t/t82inline.t @@ -0,0 +1,231 @@ +#!perl -w +# +# this tests both the Inline interface and the API +use strict; +use lib 't'; +use Test::More; +eval "require Inline::C;"; +plan skip_all => "Inline required for testing API - $@" if $@; + +plan tests => 8; +require Inline; +Inline->import(with => 'Imager'); + +Inline->bind(C => <<'EOS'); +#include + +int pixel_count(Imager::ImgRaw im) { + return im->xsize * im->ysize; +} + +int count_color(Imager::ImgRaw im, Imager::Color c) { + int count = 0, x, y, chan; + i_color read_c; + + for (x = 0; x < im->xsize; ++x) { + for (y = 0; y < im->ysize; ++y) { + int match = 1; + i_gpix(im, x, y, &read_c); + for (chan = 0; chan < im->channels; ++chan) { + if (read_c.channel[chan] != c->channel[chan]) { + match = 0; + break; + } + } + if (match) + ++count; + } + } + + return count; +} + +Imager make_10x10() { + i_img *im = i_img_8_new(10, 10, 3); + i_color c; + c.channel[0] = c.channel[1] = c.channel[2] = 255; + i_box_filled(im, 0, 0, im->xsize-1, im->ysize-1, &c); + + return im; +} + +/* tests that all of the APIs are visible - most of them anyway */ +Imager do_lots(Imager src) { + i_img *im = i_img_8_new(100, 100, 3); + i_img *fill_im = i_img_8_new(5, 5, 3); + i_img *testim; + i_color red, blue, temp_color; + i_fcolor redf, bluef; + i_fill_t *hatch, *fhatch_fill; + i_fill_t *im_fill; + i_fill_t *solid_fill, *fsolid_fill; + i_fill_t *fount_fill; + void *block; + double matrix[9] = /* 30 degree rotation */ + { + 0.866025, -0.5, 0, + 0.5, 0.866025, 0, + 0, 0, 1, + }; + i_fountain_seg fseg; + i_img_tags tags; + int entry; + double temp_double; + + red.channel[0] = 255; red.channel[1] = 0; red.channel[2] = 0; + red.channel[3] = 255; + blue.channel[0] = 0; blue.channel[1] = 0; blue.channel[2] = 255; + blue.channel[3] = 255; + hatch = i_new_fill_hatch(&red, &blue, 0, 1, NULL, 0, 0); + + i_box(im, 0, 0, 9, 9, &red); + i_box_filled(im, 10, 0, 19, 9, &blue); + i_box_cfill(im, 20, 0, 29, 9, hatch); + + /* make an image fill, and try it */ + i_box_cfill(fill_im, 0, 0, 4, 4, hatch); + im_fill = i_new_fill_image(fill_im, matrix, 2, 2, 0); + + i_box_cfill(im, 30, 0, 39, 9, im_fill); + + /* make a solid fill and try it */ + solid_fill = i_new_fill_solid(&red, 0); + i_box_cfill(im, 40, 0, 49, 9, solid_fill); + + /* floating fills */ + redf.channel[0] = 1.0; redf.channel[1] = 0; redf.channel[2] = 0; + redf.channel[3] = 1.0; + bluef.channel[0] = 0; bluef.channel[1] = 0; bluef.channel[2] = 1.0; + bluef.channel[3] = 1.0; + + fsolid_fill = i_new_fill_solidf(&redf, 0); + i_box_cfill(im, 50, 0, 59, 9, fsolid_fill); + + fhatch_fill = i_new_fill_hatchf(&redf, &bluef, 0, 2, NULL, 0, 0); + i_box_cfill(im, 60, 0, 69, 9, fhatch_fill); + + /* fountain fill */ + fseg.start = 0; + fseg.middle = 0.5; + fseg.end = 1.0; + fseg.c[0] = redf; + fseg.c[1] = bluef; + fseg.type = i_fst_linear; + fseg.color = i_fc_hue_down; + fount_fill = i_new_fill_fount(70, 0, 80, 0, i_ft_linear, i_fr_triangle, 0, i_fts_none, 1, 1, &fseg); + + i_box_cfill(im, 70, 0, 79, 9, fount_fill); + + i_line(im, 0, 10, 10, 15, &blue, 1); + i_line_aa(im, 0, 19, 10, 15, &red, 1); + + i_arc(im, 15, 15, 4, 45, 160, &blue); + i_arc_aa(im, 25, 15, 4, 75, 280, &red); + i_arc_cfill(im, 35, 15, 4, 0, 215, hatch); + i_arc_aa_cfill(im, 45, 15, 4, 30, 210, hatch); + i_circle_aa(im, 55, 15, 4, &red); + + i_box(im, 61, 11, 68, 18, &red); + i_flood_fill(im, 65, 15, &blue); + i_box(im, 71, 11, 78, 18, &red); + i_flood_cfill(im, 75, 15, hatch); + + i_fill_destroy(fount_fill); + i_fill_destroy(fhatch_fill); + i_fill_destroy(solid_fill); + i_fill_destroy(fsolid_fill); + i_fill_destroy(hatch); + i_fill_destroy(im_fill); + i_img_destroy(fill_im); + + /* make sure we can make each image type */ + testim = i_img_16_new(100, 100, 3); + i_img_destroy(testim); + testim = i_img_double_new(100, 100, 3); + i_img_destroy(testim); + testim = i_img_pal_new(100, 100, 3, 256); + i_img_destroy(testim); + testim = i_sametype(im, 50, 50); + i_img_destroy(testim); + testim = i_sametype_chans(im, 50, 50, 4); + i_img_destroy(testim); + + i_clear_error(); + i_push_error(0, "Hello"); + i_push_errorf(0, "%s", "World"); + + /* make sure tags create/destroy work */ + i_tags_new(&tags); + i_tags_destroy(&tags); + + block = mymalloc(20); + block = myrealloc(block, 50); + myfree(block); + + i_tags_set(&im->tags, "lots_string", "foo", -1); + i_tags_setn(&im->tags, "lots_number", 101); + + if (!i_tags_find(&im->tags, "lots_number", 0, &entry)) { + i_push_error(0, "lots_number tag not found"); + i_img_destroy(im); + return NULL; + } + i_tags_delete(&im->tags, entry); + + /* these won't delete anything, but it makes sure the macros and function + pointers are correct */ + i_tags_delbyname(&im->tags, "unknown"); + i_tags_delbycode(&im->tags, 501); + i_tags_set_float(&im->tags, "lots_float", 0, 3.14); + if (!i_tags_get_float(&im->tags, "lots_float", 0, &temp_double)) { + i_push_error(0, "lots_float not found"); + i_img_destroy(im); + return NULL; + } + if (fabs(temp_double - 3.14) > 0.001) { + i_push_errorf(0, "lots_float incorrect %g", temp_double); + i_img_destroy(im); + return NULL; + } + i_tags_set_float2(&im->tags, "lots_float2", 0, 100 * sqrt(2.0), 5); + if (!i_tags_get_int(&im->tags, "lots_float2", 0, &entry)) { + i_push_error(0, "lots_float2 not found as int"); + i_img_destroy(im); + return NULL; + } + if (entry != 141) { + i_push_errorf(0, "lots_float2 unexpected value %d", entry); + i_img_destroy(im); + return NULL; + } + + i_tags_set_color(&im->tags, "lots_color", 0, &red); + if (!i_tags_get_color(&im->tags, "lots_color", 0, &temp_color)) { + i_push_error(0, "lots_color not found as color"); + i_img_destroy(im); + return NULL; + } + + return im; +} + +EOS + +my $im = Imager->new(xsize=>50, ysize=>50); +is(pixel_count($im), 2500, "pixel_count"); + +my $black = Imager::Color->new(0,0,0); +is(count_color($im, $black), 2500, "count_color black on black image"); + +my $im2 = make_10x10(); +my $white = Imager::Color->new(255, 255, 255); +is(count_color($im2, $white), 100, "check new image white count"); +ok($im2->box(filled=>1, xmin=>1, ymin=>1, xmax => 8, ymax=>8, color=>$black), + "try new image"); +is(count_color($im2, $black), 64, "check modified black count"); +is(count_color($im2, $white), 36, "check modified white count"); + +my $im3 = do_lots($im2); +ok($im3, "do_lots()") + or print "# ", Imager->_error_as_msg, "\n"; +ok($im3->write(file=>'testout/t82lots.ppm'), "write t82lots.ppm"); diff --git a/tags.c b/tags.c index bf8d3a5b..951d1fe9 100644 --- a/tags.c +++ b/tags.c @@ -48,7 +48,7 @@ A tag is represented by an i_img_tag structure: =cut */ -#include "image.h" +#include "imager.h" #include #include #include @@ -60,9 +60,14 @@ void i_tags_print(i_img_tags *tags); /* =item i_tags_new(i_img_tags *tags) +=category Tags + Initialize a tags structure. Should not be used if the tags structure has been previously used. +This should be called tags member of an i_img object on creation (in +i_img_*_new() functions). + To destroy the contents use i_tags_destroy() =cut @@ -149,6 +154,16 @@ int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data, return 1; } +/* +=item i_tags_destroy(tags) + +=category Tags + +Destroys the given tags structure. Called by i_img_destroy(). + +=cut +*/ + void i_tags_destroy(i_img_tags *tags) { if (tags->tags) { int i; @@ -162,6 +177,20 @@ void i_tags_destroy(i_img_tags *tags) { } } +/* +=item i_tags_find(tags, name, start, &entry) + +=category Tags + +Searchs for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + +=cut +*/ + int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) { if (tags->tags) { while (start < tags->count) { @@ -175,6 +204,20 @@ int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) { return 0; } +/* +=item i_tags_findn(tags, code, start, &entry) + +=category Tags + +Searchs for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + +=cut +*/ + int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { if (tags->tags) { while (start < tags->count) { @@ -188,6 +231,17 @@ int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { return 0; } +/* +=item i_tags_delete(tags, index) + +=category Tags + +Delete a tag by index. + +Returns true on success. + +=cut +*/ int i_tags_delete(i_img_tags *tags, int entry) { /*printf("i_tags_delete(tags %p [count %d], entry %d)\n", tags, tags->count, entry);*/ @@ -206,6 +260,18 @@ int i_tags_delete(i_img_tags *tags, int entry) { return 0; } +/* +=item i_tags_delbyname(tags, name) + +=category Tags + +Delete any tags with the given name. + +Returns the number of tags deleted. + +=cut +*/ + int i_tags_delbyname(i_img_tags *tags, char const *name) { int count = 0; int i; @@ -224,6 +290,18 @@ int i_tags_delbyname(i_img_tags *tags, char const *name) { return count; } +/* +=item i_tags_delbycode(tags, code) + +=category Tags + +Delete any tags with the given code. + +Returns the number of tags deleted. + +=cut +*/ + int i_tags_delbycode(i_img_tags *tags, int code) { int count = 0; int i; @@ -238,6 +316,23 @@ int i_tags_delbycode(i_img_tags *tags, int code) { return count; } +/* +=item i_tags_get_float(tags, name, code, value) + +=category Tags + +Retrieves a tag as a floating point value. + +If the tag has a string value then that is parsed as a floating point +number, otherwise the integer value of the tag is used. + +On success sets *I and returns true. + +On failure returns false. + +=cut +*/ + int i_tags_get_float(i_img_tags *tags, char const *name, int code, double *value) { int index; @@ -260,6 +355,16 @@ int i_tags_get_float(i_img_tags *tags, char const *name, int code, return 1; } +/* +=item i_tags_set_float(tags, name, code, value) + +=category Tags + +Equivalent to i_tags_set_float2(tags, name, code, value, 30). + +=cut +*/ + int i_tags_set_float(i_img_tags *tags, char const *name, int code, double value) { return i_tags_set_float2(tags, name, code, value, 30); @@ -268,6 +373,8 @@ int i_tags_set_float(i_img_tags *tags, char const *name, int code, /* =item i_tags_set_float2(tags, name, code, value, places) +=category Tags + Sets the tag with the given name and code to the given floating point value. @@ -295,6 +402,20 @@ int i_tags_set_float2(i_img_tags *tags, char const *name, int code, return i_tags_add(tags, name, code, temp, strlen(temp), 0); } +/* +=item i_tags_get_int(tags, name, code, &value) + +=category Tags + +Retrieve a tag specified by name or code as an integer. + +On success sets the i_color *I to the color and returns true. + +On failure returns false. + +=cut +*/ + int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) { int index; i_img_tag *entry; @@ -380,6 +501,20 @@ static int parse_color(char *data, char **end, i_color *value) { return 1; } +/* +=item i_tags_get_color(tags, name, code, &value) + +=category Tags + +Retrieve a tag specified by name or code as color. + +On success sets the i_color *I to the color and returns true. + +On failure returns false. + +=cut +*/ + int i_tags_get_color(i_img_tags *tags, char const *name, int code, i_color *value) { int index; @@ -406,6 +541,16 @@ int i_tags_get_color(i_img_tags *tags, char const *name, int code, return 1; } +/* +=item i_tags_set_color(tags, name, code, &value) + +=category Tags + +Stores the given color as a tag with the given name and code. + +=cut +*/ + int i_tags_set_color(i_img_tags *tags, char const *name, int code, i_color const *value) { char temp[80]; @@ -420,6 +565,26 @@ int i_tags_set_color(i_img_tags *tags, char const *name, int code, return i_tags_add(tags, name, code, temp, strlen(temp), 0); } +/* +=item i_tags_get_string(tags, name, code, value, value_size) + +=category Tags + +Retrieves a tag by name or code as a string. + +On success copies the string to value for a max of value_size and +returns true. + +On failure returns false. + +value_size must be at least large enough for a string representation +of an integer. + +The copied value is always NUL terminated. + +=cut +*/ + int i_tags_get_string(i_img_tags *tags, char const *name, int code, char *value, size_t value_size) { int index; @@ -448,6 +613,40 @@ int i_tags_get_string(i_img_tags *tags, char const *name, int code, return 1; } +/* +=item i_tags_set(tags, name, data, size) + +=category Tags + +Sets the given tag to the string I + +=cut +*/ + +int +i_tags_set(i_img_tags *tags, char const *name, char const *data, int size) { + i_tags_delbyname(tags, name); + + return i_tags_add(tags, name, 0, data, size, 0); +} + +/* +=item i_tags_setn(tags, name, idata) + +=category Tags + +Sets the given tag to the integer I + +=cut +*/ + +int +i_tags_setn(i_img_tags *tags, char const *name, int idata) { + i_tags_delbyname(tags, name); + + return i_tags_addn(tags, name, 0, idata); +} + void i_tags_print(i_img_tags *tags) { int i; printf("Alloc %d\n", tags->alloc); diff --git a/tga.c b/tga.c index 2e373534..230be5bf 100644 --- a/tga.c +++ b/tga.c @@ -1,4 +1,4 @@ -#include "imagei.h" +#include "imageri.h" #include "log.h" #include "iolayer.h" diff --git a/tiff.c b/tiff.c index 9833cbc6..4f2b0e6e 100644 --- a/tiff.c +++ b/tiff.c @@ -1,7 +1,7 @@ -#include "image.h" +#include "imager.h" #include "tiffio.h" #include "iolayer.h" -#include "imagei.h" +#include "imageri.h" /* =head1 NAME diff --git a/trans2.c b/trans2.c index daf74b05..37198930 100644 --- a/trans2.c +++ b/trans2.c @@ -1,4 +1,4 @@ -#include "image.h" +#include "imager.h" #include "regmach.h" /* diff --git a/typemap b/typemap index 82d8a4a7..f3d17382 100644 --- a/typemap +++ b/typemap @@ -1,7 +1,7 @@ #i_img * T_PTR_NULL Imager::Color T_PTROBJ Imager::Color::Float T_PTROBJ -Imager::ImgRaw T_PTROBJ +Imager::ImgRaw T_IMAGER_IMAGE Imager::Font::TT T_PTROBJ Imager::IO T_PTROBJ Imager::Font::FT2 T_PTROBJ @@ -14,6 +14,17 @@ undef_int T_IV_U undef_neg_int T_IV_NEGU HASH T_HVREF utf8_str T_UTF8_STR + +# 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 @@ -27,6 +38,53 @@ T_AVREF else Perl_croak(aTHX_ \"$var is not an array reference\") +# 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}\"); + + ############################################################################# OUTPUT T_IV_U @@ -37,3 +95,26 @@ T_IV_NEGU 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 *hvref; + SV *imgref; + sv_setref_pv(imobj, \"Imager::ImgRaw\", $var); + hv_store(hv, "IMG", 3, imobj, 0); + $arg = sv_2mortal(sv_bless(newRV((SV*)hv), gv_stashpv("Imager", 1))); + } + else { + $arg = &PL_sv_undef; + } diff --git a/win32.c b/win32.c index 1a3ed5cd..ab9b8b08 100644 --- a/win32.c +++ b/win32.c @@ -1,5 +1,5 @@ #define _WIN32_WINNT 0x500 -#include "image.h" +#include "imager.h" #define STRICT #include -- 2.39.2