wave-image.cpp

Go to the documentation of this file.
00001 /*
00002  * wave-image.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Basic image loading.  See wave-image.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "wave-image.h"                 // always include our own header first!
00036 
00037 #include "common/wave_ex.h"
00038 #include "nstream/nstream.h"
00039 #include "perf/perf.h"
00040 #include "threadsafe/smart_ptr.h"
00041 #include "wave-jpeg/wave-jpeg.h"
00042 #include "wave-png/wave-png.h"
00043 
00044 
00045 
00046 namespace media {
00047 
00048 
00049 ////////////////////////////////////////////////////////////////////////////////
00050 //
00051 //      static helper methods
00052 //
00053 ////////////////////////////////////////////////////////////////////////////////
00054 
00055 
00056 ////////////////////////////////////////////////////////////////////////////////
00057 //
00058 //      Registry -- class that manages all registered image loaders
00059 //
00060 ////////////////////////////////////////////////////////////////////////////////
00061 
00062 class Registry {
00063 public:
00064         // public class methods ------------------------------------------------
00065         void addLoader(IN smart_ptr<ImageLoader>& loader);
00066         bool load(IN nstream::Manager * mgr, IN const char * name,
00067                         OUT image_t& image);
00068 
00069 private:
00070         // private typedefs ----------------------------------------------------
00071         typedef std::vector<smart_ptr<ImageLoader> > vec_loader_t;
00072 
00073         // private member data -------------------------------------------------
00074         vec_loader_t            m_loaders;
00075 };
00076 
00077 
00078 
00079 void
00080 Registry::addLoader
00081 (
00082 IN smart_ptr<ImageLoader>& loader
00083 )
00084 {
00085         ASSERT(loader, "null");
00086 
00087         m_loaders.push_back(loader);
00088 }
00089 
00090 
00091 
00092 bool
00093 Registry::load
00094 (
00095 IN nstream::Manager * mgr,
00096 IN const char * name,
00097 OUT image_t& image
00098 )
00099 {
00100         ASSERT(mgr, "null");
00101         ASSERT(name, "null");
00102 
00103         DPRINTF("Looking for a loader for image: %s", name);
00104 
00105         // loop through loaders and see if any recognize this
00106         for (vec_loader_t::iterator i = m_loaders.begin(); i != m_loaders.end();
00107              ++i) {
00108                 ImageLoader * loader = *i;
00109                 ASSERT(loader, "null");
00110 
00111                 DPRINTF("Checking loader '%s'...", loader->getLoaderName());
00112 
00113                 if (loader->canLoadImage(mgr, name)) {
00114                         DPRINTF("Found loader! '%s'", loader->getLoaderName());
00115 
00116                         // great, get a stream!
00117                         smart_ptr<nstream::File> file = mgr->getEntry(name);
00118                         ASSERT_THROW(file,
00119                             "image path is not a file: " << name);
00120                         smart_ptr<nstream::Stream> stream = file->openStream();
00121                         ASSERT_THROW(stream,
00122                             "could not open image file: " << name);
00123 
00124                         // have loader load the image from the stream
00125                         image.clear();
00126 
00127                         // construct the timer name
00128                         std::string timerName = "loadImage:";
00129                         timerName += loader->getLoaderName();
00130                         {
00131                                 perf::Timer timer(timerName.c_str());
00132                                 loader->load(stream, image);
00133                         }
00134                         ASSERT_THROW(image.isValid(),
00135                             "loader did not return a valid image for file: "
00136                             << name);
00137 
00138                         return true;
00139                 }
00140         }
00141 
00142         // no loader could load image!
00143         return false;
00144 }
00145 
00146 
00147 
00148 #define ADD_IMAGE_LOADER( reg , type )                                  \
00149         {                                                               \
00150                 DPRINTF("Adding image loader: '%s'...", #type );        \
00151                 smart_ptr<ImageLoader> loader =                         \
00152                         create ##type ##ImageLoader();                  \
00153                 ASSERT(loader, "Failed to create loader of type: %s",   \
00154                     #type );                                            \
00155                 reg->addLoader(loader);                                 \
00156         }
00157 
00158 
00159 static Registry *
00160 getRegistry
00161 (
00162 void
00163 )
00164 {
00165         // lock so that only one thread can get a registry at a time
00166         //      (avoids having two threads trying to initialize at once)
00167         static smart_mutex s_mutex;
00168         mlock l(s_mutex);
00169 
00170         static Registry * s_reg = NULL;
00171         if (!s_reg) {
00172                 s_reg = new Registry;
00173 
00174                 // first time called!  create all the actual image loaders
00175                 // Order of registration matters: the first loader that says
00176                 //      it can load the image will.  I doubt this will ever be
00177                 //      much of an issue since formats are so different...
00178                 ADD_IMAGE_LOADER(s_reg, Png);
00179                 ADD_IMAGE_LOADER(s_reg, Jpeg);
00180 
00181                 // A note on thread safety: loadImage() must be callable on
00182                 //      many threads concurrently, which means this registry
00183                 //      must also be threadsafe.
00184                 // At the moment, the registry IS threadsafe because it is
00185                 //      only modified once, during this creation block.
00186                 //      After this, the registry is only read (that is, it
00187                 //      only iterates over registered loaders and never
00188                 //      registers new ones).
00189                 // If the registration model ever changes (for instance,
00190                 //      letting callers add new image loaders on the fly),
00191                 //      then the registry object will need to use a
00192                 //      threadsafe object internally.
00193         }
00194         return s_reg;
00195 }
00196 
00197 
00198 
00199 ////////////////////////////////////////////////////////////////////////////////
00200 //
00201 //      public API
00202 //
00203 ////////////////////////////////////////////////////////////////////////////////
00204 
00205 bool
00206 loadImage
00207 (
00208 IN nstream::Manager * mgr,
00209 IN const char * name,
00210 OUT image_t& image
00211 )
00212 {
00213         perf::Timer timer("loadImage");
00214         ASSERT(mgr, "null");
00215         ASSERT(name, "null");
00216 
00217         Registry * reg = getRegistry();
00218         ASSERT(reg, "null");
00219 
00220         return reg->load(mgr, name, image);
00221 }
00222 
00223 
00224 
00225 };      // media namespace
00226