Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

ImgView.cc

Go to the documentation of this file.
00001 /*
00002     File:       ImgView.cc
00003 
00004     Function:   Simple Image Viewer
00005 
00006     Author:     Andrew Willmott
00007 
00008     Notes:      
00009 */
00010 
00011 #define GCL_WATCH_FILE
00012 
00013 #include "gcl/XGraphicsSystem.h"
00014 #include "gcl/VecUtil.h"
00015 #include "cl/Timer.h"
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <unistd.h>
00020 #include "cl/ArgParse.h"
00021 
00022 enum IPCmd 
00023 {
00024     ipNone,
00025     ipReload,
00026     ipNext,
00027     ipPrev
00028 };
00029 
00030 class ImagePane : public XBackedPane
00031 {
00032 public:
00033     ImagePane() : XBackedPane(), command(ipNone), offscreen(0), closed(false)
00034     {};
00035 
00036     Void            HandleKey(Char c);
00037     Void            PrintKeys();
00038     Void            PrintInfo();
00039     Void            CheckFile();
00040     Int             Load(StrConst filename);
00041     
00042     IPCmd           command;
00043     FileName        imageFile;
00044     RGBAImage       image;
00045     RGBEImage       radImage;
00046     Long            timeStamp;
00047     Int             offWidth, offHeight;
00048     Bool            closed;
00049     Bool            loaded;
00050     Double          alpha;
00051     XOffscreenPane  *offscreen;
00052 
00053     static XGraphicsSystem  *sXgs;
00054 };
00055 
00056 XGraphicsSystem *ImagePane::sXgs = 0;
00057 
00058 typedef ImagePane *ImagePanePtr;
00059 
00060 // XXX image stuff -- quick hack
00061 
00062 struct ImageStats
00063 {
00064     Double  avgLum;
00065     Double  avgLogLum;
00066     Double  minLum;
00067     Double  maxLum;
00068     Colour  avgClr;
00069     Colour  minClr;
00070     Colour  maxClr;
00071     Int     numSamples;
00072 };
00073 
00074 Void FindImageStats(Image &img, ImageStats &stats)
00075 {       
00076     Int     x, y;
00077     Colour  c;
00078     Double  lum;
00079     
00080     stats.numSamples = 0;
00081     stats.avgLogLum = 0.0;
00082     stats.avgLum = 0.0;
00083     stats.minLum = vl_inf;
00084     stats.maxLum = -vl_inf;
00085     stats.avgClr.MakeZero();
00086     stats.minClr.MakeBlock(vl_inf);
00087     stats.maxClr.MakeBlock(-vl_inf);
00088     
00089     for (y = 0; y < img.Height(); y++)
00090         for (x = 0; x < img.Width(); x++)
00091         {
00092             c = img.GetPixel(x, y);
00093             lum = dot(cRGBToLum, c);
00094 
00095             if (lum > 0.0)
00096             {
00097                 stats.avgClr += c;
00098                 stats.avgLum += lum;
00099                 stats.avgLogLum += log(lum);
00100                 FindMinCmpts(c, stats.minClr, stats.minClr);
00101                 FindMaxCmpts(c, stats.maxClr, stats.maxClr);
00102                 stats.minLum = Min(lum, stats.minLum);
00103                 stats.maxLum = Max(lum, stats.maxLum);
00104                 stats.numSamples++;
00105             }
00106         }
00107 
00108     stats.avgLum /= stats.numSamples;
00109     stats.avgLogLum /= stats.numSamples;
00110     stats.avgClr /= stats.numSamples;
00111 }
00112 
00113 Void LinearMapImage(const Image &img, Double start, Double slope, Image &imgOut)
00114 {       
00115     Int     x, y;
00116     Colour  c, cStart;
00117 
00118     imgOut.SetSize(img.Width(), img.Height());
00119     cStart.MakeBlock(start);
00120     
00121     for (y = 0; y < img.Height(); y++)
00122         for (x = 0; x < img.Width(); x++)
00123         {
00124             c = img.GetPixel(x, y);
00125             c -= cStart;
00126             c *= slope;
00127             imgOut.SetPixel(x, y, ClipColour(c));
00128         }
00129 }
00130 
00131 Void DoToneMap(Image &radImage, Image &image)
00132 {
00133     ImageStats  stats;
00134     Double      scale, EV;
00135     
00136     FindImageStats(radImage, stats);
00137 
00138     // roughly approximate exposure value for ISO 100 film
00139     EV = stats.avgLogLum / log(2) - 1;
00140     // crop arbitrarily to "sensible" values
00141     EV = Clip(EV, 6.0, 17.0);
00142     // use this to scale irradiances so average level is 0.18,
00143     // a la most light meters
00144     scale = 0.18 * exp(-(EV + 1) * log(2));
00145     LinearMapImage(radImage, 0.0, scale, image);
00146 }
00147 
00148 // ----
00149 
00150 Int ImagePane::Load(StrConst filename)
00151 {
00152     Int     err;
00153     Bool    justCreated = false;
00154     
00155     loaded = false;
00156     imageFile.SetPath(filename);
00157 
00158     if (imageFile.GetExtension() == "pic")
00159     {
00160         err = radImage.LoadPIC(imageFile.GetPath());
00161         if (!err)
00162             DoToneMap(radImage, image);
00163     }
00164     else
00165         err = image.Load(imageFile);
00166 
00167     if (err != 0)
00168     {
00169         cerr << "image read failed." << endl;
00170         return(err);
00171     }
00172 
00173     if (!xgs)
00174     {
00175         sXgs->CreateWindow(this, imageFile.GetFile(), image.Width(), image.Height());
00176         justCreated = true;
00177     }
00178     
00179     if (!offscreen || image.Width() > offWidth || image.Height() > offHeight)
00180     {
00181         if (offscreen)
00182             delete offscreen;
00183 
00184         offscreen = new XOffscreenPane;
00185         xgs->CreateOffscreen(offscreen, image.Width(), image.Height());
00186         offWidth = image.Width();
00187         offHeight = image.Height();
00188         Attach(offscreen);
00189     }
00190     offscreen->PutImage(image);
00191 
00192     if (!justCreated)
00193     {
00194         SetTitle(imageFile.GetFile());
00195         Resize(image.Width(), image.Height());
00196     }
00197     HandleExpose();
00198 
00199     timeStamp = imageFile.GetTimeStamp();
00200     command = ipNone;
00201     loaded = true;
00202 
00203     return(0);
00204 }
00205 
00206 Void ImagePane::CheckFile()
00207 {
00208     if (loaded && imageFile.GetTimeStamp() > timeStamp)
00209         Load(imageFile.GetPath());
00210 }
00211 
00212 Void ImagePane::HandleKey(Char c)
00213 {
00214     switch (c)
00215     {
00216     case 'h':
00217     case '?':
00218         PrintKeys();
00219         break;
00220     case 'i':
00221         PrintInfo();
00222         break;
00223     case 'd':
00224         {
00225             FileName outFile;
00226             outFile = imageFile;
00227             outFile.SetExtension("tif");
00228             image.Save(outFile);
00229         }
00230         break;
00231     case 'r':
00232         Load(imageFile.GetPath());
00233         break;
00234     case '1':
00235         image.Transform(RGBSaturate(alpha));    
00236         offscreen->PutImage(image);
00237         HandleExpose();
00238         break;
00239     case '2':
00240         image.Transform(RGBSaturate(2.0 - alpha));
00241         offscreen->PutImage(image);
00242         HandleExpose();
00243         break;
00244     case '3':
00245         image.Transform(RGBHueRotate(alpha));
00246         offscreen->PutImage(image);
00247         HandleExpose();
00248         break;
00249     case '4':
00250         image.Clear(cRed);
00251         offscreen->PutImage(image);
00252         HandleExpose();
00253         break;
00254     case ',':
00255     case 0x1D:
00256         command = ipPrev;
00257         xgs->SignalDone();
00258         break;
00259     case ' ':
00260     case '.':
00261     case 0x1C:
00262         command = ipNext;
00263         xgs->SignalDone();
00264         break;
00265     case 'w':
00266         Hide();
00267         closed = true;
00268         break;
00269     case 'q':
00270     case 0x1B:
00271         closed = true;
00272         xgs->SignalDone();
00273         break;
00274                                     
00275     default:
00276         XBackedPane::HandleKey(c);
00277     }
00278 }
00279 
00280 Void ImagePane::PrintKeys()
00281 {
00282     cout << "Viewer control:" << endl
00283          << "  r - reload image" << endl
00284          << "  d - dump tiff image" << endl
00285          << "  . or <space> - move on to next image" << endl
00286          << "  , - move back to previous image" << endl
00287          << "  i - print image information" << endl
00288          << "  q or <esc> - quit" << endl
00289          << "  w - close window" << endl
00290          << endl;
00291 }
00292 
00293 Void ImagePane::PrintInfo()
00294 {
00295     cout << String().Printf("Image %s is %d x %d", imageFile.GetPath().CString(),
00296         image.Width(), image.Height()) << endl; 
00297 }
00298 
00299 class ImgViewApp
00300 {
00301 public:
00302     ImgViewApp();
00303     
00304     Void                SetOptions(Int argc, Char **argv);
00305     Int                 Run();
00306 
00307 // options
00308     static Void         GetFileArgs(Int argc, Char *argv[]);
00309 
00310     static Char         **files;
00311     static Int          numFiles;
00312     Int                 noFork;
00313     Int                 all;
00314 
00315     Double              alpha;
00316     Int                 doSat;
00317 };
00318 
00319 Char    **ImgViewApp::files = 0;
00320 Int     ImgViewApp::numFiles = 0;
00321 
00322 ImgViewApp::ImgViewApp()
00323 {
00324 }
00325 
00326 Void ImgViewApp::GetFileArgs(Int argc, Char *argv[])
00327 {
00328     files = argv;
00329     numFiles = argc;
00330 }
00331 
00332 Void ImgViewApp::SetOptions(int argc, char **argv)
00333 {
00334     ArgForm     *arg_format;
00335     Int         formats;
00336     
00337     alpha = 1.0;
00338     
00339     arg_format = arg_to_form(0,
00340         "", 
00341             "Usage: imgview file1 file2 ... [options]",
00342         "", ARG_SUBR(GetFileArgs), 
00343             "",
00344         "-noFork", ARG_FLAG(&noFork),
00345             "Don't fork into background.",
00346         "-all", ARG_FLAG(&all),
00347             "Open all images at once.",
00348         "-alpha %F", &alpha,
00349             "Set alpha for image operation",
00350         "-sat", ARG_FLAG(&doSat),
00351             "Change saturation of the image",
00352         "-formats", ARG_FLAG(&formats), 
00353             "List supported file formats",
00354         0);
00355 
00356     if (argc == 1)
00357     {
00358         arg_form_print(arg_format);
00359         cout << endl;
00360         exit(0);
00361     }
00362 
00363     if (arg_parse_argv(argc, argv, arg_format) < 0)
00364         exit(1);
00365 
00366 #ifdef DEBUG
00367     noFork = true;
00368 #endif
00369 
00370     if (formats)
00371     {
00372         Image::PrintSupportedFormats(cout);
00373         exit(0);
00374     }
00375 }
00376 
00377 Int ImgViewApp::Run()
00378 {
00379     Int     i;
00380 
00381     if (numFiles < 1)
00382         return(1);
00383 
00384     if (!noFork && fork())
00385         return(0);
00386 
00387     ImagePane::sXgs = new XGraphicsSystem;
00388 
00389     if (all)
00390     {
00391         ImagePanePtr    *panes = new ImagePanePtr[numFiles];
00392         Int             closed = 0;
00393         
00394         for (i = 0; i < numFiles; i++)
00395         {
00396             panes[i] = new ImagePane;
00397             panes[i]->alpha = alpha;
00398             panes[i]->Load(files[i]);
00399         }
00400 
00401         while (closed < numFiles)
00402         {
00403             if (ImagePane::sXgs->RunFor(1.0))
00404                 break;
00405             for (i = 0; i < numFiles; i++)
00406                 if (panes[i])
00407                 {
00408                     if (panes[i]->closed)
00409                     {
00410                         delete panes[i];
00411                         panes[i] = 0;
00412                         closed++;
00413                     }
00414                     else
00415                         panes[i]->CheckFile();
00416                 }
00417         }
00418     }
00419     else
00420     {
00421         Int         curImage = 0;
00422         ImagePane   *imagePane = new ImagePane;
00423 
00424         imagePane->Load(files[0]);
00425         imagePane->alpha = alpha;
00426         
00427         do
00428         {
00429             ImagePane::sXgs->RunFor(1.0);
00430             
00431             imagePane->CheckFile();
00432             
00433             switch (imagePane->command)
00434             {
00435             case ipPrev:
00436                 if (curImage > 0)
00437                     curImage--;
00438                 else
00439                     curImage = numFiles - 1;
00440                 imagePane->Load(files[curImage]);
00441                 break;
00442             case ipNext:
00443                 curImage++;
00444                 if (curImage == numFiles)
00445                     curImage = 0;
00446                 imagePane->Load(files[curImage]);
00447                 break;
00448             }
00449         }
00450         while (!imagePane->closed);
00451 
00452         delete imagePane;
00453     }
00454     
00455     return(0);
00456 }
00457 
00458 int main(int argc, char **argv)
00459 {
00460     ImgViewApp  app;
00461     
00462     app.SetOptions(argc, argv);
00463         
00464     return(app.Run());
00465 }

Generated at Sat Aug 5 00:17:00 2000 for Graphics Class Library by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000