- added comment support the postfix transform2() expression
authorTony Cook <tony@develop=help.com>
Thu, 26 Jun 2003 03:50:00 +0000 (03:50 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 26 Jun 2003 03:50:00 +0000 (03:50 +0000)
          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
Imager.pm
Imager.xs
lib/Imager/Engines.pod
lib/Imager/Expr.pm
lib/Imager/Regops.pm
regmach.c
regmach.h
t/t56postfix.t
t/t58trans2.t
typemap

diff --git a/Changes b/Changes
index 63a2995..a32d377 100644 (file)
--- 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
 
 =================================================================
 
index 9ddd35c..953e111 100644 (file)
--- 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}) {
index 5e79c19..81ff9c6 100644 (file)
--- 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)
index 1791400..68aec86 100644 (file)
@@ -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<Imager::regmach.pod>.
   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
index 5effa50..8833dc9 100644 (file)
@@ -298,6 +298,7 @@ my %op_names = ( '+'=>'add', '-'=>'subtract', '*'=>'mult', '/' => 'div',
 sub compile {
   my ($self, $expr, $opts) = @_;
 
+  $expr =~ s/#.*//; # remove comments
   my @st_ops = split ' ', $expr;
 
   for (@st_ops) {
index 01712f1..644b8b5 100644 (file)
@@ -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";
index 694ed2d..cea9a79 100644 (file)
--- 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:
index 083dad5..79b8fda 100644 (file)
--- 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
 };
 
index 4ef18a3..d1379ce 100644 (file)
@@ -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=><<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";
 
index bf92dba..163570d 100644 (file)
@@ -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 7e36a8c..abcf4de 100644 (file)
--- 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