bmapdata.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2000-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Thu Jan 20 00:37:03 2000
00010 // commit: $Id: bmapdata.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/media/bmapdata.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED
00035 #define GROOVX_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED
00036 
00037 #include "bmapdata.h"
00038 
00039 #include "geom/vec2.h"
00040 
00041 #include "rutz/algo.h"
00042 #include "rutz/arrays.h"
00043 #include "rutz/error.h"
00044 #include "rutz/rand.h"
00045 #include "rutz/sfmt.h"
00046 #include "rutz/shared_ptr.h"
00047 
00048 #include <algorithm>
00049 #include <cstring>              // for memcpy
00050 
00051 #include "rutz/trace.h"
00052 #include "rutz/debug.h"
00053 GVX_DBG_REGISTER
00054 
00055 using rutz::shared_ptr;
00056 
00058 //
00059 // media::bmap_data::impl definition
00060 //
00062 
00063 class media::bmap_data::impl
00064 {
00065 public:
00066   impl(const geom::vec2<int>& ex, int bits_per_pixel, int byte_alignment) :
00067     m_size(ex),
00068     m_bits_per_pixel(bits_per_pixel),
00069     m_byte_alignment(byte_alignment),
00070     m_bytes(),
00071     m_row_order(TOP_FIRST),
00072     m_updater()
00073   {
00074     GVX_PRECONDITION(m_size.x() >= 0);
00075     GVX_PRECONDITION(m_size.y() >= 0);
00076 
00077     // If m_size.x() is 0, this is still OK, since -1/8 --> -1, so the
00078     // whole thing goes to 0
00079     int bytes_per_row = (m_size.x()*bits_per_pixel - 1)/8 + 1;
00080 
00081     GVX_ASSERT(bytes_per_row >= 0);
00082 
00083     unsigned int num_bytes = bytes_per_row * m_size.y();
00084 
00085     m_bytes.resize( num_bytes );
00086   }
00087 
00088   // default copy-ctor and assn-oper OK
00089 
00090   // These are "fast" versions of the public interface that don't call
00091   // update_if_needed() before returning data. Therefore it is the
00092   // caller's responsibility to make sure update_if_needed() has been
00093   // called at least once per public API call.
00094   unsigned char* bytes_ptr() { return &(m_bytes[0]); }
00095 
00096   unsigned int bytes_per_row() const
00097   { return ( (m_size.x()*m_bits_per_pixel - 1)/8 + 1 ); }
00098 
00099   unsigned char* row_ptr(unsigned int row)
00100   {
00101     const unsigned int offset =
00102       (m_row_order == TOP_FIRST)
00103       ?
00104       row
00105       :
00106       m_size.y() - row - 1;
00107 
00108     return bytes_ptr() + offset * bytes_per_row();
00109   }
00110 
00111   unsigned int byte_count() const { return m_bytes.size(); }
00112 
00113   geom::vec2<int>                    m_size;
00114   int                                m_bits_per_pixel;
00115   int                                m_byte_alignment;
00116   rutz::dynamic_block<unsigned char> m_bytes;
00117   row_order                          m_row_order;
00118   mutable shared_ptr<update_func>    m_updater;
00119 };
00120 
00122 //
00123 // media::bmap_data member definitions
00124 //
00126 
00127 media::bmap_data::update_func::~update_func() {}
00128 
00129 media::bmap_data::bmap_data() :
00130   rep(new impl(geom::vec2<int>(0, 0), 1, 1))
00131 {
00132 GVX_TRACE("media::bmap_data::bmap_data");
00133 }
00134 
00135 media::bmap_data::bmap_data(const geom::vec2<int>& m_size,
00136                             int bits_per_pixel, int byte_alignment) :
00137   rep(new impl(m_size, bits_per_pixel, byte_alignment))
00138 {
00139 GVX_TRACE("media::bmap_data::bmap_data");
00140 }
00141 
00142 media::bmap_data::bmap_data(const media::bmap_data& other) :
00143   rep(new impl(*(other.rep)))
00144 {
00145 GVX_TRACE("media::bmap_data::bmap_data(copy)");
00146 }
00147 
00148 media::bmap_data::~bmap_data()
00149 {
00150   delete rep;
00151 }
00152 
00153 unsigned char* media::bmap_data::bytes_ptr() const
00154 {
00155 GVX_TRACE("media::bmap_data::bytes_ptr");
00156   update_if_needed();
00157   return rep->bytes_ptr();
00158 }
00159 
00160 unsigned char* media::bmap_data::row_ptr(unsigned int row) const
00161 {
00162 GVX_TRACE("media::bmap_data::row_ptr");
00163 
00164   update_if_needed();
00165 
00166   return rep->row_ptr(row);
00167 }
00168 
00169 long int media::bmap_data::bytes_sum() const
00170 {
00171 GVX_TRACE("media::bmap_data::bytes_sum");
00172 
00173   update_if_needed();
00174   long int sum = 0;
00175   unsigned int c = byte_count();
00176   unsigned char* m_bytes = rep->bytes_ptr();
00177   while (c > 0)
00178     {
00179       sum += m_bytes[--c];
00180     }
00181   return sum;
00182 }
00183 
00184 int media::bmap_data::width() const
00185 {
00186 GVX_TRACE("media::bmap_data::width");
00187   update_if_needed();
00188   return rep->m_size.x();
00189 }
00190 
00191 int media::bmap_data::height() const
00192 {
00193 GVX_TRACE("media::bmap_data::height");
00194   update_if_needed();
00195   return rep->m_size.y();
00196 }
00197 
00198 geom::vec2<int> media::bmap_data::size() const
00199 {
00200 GVX_TRACE("media::bmap_data::size");
00201   update_if_needed();
00202   return rep->m_size;
00203 }
00204 
00205 int media::bmap_data::bits_per_pixel() const
00206 {
00207 GVX_TRACE("media::bmap_data::bits_per_pixel");
00208   update_if_needed();
00209   return rep->m_bits_per_pixel;
00210 }
00211 
00212 int media::bmap_data::bits_per_component() const
00213 {
00214 GVX_TRACE("media::bmap_data::bits_per_component");
00215   update_if_needed();
00216   return rep->m_bits_per_pixel > 1
00217     ? 8
00218     : 1;
00219 }
00220 
00221 int media::bmap_data::byte_alignment() const
00222 {
00223 GVX_TRACE("media::bmap_data::byte_alignment");
00224   update_if_needed();
00225   return rep->m_byte_alignment;
00226 }
00227 
00228 unsigned int media::bmap_data::byte_count() const
00229 {
00230 GVX_TRACE("media::bmap_data::byte_count");
00231   update_if_needed();
00232 
00233   GVX_ASSERT(rep->m_bytes.size() == rep->bytes_per_row() * rep->m_size.y());
00234 
00235   return rep->byte_count();
00236 }
00237 
00238 unsigned int media::bmap_data::bytes_per_row() const
00239 {
00240 GVX_TRACE("media::bmap_data::bytes_per_row");
00241   update_if_needed();
00242   return rep->bytes_per_row();
00243 }
00244 
00245 media::bmap_data::row_order
00246 media::bmap_data::get_row_order() const
00247 {
00248   return rep->m_row_order;
00249 }
00250 
00251 void media::bmap_data::flip_contrast()
00252 {
00253 GVX_TRACE("media::bmap_data::flip_contrast");
00254   update_if_needed();
00255 
00256   unsigned int num_bytes = rep->m_bytes.size();
00257 
00258   // In this case we want to flip each bit
00259   if (rep->m_bits_per_pixel == 1)
00260     {
00261       for (unsigned int i = 0; i < num_bytes; ++i)
00262         {
00263           rep->m_bytes[i] =
00264             static_cast<unsigned char>(0xff ^ rep->m_bytes[i]);
00265         }
00266     }
00267   // In this case we want to reflect the value of each byte around the
00268   // middle value, 127.5
00269   else
00270     {
00271       for (unsigned int i = 0; i < num_bytes; ++i)
00272         {
00273           rep->m_bytes[i] =
00274             static_cast<unsigned char>(0xff - rep->m_bytes[i]);
00275         }
00276     }
00277 }
00278 
00279 void media::bmap_data::flip_vertical()
00280 {
00281 GVX_TRACE("media::bmap_data::flip_vertical");
00282   update_if_needed();
00283 
00284   int bytes_per_row = rep->bytes_per_row();
00285   int num_bytes = rep->byte_count();
00286 
00287   rutz::dynamic_block<unsigned char> new_bytes(num_bytes);
00288 
00289   for (int row = 0; row < rep->m_size.y(); ++row)
00290     {
00291       int new_row = (rep->m_size.y()-1)-row;
00292       memcpy(static_cast<void*> (&(new_bytes   [new_row * bytes_per_row])),
00293              static_cast<void*> (&(rep->m_bytes[row     * bytes_per_row])),
00294              bytes_per_row);
00295     }
00296 
00297   rep->m_bytes.swap(new_bytes);
00298 }
00299 
00300 void media::bmap_data::clear()
00301 {
00302 GVX_TRACE("media::bmap_data::clear");
00303 
00304   media::bmap_data empty;
00305   swap(empty);
00306 }
00307 
00308 void media::bmap_data::swap(media::bmap_data& other)
00309 {
00310 GVX_TRACE("media::bmap_data::swap");
00311 
00312   rutz::swap2(rep, other.rep);
00313 }
00314 
00315 void media::bmap_data::queue_update(shared_ptr<update_func> updater) const
00316 {
00317 GVX_TRACE("media::bmap_data::queue_update");
00318   rep->m_updater = updater;
00319 }
00320 
00321 void media::bmap_data::update_if_needed() const
00322 {
00323 GVX_TRACE("media::bmap_data::update_if_needed");
00324   if (rep->m_updater.get() != 0)
00325     {
00326       shared_ptr<update_func> tmp_updater(rep->m_updater);
00327 
00328       // We release rep->m_updater before doing the update, so that we
00329       // avoid endless recursion if update_if_needed is called again
00330       // during the updating.
00331       rep->m_updater.reset();
00332 
00333       tmp_updater->update(const_cast<media::bmap_data&>(*this));
00334     }
00335 }
00336 
00337 void media::bmap_data::clear_queued_update() const
00338 {
00339 GVX_TRACE("media::bmap_data::clear_queued_update");
00340   rep->m_updater.reset();
00341 }
00342 
00343 void media::bmap_data::set_row_order(row_order order) const
00344 {
00345   if (order != rep->m_row_order)
00346     {
00347       const_cast<bmap_data*>(this)->flip_vertical();
00348       rep->m_row_order = order;
00349     }
00350 }
00351 
00352 void media::bmap_data::specify_row_order(row_order order) const
00353 {
00354   rep->m_row_order = order;
00355 }
00356 
00357 shared_ptr<media::bmap_data>
00358 media::bmap_data::make_scrambled(int nsubimg_x, int nsubimg_y, int seed,
00359                                  bool allow_move_subparts,
00360                                  bool allow_flip_left_right,
00361                                  bool allow_flip_top_bottom) const
00362 {
00363 GVX_TRACE("media::bmap_data::make_scrambled");
00364 
00365   update_if_needed();
00366 
00367   if ( width() % nsubimg_x != 0 )
00368     {
00369       throw rutz::error("not an evenly divisible width", SRC_POS);
00370     }
00371 
00372   if ( height() % nsubimg_y != 0 )
00373     {
00374       throw rutz::error("not an evenly divisible width", SRC_POS);
00375     }
00376 
00377   shared_ptr<media::bmap_data> result
00378     (new media::bmap_data(this->size(),
00379                           this->bits_per_pixel(),
00380                           this->byte_alignment()));
00381 
00382   const int npos = nsubimg_x * nsubimg_y;
00383 
00384   rutz::fixed_block<int> newpos(npos);
00385   for (int i = 0; i < npos; ++i)
00386     {
00387       newpos[i] = i;
00388     }
00389 
00390   rutz::urand generator(seed);
00391 
00392   if (allow_move_subparts)
00393     {
00394       std::random_shuffle(newpos.begin(), newpos.end(), generator);
00395     }
00396 
00397   if (rep->m_bits_per_pixel != 8 && rep->m_bits_per_pixel != 24)
00398     {
00399       throw rutz::error(rutz::sfmt("unknown bits-per-pixel value: %d",
00400                                    rep->m_bits_per_pixel), SRC_POS);
00401     }
00402 
00403   const int bytes_per_pixel = rep->m_bits_per_pixel/8;
00404 
00405   const int size_subimg_x = result->width() / nsubimg_x * bytes_per_pixel;
00406   const int size_subimg_y = result->height() / nsubimg_y;
00407 
00408   for (int i = 0; i < npos; ++i)
00409     {
00410       const bool fliplr = allow_flip_left_right && generator.booldraw();
00411       const bool fliptb = allow_flip_top_bottom && generator.booldraw();
00412 
00413       const int src_subimg_y = i / nsubimg_x;
00414       const int src_subimg_x = i % nsubimg_x;
00415 
00416       const int src_fullimg_y = src_subimg_y * size_subimg_y;
00417       const int src_fullimg_x = src_subimg_x * size_subimg_x;
00418 
00419       const int dst_subimg_y = newpos[i] / nsubimg_x;
00420       const int dst_subimg_x = newpos[i] % nsubimg_x;
00421 
00422       const int dst_fullimg_y = dst_subimg_y * size_subimg_y;
00423       const int dst_fullimg_x = dst_subimg_x * size_subimg_x;
00424 
00425       for (int y = 0; y < size_subimg_y; ++y)
00426         {
00427           // NOTE: I tried hand-optimizing all this stuff to avoid
00428           // calls to row_ptr()... basically optimizing all the math
00429           // so that we just increment pointers in each loop iteration
00430           // rather than re-compute positions afresh. But, it made no
00431           // helpful difference in runtimes. So, better to keep the
00432           // clean easier-to-read code here. My guess is that the best
00433           // way to speed this algorithm up, if needed, would be by
00434           // improving cache performance. Right now we jump around in
00435           // both the src and dst images. We could speed things up by
00436           // designing the algorithm so that one of src/dst gets read
00437           // straight through from beginning to end.
00438 
00439           const unsigned char* src =
00440             rep->row_ptr(src_fullimg_y+y) + src_fullimg_x;
00441 
00442           const unsigned int dst_row =
00443             fliptb
00444             ? dst_fullimg_y+size_subimg_y-1-y
00445             : dst_fullimg_y+y;
00446 
00447           unsigned char* dst =
00448             result->rep->row_ptr(dst_row) + dst_fullimg_x;
00449 
00450           unsigned char* dst_end = dst + size_subimg_x;
00451 
00452           if (fliplr)
00453             {
00454               if (bytes_per_pixel == 1)
00455                 while (dst_end != dst) { *--dst_end = *src++; }
00456               else if (bytes_per_pixel == 3)
00457                 while (dst_end != dst)
00458                   {
00459                     *(dst_end-3) = *src++;
00460                     *(dst_end-2) = *src++;
00461                     *(dst_end-1) = *src++;
00462                     dst_end -= 3;
00463                   }
00464               else
00465                 {
00466                   GVX_ASSERT(0);
00467                 }
00468             }
00469           else
00470             {
00471               while (dst != dst_end) { *dst++ = *src++; }
00472             }
00473         }
00474     }
00475 
00476   return result;
00477 }
00478 
00479 static const char __attribute__((used)) vcid_groovx_media_bmapdata_cc_utc20050626084018[] = "$Id: bmapdata.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00480 #endif // !GROOVX_MEDIA_BMAPDATA_CC_UTC20050626084018_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:39 2008 by Doxygen version 1.5.5.