From e5744e01adf453d82e6feacc8425dda7ffcc1772 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Thu, 26 Jun 2003 03:50:00 +0000 Subject: [PATCH] - added comment support the postfix transform2() expression parser - transform2() can now produce images with other than 3 channels. - added a correct T_AVREF input mapping to the typemap to simplify parameter lists --- Changes | 5 + Imager.pm | 7 +- Imager.xs | 58 ++--- lib/Imager/Engines.pod | 27 +- lib/Imager/Expr.pm | 1 + lib/Imager/Regops.pm | 556 +++++++++++++++++++++-------------------- regmach.c | 29 ++- regmach.h | 3 + t/t56postfix.t | 6 +- t/t58trans2.t | 77 ++++-- typemap | 8 + 11 files changed, 444 insertions(+), 333 deletions(-) diff --git a/Changes b/Changes index 63a29956..a32d377d 100644 --- a/Changes +++ b/Changes @@ -720,6 +720,11 @@ Revision history for Perl extension Imager. source image is used. - the image fills didn't handle filling with source images of less than four channels correctly + - added comment support the postfix transform2() expression + parser + - transform2() can now produce images with other than 3 channels. + - added a correct T_AVREF input mapping to the typemap to + simplify parameter lists ================================================================= diff --git a/Imager.pm b/Imager.pm index 9ddd35c0..953e1114 100644 --- a/Imager.pm +++ b/Imager.pm @@ -1722,9 +1722,14 @@ sub transform2 { $Imager::ERRSTR = Imager::Expr::error(); return; } + my $channels = $opts->{channels} || 3; + unless ($channels >= 1 && $channels <= 4) { + return Imager->_set_error("channels must be an integer between 1 and 4"); + } my $img = Imager->new(); - $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, $code->code(), + $img->{IMG} = i_transform2($opts->{width}, $opts->{height}, + $channels, $code->code(), $code->nregs(), $code->cregs(), [ map { $_->{IMG} } @imgs ]); if (!defined $img->{IMG}) { diff --git a/Imager.xs b/Imager.xs index 5e79c193..81ff9c62 100644 --- a/Imager.xs +++ b/Imager.xs @@ -2870,7 +2870,14 @@ i_transform(im,opx,opy,parm) else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL); Imager::ImgRaw -i_transform2(width,height,ops,n_regs,c_regs,in_imgs) +i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs) + SV *sv_width + SV *sv_height + SV *sv_ops + AV *av_n_regs + AV *av_c_regs + AV *av_in_imgs + int channels PREINIT: int width; int height; @@ -2889,32 +2896,18 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs) IV tmp; int i; CODE: - if (!SvROK(ST(3))) croak("Imager: Parameter 4 must be a reference to an array\n"); - if (!SvROK(ST(4))) croak("Imager: Parameter 5 must be a reference to an array\n"); - if (!SvROK(ST(5))) croak("Imager: Parameter 6 must be a reference to an array of images\n"); - if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 5 must be a reference to an array\n"); - - /*if (SvTYPE(SvRV(ST(5))) != SVt_PVAV) croak("Imager: Parameter 6 must be a reference to an array\n");*/ - - if (SvTYPE(SvRV(ST(5))) == SVt_PVAV) { - av = (AV*)SvRV(ST(5)); - in_imgs_count = av_len(av)+1; - for (i = 0; i < in_imgs_count; ++i) { - sv1 = *av_fetch(av, i, 0); - if (!sv_derived_from(sv1, "Imager::ImgRaw")) { - croak("Parameter 5 must contain only images"); - } + + in_imgs_count = av_len(av_in_imgs)+1; + for (i = 0; i < in_imgs_count; ++i) { + sv1 = *av_fetch(av_in_imgs, i, 0); + if (!sv_derived_from(sv1, "Imager::ImgRaw")) { + croak("sv_in_img must contain only images"); } } - else { - in_imgs_count = 0; - } if (in_imgs_count > 0) { - av = (AV*)SvRV(ST(5)); in_imgs = mymalloc(in_imgs_count*sizeof(i_img*)); for (i = 0; i < in_imgs_count; ++i) { - sv1 = *av_fetch(av,i,0); + sv1 = *av_fetch(av_in_imgs,i,0); if (!sv_derived_from(sv1, "Imager::ImgRaw")) { croak("Parameter 5 must contain only images"); } @@ -2927,38 +2920,37 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs) in_imgs = NULL; } /* default the output size from the first input if possible */ - if (SvOK(ST(0))) - width = SvIV(ST(0)); + if (SvOK(sv_width)) + width = SvIV(sv_width); else if (in_imgs_count) width = in_imgs[0]->xsize; else croak("No output image width supplied"); - if (SvOK(ST(1))) - height = SvIV(ST(1)); + if (SvOK(sv_height)) + height = SvIV(sv_height); else if (in_imgs_count) height = in_imgs[0]->ysize; else croak("No output image height supplied"); - ops = (struct rm_op *)SvPV(ST(2), ops_len); + ops = (struct rm_op *)SvPV(sv_ops, ops_len); if (ops_len % sizeof(struct rm_op)) croak("Imager: Parameter 3 must be a bitmap of regops\n"); ops_count = ops_len / sizeof(struct rm_op); - av = (AV*)SvRV(ST(3)); - n_regs_count = av_len(av)+1; + + n_regs_count = av_len(av_n_regs)+1; n_regs = mymalloc(n_regs_count * sizeof(double)); for (i = 0; i < n_regs_count; ++i) { - sv1 = *av_fetch(av,i,0); + sv1 = *av_fetch(av_n_regs,i,0); if (SvOK(sv1)) n_regs[i] = SvNV(sv1); } - av = (AV*)SvRV(ST(4)); - c_regs_count = av_len(av)+1; + c_regs_count = av_len(av_c_regs)+1; c_regs = mymalloc(c_regs_count * sizeof(i_color)); /* I don't bother initializing the colou?r registers */ - RETVAL=i_transform2(width, height, 3, ops, ops_count, + RETVAL=i_transform2(width, height, channels, ops, ops_count, n_regs, n_regs_count, c_regs, c_regs_count, in_imgs, in_imgs_count); if (in_imgs) diff --git a/lib/Imager/Engines.pod b/lib/Imager/Engines.pod index 17914006..68aec86c 100644 --- a/lib/Imager/Engines.pod +++ b/lib/Imager/Engines.pod @@ -91,6 +91,11 @@ images an error occurs. constants - a reference to hash of constants to define for the expression engine. Some extra constants are defined by Imager +=item * + +channels - the number of channels in the output image. If this isn't +supplied a 3 channel image will be created. + =back The tranformation function is specified using either the expr or @@ -180,16 +185,21 @@ respectively. I may add a getpn() function at some point, but this prevents static checking of the instructions against the number of images actually passed in. -=item value(c), hue(c), sat(c), hsv(h,s,v) +=item value(c), hue(c), sat(c), hsv(h,s,v), hsva(h,s,v,alpha) Separates a colour value into it's value (brightness), hue (colour) and saturation elements. Use hsv() to put them back together (after -suitable manipulation). +suitable manipulation), or hsva() to include a tranparency value. =item red(c), green(c), blue(c), rgb(r,g,b) Separates a colour value into it's red, green and blue colours. Use -rgb(r,g,b) to put it back together. +rgb(r,g,b) to put it back together, or rgba() to include a +transparency value. + +=item alpha(c) + +Retrieve the alpha value from a colour. =item int(n) @@ -262,6 +272,17 @@ L. EOS }); + # replace green portions of an image with another image + my $newimg = Imager::transform2({ + rpnexpr => <'add', '-'=>'subtract', '*'=>'mult', '/' => 'div', sub compile { my ($self, $expr, $opts) = @_; + $expr =~ s/#.*//; # remove comments my @st_ops = split ' ', $expr; for (@st_ops) { diff --git a/lib/Imager/Regops.pm b/lib/Imager/Regops.pm index 01712f1f..644b8b5e 100644 --- a/lib/Imager/Regops.pm +++ b/lib/Imager/Regops.pm @@ -52,340 +52,364 @@ use constant RBC_JUMPNZ => 42; use constant RBC_SET => 43; use constant RBC_SETP => 44; use constant RBC_PRINT => 45; -use constant RBC_OP_COUNT => 46; +use constant RBC_RGBA => 46; +use constant RBC_HSVA => 47; +use constant RBC_ALPHA => 48; +use constant RBC_OP_COUNT => 49; -@EXPORT = qw(RBC_ADD RBC_SUBTRACT RBC_MULT RBC_DIV RBC_MOD RBC_POW RBC_UMINUS RBC_MULTP RBC_ADDP RBC_SUBTRACTP RBC_SIN RBC_COS RBC_ATAN2 RBC_SQRT RBC_DISTANCE RBC_GETP1 RBC_GETP2 RBC_GETP3 RBC_VALUE RBC_HUE RBC_SAT RBC_HSV RBC_RED RBC_GREEN RBC_BLUE RBC_RGB RBC_INT RBC_IF RBC_IFP RBC_LE RBC_LT RBC_GE RBC_GT RBC_EQ RBC_NE RBC_AND RBC_OR RBC_NOT RBC_ABS RBC_RET RBC_JUMP RBC_JUMPZ RBC_JUMPNZ RBC_SET RBC_SETP RBC_PRINT RBC_OP_COUNT); +@EXPORT = qw(RBC_ADD RBC_SUBTRACT RBC_MULT RBC_DIV RBC_MOD RBC_POW RBC_UMINUS RBC_MULTP RBC_ADDP RBC_SUBTRACTP RBC_SIN RBC_COS RBC_ATAN2 RBC_SQRT RBC_DISTANCE RBC_GETP1 RBC_GETP2 RBC_GETP3 RBC_VALUE RBC_HUE RBC_SAT RBC_HSV RBC_RED RBC_GREEN RBC_BLUE RBC_RGB RBC_INT RBC_IF RBC_IFP RBC_LE RBC_LT RBC_GE RBC_GT RBC_EQ RBC_NE RBC_AND RBC_OR RBC_NOT RBC_ABS RBC_RET RBC_JUMP RBC_JUMPZ RBC_JUMPNZ RBC_SET RBC_SETP RBC_PRINT RBC_RGBA RBC_HSVA RBC_ALPHA RBC_OP_COUNT); %Attr = ( - 'or' => { - 'opcode' => 36, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'getp1' => { - 'opcode' => 15, - 'parms' => 2, - 'func' => 1, - 'types' => 'rr', - 'result' => 'p' - }, - 'uminus' => { - 'opcode' => 6, - 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => 'r' - }, - 'getp2' => { - 'opcode' => 16, - 'parms' => 2, - 'func' => 1, - 'types' => 'rr', - 'result' => 'p' - }, - 'getp3' => { - 'opcode' => 17, - 'parms' => 2, - 'func' => 1, - 'types' => 'rr', - 'result' => 'p' - }, - 'jumpnz' => { - 'opcode' => 42, - 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => undef - }, - 'op_count' => { - 'opcode' => 46, - 'parms' => '0', - 'func' => '0', - 'types' => '', - 'result' => undef - }, - 'blue' => { - 'opcode' => 24, + 'setp' => { + 'result' => 'p', 'parms' => 1, - 'func' => 1, - 'types' => 'p', - 'result' => 'r' + 'opcode' => 44, + 'func' => 0, + 'types' => 'p' }, - 'int' => { - 'opcode' => 26, + 'green' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 23, + 'func' => 1, + 'types' => 'p' + }, + 'abs' => { + 'result' => 'r', 'parms' => 1, + 'opcode' => 38, 'func' => 1, - 'types' => 'r', - 'result' => 'r' + 'types' => 'r' }, 'le' => { - 'opcode' => 29, + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 29, + 'func' => 0, + 'types' => 'rr' }, - 'multp' => { - 'opcode' => 7, - 'parms' => 2, - 'func' => '0', - 'types' => 'pr', - 'result' => 'p' - }, + 'cos' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 11, + 'func' => 1, + 'types' => 'r' + }, + 'not' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 37, + 'func' => 0, + 'types' => 'r' + }, 'ne' => { + 'result' => 'r', + 'parms' => 2, 'opcode' => 34, + 'func' => 0, + 'types' => 'rr' + }, + 'blue' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 24, + 'func' => 1, + 'types' => 'p' + }, + 'and' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 35, + 'func' => 0, + 'types' => 'rr' + }, + 'mult' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 2, + 'func' => 0, + 'types' => 'rr' + }, + 'rgba' => { + 'result' => 'p', + 'parms' => 4, + 'opcode' => 46, + 'func' => 1, + 'types' => 'rrrr' + }, + 'pow' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 5, + 'func' => 0, + 'types' => 'rr' + }, + 'lt' => { + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 30, + 'func' => 0, + 'types' => 'rr' }, - 'jumpz' => { - 'opcode' => 41, - 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => undef + 'mod' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 4, + 'func' => 0, + 'types' => 'rr' + }, + 'getp1' => { + 'result' => 'p', + 'parms' => 2, + 'opcode' => 15, + 'func' => 1, + 'types' => 'rr' }, 'atan2' => { + 'result' => 'r', + 'parms' => 2, 'opcode' => 12, + 'func' => 1, + 'types' => 'rr' + }, + 'getp2' => { + 'result' => 'p', + 'parms' => 2, + 'opcode' => 16, + 'func' => 1, + 'types' => 'rr' + }, + 'getp3' => { + 'result' => 'p', 'parms' => 2, + 'opcode' => 17, + 'func' => 1, + 'types' => 'rr' + }, + 'value' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 18, 'func' => 1, - 'types' => 'rr', - 'result' => 'r' + 'types' => 'p' }, 'subtractp' => { - 'opcode' => 9, + 'result' => 'p', 'parms' => 2, - 'func' => '0', - 'types' => 'pp', - 'result' => 'p' + 'opcode' => 9, + 'func' => 0, + 'types' => 'pp' }, - 'rgb' => { - 'opcode' => 25, - 'parms' => 3, - 'func' => 1, - 'types' => 'rrr', - 'result' => 'p' - }, - 'red' => { - 'opcode' => 22, + 'ge' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 31, + 'func' => 0, + 'types' => 'rr' + }, + 'sat' => { + 'result' => 'r', 'parms' => 1, + 'opcode' => 20, 'func' => 1, - 'types' => 'p', - 'result' => 'r' + 'types' => 'p' }, - 'setp' => { - 'opcode' => 44, - 'parms' => 1, - 'func' => '0', - 'types' => 'p', - 'result' => 'p' - }, 'jump' => { + 'result' => undef, + 'parms' => 0, 'opcode' => 40, - 'parms' => '0', - 'func' => '0', - 'types' => '', - 'result' => undef + 'func' => 0, + 'types' => '' }, - 'value' => { - 'opcode' => 18, - 'parms' => 1, - 'func' => 1, - 'types' => 'p', - 'result' => 'r' - }, - 'mod' => { - 'opcode' => 4, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'lt' => { - 'opcode' => 30, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'if' => { + 'result' => 'r', + 'parms' => 3, + 'opcode' => 27, + 'func' => 1, + 'types' => 'rrr' }, - 'mult' => { - 'opcode' => 2, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'hue' => { - 'opcode' => 19, - 'parms' => 1, - 'func' => 1, - 'types' => 'p', - 'result' => 'r' - }, 'div' => { - 'opcode' => 3, + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 3, + 'func' => 0, + 'types' => 'rr' }, - 'cos' => { - 'opcode' => 11, - 'parms' => 1, + 'ifp' => { + 'result' => 'p', + 'parms' => 3, + 'opcode' => 28, 'func' => 1, - 'types' => 'r', - 'result' => 'r' + 'types' => 'rpp' }, - 'subtract' => { - 'opcode' => 1, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'sat' => { - 'opcode' => 20, + 'set' => { + 'result' => 'r', 'parms' => 1, - 'func' => 1, - 'types' => 'p', - 'result' => 'r' - }, - 'add' => { - 'opcode' => '0', - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 43, + 'func' => 0, + 'types' => 'r' }, + 'eq' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 33, + 'func' => 0, + 'types' => 'rr' + }, + 'multp' => { + 'result' => 'p', + 'parms' => 2, + 'opcode' => 7, + 'func' => 0, + 'types' => 'pr' + }, 'sin' => { - 'opcode' => 10, + 'result' => 'r', 'parms' => 1, + 'opcode' => 10, 'func' => 1, - 'types' => 'r', - 'result' => 'r' + 'types' => 'r' }, 'sqrt' => { - 'opcode' => 13, + 'result' => 'r', 'parms' => 1, + 'opcode' => 13, 'func' => 1, - 'types' => 'r', - 'result' => 'r' + 'types' => 'r' }, - 'ret' => { - 'opcode' => 39, - 'parms' => 1, - 'func' => '0', - 'types' => 'p', - 'result' => undef - }, + 'alpha' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 48, + 'func' => 1, + 'types' => 'p' + }, 'distance' => { - 'opcode' => 14, + 'result' => 'r', 'parms' => 4, + 'opcode' => 14, 'func' => 1, - 'types' => 'rrrr', - 'result' => 'r' + 'types' => 'rrrr' }, - 'set' => { - 'opcode' => 43, - 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => 'r' - }, - 'ge' => { - 'opcode' => 31, + 'gt' => { + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'print' => { - 'opcode' => 45, - 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => undef - }, - 'if' => { - 'opcode' => 27, - 'parms' => 3, - 'func' => 1, - 'types' => 'rrr', - 'result' => 'r' + 'opcode' => 32, + 'func' => 0, + 'types' => 'rr' }, - 'not' => { - 'opcode' => 37, + 'red' => { + 'result' => 'r', 'parms' => 1, - 'func' => '0', - 'types' => 'r', - 'result' => 'r' + 'opcode' => 22, + 'func' => 1, + 'types' => 'p' }, - 'hsv' => { - 'opcode' => 21, + 'rgb' => { + 'result' => 'p', 'parms' => 3, + 'opcode' => 25, 'func' => 1, - 'types' => 'rrr', - 'result' => 'p' + 'types' => 'rrr' }, - 'green' => { - 'opcode' => 23, + 'hue' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 19, + 'func' => 1, + 'types' => 'p' + }, + 'hsva' => { + 'result' => 'p', + 'parms' => 4, + 'opcode' => 47, + 'func' => 1, + 'types' => 'rrrr' + }, + 'print' => { + 'result' => undef, 'parms' => 1, - 'func' => 1, - 'types' => 'p', - 'result' => 'r' + 'opcode' => 45, + 'func' => 0, + 'types' => 'r' }, - 'and' => { - 'opcode' => 35, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'abs' => { - 'opcode' => 38, + 'jumpnz' => { + 'result' => undef, + 'parms' => 1, + 'opcode' => 42, + 'func' => 0, + 'types' => 'r' + }, + 'addp' => { + 'result' => 'p', + 'parms' => 2, + 'opcode' => 8, + 'func' => 0, + 'types' => 'pp' + }, + 'int' => { + 'result' => 'r', 'parms' => 1, + 'opcode' => 26, 'func' => 1, - 'types' => 'r', - 'result' => 'r' + 'types' => 'r' }, - 'eq' => { - 'opcode' => 33, + 'op_count' => { + 'result' => undef, + 'parms' => 0, + 'opcode' => 49, + 'func' => 0, + 'types' => '' + }, + 'or' => { + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 36, + 'func' => 0, + 'types' => 'rr' }, - 'pow' => { - 'opcode' => 5, + 'jumpz' => { + 'result' => undef, + 'parms' => 1, + 'opcode' => 41, + 'func' => 0, + 'types' => 'r' + }, + 'add' => { + 'result' => 'r', 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' + 'opcode' => 0, + 'func' => 0, + 'types' => 'rr' }, - 'addp' => { - 'opcode' => 8, - 'parms' => 2, - 'func' => '0', - 'types' => 'pp', - 'result' => 'p' - }, - 'gt' => { - 'opcode' => 32, - 'parms' => 2, - 'func' => '0', - 'types' => 'rr', - 'result' => 'r' - }, - 'ifp' => { - 'opcode' => 28, + 'subtract' => { + 'result' => 'r', + 'parms' => 2, + 'opcode' => 1, + 'func' => 0, + 'types' => 'rr' + }, + 'ret' => { + 'result' => undef, + 'parms' => 1, + 'opcode' => 39, + 'func' => 0, + 'types' => 'p' + }, + 'hsv' => { + 'result' => 'p', 'parms' => 3, + 'opcode' => 21, 'func' => 1, - 'types' => 'rpp', - 'result' => 'p' - } + 'types' => 'rrr' + }, + 'uminus' => { + 'result' => 'r', + 'parms' => 1, + 'opcode' => 6, + 'func' => 0, + 'types' => 'r' + } ); $MaxOperands = 4; $PackCode = "i"; diff --git a/regmach.c b/regmach.c index 694ed2d9..cea9a791 100644 --- a/regmach.c +++ b/regmach.c @@ -66,7 +66,7 @@ static double hsv_sat(i_color color) { } } -static i_color make_hsv(double hue, double sat, double val) { +static i_color make_hsv(double hue, double sat, double val, int alpha) { int i; i_color c; for( i=0; i< MAXCHANNELS; i++) c.channel[i]=0; @@ -119,11 +119,12 @@ static i_color make_hsv(double hue, double sat, double val) { break; } } + c.rgba.a = alpha; return c; } -static i_color make_rgb(int r, int g, int b) { +static i_color make_rgb(int r, int g, int b, int a) { i_color c; if (r < 0) r = 0; @@ -141,6 +142,8 @@ static i_color make_rgb(int r, int g, int b) { b = 255; c.rgb.b = b; + c.rgba.a = a; + return c; } @@ -210,17 +213,17 @@ i_color i_rm_run(struct rm_op codes[], size_t code_count, nout = -na; case rbc_multp: - cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb); + cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255); break; case rbc_addp: cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g, - ca.rgb.b + cb.rgb.b); + ca.rgb.b + cb.rgb.b, 255); break; case rbc_subtractp: cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g, - ca.rgb.b - cb.rgb.b); + ca.rgb.b - cb.rgb.b, 255); break; case rbc_sin: @@ -270,7 +273,11 @@ i_color i_rm_run(struct rm_op codes[], size_t code_count, break; case rbc_hsv: - cout = make_hsv(na, nb, nc); + cout = make_hsv(na, nb, nc, 255); + break; + + case rbc_hsva: + cout = make_hsv(na, nb, nc, nd); break; case rbc_red: @@ -285,8 +292,16 @@ i_color i_rm_run(struct rm_op codes[], size_t code_count, nout = ca.rgb.b; break; + case rbc_alpha: + nout = ca.rgba.a; + break; + case rbc_rgb: - cout = make_rgb(na, nb, nc); + cout = make_rgb(na, nb, nc, 255); + break; + + case rbc_rgba: + cout = make_rgb(na, nb, nc, nd); break; case rbc_int: diff --git a/regmach.h b/regmach.h index 083dad53..79b8fda2 100644 --- a/regmach.h +++ b/regmach.h @@ -54,6 +54,9 @@ enum rm_byte_codes { rbc_set, /* ra -> r */ rbc_setp, /* pa -> p*/ rbc_print, /* prints ra */ + rbc_rgba, /* rgba(ra, rb, rc, rd) -> p */ + rbc_hsva, /* hsva(ra, rb, rc, rd) -> p */ + rbc_alpha, /* alpha(pa) -> r */ rbc_op_count }; diff --git a/t/t56postfix.t b/t/t56postfix.t index 4ef18a33..d1379cef 100644 --- a/t/t56postfix.t +++ b/t/t56postfix.t @@ -7,7 +7,11 @@ print "ok 1\n"; #$Imager::DEBUG=1; -my $expr = Imager::Expr->new({rpnexpr=>'x two * y one + getp1', variables=>[ qw(x y) ], constants=>{one=>1, two=>2}}); +my $expr = Imager::Expr->new({rpnexpr=><[ qw(x y) ], constants=>{one=>1, two=>2}}); +x two * # see if comments work +y one + +getp1 +EXPR if ($expr) { print "ok 2\n"; diff --git a/t/t58trans2.t b/t/t58trans2.t index bf92dba8..163570d2 100644 --- a/t/t58trans2.t +++ b/t/t58trans2.t @@ -1,11 +1,14 @@ -BEGIN { $| = 1; print "1..12\n"; } +#!perl -w +BEGIN { $| = 1; print "1..15\n"; } END {print "not ok 1\n" unless $loaded;} use Imager; -sub ok($$$); +sub ok($$); +sub is($$$); +my $num = 1; $loaded = 1; -print "ok 1\n"; +ok(1, "loaded"); #$Imager::DEBUG=1; @@ -21,14 +24,14 @@ $im2->open(file=>'testimg/scale.ppm',type=>'pnm') # error handling my $opts = { rpnexpr=>'x x 10 / sin 10 * y + get1' }; my $im3 = Imager::transform2($opts); -ok(2, !$im3, "returned an image on error"); -ok(3, defined($Imager::ERRSTR), "No error message on failure"); +ok(!$im3, "returned an image on error"); +ok(defined($Imager::ERRSTR), "No error message on failure"); # image synthesis my $im4 = Imager::transform2({ width=>300, height=>300, rpnexpr=>'x y cx cy distance !d y cy - x cx - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 cy * 3.1416 / 1 @a2 sin 1 + 2 / hsv'}); -ok(4, $im4, "synthesis failed"); +ok($im4, "synthesis failed"); if ($im4) { $im4->write(type=>'pnm', file=>'testout/t56a.ppm') @@ -39,7 +42,7 @@ if ($im4) { my $im5 = Imager::transform2({ rpnexpr=>'x x 10 / sin 10 * y + getp1' }, $im1); -ok(5, $im5, "image distortion"); +ok($im5, "image distortion"); if ($im5) { $im5->write(type=>'pnm', file=>'testout/t56b.ppm') || die "Cannot write testout/t56b.ppm"; @@ -50,46 +53,76 @@ $opts = { rpnexpr=>'x h / !rat x w2 % y h2 % getp2 !pat x y getp1 @rat * @pat 1 @rat - * +' }; my $im6 = Imager::transform2($opts,$im1,$im2); -ok(6, $im6, "image combination"); +ok($im6, "image combination"); if ($im6) { $im6->write(type=>'pnm', file=>'testout/t56c.ppm') || die "Cannot write testout/t56c.ppm"; } +# alpha +$opts = + { + rpnexpr => '0 0 255 x y + w h + 2 - / 255 * rgba', + channels => 4, + width => 50, + height => 50, + }; +my $im8 = Imager::transform2($opts); +ok($im8, "alpha output"); +my $c = $im8->getpixel(x=>0, 'y'=>0); +is(($c->rgba)[3], 0, "zero alpha"); +$c = $im8->getpixel(x=>49, 'y'=>49); +is(($c->rgba)[3], 255, "max alpha"); + use Imager::Transform; # some simple tests -my @funcs = Imager::Transform->list or print "not "; -print "ok 7\n"; -my $tran = Imager::Transform->new($funcs[0]) or print "not "; -print "ok 8\n"; -$tran->describe() eq Imager::Transform->describe($funcs[0]) or print "not "; -print "ok 9\n"; +print "# Imager::Transform\n"; +my @funcs = Imager::Transform->list; +ok(@funcs, "funcs"); + +my $tran = Imager::Transform->new($funcs[0]); +ok($tran, "got tranform"); +ok($tran->describe() eq Imager::Transform->describe($funcs[0]), + "description"); # look for a function that takes inputs (at least one does) my @needsinputs = grep Imager::Transform->new($_)->inputs, @funcs; # make sure they're my @inputs = Imager::Transform->new($needsinputs[0])->inputs; -$inputs[0]{desc} or print "not "; -print "ok 10\n"; +ok($inputs[0]{desc}, "input description"); # at some point I might want to test the actual transformations # check lower level error handling my $im7 = Imager::transform2({rpnexpr=>'x y getp2', width=>100, height=>100}); -ok(11, !$im7, "expected failure on accessing invalid image"); +ok(!$im7, "expected failure on accessing invalid image"); print "# ", Imager->errstr, "\n"; -ok(12, Imager->errstr =~ /not enough images/, "didn't get expected error"); - +ok(Imager->errstr =~ /not enough images/, "didn't get expected error"); -sub ok ($$$) { - my ($num, $test, $desc) = @_; +sub ok ($$) { + my ($test, $desc) = @_; if ($test) { - print "ok $num\n"; + print "ok $num # $desc\n"; } else { print "not ok $num # $desc\n"; } + ++$num; $test; } +sub is ($$$) { + my ($left, $right, $desc) = @_; + + my $eq = $left == $right; + unless (ok($eq, $desc)) { + $left =~ s/\n/# \n/g; + $left =~ s/([^\n\x20-\x7E])/"\\x".sprintf("%02X", ord $1)/ge; + $right =~ s/\n/# \n/g; + $right =~ s/([^\n\x20-\x7E])/"\\x".sprintf("%02X", ord $1)/ge; + print "# not equal, left = '$left'\n"; + print "# right = '$right'\n"; + } + $eq; +} diff --git a/typemap b/typemap index 7e36a8ce..abcf4de9 100644 --- a/typemap +++ b/typemap @@ -17,6 +17,14 @@ INPUT T_PTR_NULL if (SvOK($arg)) $var = INT2PTR($type,SvIV($arg)); else $var = NULL + +# the pre-5.8.0 T_AVREF input map was fixed in 5.8.0 +T_AVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) + $var = (AV*)SvRV($arg); + else + Perl_croak(aTHX_ \"$var is not an array reference\") + ############################################################################# OUTPUT T_IV_U