ImageTkScript.C

Go to the documentation of this file.
00001 /*!@file Script/ImageTkScript.C */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Script/ImageTkScript.C $
00035 // $Id: ImageTkScript.C 11876 2009-10-22 15:53:06Z icore $
00036 //
00037 
00038 #ifndef SCRIPT_IMAGETKSCRIPT_C_DEFINED
00039 #define SCRIPT_IMAGETKSCRIPT_C_DEFINED
00040 
00041 #include "Script/ImageTkScript.H"
00042 
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 #include "Script/ImageScript.H"
00046 #include "Util/Assert.H"
00047 #include "Util/Types.H"
00048 #include "Util/log.H"
00049 #include "tcl/interp.h"
00050 #include "tcl/pkg.h"
00051 
00052 #include <X11/Xlib.h>
00053 #include <X11/Xutil.h>
00054 #include <X11/extensions/XShm.h>
00055 #include <stdlib.h>
00056 #include <sys/shm.h>
00057 #include <tk.h>
00058 
00059 namespace
00060 {
00061   int fourByteAlign(int v)
00062   {
00063     const int remainder = v % 4;
00064     return (remainder == 0) ? v : v + (4-remainder);
00065   }
00066 }
00067 
00068 template <class T>
00069 struct ImageTk
00070 {
00071   // typedef struct Tk_ImageType {
00072   //     char *name;
00073   //     Tk_ImageCreateProc *createProc;
00074   //     Tk_ImageGetProc *getProc;
00075   //     Tk_ImageDisplayProc *displayProc;
00076   //     Tk_ImageFreeProc *freeProc;
00077   //     Tk_ImageDeleteProc *deleteProc;
00078   // } Tk_ImageType;
00079 
00080   static Tk_ImageType imageType;
00081 
00082   struct Master
00083   {
00084     Tk_ImageMaster token;
00085     Image<T>       image;
00086   };
00087 
00088   struct Instance
00089   {
00090     Master*         const master;
00091     Tk_Window       const tkwin;
00092     GC                    gc;   // current graphic context
00093     XImage*               image; // pointer to image data
00094     XShmSegmentInfo       shminfo; // info on shared memory segment
00095     char*                 buffer; // shared memory buffer
00096     bool                  shm_buffer; // true if we can use shared memory
00097 
00098     Instance(Tk_Window tkw, Master* m)
00099       :
00100       master(m),
00101       tkwin(tkw),
00102       gc(0),
00103       image(0)
00104     {
00105       const Image<PixRGB<byte> > img = m->image;
00106 
00107       const Dims idims = img.getDims();
00108 
00109       // get default screen:
00110       int byt_per_pix = 4;
00111       if (Tk_Depth(tkwin) == 16) byt_per_pix = 2;
00112 
00113       // alloc XImage in shared memory if posible (for faster display):
00114       int Shm_OK = XShmQueryExtension(Tk_Display(tkwin));
00115 
00116       // check if remote display, and disable shared memory if so:
00117       char* disp = getenv("DISPLAY");
00118       if (disp != NULL && disp[0] != ':')
00119         {
00120           Shm_OK = 0;
00121           LDEBUG("Not using shared memory for remote display");
00122         }
00123 
00124       // Get a padded row width that is 4-byte aligned
00125       const int padded_width = fourByteAlign(idims.w());
00126 
00127       // allocate an image buffer of the size of the window:
00128       if (Shm_OK)
00129         {
00130           shminfo.shmid = shmget(IPC_PRIVATE,
00131                                  padded_width*idims.h()*byt_per_pix,
00132                                  IPC_CREAT | 0777);
00133           buffer = (char *)shmat(shminfo.shmid, NULL, 0);  // attach shared memory
00134           if (buffer == 0) LFATAL("Cannot get shared memory");
00135           shminfo.shmaddr = buffer;        // link buffer to shminfo structure
00136           shminfo.readOnly = False;
00137           XShmAttach(Tk_Display(tkwin), &shminfo);   // now attach to X
00138           shm_buffer = true;
00139         }
00140       else
00141         {
00142           const int bufsiz = padded_width * idims.h() * byt_per_pix;
00143           buffer = (char *)malloc(bufsiz);
00144           LDEBUG("buffer: %p", buffer);
00145           if (buffer == NULL) LFATAL("Cannot allocate image buffer");
00146           shm_buffer = false;
00147         }
00148 
00149       uint idepth;
00150       int pad;
00151 
00152       // make sure we use the correct depth values
00153       if (byt_per_pix == 2)
00154         { idepth = 16; pad = 16;}
00155       else
00156         { idepth = 24; pad = 32;}
00157 
00158       if (shm_buffer)
00159         // ok for shared memory; X will allocate the buffer:
00160         image = XShmCreateImage(Tk_Display(tkwin), Tk_Visual(tkwin), idepth, ZPixmap,
00161                                 buffer, &shminfo, idims.w(), idims.h());
00162       else
00163         // cannot alloc in shared memory... do conventional alloc
00164         image = XCreateImage(Tk_Display(tkwin), Tk_Visual(tkwin), idepth,
00165                              ZPixmap , 0, buffer,
00166                              idims.w(), idims.h(), pad,
00167                              fourByteAlign(byt_per_pix * idims.w()));
00168 
00169       int w = idims.w(); int h = idims.h();
00170 
00171       const byte* im = reinterpret_cast<const byte*>(img.getArrayPtr());
00172       byte* bu = reinterpret_cast<byte*>(buffer);
00173 
00174       if (byt_per_pix == 2)
00175         {
00176           const int bytes_per_row = fourByteAlign(byt_per_pix * w);
00177 
00178           // 16 bit format: 565, lowest byte first
00179           for (int j = 0; j < h; ++j)
00180             {
00181               byte* bu_row = bu + j*bytes_per_row;
00182               for (int i = 0; i < w; ++i)
00183                 {
00184                   *bu_row++ = ((im[1] & 0x1C)<<3) | ((im[2] & 0xF8)>>3);
00185                   *bu_row++ = ((im[1] & 0xE0)>>5) | (im[0] & 0xF8);
00186                   im += 3;
00187                 }
00188             }
00189         }
00190       else
00191         {
00192           // 24 bit format with extra byte for padding
00193           for (int i = 0; i < w * h; i ++)
00194             { *bu++ = im[2]; *bu++ = im[1]; *bu++ = *im; *bu++ = 255; im += 3; }
00195         }
00196     }
00197 
00198     ~Instance()
00199     {
00200       if (this->shm_buffer)
00201         {
00202           XShmDetach(Tk_Display(this->tkwin), &this->shminfo);
00203         }
00204 
00205       if (this->image)
00206         {
00207           // We have to set the XImage's data to zero before
00208           // destroying the XImage, because otherwise the XImage will
00209           // want to free the data as it is destroyed, which means
00210           // that our 'buffer' would become a dangling pointer, and
00211           // that we'd be double-free'ing it when we try to free() it
00212           // ourselves later.
00213           this->image->data = 0;
00214           XDestroyImage(this->image);
00215           this->image = 0;
00216         }
00217 
00218       if (this->shm_buffer)
00219         {
00220           shmdt(this->shminfo.shmaddr);
00221           shmctl(this->shminfo.shmid, IPC_RMID, NULL);
00222         }
00223       else
00224         {
00225           free(this->buffer);
00226         }
00227 
00228       if (this->gc)
00229         XFreeGC(Tk_Display(this->tkwin), this->gc);
00230     }
00231 
00232     void draw(Display* display,
00233               Drawable drawable,
00234               int imageX, int imageY,
00235               int width, int height,
00236               int drawableX, int drawableY)
00237     {
00238       if (this->gc == 0)
00239         this->gc = XCreateGC(display, drawable, 0, NULL);
00240 
00241       if (this->shm_buffer)
00242         XShmPutImage(display, drawable, this->gc, this->image,
00243                      imageX, imageY, drawableX, drawableY,
00244                      width, height, 0);
00245       else
00246         XPutImage(display, drawable, this->gc, this->image,
00247                   imageX, imageY, drawableX, drawableY,
00248                   width, height);
00249       XFlush(display);
00250     }
00251   };
00252 
00253 #ifdef INVT_NEWER_TCL_VERSION
00254   static int createMaster(Tcl_Interp* intp,
00255                           const char* name,
00256                           int objc,
00257                           Tcl_Obj* CONST objv[],
00258                           const Tk_ImageType* typePtr,
00259                           Tk_ImageMaster token,
00260                           ClientData* masterDataPtr)
00261 #else
00262   static int createMaster(Tcl_Interp* intp,
00263                           /* should be: const */ char* name,
00264                           int objc,
00265                           Tcl_Obj* CONST objv[],
00266                           /* should be: const */ Tk_ImageType* typePtr,
00267                           Tk_ImageMaster token,
00268                           ClientData* masterDataPtr)
00269 #endif
00270   {
00271     tcl::interpreter interp(intp);
00272 
00273     try
00274       {
00275         if (objc != 1)
00276           {
00277             Tcl_AppendResult
00278               (intp, "wrong # args: expected\n"
00279                "\timage create Image<type> name img", 0);
00280             return TCL_ERROR;
00281           }
00282 
00283         const Image<T> image = tcl::convert_to<Image<T> >(objv[0]);
00284 
00285         Master* master = new Master;
00286 
00287         master->token = token;
00288         master->image = image;
00289 
00290         *masterDataPtr = static_cast<void*>(master);
00291 
00292         Tk_ImageChanged(token, 0, 0,
00293                         master->image.getWidth(),
00294                         master->image.getHeight(),
00295                         master->image.getWidth(),
00296                         master->image.getHeight());
00297 
00298         return TCL_OK;
00299       }
00300     catch (...)
00301       {
00302         interp.handle_live_exception(imageType.name, SRC_POS);
00303       }
00304     return TCL_ERROR;
00305   }
00306 
00307   static ClientData getInstance(Tk_Window tkwin,
00308                                 ClientData masterData)
00309   {
00310     return static_cast<void*>
00311       (new Instance(tkwin, static_cast<Master*>(masterData)));
00312   }
00313 
00314   static void displayInstance(ClientData instanceData,
00315                               Display* display,
00316                               Drawable drawable,
00317                               int imageX,
00318                               int imageY,
00319                               int width,
00320                               int height,
00321                               int drawableX,
00322                               int drawableY)
00323   {
00324     LDEBUG("image x=%d, y=%d", imageX, imageY);
00325     LDEBUG("image w=%d, h=%d", width, height);
00326     LDEBUG("drawable x=%d, y=%d", drawableX, drawableY);
00327 
00328     Instance* instance = static_cast<Instance*>(instanceData);
00329 
00330     instance->draw(display, drawable, imageX, imageY,
00331                    width, height, drawableX, drawableY);
00332   }
00333 
00334   static void freeInstance(ClientData instanceData,
00335                            Display* display)
00336   {
00337     delete static_cast<Instance*>(instanceData);
00338   }
00339 
00340   static void deleteMaster(ClientData masterData)
00341   {
00342     delete static_cast<Master*>(masterData);
00343   }
00344 };
00345 
00346 #ifdef INVT_NEWER_TCL_VERSION
00347 
00348 #define INST_IMG_TK_TYPE(T)                     \
00349                                                 \
00350 template <>                                     \
00351 Tk_ImageType ImageTk< T >::imageType =          \
00352   {                                             \
00353     "Image<" #T ">",                            \
00354     &ImageTk< T >::createMaster,                \
00355     &ImageTk< T >::getInstance,                 \
00356     &ImageTk< T >::displayInstance,             \
00357     &ImageTk< T >::freeInstance,                \
00358     &ImageTk< T >::deleteMaster                 \
00359   }
00360 #else
00361 #define INST_IMG_TK_TYPE(T)                     \
00362                                                 \
00363 template <>                                     \
00364 Tk_ImageType ImageTk< T >::imageType =          \
00365   {                                             \
00366     /*FIXME*/ const_cast<char*>("Image<" #T ">"),       \
00367     &ImageTk< T >::createMaster,                \
00368     &ImageTk< T >::getInstance,                 \
00369     &ImageTk< T >::displayInstance,             \
00370     &ImageTk< T >::freeInstance,                \
00371     &ImageTk< T >::deleteMaster                 \
00372   }
00373 #endif
00374 
00375 INST_IMG_TK_TYPE(byte);
00376 INST_IMG_TK_TYPE(float);
00377 INST_IMG_TK_TYPE(PixRGB<byte>);
00378 INST_IMG_TK_TYPE(PixRGB<float>);
00379 
00380 
00381 extern "C"
00382 int Imagetk_Init(Tcl_Interp* interp)
00383 {
00384   GVX_PKG_CREATE(pkg, interp, "ImageTk", "4.$Revision: 1$");
00385 
00386   Tk_CreateImageType(&ImageTk<byte>::imageType);
00387   Tk_CreateImageType(&ImageTk<float>::imageType);
00388   Tk_CreateImageType(&ImageTk<PixRGB<byte> >::imageType);
00389   Tk_CreateImageType(&ImageTk<PixRGB<float> >::imageType);
00390 
00391   GVX_PKG_RETURN(pkg);
00392 }
00393 
00394 // ######################################################################
00395 /* So things look consistent in everyone's emacs... */
00396 /* Local Variables: */
00397 /* indent-tabs-mode: nil */
00398 /* End: */
00399 
00400 #endif // SCRIPT_IMAGETKSCRIPT_C_DEFINED
Generated on Sun May 8 08:42:13 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3