diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 72005e4ca44fa9e76447c85da5bf11df953e6291..c2b41e2c715c0d2f7b20104e3b83f748f6fa68c8 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -797,6 +797,7 @@ static void fielddesc_setfloat_var(t_fielddesc *fd, t_symbol *s)
 #define CLOSED 1
 #define BEZ 2
 #define NOMOUSE 4
+#define BBOX 8          /* pair of coords for rectangles and ellipses */
 #define A_ARRAY 55      /* LATER decide whether to enshrine this in m_pd.h */
 
 static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
@@ -964,6 +965,7 @@ typedef struct _curve
     t_object x_obj;
     int x_flags;            /* CLOSED and/or BEZ and/or NOMOUSE */
     t_fielddesc x_fillcolor;
+    t_fielddesc x_fillopacity;
     t_fielddesc x_outlinecolor;
     t_fielddesc x_width;
     t_fielddesc x_vis;
@@ -986,7 +988,8 @@ static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
         flags |= CLOSED;
     }
     else classname += 4;
-    if (classname[0] == 'c') flags |= BEZ;
+    if (classname[0] == 'c' || classname[0] == 'e') flags |= BEZ;
+    if (classname[0] == 'e' || classname[0] == 'r') flags |= BBOX;
     fielddesc_setfloat_const(&x->x_vis, 1);
     while (1)
     {
@@ -1018,7 +1021,7 @@ static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
     for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
         fielddesc_setfloatarg(fd, 1, argv);
     if (argc & 1) fielddesc_setfloat_const(fd, 0);
-
+    fielddesc_setfloat_const(&x->x_fillopacity, 1);
     return (x);
 }
 
@@ -1039,6 +1042,17 @@ void curve_float(t_curve *x, t_floatarg f)
     canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
 }
 
+void curve_fillopacity(t_curve *x, t_symbol *s, t_int argc, t_atom *argv)
+{
+    char *classname = s->s_name;
+    if (classname[0] == 'd' || argc < 1) return;
+    if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+    {
+        fielddesc_setfloatarg(&x->x_fillopacity, argc, argv);
+        canvas_redrawallfortemplatecanvas(x->x_canvas, 0);
+    }
+}
+
 /* -------------------- widget behavior for curve ------------ */
 
 static void curve_getrect(t_gobj *z, t_glist *glist,
@@ -1067,6 +1081,23 @@ static void curve_getrect(t_gobj *z, t_glist *glist,
         if (xloc > x2) x2 = xloc;
         if (yloc < y1) y1 = yloc;
         if (yloc > y2) y2 = yloc;
+    }
+    if ((x->x_flags & BEZ) && (x->x_flags & BBOX))
+    {
+        int cx = glist_xtopixels(glist,
+            basex + fielddesc_getcoord(x->x_vec, template,
+                data, 0));
+        int cy = glist_ytopixels(glist,
+            basey + fielddesc_getcoord(x->x_vec+1, template,
+                data, 0));
+        int rx = fielddesc_getfloat(x->x_vec+2, template,
+            data, 0);
+        int ry = fielddesc_getfloat(x->x_vec+3, template,
+            data, 0);
+        x1 = cx - rx;
+        y1 = cy - ry;
+        x2 = cx + rx;
+        y2 = cy + ry;
     }
 	//fprintf(stderr,"FINAL curve_getrect %d %d %d %d\n", x1, y1, x2, y2);
     *xp1 = x1;
@@ -1172,17 +1203,52 @@ static void curve_vis(t_gobj *z, t_glist *glist,
                 numbertocolor(
                     fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
                     fill);
-                sys_vgui(".x%lx.c create ppolygon\\\n",
-                    glist_getcanvas(glist));
+                if (flags & CLOSED && !(flags & BBOX))
+                {
+                    sys_vgui(".x%lx.c create ppolygon\\\n",
+                        glist_getcanvas(glist));
+                }
+                else if (flags & BBOX) /* rectangles and ellipses */
+                {
+                    n = 2; /* silently truncate extra coordinates */
+                    if(flags & BEZ)
+                        sys_vgui(".x%lx.c create ellipse\\\n",
+                            glist_getcanvas(glist));
+                    else
+                        sys_vgui(".x%lx.c create prect\\\n",
+                        glist_getcanvas(glist));
+                }
+            }
+            else
+            {
+                if(flags & BBOX)
+                {
+                    if(flags & BEZ)
+                        sys_vgui(".x%lx.c create ellipse\\\n", glist_getcanvas(glist));
+                    else
+                        sys_vgui(".x%lx.c create prect\\\n", glist_getcanvas(glist));
+                } else
+                    sys_vgui(".x%lx.c create polyline\\\n", glist_getcanvas(glist));
             }
-            else sys_vgui(".x%lx.c create polyline\\\n", glist_getcanvas(glist));
             for (i = 0; i < n; i++)
+            {
                 sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]);
