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
=================================================================
$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}) {
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;
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");
}
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)
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
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)
EOS
});
+ # replace green portions of an image with another image
+ my $newimg = Imager::transform2({
+ rpnexpr => <<EOS
+ x y getp2 !pat # used to replace green portions
+ x y getp1 !pix # source with "green screen"
+ @pix red 10 lt @pix blue 10 lt && # low blue and red
+ @pix green 254 gt && # and high green
+ @pat @pix ifp
+ EOS
+ }, $source, $background);
+
=head2 Matrix Transformations
Rather than having to write code in a little language, you can use a
sub compile {
my ($self, $expr, $opts) = @_;
+ $expr =~ s/#.*//; # remove comments
my @st_ops = split ' ', $expr;
for (@st_ops) {
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";
}
}
-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;
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;
b = 255;
c.rgb.b = b;
+ c.rgba.a = a;
+
return c;
}
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:
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:
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:
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
};
#$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=><<EXPR, variables=>[ qw(x y) ], constants=>{one=>1, two=>2}});
+x two * # see if comments work
+y one +
+getp1
+EXPR
if ($expr) {
print "ok 2\n";
-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;
# 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')
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";
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;
+}
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