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