+                if ((flags & BEZ) && (flags & BBOX))
+                {
+                    sys_vgui("-rx %d -ry %d\\\n",
+                        (t_int)fielddesc_getfloat(x->x_vec+2,
+                            template, data, 1),
+                        (t_int)fielddesc_getfloat(x->x_vec+3,
+                            template, data, 1));
+                    break;
+                }
+            }
             sys_vgui("-strokewidth %f\\\n", width);
-			if (flags & CLOSED) sys_vgui("-fill %s -stroke %s\\\n",
-                fill, outline);
+		if (flags & CLOSED) sys_vgui("-fill %s -stroke %s -fillopacity %g\\\n",
+                fill, outline, fielddesc_getfloat(&x->x_fillopacity, template, data, 1));
+            else if(flags & BBOX) sys_vgui("-stroke %s\\\n", outline);
             else sys_vgui("-stroke %s\\\n", outline);
-            //if (flags & BEZ) sys_vgui("-smooth 1\\\n"); //this doesn't work with tkpath
+            //if ((flags & BEZ) && !(flags & BBOX)) sys_vgui("-smooth 1\\\n"); //this doesn't work with tkpath
             sys_vgui("-tags {.x%lx.x%lx.template%lx}\n", glist_getcanvas(glist), glist,
 				data);
 			if (!glist_istoplevel(glist)) {
@@ -1344,8 +1410,18 @@ static void curve_setup(void)
         A_GIMME, 0);
     class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
         A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("drawrectangle"),
+        A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("filledrectangle"),
+        A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("drawellipse"),
+        A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("filledellipse"),
+        A_GIMME, 0);
     class_setparentwidget(curve_class, &curve_widgetbehavior);
     class_addfloat(curve_class, curve_float);
+    class_addmethod(curve_class, (t_method)curve_fillopacity,
+        gensym("fillopacity"), A_GIMME, 0);
 }
 
 /* --------- plots for showing arrays --------------- */
@@ -2764,6 +2840,381 @@ static void drawsymbol_setup(void)
     class_setparentwidget(drawsymbol_class, &drawsymbol_widgetbehavior);
 }
 
