app-slideshow.C

Go to the documentation of this file.
00001 /*!@file AppMedia/app-slideshow.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/AppMedia/app-slideshow.C $
00035 // $Id: app-slideshow.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 #ifndef APPMEDIA_APP_SLIDESHOW_C_DEFINED
00039 #define APPMEDIA_APP_SLIDESHOW_C_DEFINED
00040 
00041 #include "GUI/XWinManaged.H"
00042 #include "Image/CutPaste.H"
00043 #include "Image/DrawOps.H"
00044 #include "Image/Image.H"
00045 #include "Image/MatrixOps.H"
00046 #include "Image/Pixels.H"
00047 #include "Image/ShapeOps.H"
00048 #include "Image/SimpleFont.H"
00049 #include "Raster/Raster.H"
00050 #include "Util/FileUtil.H"
00051 #include "rutz/time.h"
00052 #include "rutz/unixcall.h"
00053 
00054 #include <cstdio>
00055 #include <cstdlib>
00056 #include <fstream>
00057 #include <string>
00058 #include <time.h>
00059 
00060 #include <sys/types.h>
00061 #include <sys/stat.h>
00062 #include <X11/keysym.h>
00063 
00064 enum TransformType
00065   {
00066     TXTYPE_NONE,
00067     TXTYPE_TRANSPOSE,
00068     TXTYPE_BEST_FIT
00069   };
00070 
00071 std::string convertToString(const TransformType txtype)
00072 {
00073   switch (txtype)
00074     {
00075     case TXTYPE_NONE: return "none";
00076     case TXTYPE_TRANSPOSE: return "transpose";
00077     case TXTYPE_BEST_FIT: return "bestfit";
00078     }
00079 
00080   // default:
00081   return "invalid";
00082 }
00083 
00084 class random_sequence
00085 {
00086   double m_current;
00087   double m_next;
00088 
00089   static int irange(double rval, int min, int max)
00090   {
00091     return int(rval * (max - min) + min);
00092   }
00093 
00094 public:
00095   random_sequence()
00096   {
00097     srand48(time(NULL) / 2);
00098 
00099     m_current =  drand48();
00100     m_next = drand48();
00101   }
00102 
00103   int inext(int min, int max)
00104   {
00105     m_current = m_next;
00106     while (m_current == m_next)
00107       m_next = drand48();
00108 
00109     return irange(m_current, min, max);
00110   }
00111 
00112   int ipeek(int min, int max) const
00113   {
00114     return irange(m_next, min, max);
00115   }
00116 };
00117 
00118 template <class T>
00119 Image<T> myDownSize(const Image<T>& src, const Dims& new_dims)
00120 {
00121   if (src.getDims() == new_dims) return src;
00122 
00123   ASSERT(new_dims.isNonEmpty());
00124 
00125   Image<T> result = src;
00126 
00127   while (result.getWidth() > new_dims.w() * 2 &&
00128          result.getHeight() > new_dims.h() * 2)
00129     {
00130       result = decY(decX(quickLocalAvg2x2(result)));
00131     }
00132 
00133   return rescale(result, new_dims);
00134 }
00135 
00136 struct ImageInfo
00137 {
00138   ImageInfo() {}
00139 
00140   ImageInfo(const Image<PixRGB<byte> >& raw, const Dims& dsize,
00141             const TransformType ttype,
00142             const RescaleType rtype)
00143     :
00144     rawdims(raw.getDims())
00145   {
00146     switch (ttype)
00147       {
00148       case TXTYPE_NONE: img = raw; break;
00149       case TXTYPE_TRANSPOSE: img = transpose(raw); break;
00150       case TXTYPE_BEST_FIT:
00151         if ( (dsize.w() >= dsize.h()) != (raw.getWidth() >= raw.getHeight()) )
00152           img = transpose(raw);
00153         else
00154           img = raw;
00155         break;
00156       }
00157     const Dims ssize = img.getDims();
00158 
00159     const double wratio = double(dsize.w()) / double(ssize.w());
00160     const double hratio = double(dsize.h()) / double(ssize.h());
00161     this->ratio = std::min(wratio, hratio);
00162 
00163     img = rescale(img, Dims(std::min(dsize.w(), int(ssize.w() * this->ratio)),
00164                             std::min(dsize.h(), int(ssize.h() * this->ratio))),
00165                   rtype);
00166   }
00167 
00168   Dims rawdims;
00169   Image<PixRGB<byte> > img;
00170   double ratio;
00171 };
00172 
00173 namespace aux
00174 {
00175   void msg(const std::string& tag, const std::string& content)
00176   {
00177     fprintf(stderr, "%20s: %s\n", tag.c_str(), content.c_str());
00178   }
00179 
00180   bool file_exists(const std::string& fname)
00181   {
00182     struct stat statbuf;
00183     int res = ::stat(fname.c_str(), &statbuf);
00184     return (res == 0);
00185   }
00186 
00187   bool image_file_exists(const std::string& fname)
00188   {
00189     struct stat statbuf;
00190     int res = ::stat(fname.c_str(), &statbuf);
00191     if (res != 0)
00192       return false;
00193 
00194     if (statbuf.st_size == 0)
00195       {
00196         aux::msg("empty file", fname);
00197         return false;
00198       }
00199 
00200     return true;
00201   }
00202 
00203   ImageInfo build_scaled_pixmap(const std::string& fname, const Dims& dsize,
00204                                 const TransformType ttype,
00205                                 const RescaleType rtype)
00206   {
00207     const Image<PixRGB<byte> > raw = Raster::ReadRGB(fname);
00208     return ImageInfo(raw, dsize, ttype, rtype);
00209   }
00210 
00211   bool is_img_file(const std::string& fname)
00212   {
00213     return (hasExtension(fname, ".jpg")
00214             || hasExtension(fname, ".jpeg")
00215             || hasExtension(fname, ".gif")
00216             || hasExtension(fname, ".pnm")
00217             || hasExtension(fname, ".png"));
00218   }
00219 }
00220 
00221 class playlist
00222 {
00223 public:
00224   enum play_mode
00225     {
00226       SPINNING,
00227       JUMPING,
00228     };
00229 
00230 private:
00231 
00232   const std::string m_list_file;
00233   std::vector<std::string> m_list;
00234   int m_idx;
00235   int m_guess_next;
00236   const rutz::shared_ptr<XWinManaged> m_widget;
00237   ImageInfo m_pixmap;
00238   std::map<std::string, ImageInfo> m_pixmap_cache;
00239   std::vector<std::string> m_purge_list;
00240   play_mode m_mode;
00241   int m_ndeleted;
00242   int m_nshown;
00243   int m_nmissed;
00244   int m_last_spin;
00245   rutz::time m_last_show_time;
00246   TransformType m_txtype;
00247   RescaleType m_rtype;
00248   bool m_didcache;
00249   bool m_looping;
00250   int m_loop_delay_power;
00251   bool m_show_overlay;
00252   random_sequence m_rseq;
00253 
00254 public:
00255   playlist(const std::string& fname, rutz::shared_ptr<XWinManaged> widget)
00256     :
00257     m_list_file(fname),
00258     m_idx(0),
00259     m_guess_next(1),
00260     m_widget(widget),
00261     m_mode(SPINNING),
00262     m_ndeleted(0),
00263     m_nshown(0),
00264     m_nmissed(0),
00265     m_last_spin(1),
00266     m_txtype(TXTYPE_NONE),
00267     m_rtype(RESCALE_SIMPLE_BILINEAR),
00268     m_didcache(false),
00269     m_looping(false),
00270     m_loop_delay_power(0),
00271     m_show_overlay(true),
00272     m_rseq()
00273   {
00274     std::ifstream ifs(m_list_file.c_str());
00275     if (!ifs.is_open())
00276       LFATAL("couldn't open %s for reading", m_list_file.c_str());
00277     std::string line;
00278 
00279     while (std::getline(ifs, line))
00280       m_list.push_back(line);
00281   }
00282 
00283   void save()
00284   {
00285     aux::msg("write playlist", m_list_file);
00286     if (aux::file_exists(sformat("%s.bkp", m_list_file.c_str())))
00287       rutz::unixcall::remove(sformat("%s.bkp", m_list_file.c_str()).c_str());
00288     if (aux::file_exists(m_list_file))
00289       rutz::unixcall::rename(m_list_file.c_str(),
00290                              sformat("%s.bkp", m_list_file.c_str()).c_str());
00291 
00292     std::ofstream ofs(m_list_file.c_str());
00293     if (!ofs.is_open())
00294       LFATAL("couldn't open %s for writing", m_list_file.c_str());
00295     for (size_t i = 0; i < m_list.size(); ++i)
00296       ofs << m_list.at(i) << '\n';
00297     ofs.close();
00298   }
00299 
00300   void spin(int step)
00301   {
00302     m_mode = SPINNING;
00303 
00304     if (m_list.size() == 0)
00305       {
00306         m_idx = 0;
00307         m_last_spin = 0;
00308         m_guess_next = 0;
00309       }
00310     else
00311       {
00312         ASSERT(m_list.size() > 0);
00313 
00314         m_idx += step;
00315         while (m_idx < 0) m_idx += int(m_list.size());
00316         while (m_idx >= int(m_list.size())) m_idx -= int(m_list.size());
00317         m_last_spin = step;
00318 
00319         int guess_step = step;
00320         if (guess_step == 0) { guess_step = 1; }
00321 
00322         m_guess_next = m_idx + guess_step;
00323         while (m_guess_next < 0) m_guess_next += int(m_list.size());
00324         while (m_guess_next >= int(m_list.size())) m_guess_next -= int(m_list.size());
00325       }
00326   }
00327 
00328   void jump(int oldlength = -1, int adjust = 0)
00329   {
00330     m_mode = JUMPING;
00331 
00332     if (m_list.size() == 0)
00333       {
00334         m_idx = 0;
00335         m_guess_next = 0;
00336       }
00337     else
00338       {
00339         if (oldlength == -1)
00340           oldlength = m_list.size();
00341 
00342         ASSERT(m_list.size() >= 1);
00343 
00344         m_idx = m_rseq.inext(0, oldlength) + adjust;
00345         if (m_idx < 0) m_idx = 0;
00346         else if (size_t(m_idx) >= m_list.size()) m_idx = m_list.size() - 1;
00347         m_guess_next = m_rseq.ipeek(0, m_list.size());
00348       }
00349   }
00350 
00351   std::string filename() const
00352   {
00353     if (m_list.size() == 0)
00354       return "(none)";
00355 
00356     ASSERT(size_t(m_idx) < m_list.size());
00357     return m_list.at(m_idx);
00358   }
00359 
00360   std::string status() const
00361   {
00362     if (m_list.size() == 0)
00363       return "(empty)";
00364 
00365     return sformat("(%d of %"ZU") %s", m_idx + 1, m_list.size(),
00366                    this->filename().c_str());
00367   }
00368 
00369   void mode(const play_mode m)
00370   {
00371     m_mode = m;
00372   }
00373 
00374   void remove_helper(bool do_purge)
00375   {
00376     if (m_list.size() == 0)
00377       return;
00378 
00379     ASSERT(size_t(m_idx) < m_list.size());
00380     std::string target = m_list.at(m_idx);
00381     aux::msg(sformat("hide file[%d]", m_idx), target.c_str());
00382     if (do_purge)
00383       m_purge_list.push_back(target);
00384 
00385     const size_t oldlength = m_list.size();
00386 
00387     m_list.erase(m_list.begin() + m_idx);
00388 
00389     switch (m_mode)
00390       {
00391       case JUMPING:
00392         if (m_idx < m_guess_next)
00393           {
00394             aux::msg("jump offset", "1");
00395             this->jump(oldlength, -1);
00396           }
00397         else
00398           {
00399             aux::msg("jump offset", "0");
00400             this->jump(oldlength, 0);
00401           }
00402         break;
00403 
00404       case SPINNING:
00405       default:
00406         if (m_last_spin <= 0)
00407           this->spin(m_last_spin);
00408         else
00409           this->spin(m_last_spin - 1);
00410         break;
00411       }
00412   }
00413 
00414   void remove() { this->remove_helper(true); }
00415   void remove_no_purge() { this->remove_helper(false); }
00416 
00417   void purge()
00418   {
00419     const size_t N = m_purge_list.size();
00420     size_t n = 0;
00421 
00422     while (!m_purge_list.empty())
00423       {
00424         const std::string f = m_purge_list.back();
00425         m_purge_list.pop_back();
00426         ++n;
00427         aux::msg("purging", sformat("%"ZU" of %"ZU, n, N));
00428         aux::msg("delete file", f);
00429 
00430         std::string dirname, tail;
00431         splitPath(f, dirname, tail);
00432         const std::string stubfile =
00433           sformat("%s/.%s.deleted", dirname.c_str(), tail.c_str());
00434 
00435         std::ofstream ofs(stubfile.c_str());
00436         ofs.close();
00437 
00438         try {
00439           rutz::unixcall::remove(f.c_str());
00440           ++m_ndeleted;
00441         }
00442         catch (std::exception& e) {
00443           aux::msg("error during deletion",
00444                    sformat("%s (%s)", f.c_str(), e.what()));
00445         }
00446 
00447         this->redraw(false);
00448       }
00449 
00450     m_purge_list.resize(0);
00451     this->save();
00452     aux::msg("files deleted", sformat("%d", m_ndeleted));
00453     aux::msg("files shown", sformat("%d", m_nshown));
00454     aux::msg("cache misses", sformat("%d", m_nmissed));
00455     aux::msg("percent kept",
00456              sformat("%.2f%%", 100.0 * (1.0 - double(m_ndeleted)
00457                                         / m_nshown)));
00458   }
00459 
00460   void cachenext()
00461   {
00462     if (m_list.size() == 0)
00463       return;
00464 
00465     if (m_guess_next < 0) m_guess_next = 0;
00466     if (size_t(m_guess_next) >= m_list.size()) m_guess_next = m_list.size() - 1;
00467     int i = m_guess_next;
00468     std::string f = m_list.at(i);
00469     while (!aux::image_file_exists(f))
00470       {
00471         aux::msg(sformat("no such file[%d]", i), f);
00472         m_list.erase(m_list.begin() + i);
00473         i = i % m_list.size();
00474         f = m_list.at(i);
00475       }
00476     if (m_pixmap_cache.find(f) == m_pixmap_cache.end())
00477       {
00478         m_pixmap_cache[f] =
00479           aux::build_scaled_pixmap(f, m_widget->getDims(), m_txtype, m_rtype);
00480 
00481         aux::msg(sformat("cache insert[%d]", i), f);
00482       }
00483     else
00484       {
00485         const Image<PixRGB<byte> > img = m_pixmap_cache[f].img;
00486         aux::msg(sformat("cache exists[%d]", i),
00487                  sformat("%dx%d %s", img.getWidth(), img.getHeight(),
00488                          f.c_str()));
00489       }
00490   }
00491 
00492   double loop_delay() const
00493   {
00494     return 250.0 * pow(2.0, 0.5 * m_loop_delay_power);
00495   }
00496 
00497   void redraw(bool show_image)
00498   {
00499     Image<PixRGB<byte> > img(m_widget->getDims(), ZEROS);
00500 
00501     if (m_list.size() > 0 && show_image)
00502       inplacePaste(img, m_pixmap.img,
00503                    Point2D<int>((img.getWidth() - m_pixmap.img.getWidth()) / 2,
00504                            (img.getHeight() - m_pixmap.img.getHeight()) / 2));
00505 
00506     if (m_show_overlay)
00507       {
00508         const SimpleFont font = SimpleFont::FIXED(7);
00509 
00510         struct stat statbuf;
00511         std::string mtime;
00512         if (0 == stat(this->filename().c_str(), &statbuf))
00513           {
00514             char buf[32];
00515             ctime_r(&statbuf.st_mtime, &buf[0]);
00516             mtime = buf;
00517           }
00518 
00519         const std::string msgs[] =
00520           {
00521             sformat("#%d:%s", m_idx, this->filename().c_str()),
00522             sformat("    %s", mtime.c_str()),
00523             sformat("    %dx%d @ %d%%", m_pixmap.rawdims.w(), m_pixmap.rawdims.h(), int(0.5 + m_pixmap.ratio * 100.0)),
00524             m_looping ? sformat("loop:%.2fms", this->loop_delay()) : std::string("loop:off"),
00525             std::string(m_mode == JUMPING ? "mode:jumping" : "mode:spinning"),
00526             sformat("tx:%s", convertToString(m_txtype).c_str()),
00527             sformat("rs:%s", convertToString(m_rtype).c_str()),
00528             sformat("c:%"ZU, m_list.size()),
00529             sformat("p:%"ZU, m_purge_list.size()),
00530             sformat("d:%d", m_ndeleted),
00531             sformat("s:%d", m_nshown),
00532             sformat("m:%d", m_nmissed),
00533           };
00534 
00535         const int nmsg = sizeof(msgs) / sizeof(msgs[0]);
00536 
00537         for (int i = 0; i < nmsg; ++i)
00538           writeText(img, Point2D<int>(1,1+i*font.h()), msgs[i].c_str(),
00539                     PixRGB<byte>(255, 160, 0),
00540                     PixRGB<byte>(0, 0, 0),
00541                     font,
00542                     true);
00543       }
00544 
00545     m_widget->drawImage(img);
00546   }
00547 
00548   void show()
00549   {
00550     if (m_list.size() > 0)
00551       {
00552         std::string f = this->filename();
00553 
00554         while (!aux::image_file_exists(f))
00555           {
00556             aux::msg(sformat("no such file(%d)", m_idx), f);
00557             ASSERT(size_t(m_idx) < m_list.size());
00558             m_list.erase(m_list.begin() + m_idx);
00559             m_idx = m_idx % m_list.size();
00560             f = this->filename();
00561           }
00562 
00563         aux::msg("index", sformat("%d of %"ZU, m_idx,
00564                                   m_list.size()));
00565         aux::msg(sformat("show file[%d]", m_idx), f);
00566 
00567         if (m_pixmap_cache.find(f) != m_pixmap_cache.end())
00568           {
00569             m_pixmap = m_pixmap_cache[f];
00570             m_pixmap_cache.erase(m_pixmap_cache.find(f));
00571             aux::msg(sformat("cache hit[%d]", m_idx), f);
00572           }
00573         else
00574           {
00575             aux::msg(sformat("cache miss[%d]", m_idx), f);
00576             ++m_nmissed;
00577             m_pixmap =
00578               aux::build_scaled_pixmap(f, m_widget->getDims(), m_txtype, m_rtype);
00579           }
00580       }
00581 
00582     this->redraw(true);
00583     ++m_nshown;
00584 
00585     m_last_show_time = rutz::time::wall_clock_now();
00586   }
00587 
00588   rutz::time last_show_time() const { return m_last_show_time; }
00589 
00590   void cycle_txtype()
00591   {
00592     switch (m_txtype)
00593       {
00594       case TXTYPE_NONE:      m_txtype = TXTYPE_TRANSPOSE; break;
00595       case TXTYPE_TRANSPOSE: m_txtype = TXTYPE_BEST_FIT; break;
00596       case TXTYPE_BEST_FIT:  m_txtype = TXTYPE_NONE; break;
00597       }
00598     m_pixmap_cache.clear();
00599   }
00600 
00601   void cycle_rtype()
00602   {
00603     switch (m_rtype)
00604       {
00605       case RESCALE_SIMPLE_NOINTERP: m_rtype = RESCALE_SIMPLE_BILINEAR; break;
00606       case RESCALE_SIMPLE_BILINEAR: m_rtype = RESCALE_FILTER_BSPLINE; break;
00607       case RESCALE_FILTER_BSPLINE: m_rtype = RESCALE_FILTER_LANCZOS3; break;
00608       default: m_rtype = RESCALE_SIMPLE_NOINTERP; break;
00609       }
00610     m_pixmap_cache.clear();
00611   }
00612 
00613   int run()
00614   {
00615     this->show();
00616 
00617     while (1)
00618       {
00619         KeySym ks = m_widget->getLastKeySym();
00620         switch (ks)
00621           {
00622           case NoSymbol:
00623             if (!m_didcache)
00624               this->cachenext();
00625             m_didcache = true;
00626             if (m_looping
00627                 &&
00628                 (rutz::time::wall_clock_now() - this->last_show_time()).msec()
00629                 >= this->loop_delay())
00630               {
00631                 if (JUMPING == m_mode)
00632                   this->jump();
00633                 else
00634                   this->spin(1);
00635                 this->show();
00636                 m_didcache = false;
00637               }
00638             else
00639               usleep(10000);
00640             break;
00641 
00642           case XK_Left:
00643             this->spin(-1);
00644             this->show();
00645             m_didcache = false;
00646             break;
00647 
00648           case XK_Right:
00649             this->spin(1);
00650             this->show();
00651             m_didcache = false;
00652             break;
00653 
00654           case XK_Up:
00655             this->jump();
00656             this->show();
00657             m_didcache = false;
00658             break;
00659 
00660           case XK_Down:
00661             this->remove();
00662             this->show();
00663             m_didcache = false;
00664             break;
00665 
00666           case XK_e:
00667           case XK_0:
00668           case XK_KP_0:
00669             this->remove_no_purge();
00670             this->show();
00671             m_didcache = false;
00672             break;
00673 
00674           case XK_Return:
00675             this->save();
00676             break;
00677 
00678           case XK_x:
00679             this->purge();
00680             this->redraw(true);
00681             break;
00682 
00683           case XK_Escape:
00684             this->redraw(false);
00685             this->purge();
00686             return 0;
00687 
00688           case XK_l:
00689             m_looping = !m_looping;
00690             this->show();
00691             break;
00692 
00693           case XK_m:
00694             if (SPINNING == m_mode) m_mode = JUMPING;
00695             else if (JUMPING == m_mode) m_mode = SPINNING;
00696             this->show();
00697             m_didcache = false;
00698             break;
00699 
00700           case XK_o:
00701             m_show_overlay = !m_show_overlay;
00702             this->show();
00703             break;
00704 
00705           case XK_comma:
00706             ++m_loop_delay_power;
00707             break;
00708 
00709           case XK_period:
00710             --m_loop_delay_power;
00711             break;
00712 
00713           case XK_t:
00714             this->cycle_txtype();
00715             this->show();
00716             m_didcache = false;
00717             break;
00718 
00719           case XK_r:
00720             this->cycle_rtype();
00721             this->show();
00722             m_didcache = false;
00723             break;
00724           }
00725       }
00726   }
00727 };
00728 
00729 int main(int argc, const char** argv)
00730 {
00731   Dims dims(800, 800);
00732 
00733   if (argc != 2 && argc != 3)
00734     {
00735       fprintf(stderr, "usage: %s playlist ?WxH?\n", argv[0]);
00736       return 1;
00737     }
00738 
00739   if (argc >= 3)
00740     convertFromString(argv[2], dims);
00741 
00742   rutz::shared_ptr<XWinManaged> window(new XWinManaged(dims, -1, -1,
00743                                                        argv[1]));
00744 
00745   playlist pl(argv[1], window);
00746 
00747   return pl.run();
00748 }
00749 
00750 // ######################################################################
00751 /* So things look consistent in everyone's emacs... */
00752 /* Local Variables: */
00753 /* mode: c++ */
00754 /* indent-tabs-mode: nil */
00755 /* End: */
00756 
00757 #endif // APPMEDIA_APP_SLIDESHOW_C_DEFINED
Generated on Sun May 8 08:04:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3