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 namespace media {
00046 
00047 
00048 ////////////////////////////////////////////////////////////////////////////////
00049 //
00050 //      static helper methods
00051 //
00052 ////////////////////////////////////////////////////////////////////////////////
00053 
00054 
00055 ////////////////////////////////////////////////////////////////////////////////
00056 //
00057 //      Registry -- class that manages all registered image loaders
00058 //
00059 ////////////////////////////////////////////////////////////////////////////////
00060 
00061 class Registry {
00062 public:
00063         // public class methods ------------------------------------------------
00064         void addLoader(IN smart_ptr<ImageLoader>& loader);
00065         bool load(IN nstream::Manager * mgr, IN const char * name,
00066                         OUT image_t& image);
00067 
00068 private:
00069         // private typedefs ----------------------------------------------------
00070         typedef std::vector<smart_ptr<ImageLoader> > vec_loader_t;
00071 
00072         // private member data -------------------------------------------------
00073         vec_loader_t            m_loaders;
00074 };
00075 
00076 
00077 
00078 void
00079 Registry::addLoader
00080 (
00081 IN smart_ptr<ImageLoader>& loader
00082 )
00083 {
00084         ASSERT(loader, "null");
00085 
00086         m_loaders.push_back(loader);
00087 }
00088 
00089 
00090 
00091 bool
00092 Registry::load
00093 (
00094 IN nstream::Manager * mgr,
00095 IN const char * name,
00096 OUT image_t& image
00097 )
00098 {
00099         ASSERT(mgr, "null");
00100         ASSERT(name, "null");
00101 
00102         DPRINTF("Looking for a loader for image: %s", name);
00103 
00104         // loop through loaders and see if any recognize this
00105         for (vec_loader_t::iterator i = m_loaders.begin(); i != m_loaders.end();
00106              ++i) {
00107                 ImageLoader * loader = *i;
00108                 ASSERT(loader, "null");
00109 
00110                 DPRINTF("Checking loader '%s'...", loader->getLoaderName());
00111 
00112                 if (loader->canLoadImage(mgr, name)) {
00113                         DPRINTF("Found loader! '%s'", loader->getLoaderName());
00114 
00115                         // great, get a stream!
00116                         smart_ptr<nstream::File> file = mgr->getEntry(name);
00117                         ASSERT_THROW(file,
00118                             "image path is not a file: " << name);
00119                         smart_ptr<nstream::Stream> stream = file->openStream();
00120                         ASSERT_THROW(stream,
00121                             "could not open image file: " << name);
00122 
00123                         // have loader load the image from the stream
00124                         image.clear();
00125 
00126                         // construct the timer name
00127                         std::string timerName = "loadImage:";
00128                         timerName += loader->getLoaderName();
00129                         {
00130                                 perf::Timer timer(timerName.c_str());
00131                                 loader->load(stream, image);
00132                         }
00133                         //image.dump("Just loaded this...");
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         // posix/linux: need to use our registry of format-specific libraries
00218         Registry * reg = getRegistry();
00219         ASSERT(reg, "null");
00220         return reg->load(mgr, name, image);
00221 }
00222 
00223 
00224 
00225 };      // media namespace
00226