+/* ---------------- drawimage: draw an image ---------------- */
+/* ---------------- drawsprite: draw a sprite ---------------- */
+
+/*
+    drawimage draws an image (gif) at controllable locations.
+    invocation:
+    (drawimage|drawsprite) [-v <visible>] variable x y directory
+*/
+
+t_class *drawimage_class;
+
+#define DRAW_SPRITE 1
+
+typedef struct _drawimage
+{
+    t_object x_obj;
+    t_fielddesc x_value;
+    t_fielddesc x_xloc;
+    t_fielddesc x_yloc;
+    t_fielddesc x_vis;
+    t_symbol *x_img;
+    t_float x_w;
+    t_float x_h;
+    int x_flags;
+    t_canvas *x_canvas;
+} t_drawimage;
+
+static void *drawimage_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+    t_drawimage *x = (t_drawimage *)pd_new(drawimage_class);
+    char *classname = classsym->s_name;
+    char buf[50];
+    sprintf(buf, ".x%lx", (t_int)x);
+    pd_bind(&x->x_obj.ob_pd, gensym(buf));
+    int flags = 0;
+    
+    if (classname[4] == 's')
+        flags |= DRAW_SPRITE;
+    x->x_flags = flags;
+    fielddesc_setfloat_const(&x->x_vis, 1);
+    x->x_canvas = canvas_getcurrent();
+    t_symbol *dir = canvas_getdir(x->x_canvas);
+    while (1)
+    {
+        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else break;
+    }
+    if (argc && argv->a_type == A_SYMBOL)
+        x->x_img = atom_getsymbolarg(0, argc--, argv++);
+    else x->x_img = &s_;
+    if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_xloc, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_yloc, 0);
+    if (argc)
+    {
+        fielddesc_setfloatarg(&x->x_value, argc--, argv++);
+        if (!(x->x_flags & DRAW_SPRITE))
+            post("drawimage warning: sequence variable is only "
+                 "used with drawsprite");
+    }
+    else fielddesc_setfloat_const(&x->x_value, 0);
+
+    /* [drawimage] allocates memory for an image or image sequence
+       while the object is creating. The corresponding scalar gets
+       drawn as a canvas image item using the "parent" tk image as
+       the source. ".x%lx" is the name for the parent tk image and
+       ".x%lx.i" is the tag given to a scalar's canvas image item.
+    */
+    sys_vgui("pdtk_drawimage_new .x%lx {%s} {%s} %d\n", (t_int)x,
+        x->x_img->s_name, dir->s_name, x->x_flags);
+    return (x);
+}
+
+void drawimage_float(t_drawimage *x, t_floatarg f)
+{
+    int viswas;
+    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
+    {
+        pd_error(x, "global vis/invis for a template with variable visibility");
+        return;
+    }
+    viswas = (x->x_vis.fd_un.fd_float != 0);
+    
+    if ((f != 0 && viswas) || (f == 0 && !viswas))
+        return;
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
+    fielddesc_setfloat_const(&x->x_vis, (f != 0));
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
+}
+
+void drawimage_size(t_drawimage *x, t_float w, t_float h)
+{
+    x->x_w = w;
+    x->x_h = h;
+}
+
+/* -------------------- widget behavior for drawimage ------------ */
+
+
+/*
+static void drawimage_sprintf(t_drawimage *x, char *buf, t_atom *ap)
+{
+    int nchars;
+    strncpy(buf, x->x_label->s_name, MAXPDSTRING);
+    buf[DRAWNUMBER_BUFSIZE - 1] = 0;
+    nchars = strlen(buf);
+    atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
+}
+*/
+
+
+static void drawimage_getrect(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_drawimage *x = (t_drawimage *)z;
+    int xloc, yloc;
+//    char buf[DRAWNUMBER_BUFSIZE];
+
+    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        *xp1 = *yp1 = 0x7fffffff;
+        *xp2 = *yp2 = -0x7fffffff;
+        return;
+    }
+    xloc = glist_xtopixels(glist,
+        basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+    yloc = glist_ytopixels(glist,
+        basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+    *xp1 = xloc;
+    *yp1 = yloc;
+
+    *xp2 = xloc + x->x_w;
+    *yp2 = yloc + x->x_h;
+}
+
+static void drawimage_displace(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int dx, int dy)
+{
+    /* refuse */
+}
+
+static void drawimage_select(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int state)
+{
+    post("drawimage_select %d", state);
+    /* fill in later */
+}
+
+static void drawimage_activate(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int state)
+{
+    post("drawimage_activate %d", state);
+}
+
+static void drawimage_vis(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_float basex, t_float basey,
+    int vis)
+{
+    t_drawimage *x = (t_drawimage *)z;
+    
+        /* see comment in plot_vis() */
+    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
+        return;
+    if (vis)
+    {
+        t_atom at;
+        int xloc = glist_xtopixels(glist,
+            basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+        int yloc = glist_ytopixels(glist,
+            basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+        sys_vgui("pdtk_drawimage_vis .x%lx.c %d %d .x%lx .x%lx.i %d ",
+            glist_getcanvas(glist), xloc, yloc, x, data,
+            (int)fielddesc_getfloat(&x->x_value, template, data, 0));
+        sys_vgui(".x%lx.x%lx.template%lx\n", glist_getcanvas(glist),
+            glist, data);
+    }
+    else sys_vgui("pdtk_drawimage_unvis .x%lx.c .x%lx.i\n",
+        glist_getcanvas(glist), data);
+}
+
+static t_float drawimage_motion_ycumulative;
+static t_glist *drawimage_motion_glist;
+static t_scalar *drawimage_motion_scalar;
+static t_array *drawimage_motion_array;
+static t_word *drawimage_motion_wp;
+static t_template *drawimage_motion_template;
+static t_gpointer drawimage_motion_gpointer;
+static int drawimage_motion_sprite;
+static int drawimage_motion_firstkey;
+
+    /* LATER protect against the template changing or the scalar disappearing
+    probably by attaching a gpointer here ... */
+
+static void drawimage_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+    t_drawimage *x = (t_drawimage *)z;
+    t_fielddesc *f = &x->x_value;
+    t_atom at;
+    if (!gpointer_check(&drawimage_motion_gpointer, 0))
+    {
+        post("drawimage_motion: scalar disappeared");
+        return;
+    }
+    if (!drawimage_motion_sprite)
+    {
+        /* post("drawimage_motion: image"); */
+        return;
+    }
+    drawimage_motion_ycumulative -= dy;
+    template_setfloat(drawimage_motion_template,
+        f->fd_un.fd_varsym,
+            drawimage_motion_wp, 
+            drawimage_motion_ycumulative,
+                1);
+    if (drawimage_motion_scalar)
+        template_notifyforscalar(drawimage_motion_template,
+            drawimage_motion_glist, drawimage_motion_scalar,
+                gensym("change"), 1, &at);
+
+    if (drawimage_motion_scalar)
+        scalar_redraw(drawimage_motion_scalar, drawimage_motion_glist);
+    if (drawimage_motion_array)
+        array_redraw(drawimage_motion_array, drawimage_motion_glist);
+}
+
+static void drawimage_key(void *z, t_floatarg fkey)
+{
+    return;
+    t_drawnumber *x = (t_drawnumber *)z;
+    t_fielddesc *f = &x->x_value;
+    int key = fkey;
+    char sbuf[MAXPDSTRING];
+    t_atom at;
+    if (!gpointer_check(&drawnumber_motion_gpointer, 0))
+    {
+        post("drawnumber_motion: scalar disappeared");
+        return;
+    }
+    if (key == 0)
+        return;
+    if (drawnumber_motion_symbol)
+    {
+            /* key entry for a symbol field */
+        if (drawnumber_motion_firstkey)
+            sbuf[0] = 0;
+        else strncpy(sbuf, template_getsymbol(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, 1)->s_name,
+                MAXPDSTRING);
+        sbuf[MAXPDSTRING-1] = 0;
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+    }
+    else
+    {
+            /* key entry for a numeric field.  This is just a stopgap. */
+        double newf;
+        if (drawnumber_motion_firstkey)
+            sbuf[0] = 0;
+        else sprintf(sbuf, "%g", template_getfloat(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, 1));
+        drawnumber_motion_firstkey = (key == '\n');
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+        if (sscanf(sbuf, "%lg", &newf) < 1)
+            newf = 0;
+        template_setfloat(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, (t_float)newf, 1);
+        if (drawnumber_motion_scalar)
+            template_notifyforscalar(drawnumber_motion_template,
+                drawnumber_motion_glist, drawnumber_motion_scalar,
+                    gensym("change"), 1, &at);
+        if (drawnumber_motion_scalar)
+            scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist);
+        if (drawnumber_motion_array)
+            array_redraw(drawnumber_motion_array, drawnumber_motion_glist);
+    }
+}
+
+static int drawimage_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    t_float basex, t_float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_drawimage *x = (t_drawimage *)z;
+    int x1, y1, x2, y2;
+    drawimage_getrect(z, glist,
+        data, template, basex, basey,
+        &x1, &y1, &x2, &y2);
+    if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+        && x->x_value.fd_var &&
+            fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        if (doit)
+        {
+            drawimage_motion_glist = glist;
+            drawimage_motion_wp = data;
+            drawimage_motion_template = template;
+            drawimage_motion_scalar = sc;
+            drawimage_motion_array = ap;
+            drawimage_motion_firstkey = 1;
+            drawimage_motion_ycumulative =
+                fielddesc_getfloat(&x->x_value, template, data, 0);
+            drawimage_motion_sprite = ((x->x_flags & DRAW_SPRITE) != 0);
+            if (drawimage_motion_scalar)
+                gpointer_setglist(&drawimage_motion_gpointer, 
+                    drawimage_motion_glist, drawimage_motion_scalar);
+            else gpointer_setarray(&drawimage_motion_gpointer,
+                    drawimage_motion_array, drawimage_motion_wp);
+           glist_grab(glist, z, drawimage_motion, drawimage_key,
+                xpix, ypix);
+        }
+        return (1);
+    }
+    else return (0);
+}
+
+t_parentwidgetbehavior drawimage_widgetbehavior =
+{
+    drawimage_getrect,
+    drawimage_displace,
+    drawimage_select,
+    drawimage_activate,
+    drawimage_vis,
+    drawimage_click,
+};
+
+static void drawimage_free(t_drawimage *x)
+{
+    /* delete the parent image in the gui */
+    char buf[50];
+    sprintf(buf, ".x%lx", (t_int)x);
+    pd_unbind(&x->x_obj.ob_pd, gensym(buf));
+    sys_vgui("pdtk_drawimage_free .x%lx\n", (t_int)x);
+}
+
+static void drawimage_setup(void)
+{
+    drawimage_class = class_new(gensym("drawimage"),
+        (t_newmethod)drawimage_new, (t_method)drawimage_free,
+        sizeof(t_drawimage), 0, A_GIMME, 0);
+    class_setdrawcommand(drawimage_class);
+    class_addfloat(drawimage_class, drawimage_float);
+    class_addmethod(drawimage_class, (t_method)drawimage_size,
+        gensym("size"), A_FLOAT, A_FLOAT, 0);
+    class_addcreator((t_newmethod)drawimage_new, gensym("drawsprite"),
+        A_GIMME, 0);
+    class_setparentwidget(drawimage_class, &drawimage_widgetbehavior);
+}
+
 /* ---------------------- setup function ---------------------------- */
 
 void g_template_setup(void)
@@ -2773,6 +3224,7 @@ void g_template_setup(void)
     curve_setup();
     plot_setup();
     drawnumber_setup();
-	drawsymbol_setup();
+    drawsymbol_setup();
+    drawimage_setup();
 }
 
diff --git a/pd/src/pd.tk b/pd/src/pd.tk
index 082c61d696da6e4d394a92dba51bdf84526a0cb0..cb6284da197c024334e76588302ec6cbf7ddb716 100644
--- a/pd/src/pd.tk
+++ b/pd/src/pd.tk
@@ -9013,4 +9013,8 @@ proc pdtk_check_unique {unique filenames} {
 	#puts stderr "this is unique instance [tk appname]"
 }
 
+# Search plugin
 source [file join [file dirname [info script]] search-plugin.tcl]
+
+# Tcl/tk code for drawimage and drawsprite
+source [file join [file dirname [info script]] pdtk_drawimage.tcl]
diff --git a/pd/src/pdtk_drawimage.tcl b/pd/src/pdtk_drawimage.tcl
new file mode 100644
index 0000000000000000000000000000000000000000..d8b2e9a3bfa3a78456f694c6c9b7d71e0ca4b2ba
--- /dev/null
+++ b/pd/src/pdtk_drawimage.tcl
@@ -0,0 +1,88 @@
+#todo: rename img to imgprefix
+
+# package provide pdtk_drawimage 0.1
+# package require tkpng
+
+namespace eval ::pdtk_drawimage:: {
+    namespace export pdtk_drawimage_new
+    namespace export pdtk_drawimage_vis
+}
+
+# Some GUI procs for [drawimage] and [drawsprite]
+
+# Draw an image
+proc pdtk_drawimage_new {obj path canvasdir flags} {
+    set drawsprite 1
+    set image_seq [expr {$flags & $drawsprite}]
+    # obj  - .x%lx name for [drawimage] instance
+    # path - this is absolute or relative
+    #        for [drawsprite] this is the directory of the image sequence
+    #        for [drawimage] this is the file path of the image
+    # canvasdir - relative paths should be relative to this
+    #        (any other possibilities?)
+    set i 0
+    set matchchar *
+    # this will discard $canvasdir for absolute paths, which is nice
+    set path [file normalize [file join $canvasdir $path]]
+    if {[file isdir $path]} {
+        # put a final directory separator for a dir
+        set path [string trimright [file join $path { }]]
+    } else {
+        # if it's a file we don't want a wildcard character
+        set matchchar {}
+    }
+    if {![file exists $path]} {
+        pdtk_post "drawimage: warning: path doesn't exist: $path\n"
+        pd [concat $obj size 1 1 \;]
+        return
+    }
+    foreach filename [lsort -dictionary [glob -nocomplain -type {f r} \
+        -path $path $matchchar]] {
+        if {[file extension $filename] eq ".gif" ||
+            [file extension $filename] eq ".png"} {
+            image create photo ::drawimage_${obj}$i -file "$filename"
+            pdtk_post "image is ::drawimage_${obj}$i\n"
+            incr i
+        }
+        if {$i > 1000 || !$image_seq} {break}
+    }
+    pdtk_post "no of files: $i\n"
+    # we bound a symbol to $img in drawimage_new, so we
+    # can send back a message with the image dimensions
+    # to be used for the selection bbox. This is dumb--
+    # pd has no business handling a gui issue like size
+    # of a selection rectangle.  That's what Tk is for.
+    # But that's a bigger issue to be dealt with later.
+    if {$i > 0} {
+    pdtk_post "image width is [image width ::drawimage_${obj}0]\n"
+    pdtk_post "image height is [image height ::drawimage_${obj}0]\n"
+    pdtk_post "obj is $obj\n"
+        pd [concat $obj size [image width ::drawimage_${obj}0] \
+            [image height ::drawimage_${obj}0] \;]
+    } else {
+        pdtk_post "drawimage: warning: no images loaded"
+    }
+}
+
+proc pdtk_drawimage_vis {c x y obj tag seqno l2orktag} {
+    set img ::drawimage_${obj}
+    set len [llength [lsearch -glob -all [image names] ${img}*]]
+    if {$len < 1} {return}
+    if {$seqno >= $len || $seqno < 0} {set seqno [expr {$seqno % $len}]}
+    $c create image $x $y -image ${img}$seqno -anchor nw -tags [list $tag $l2orktag]
+}
+
+proc pdtk_drawimage_unvis {c tag} {
+    $c delete $tag
+}
+
+proc pdtk_drawimage_free {img} {
+#    image delete [lsearch -glob -all -inline [image names] ::drawimage_${img}*]
+
+    foreach globalimage [image names] {
+        if {[lsearch -glob $globalimage ::drawimage_${img}*] != -1} {
+            image delete $globalimage
+            pdtk_post "Deleted $globalimage\n"
+        }
+    }
+}