Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phImage.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 /* ---------------------------------------------------------------------- *
00027  * thread safe pointer object copying, setting, etc.
00028  *
00029  *  "Encapsulate"
00030  *      Data is stored in a phImage object that allows safe sharing 
00031  *      with of the image data with other objects. All data about the 
00032  *      image is contained within the phImage object as it should be. 
00033  *      RGBA Masks allow for any order of color byte storage. The 
00034  *      assumption is that the receiving class uses the 
00035  *      phImage correctly; 
00036  *
00037  *  "Inheritance"
00038  *      The phImage only adds image specific variables to the phDataObject 
00039  *      class. "Width", "Height", and Image format are stored in
00040  *      the phImage. The actual locks are implemented in the phMutex
00041  *      class. The phDataObject class provides the base and framework 
00042  *      (for Safe Objects that manage a pointer)to be built on top of it.
00043  *
00044  *  "Polymorphism"
00045  *      The type of data safely stored in a pointer within the phDataObject
00046  *      class can be anything of any size. Ideally, a new class will
00047  *      inherit from phDataObject to make more sense of the data if necessary.
00048  *      This is what the phImage class does.
00049  *
00050  * ---------------------------------------------------------------------- *
00051  * Compression:
00052  *
00053  *      Compression is done using ZLib. All the compressed data is stored 
00054  * in a buffer large enough to hold the uncompressed data. However,
00055  * during a copy, only the compressed data is copied. If for some 
00056  * reason the buffer isn't large enough to hold the data when it's
00057  * decompressed, the buffer will be grown to fit it. 
00058  * ---------------------------------------------------------------------- */
00059 
00060 /*
00061  * TODO: an issue here is that inheriting classes
00062  * may want to define their own formats; 
00063  * Should provide for a USER_DEFINE image format and
00064  * support user depth setting and user size calculation
00065  * settings.
00066  */
00067 
00068 #ifdef HAVE_CONFIG_H
00069     #include <phissionconfig.h>
00070 #endif
00071 #if HAVE_LIBZ
00072     #include <zlib.h>
00073     #include <math.h> /* needed in phImage::compress */
00074 #endif
00075 
00076 #include <phStandard.h>
00077 #include <ImagePPM.h>
00078 #include <ImageConversions.h>   
00079 
00080 #include <phObject.h>
00081 #include <phMutex.h>
00082 #include <phSemaphore.h>
00083 #include <phCondition.h>
00084 #include <phRWLock.h>
00085 #include <phThread.h>
00086 #include <phList.h>
00087 #include <phTimeStamp.h>
00088 #include <phTimeInterval.h>
00089 #include <phLiveObject.h>
00090 #include <phDataObject.h>
00091 
00092 #include <phImage.h>
00093 
00094 #if defined(HAVE_UNISTD_H)
00095 //    #include <unistd.h>
00096 #endif
00097 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00098 //    #include <pthread.h>
00099 #endif
00100 #if defined(HAVE_ERRNO_H)
00101 //    #include <errno.h>
00102 #endif
00103 #if USE_FILETYPE
00104 #else
00105     //#include <sys/file.h>
00106     #include <sys/types.h>
00107     #include <sys/stat.h>
00108     #include <fcntl.h>
00109     //#include <unistd.h>
00110 #endif
00111 
00112 #include <phError.h>
00113 #include <phMemory.h>
00114 #include <phPrint.h>
00115 
00116 /* ---------------------------------------------------------------------- */
00117 /* phImage : thread safe image pointer setting, copying, etc.             */
00118 /* ---------------------------------------------------------------------- */
00119 phImage::phImage( )
00120 {
00121     phFUNCTION("phImage::phImage")
00122 
00123     phDataObject::setName("phImage");
00124 
00125     this->m_width = 0;
00126     this->m_height = 0;
00127 
00128     this->m_format = phImageRGB24;
00129 
00130     rc = this->initFileSave();
00131     rc = this->initResize();
00132     rc = this->initCrop();
00133     rc = this->initConversion();
00134     rc = this->initJPEGCompression();
00135     rc = this->initZlibCompression();
00136 }
00137 
00138 /* ---------------------------------------------------------------------- */
00139 phImage::~phImage()
00140 {
00141     phFUNCTION("phImage::~phImage")
00142     int locked = 0;
00143 
00144     phTHIS_LOOSE_LOCK(locked);
00145 
00146     /* Free all the data; calls up to phDataObject also */
00147     rc = this->reset();
00148     phPRINT_RC(rc,NULL,"this->reset");
00149 }
00150 
00151 /* ---------------------------------------------------------------------- */
00152 uint32_t phImage::getWidth()
00153 { 
00154     return this->m_width;  
00155 }
00156 
00157 /* ---------------------------------------------------------------------- */
00158 uint32_t phImage::getHeight()
00159 { 
00160     return this->m_height; 
00161 }
00162 
00163 /* ---------------------------------------------------------------------- */
00164 int32_t phImage::getFormat()
00165 { 
00166     return this->m_format; 
00167 }
00168 
00169 /* ---------------------------------------------------------------------- */
00170 /* setFormat: This merely sets the format flag. If the data isn't already
00171  * in the specified format then unexpected results may occur.             */
00172 /* ---------------------------------------------------------------------- */
00173 int phImage::setFormat( uint32_t type )
00174 {
00175     phFUNCTION("phImage::setFormat")
00176     int         locked      = 0;
00177     uint32_t    extra_type  = 0;
00178     
00179     phTHIS_WRITELOCK(locked);
00180 
00181     /* Remove special flags; */ 
00182     if (type & phImageSpecialMask)
00183     {
00184         extra_type |= type & phImageSpecialMask;
00185         type &= ~phImageSpecialMask;
00186     }
00187     
00188     /* Try to prevent an invalid format from being set by using == 
00189      * instead of using & */
00190     if ((type == phImageRGB24) ||
00191         (type == phImageBGR24) ||
00192         (type == phImageYUV9) ||
00193         (type == phImageRGBA32)||
00194         (type == phImageABGR32)||
00195         (type == phImageBGRA32)||
00196         (type == phImageGREY8)||
00197         (type == phImageHSV24)||
00198         (type == phImageSCT24))
00199     {
00200         this->m_format = type | extra_type;
00201     }
00202     else
00203     {
00204         phERR_PRINT("Invalid format.\n");
00205         goto error;
00206     }
00207 
00208     phTHIS_RWUNLOCK(locked);
00209     
00210     return phSUCCESS;
00211 error:
00212     phTHIS_RWUNLOCK_ERROR(locked);
00213     
00214     return phFAIL;
00215 }
00216 
00217 /* ---------------------------------------------------------------------- */
00218 const uint8_t *phImage::getImage() 
00219 { 
00220     return (const uint8_t *)this->getData(); 
00221 }
00222 
00223 /* ---------------------------------------------------------------------- */
00224 uint32_t phImage::calculateSize( uint32_t w, uint32_t h, int32_t f )
00225 {
00226     phFUNCTION("phImage::calculateSize")
00227     
00228     uint32_t s = 0;
00229 
00230     phIMAGE_SIZE_IN_BYTES(s,w,h,f);
00231    
00232     return s;
00233 }
00234 
00235 /* ---------------------------------------------------------------------- */
00236 int phImage::copy( phObject *copyto_object )
00237 {
00238     phFUNCTION("phImage::copy")
00239     
00240     if (this->isNamed(((phObject *)copyto_object)->getName()))
00241     {
00242         phImage *copyto_img = (phImage *)copyto_object;
00243         return copyto_img->setImage(*this);
00244     }
00245     /* Otherwise I'll assume they are incompatible */
00246     else
00247     {
00248         phPRINT_RC(-1,NULL, "Invalid object pairing in update."
00249                           "[ this:%s != target:%s ]",
00250                  this->getName(), ((phObject *)copyto_object)->getName());
00251         return phFAIL;
00252     }
00253 }
00254 
00255 /* ---------------------------------------------------------------------- */
00256 int phImage::swap( phObject *object )
00257 {
00258     phFUNCTION("phImage::swap")
00259 
00260     if (this->isNamed(((phObject *)object)->getName()))
00261     {
00262         phImage *img = (phImage *)object;
00263         
00264         return img->swapImage(*this);
00265     }
00266     /* Otherwise I'll assume they are incompatible */
00267     else
00268     {
00269         phPRINT_RC(-1,NULL, "Invalid object pairing in update."
00270                           "[ this:%s != target:%s ]",
00271                  this->getName(), ((phObject *)object)->getName());
00272         return phFAIL;
00273     }    
00274 }
00275 
00276 /* ---------------------------------------------------------------------- */
00277 int phImage::getImage( int8_t image[] )
00278 {
00279     phFUNCTION("phImage::getImage")
00280     int locked  = 0;
00281     int retrc   = phSUCCESS;
00282     
00283     phTHIS_READLOCK(locked);
00284 
00285     if (this->m_data == NULL) { retrc = 1; goto success; }
00286 
00287     if (image != NULL)
00288     {
00289         phMemcpy(image,this->m_data,this->m_size);
00290     }
00291 success:
00292     phTHIS_RWUNLOCK(locked);
00293     
00294     return retrc;
00295 error:
00296     phTHIS_RWUNLOCK_ERROR(locked);
00297     
00298     return phFAIL;
00299 }
00300 
00301 /* ---------------------------------------------------------------------- */
00302 /* Temporary 
00303 void phImage::print()
00304 {
00305     int i = 0;
00306     int j = 0;
00307 
00308     if (this->isNull()) return;
00309 
00310     printf("phImage:");
00311     for (i = 0; i < 20; i++)
00312     {
00313         printf("[");
00314         for (j = 0; j < 3; j++ )
00315         {
00316             printf("%d",((uint8_t *)this->m_data)[i * 3 + j]);
00317             if (j == 2)
00318             {
00319                 printf("]");
00320             }
00321             else
00322             {
00323                 printf(",");
00324             }
00325         }
00326     }
00327     printf("\n");
00328     fflush(stdout);
00329 }
00330 */
00331 
00332 /* ---------------------------------------------------------------------- */
00333 int phImage::getCopy(   uint32_t *w, 
00334                         uint32_t *h, 
00335                         uint32_t *format,
00336                         uint32_t *s,
00337                         uint8_t  *image[] )
00338 {
00339     phFUNCTION("phImage::getCopy")
00340     int         locked  = 0;
00341     int         retrc   = phSUCCESS;
00342     uint32_t    newsize = 0;
00343 
00344     phTHIS_READLOCK(locked);
00345 
00346     if (this->m_data == NULL) { retrc = 1; goto success; }
00347 
00348     if (w != NULL) *w = this->m_width;
00349     if (h != NULL) *h = this->m_height;
00350     if (format != NULL) *format = this->m_format;
00351 
00352     newsize = this->m_size;
00353     
00354     if (image != NULL)
00355     {
00356         if (*image == NULL)
00357         {
00358             /* need to initialize data to some memory */
00359             *image = (uint8_t *)phMalloc(newsize);
00360             phCHECK_NULLPTR(*image,"phMalloc","phMalloc failed");
00361             
00362             phMemset(*image,0,newsize);
00363             
00364             if (s != NULL)
00365                 *s = newsize;
00366         }
00367         else
00368         {
00369             /* allocate a different amount of space, more.. less.. */
00370             *image = (uint8_t  *)phRealloc((void *)*image, newsize );
00371             phCHECK_NULLPTR(*image,"phRealloc","phRealloc failed");        
00372             
00373             if (s != NULL)
00374                 *s = newsize;
00375         }
00376         
00377         phMemcpy(*image,this->m_data,newsize);
00378     }
00379 success:
00380     phTHIS_RWUNLOCK(locked);
00381     
00382     return retrc;
00383 error:
00384     phTHIS_RWUNLOCK_ERROR(locked);
00385     
00386     return phFAIL;
00387 }
00388 
00389 /* ---------------------------------------------------------------------- */
00390 int phImage::getCopy( phImage &image )
00391 {
00392     phFUNCTION("phImage::getCopy")
00393     int locked      = 0;
00394     int img_locked  = 0;
00395     
00396     phTHIS_READLOCK(locked);
00397     phWRITELOCK(image,img_locked);
00398 
00399     rc = image.setImage(*this);
00400     phCHECK_RC(rc,NULL,"image.setImage(*this)");
00401     
00402     phRWUNLOCK(image,img_locked);
00403     phTHIS_RWUNLOCK(locked);
00404     
00405     return phSUCCESS;
00406 error:
00407     phRWUNLOCK_ERROR(image,img_locked);
00408     phTHIS_RWUNLOCK_ERROR(locked);
00409     
00410     return phFAIL;
00411 }
00412 
00413 /* ---------------------------------------------------------------------- */
00414 int phImage::setImage( phImage &copyfrom )
00415 {
00416     phFUNCTION("phImage::setImage")
00417     int locked      = 0;
00418     int copy_locked = 0;
00419     int retrc       = phSUCCESS;
00420     
00421     phTHIS_WRITELOCK(locked);
00422     phREADLOCK(copyfrom,copy_locked);
00423 
00424     if ((copyfrom.m_format & phImageValidFormatMask) && 
00425         (copyfrom.getImage() != NULL))
00426     {    
00427         this->m_width       = copyfrom.m_width;
00428         this->m_height      = copyfrom.m_height;
00429         this->m_compressed  = copyfrom.m_compressed;
00430         this->m_jpegCompressed  = copyfrom.m_jpegCompressed;
00431         
00432         /* don't copy compression level, it's an individual setting not to be
00433          * copied among individuals using this method */
00434 
00435         /* setFormat error checks things */
00436         rc = this->setFormat(copyfrom.m_format);
00437         phPRINT_RC(rc,NULL,"setFormat");
00438         
00439         /* setData will call notify for phImage */
00440         rc = this->phDataObject::setData(copyfrom.getSize(),
00441                                         (void *)copyfrom.getImage());
00442         phCHECK_RC(rc,NULL,"phDataObject::setData()");
00443     } 
00444     else
00445     {
00446         retrc = 1;
00447     }
00448 
00449     phRWUNLOCK(copyfrom,copy_locked);
00450     phTHIS_RWUNLOCK(locked);
00451     
00452     return retrc;
00453 error:
00454     phRWUNLOCK_ERROR(copyfrom,copy_locked);
00455     phTHIS_RWUNLOCK_ERROR(locked);
00456     
00457     return phFAIL;
00458 }
00459 
00460 /* ---------------------------------------------------------------------- */
00461 int phImage::setImage(  uint32_t        w, 
00462                         uint32_t        h, 
00463                         int32_t         f,
00464                         uint32_t        s,
00465                         const uint8_t   image[] )
00466 {
00467     phFUNCTION("phImage::setImage")
00468     int locked = 0;
00469 
00470     /* uint32_t size = 0;*/
00471     
00472     if (image == NULL) return 1;
00473 
00474     if (!(f & phImageValidFormatMask)) return 1;
00475     
00476     phTHIS_WRITELOCK(locked);
00477 
00478     /*
00479     phPROGRESS("w:%u\th:%u\tf:%u\timage:%p\n",
00480              w, h, f, image );
00481     */
00482     this->m_width   = w;
00483     this->m_height  = h;
00484     /* setFormat error checks things */
00485     rc = this->setFormat(f);
00486     phPRINT_RC(rc,NULL,"setFormat");
00487     
00488     if ((this->m_format & phImageJPEG) == phImageJPEG)
00489     {
00490         this->m_jpegCompressed = 1;
00491     }
00492     else
00493         this->m_jpegCompressed = 0;
00494     
00495     if ((this->m_format & phImageZlib) == phImageZlib)
00496     {
00497         this->m_compressed = 1;
00498     }
00499     else
00500         this->m_compressed = 0;
00501     
00502     if (s == 0)
00503     {
00504         s = calculateSize(w,h,f);
00505     }
00506     
00507     /* setData will call notify for phImage */
00508     rc = this->phDataObject::setData(s,(void *)image);
00509     phCHECK_RC(rc,NULL,"phDataObject::setData()");
00510    
00511     phTHIS_RWUNLOCK(locked);
00512     
00513     return phSUCCESS;
00514 error:
00515     phTHIS_RWUNLOCK_ERROR(locked);
00516     
00517     return phFAIL;
00518 }
00519 
00520 /* ---------------------------------------------------------------------- */
00521 int phImage::swapImage( phImage &image )
00522 {
00523     return this->swapData(image); 
00524 };
00525 
00526 /* ---------------------------------------------------------------------- */
00527 int phImage::swapData(  uint32_t *w, 
00528                         uint32_t *h, 
00529                         uint32_t *format, 
00530                         uint8_t  *image[],
00531                         uint32_t *psize )
00532 {
00533     phFUNCTION("phImage::swapData")
00534     int         locked  = 0;
00535     uint32_t    nw      = 0;
00536     uint32_t    nh      = 0;
00537     uint32_t    nformat = 0;
00538     uint32_t    temp_size = 0;
00539     
00540     phTHIS_WRITELOCK(locked);
00541     if (this->isSwapEnabled())
00542     {
00543         /* TODO: check arguments for valid ptr values */
00544         nw = *w;
00545         nh = *h;
00546         nformat = *format;
00547 
00548         *w = this->m_width;
00549         *h = this->m_height;
00550         *format = this->m_format;
00551 
00552         this->m_width = nw;
00553         this->m_height = nh;
00554         this->m_format = nformat;
00555 
00556         if ((this->m_format & phImageJPEG) == phImageJPEG)
00557         {
00558             this->m_jpegCompressed = 1;
00559         }
00560         else
00561             this->m_jpegCompressed = 0;
00562     
00563         if ((this->m_format & phImageZlib) == phImageZlib)
00564         {
00565             this->m_compressed = 1;
00566         }
00567         else
00568             this->m_compressed = 0;
00569         
00570         /*
00571         ptr = this->m_data;
00572         this->m_data = *image;
00573         *image = (uint8_t *)ptr;
00574         */
00575         if (psize != NULL)
00576         {
00577             if (*psize > 0)
00578             {
00579                 temp_size = *psize;
00580             }
00581             else 
00582             {
00583                 temp_size = 0;
00584             }
00585         }
00586         else
00587         {
00588             temp_size = 0;
00589         }
00590     
00591         if (temp_size == 0)
00592         {
00593             temp_size = calculateSize( this->m_width,
00594                                        this->m_height,
00595                                        this->m_format);
00596         }
00597  
00598         /* phDataObject::swapData will call notify for phImage */
00599         /* This will also swap 'size' and 'data' */
00600         rc = this->phDataObject::swapData(&temp_size, (void **)image);
00601         phCHECK_RC(rc,NULL,"this->phDataObject::swapData() failed.");
00602    
00603         if (psize != NULL)
00604         {
00605             *psize = temp_size;
00606         }
00607     
00608     }
00609     else
00610     {
00611         rc = this->setImage( *w, *h, *format, *psize, *image );
00612         phCHECK_RC(rc,NULL,"this->setImage()");
00613     }   
00614         
00615     phTHIS_RWUNLOCK(locked);
00616 
00617     return phSUCCESS;
00618 error:
00619     phTHIS_RWUNLOCK_ERROR(locked);
00620     
00621     return phFAIL;
00622 }
00623 
00624 /* ---------------------------------------------------------------------- */
00625 int phImage::swapData( phImage &image  )
00626 {
00627     phFUNCTION("phImage::swapData")
00628     int      locked     = 0;
00629     int      img_locked = 0;
00630     uint32_t w = 0;
00631     uint32_t h = 0;
00632     uint32_t f = 0;
00633     int      c = 0;
00634     int      jc = 0;
00635     
00636     phTHIS_WRITELOCK(locked);
00637     
00638     if (this->isSwapEnabled())
00639     {
00640         phWRITELOCK(image,img_locked);
00641 
00642         /* NOTE: don't copy compression level, it's an individual setting not to be
00643          * copied among individuals using this method */
00644 
00645         w = image.m_width;
00646         h = image.m_height;
00647         f = image.m_format;
00648         c = image.m_compressed;
00649         jc = image.m_jpegCompressed;
00650     
00651         image.m_width = this->m_width;
00652         image.m_height = this->m_height;
00653         image.m_format = this->m_format;
00654         image.m_compressed = this->m_compressed;
00655         image.m_jpegCompressed = this->m_jpegCompressed;
00656 
00657         this->m_width = w;
00658         this->m_height = h;
00659         this->m_format = f;
00660         this->m_compressed = c;
00661         this->m_jpegCompressed = jc;
00662 
00663         /* swapData will call notify for phImage */
00664         /* This will also swap 'size' and 'data' */
00665         rc = this->phDataObject::swapData(image);
00666         phCHECK_RC(rc,NULL,"phDataObject::swapData()");
00667 
00668         phRWUNLOCK(image,img_locked);
00669     }
00670     else
00671     {
00672         rc = this->setImage(image);
00673         phCHECK_RC(rc,NULL,"phImage::setImage");
00674     }
00675 
00676     phTHIS_RWUNLOCK(locked);
00677     
00678     return phSUCCESS;
00679 error:
00680     phRWUNLOCK_ERROR(image,img_locked);
00681     phTHIS_RWUNLOCK_ERROR(locked);
00682     
00683     return phFAIL;
00684 }
00685 
00686 /* ---------------------------------------------------------------------- */
00687 int phImage::allocate( uint32_t w, uint32_t h, uint32_t f )
00688 {
00689     phFUNCTION("phImage::allocate")
00690     int locked = 0;
00691     
00692     phTHIS_WRITELOCK(locked);
00693 
00694     this->m_width           = w;
00695     this->m_height          = h;
00696     this->m_format          = (f & ~phImageSpecialMask);
00697     this->m_jpegCompressed  = 0;
00698     this->m_compressed      = 0;
00699 
00700     rc = this->phDataObject::allocate(phIMAGE_SIZE(w,h,f));
00701     phCHECK_RC(rc,NULL,"this->phDataObject::allocate(phIMAGE_SIZE(w,h,f))");
00702 
00703     phTHIS_RWUNLOCK(locked);
00704     
00705     return phSUCCESS;
00706 error:
00707     phTHIS_RWUNLOCK_ERROR(locked);
00708     
00709     return phFAIL;
00710 }
00711 
00712 /* ---------------------------------------------------------------------- */
00713 int phImage::reset(  )
00714 {
00715     phFUNCTION("phImage::reset")
00716     int locked = 0;
00717     
00718     phTHIS_WRITELOCK(locked);
00719 
00720     this->m_width = 0;
00721     this->m_height = 0;
00722     this->m_format = phImageRGB24;
00723 
00724     rc = this->resetFileSave();
00725     phPRINT_RC(rc,NULL,"resetFileSave");
00726     
00727     rc = this->resetResize();
00728     phPRINT_RC(rc,NULL,"resetResize");
00729     
00730     rc = this->resetCrop();
00731     phPRINT_RC(rc,NULL,"resetCrop");
00732     
00733     rc = this->resetConversion();
00734     phPRINT_RC(rc,NULL,"resetConversion");
00735 
00736     rc = this->resetJPEGCompression();
00737     phPRINT_RC(rc,NULL,"resetJPEGCompression");
00738 
00739     rc = this->resetZlibCompression();
00740     phPRINT_RC(rc,NULL,"resetZlibCompression");
00741 
00742     rc = this->phDataObject::reset();
00743     phCHECK_RC(rc,NULL,"phDataObject::reset()");
00744     
00745     phTHIS_RWUNLOCK(locked);
00746     
00747     return phSUCCESS;
00748 error:
00749     phTHIS_RWUNLOCK_ERROR(locked);
00750     
00751     return phFAIL;
00752 }
00753 
00754 /* ---------------------------------------------------------------------- */
00755 phImage& phImage::operator = (phImage &rightHandSide)
00756 {
00757     phFUNCTION("phImage::operator =")
00758     int locked      = 0;
00759     int right_locked= 0;
00760     
00761     phTHIS_WRITELOCK(locked);
00762     phWRITELOCK(rightHandSide,right_locked);
00763 
00764     rc = rightHandSide.getCopy(*this);
00765     phCHECK_RC(rc,NULL,"rightHandSide.getCopy(*this)");
00766 
00767     phRWUNLOCK(rightHandSide,right_locked);
00768     phTHIS_RWUNLOCK(locked);
00769 
00770     return *this;
00771 error:
00772     phRWUNLOCK_ERROR(rightHandSide,right_locked);
00773     phTHIS_RWUNLOCK_ERROR(locked);
00774 
00775     return *this;
00776 }
00777 
00778 /* ---------------------------------------------------------------------- */
00779 int phImage::initCrop()
00780 {
00781     phFUNCTION("phImage::initCrop")
00782 
00783     /* cropping member variables */
00784     this->m_crop_buf        = NULL;
00785     this->m_crop_buf_size   = 0;
00786 
00787     return phSUCCESS;
00788 }
00789 
00790 /* ---------------------------------------------------------------------- */
00791 int phImage::resetCrop()
00792 {
00793     phFUNCTION("phImage::resetCrop")
00794 
00795     /* Cropping member variables */
00796     phFree(this->m_crop_buf);
00797     this->m_crop_buf_size = 0;
00798 
00799     return phSUCCESS;
00800 }
00801 
00802 
00803 /* ---------------------------------------------------------------------- */
00804 int phImage::initResize()
00805 {
00806     phFUNCTION("phImage::initResize")
00807 
00808     /* Resizing temporary variables */
00809     this->m_bilinear_table      = NULL;
00810     this->m_nn_table            = NULL;
00811     this->m_resize_buf          = NULL;
00812     this->m_resize_buf_size     = 0;
00813 
00814     return phSUCCESS;
00815 }
00816 
00817 /* ---------------------------------------------------------------------- */
00818 int phImage::resetResize()
00819 {
00820     phFUNCTION("phImage::resetResize")
00821 
00822     /* Resizing member variables */
00823     phFree(this->m_resize_buf);
00824     this->m_resize_buf_size = 0;
00825 
00826     if (this->m_bilinear_table)
00827     {
00828         ph_bilinear_table_free(&this->m_bilinear_table);
00829     }
00830     if (this->m_nn_table)
00831     {
00832         ph_nearest_neighbor_table_free(&this->m_nn_table);
00833     }
00834 
00835     return phSUCCESS;
00836 }
00837 
00838 /* ---------------------------------------------------------------------- */
00839 int phImage::resize( phImage &original,
00840                      uint32_t w, 
00841                      uint32_t h, 
00842                      uint32_t algorithm )
00843 {
00844     phFUNCTION("phImage::resize(phImage,w,h,algorithm)")
00845     int locked          = 0;
00846     int original_locked = 0;
00847     int reenable_notify = 0;
00848 
00849     if ((w == 0) || (h == 0)) goto error;
00850     
00851     phTHIS_WRITELOCK(locked);
00852     /* do the READLOCK after the WRITELOCK just in case original == this */
00853     phREADLOCK(original,original_locked);
00854     
00855     if (original.m_data == NULL) goto error;
00856 
00857     if (w == 0) w = 1;
00858     if (h == 0) h = 1;
00859     
00860     /* if we need to scale, then scale, otherwise don't */
00861     if ((w != original.m_width) || (h != original.m_height))
00862     {
00863         int         recompress      = 0;
00864         int         jpeg_recompress = 0;
00865         uint32_t    format          = original.m_format;
00866 
00867         if (original.isNotifyEnabled())
00868         {
00869             reenable_notify = 1;
00870             original.disableNotify();
00871         }
00872         
00873         if (original.m_compressed)
00874         {
00875             rc = original.decompress();
00876             phPRINT_RC(rc,NULL,"original.decompress()");
00877             
00878             recompress = 1;
00879         }
00880  
00881         if (original.m_jpegCompressed)
00882         {
00883             rc = original.jpegDecompress();
00884             phPRINT_RC(rc,NULL,"original.jpegDecompress()");
00885             
00886             jpeg_recompress = 1;
00887         }
00888     
00889         /* Allocate here so phImage has control of the memory */
00890         phDALLOC_RESIZE(this->m_resize_buf,
00891                         this->m_resize_buf_size,
00892                         phIMAGE_SIZE(w,h,original.m_format),
00893                         uint8_t);
00894 
00895         if (algorithm & phResizeNN)
00896         {
00897             rc = ph_nearest_neighbor_scale((const uint8_t *)original.m_data,
00898                                 original.m_width,
00899                                 original.m_height,
00900                                 original.m_format,
00901                                 w, h,
00902                                 &this->m_nn_table,
00903                                 &this->m_resize_buf );
00904             phCHECK_RC(rc,NULL,"ph_nearest_neighbor_scale failed");
00905         }
00906         else if (algorithm & phResizeBilinear)
00907         {
00908             rc = ph_bilinear_scale((const uint8_t *)original.m_data,
00909                                 original.m_width,
00910                                 original.m_height,
00911                                 original.m_format,
00912                                 w, h,
00913                                 &this->m_bilinear_table,
00914                                 &this->m_resize_buf );
00915             phCHECK_RC(rc,NULL,"ph_bilinear_scale failed");
00916         }
00917         else
00918             phCHECK_RC(-1,NULL,"Invalid phResize algorithm flag");
00919         
00920         rc = this->swapData( &w, &h, &format,
00921                              &(this->m_resize_buf),
00922                              &(this->m_resize_buf_size) );
00923         phCHECK_RC(rc,NULL,"this->swapData failed.");
00924 
00925         /* Won't compress if JPEG Compression isn't available */
00926         if (jpeg_recompress)
00927         {
00928             rc = original.jpegCompress();
00929             phPRINT_RC(rc,NULL,"original.jpegCompress()");
00930         }
00931         
00932         /* Won't compress if Zlib Compression isn't available */
00933         if (recompress)
00934         {
00935             rc = original.compress();
00936             phPRINT_RC(rc,NULL,"original.compress()");
00937         }
00938 
00939         if (reenable_notify)
00940         {
00941             reenable_notify = 0;
00942             original.enableNotify();
00943         }
00944     }
00945     else
00946     {
00947         rc = this->setImage(original);
00948         phCHECK_RC(rc,NULL,"this->setImage(original)");
00949     }
00950 
00951     phRWUNLOCK(original,original_locked);
00952     phTHIS_RWUNLOCK(locked);
00953 
00954     return phSUCCESS;
00955     
00956 error:
00957     if (reenable_notify)
00958     {
00959         original.enableNotify();
00960     }
00961     
00962     phRWUNLOCK_ERROR(original,original_locked);
00963     phTHIS_RWUNLOCK_ERROR(locked);
00964 
00965     return phFAIL;
00966 }
00967 
00968 
00969 /* ---------------------------------------------------------------------- */
00970 int phImage::resize( uint32_t w, 
00971                      uint32_t h, 
00972                      uint32_t algorithm )
00973 {
00974     phFUNCTION("phImage::resize(w,h,algorithm)")
00975     int locked          = 0;
00976     int reenable_notify = 0;
00977 
00978     phTHIS_WRITELOCK(locked);
00979         
00980     if (this->isNotifyEnabled())
00981     {
00982         reenable_notify = 1;
00983         this->disableNotify();
00984     }
00985     
00986     rc = this->resize(*this,w,h,algorithm);
00987     phCHECK_RC(rc,NULL,"this->resize(*this,w,h,algorithm)");
00988         
00989     if (reenable_notify)
00990     {
00991         reenable_notify = 0;
00992         this->enableNotify();
00993     }
00994         
00995     /* notify won't actually notify unless notify is enabled */
00996     rc = this->notify();
00997     phPRINT_RC(rc,NULL,"notify() failed.");
00998 
00999     phTHIS_RWUNLOCK(locked);
01000 
01001     return phSUCCESS;
01002     
01003 error:
01004     if (reenable_notify)
01005     {
01006         this->enableNotify();
01007     }
01008     
01009     phTHIS_RWUNLOCK_ERROR(locked);
01010 
01011     return phFAIL;
01012 }
01013 
01014 /* ---------------------------------------------------------------------- */
01015 int phImage::crop( phImage &original,
01016                    uint32_t x1, 
01017                    uint32_t y1, 
01018                    uint32_t x2,
01019                    uint32_t y2 )
01020 {
01021     phFUNCTION("phImage::crop(phImage,x1,y1,x2,y2)")
01022     int locked          = 0;
01023     int original_locked = 0;
01024     int reenable_notify = 0;
01025 
01026     phTHIS_WRITELOCK(locked);
01027     /* read lock after THIS_WRITELOCK for the case where original == this */
01028     phREADLOCK(original,original_locked);
01029     
01030     if (original.m_data == NULL) goto error;
01031 
01032     /* if the bounds of the crop box are within the image dimensions
01033      * then we can crop this image, otherwise it will be the same size */
01034     if ((x1 > 0) || (x2 < (original.m_width-1)) ||
01035         (y1 > 0) || (y2 < (original.m_height-1)))
01036     {
01037         uint32_t    crop_width      = 0;
01038         uint32_t    crop_height     = 0;
01039         int         recompress      = 0;
01040         int         jpeg_recompress = 0;
01041         uint32_t    format          = original.m_format;
01042 
01043         if (original.isNotifyEnabled())
01044         {
01045             reenable_notify = 1;
01046             original.disableNotify();
01047         }
01048         
01049         if (original.m_compressed)
01050         {
01051             rc = original.decompress();
01052             phPRINT_RC(rc,NULL,"original.decompress()");
01053             
01054             recompress = 1;
01055         }
01056  
01057         if (original.m_jpegCompressed)
01058         {
01059             rc = original.jpegDecompress();
01060             phPRINT_RC(rc,NULL,"original.jpegDecompress()");
01061             
01062             jpeg_recompress = 1;
01063         }
01064     
01065         rc = ph_image_crop((const uint8_t *)original.m_data,
01066                            original.m_width,
01067                            original.m_height,
01068                            original.m_format,
01069                            x1,y1,x2,y2,
01070                            &this->m_crop_buf,
01071                            &this->m_crop_buf_size,
01072                            &crop_width,
01073                            &crop_height );
01074         phCHECK_RC(rc,NULL,"ph_image_crop failed");
01075         
01076         rc = this->swapData( &crop_width, &crop_height, &format,
01077                              &(this->m_crop_buf),
01078                              &(this->m_crop_buf_size) );
01079         phCHECK_RC(rc,NULL,"this->swapData failed.");
01080 
01081         /* Won't compress if JPEG Compression isn't available */
01082         if (jpeg_recompress)
01083         {
01084             rc = original.jpegCompress();
01085             phPRINT_RC(rc,NULL,"original.jpegCompress()");
01086         }
01087         
01088         /* Won't compress if Zlib Compression isn't available */
01089         if (recompress)
01090         {
01091             rc = original.compress();
01092             phPRINT_RC(rc,NULL,"original.compress()");
01093         }
01094         
01095         if (reenable_notify)
01096         {
01097             reenable_notify = 0;
01098             original.enableNotify();
01099         }
01100     }
01101     else
01102     {
01103         rc = this->setImage(original);
01104         phCHECK_RC(rc,NULL,"this->setImage(original)");
01105     }
01106 
01107     phRWUNLOCK(original,original_locked);
01108     phTHIS_RWUNLOCK(locked);
01109 
01110     return phSUCCESS;
01111     
01112 error:
01113     if (reenable_notify)
01114     {
01115         original.enableNotify();
01116     }
01117     phRWUNLOCK_ERROR(original,original_locked);
01118     phTHIS_RWUNLOCK_ERROR(locked);
01119 
01120     return phFAIL;
01121 }
01122 
01123 /* ---------------------------------------------------------------------- */
01124 int phImage::crop( uint32_t x1, 
01125                    uint32_t y1, 
01126                    uint32_t x2,
01127                    uint32_t y2 )
01128 {
01129     phFUNCTION("phImage::crop(x1,y1,x2,y2)")
01130     int locked          = 0;
01131     int reenable_notify = 0;
01132 
01133     phTHIS_WRITELOCK(locked);
01134     
01135     if (this->m_data == NULL) goto error;
01136 
01137     if (this->isNotifyEnabled())
01138     {
01139         reenable_notify = 1;
01140         this->disableNotify();
01141     }
01142 
01143     rc = this->crop(*this,x1,y1,x2,y2);
01144     phCHECK_RC(rc,NULL,"this->crop(*this,x1,y1,x2,y2)");
01145 
01146     if (reenable_notify)
01147     {
01148         reenable_notify = 0;
01149         this->enableNotify();
01150     }
01151 
01152     /* notify won't actually notify unless notify is enabled */
01153     rc = this->notify();
01154     phPRINT_RC(rc,NULL,"notify() failed.");
01155 
01156     phTHIS_RWUNLOCK(locked);
01157 
01158     return phSUCCESS;
01159     
01160 error:
01161     if (reenable_notify)
01162     {
01163         this->enableNotify();
01164     }
01165     phTHIS_RWUNLOCK_ERROR(locked);
01166 
01167     return phFAIL;
01168 }
01169 
01170 /* ---------------------------------------------------------------------- */
01171 int phImage::initFileSave()
01172 {
01173     phFUNCTION("phImage::initFileSave")
01174 
01175     /* file saving temporary variables */
01176     this->m_saveImageBuf = NULL;
01177 
01178     return phSUCCESS;
01179 }
01180 
01181 /* ---------------------------------------------------------------------- */
01182 int phImage::resetFileSave()
01183 {
01184     phFUNCTION("phImage::resetFileSave")
01185 
01186     /* File saving temporary variables */
01187     phDelete(this->m_saveImageBuf);
01188 
01189     return phSUCCESS;
01190 }
01191 /* ---------------------------------------------------------------------- */
01192 phFileType phImage::fileTypeFromName( char *filename )
01193 {
01194     phFUNCTION("phImage::fileTypeFromName")
01195     int32_t len = 0;
01196 
01197     if (filename == NULL) goto error;
01198     
01199     len = strlen(filename);
01200     
01201     if (len == 0) goto error;
01202     
01203     if (len >= 4)
01204     {
01205         if (strncmp(&(filename[len - 4]),".ppm",4) == 0)
01206         {
01207             return phFilePPM;
01208         }
01209         else if ((strncmp(&(filename[len - 4]),".jpg",4) == 0) ||
01210                  (strncmp(&(filename[len - 5]),".jpeg",5) == 0))
01211         {
01212             return phFileJPEG;
01213         }
01214     }
01215 
01216 error:
01217     return phFileUnknown;
01218 }
01219 
01220 /* ---------------------------------------------------------------------- */
01221 int phImage::save( char *filename, phFileType filetype )
01222 {
01223     phFUNCTION("phImage::save")
01224     int locked = 0;
01225 
01226     phTHIS_READLOCK(locked);
01227 
01228     if (filetype == phFileAuto)
01229     {
01230         filetype = fileTypeFromName(filename);
01231     }
01232     
01233     switch (filetype) 
01234     {
01235         case phFilePPM:
01236             rc = this->savePPM(filename);
01237             phCHECK_RC(rc,NULL,"savePPM failed.");
01238             break;
01239         case phFileJPEG:
01240             rc = this->saveJPEG(filename);
01241             phCHECK_RC(rc,NULL,"savePPM failed.");
01242             break;
01243         default:
01244             phERR_PRINT("Unsupported file output type for file %s.",filename);
01245             break;
01246     }
01247 
01248     phTHIS_RWUNLOCK(locked);
01249 
01250     return phSUCCESS;
01251 error:
01252     phTHIS_RWUNLOCK_ERROR(locked);
01253 
01254     return phFAIL;
01255 }
01256 
01257 /* ---------------------------------------------------------------------- */
01258 int phImage::load( char *filename, phFileType filetype )
01259 {
01260     phFUNCTION("phImage::load")
01261     int locked = 0;
01262 
01263     phTHIS_WRITELOCK(locked);
01264 
01265     if (filetype == phFileAuto)
01266     {
01267         filetype = fileTypeFromName(filename);
01268     }
01269     
01270     switch (filetype) 
01271     {
01272         case phFilePPM:
01273             rc = this->loadPPM(filename);
01274             phCHECK_RC(rc,NULL,"loadPPM failed.");
01275             break;
01276 
01277         case phFileJPEG:
01278             rc = this->loadJPEG(filename);
01279             phCHECK_RC(rc,NULL,"loadJPEG failed.");
01280             break;
01281             
01282         case phFileUnknown:
01283     
01284         default:
01285             phERR_PRINT("Unsupported file input type (%s).\n", filename );
01286             break;
01287     }
01288 
01289     phTHIS_RWUNLOCK(locked);
01290 
01291     return phSUCCESS;
01292 error:
01293     phTHIS_RWUNLOCK_ERROR(locked);
01294 
01295     return phFAIL;
01296 }
01297 
01298 
01299 /* ---------------------------------------------------------------------- */
01300 int phImage::savePPM( char *filename ) 
01301 {
01302     phFUNCTION("phImage::savePPM")
01303     int         locked      = 0;
01304     uint8_t     *imgdata    = NULL;
01305     uint32_t    imgwidth    = 0;
01306     uint32_t    imgheight   = 0;
01307     
01308     phPPM_image img = NULL;
01309 
01310     phTHIS_READLOCK(locked);
01311 
01312     if (this->m_format != phImageRGB24)
01313     {
01314         /* This will lessen the overhead of saving an image often.
01315          * The whole inherited class line won't need to be constructed
01316          * again everytime this function is called.
01317          * The first time the image is saved for "this", the buffer will
01318          * be allocated and used for every successive save call. */
01319         if (this->m_saveImageBuf == NULL)
01320         {
01321             this->m_saveImageBuf = new phImage();
01322         }
01323         this->m_saveImageBuf->setImage(this->m_width,
01324                                         this->m_height,
01325                                         this->m_format,
01326                                         this->m_size,
01327                                         (uint8_t *)this->m_data);
01328         rc = this->m_saveImageBuf->convert(phImageRGB24);
01329         phCHECK_RC(rc,NULL,"converting of image failed.");
01330         
01331         imgdata = (uint8_t *)this->m_saveImageBuf->getData(); 
01332         imgwidth = this->m_saveImageBuf->getWidth();
01333         imgheight = this->m_saveImageBuf->getHeight();
01334     }
01335     else
01336     {
01337         imgdata = (uint8_t *)this->m_data;
01338         imgwidth = this->m_width;
01339         imgheight = this->m_height;
01340     }
01341     
01342     phCHECK_NULLPTR(this->m_data,NULL,"data == NULL");
01343     
01344     rc = ph_ppm_create_raw( &img,
01345                          imgdata,
01346                          imgwidth,
01347                          imgheight ); 
01348     phCHECK_RC(rc,NULL,"ph_ppm_create_raw failed.");
01349 
01350     rc = ph_ppm_save(img, filename);
01351     phCHECK_RC(rc,NULL,"ph_ppm_save failed.");
01352 
01353     ph_ppm_destroy(&img); 
01354     
01355     phTHIS_RWUNLOCK(locked);
01356 
01357     return phSUCCESS;
01358 
01359 error:
01360     ph_ppm_destroy(&img); 
01361     
01362     phTHIS_RWUNLOCK_ERROR(locked);
01363 
01364     return phFAIL;
01365 }
01366 
01367 /* ---------------------------------------------------------------------- */
01368 int phImage::loadPPM( char *filename ) 
01369 {
01370     phFUNCTION("phImage::loadPPM")
01371     int         locked  = 0;
01372     phPPM_image   img     = NULL;
01373     int         w       = 0;
01374     int         h       = 0;
01375     uint8_t    *ppmData = NULL;
01376 
01377     phTHIS_WRITELOCK(locked);
01378 
01379     rc = ph_ppm_load(&img, filename);
01380     phCHECK_RC(rc,NULL,"ph_ppm_load failed.");
01381 
01382     w       = ph_ppm_get_width(img);
01383     h       = ph_ppm_get_height(img);
01384     ppmData = ph_ppm_get_data(img);
01385 
01386     rc = this->setImage(w, h, phImageRGB24, 
01387                         0, /* size: let the method figure
01388                             * it out from the format */
01389                         ppmData );
01390     phCHECK_RC(rc,NULL,"this->setImage() failed.");
01391 
01392     ph_ppm_destroy(&img); 
01393     
01394     phTHIS_RWUNLOCK(locked);
01395 
01396     return phSUCCESS;
01397 
01398 error:
01399     ph_ppm_destroy(&img); 
01400     
01401     phTHIS_RWUNLOCK_ERROR(locked);
01402 
01403     return phFAIL;
01404 }
01405 
01406 /* ---------------------------------------------------------------------- */
01407 int phImage::initConversion()
01408 {
01409     phFUNCTION("phImage::initConversion")
01410 
01411     /* conversion temporary variables */
01412     this->m_conv_dst_format = phImageNOFORMAT;
01413     this->m_conv_dst        = NULL;
01414     this->m_conv_dstsize    = 0;
01415 
01416     return phSUCCESS;
01417 }
01418 
01419 /* ---------------------------------------------------------------------- */
01420 int phImage::resetConversion()
01421 {
01422     phFUNCTION("phImage::resetConversion")
01423 
01424     /* Conversion temporary variables */
01425     this->m_conv_dst_format = phImageNOFORMAT;
01426     this->m_conv_dstsize    = 0;
01427     phFree(this->m_conv_dst);
01428 
01429     return phSUCCESS;
01430 }
01431 
01432 /* ---------------------------------------------------------------------- */
01433 /* Supported conversions
01434  *  C       _________DESTINATION FORMAT_________
01435  *  U       |   |   |   |   |   |   |   |   |   |
01436  *  R F     |   |   | R | A |   |   |   |   |   |
01437  *  R O     | R | B | G | B | G |   |   |   |   |
01438  *  E R     | G | G | B | G | R | Y |   |   |   |
01439  *  N M     | B | R | A | R | E | U | H | S |   |
01440  *  T A     | 2 | 2 | 3 | 3 | Y | V | S | C |   |
01441  *    T     | 4 | 4 | 2 | 2 | 8 | 9 | V | T |   |
01442  *          |---|---|---|---|---|---|---|---|---|
01443  * RGB24    | / | X | X | X | X | X | X | X |   |
01444  * BGR24    | X | / | X | X | X | X | X | X |   |
01445  * RGBA32   | X | X | / | X | X | X | X |   |   |
01446  * ABGR32   | X | X | X | / | X | X | X |   |   |
01447  * GREY8    | X | X | X | X | / | X | C |   |   |
01448  * YUV9     | X | X | X | X | X | / | C |   |   |
01449  * HSV24    | X | X | C | X | C | C | / |   |   |
01450  * SCT24    | X | X |   |   |   |   |   |   |   |
01451  *          |   |   |   |   |   |   |   |   |   |
01452  *          -------------------------------------
01453  *          O = supported, but not coded in yet
01454  *          X = supported and coded into convert method
01455  *          C = easy to support, no code yet
01456  * ---------------------------------------------------------------------- */
01457 int phImage::convert( uint32_t to_format, uint32_t force_format )
01458 {
01459     phFUNCTION("phImage::convert")
01460     int         locked                  = 0;
01461     int         send_notify             = 0;
01462     uint32_t    special_format_flags    = 0;
01463     int         reenable_notify         = 0;
01464     int         jpeg_decompressed       = 0;
01465     int         zlib_decompressed       = 0;
01466     int32_t     conversion_type         = 0;
01467     /* Set the default to 1: ie the image hasn't converted */
01468     int         retrc                   = 1;
01469     
01470     if (to_format & phImageNOFORMAT) return 1;
01471     
01472     phTHIS_WRITELOCK(locked);
01473 
01474     /* Data could be updated multiple times so we want to 
01475      * disable multiple notifications to clients */
01476     if (this->isNotifyEnabled())
01477     {
01478         this->disableNotify();
01479         reenable_notify = 1;
01480     }
01481     /* TODO: Make sure JPEG is in RGB or GREYSCALE before converting */
01482     
01483     /* if the regular image format matches one in the to_format... */
01484     if (((this->m_format & phImageValidFormatMask) & to_format) && 
01485         (this->m_data != NULL))    
01486     {
01487         /* NOTE: We're here if the image data format is 
01488          * of a desired format already and we're just going
01489          * to check if the image data needs to be packaged or
01490          * unpackaged before returning */
01491      
01492         int jpeg_compress = 0;
01493         int zlib_compress = 0;
01494         
01495         /* JPEG COMPRESSION: check for this first, before Zlib */
01496         
01497         /* if this is compressed, and to_format
01498          * doesn't want compression, decompress it */
01499         if ((this->m_format & phImageJPEG) &&
01500             (!(to_format & phImageJPEG)))
01501         {
01502             /* decompress */
01503             jpeg_compress = -1;
01504 
01505             /* Conversion happened */
01506             retrc = phSUCCESS;
01507             send_notify = 1;
01508         }
01509         /* if this isn't compressed, and to_format 
01510          * wants compression, then compress it */
01511         else if ((!(this->m_format & phImageJPEG)) &&
01512                  (to_format & phImageJPEG))
01513         {
01514             jpeg_compress = 1;
01515 
01516             /* Conversion happened */
01517             retrc = phSUCCESS;
01518             send_notify = 1;
01519         }
01520         
01521         /* ZLIB COMPRESS: Zlib compress last, because it is data independent */
01522         
01523         /* if this is compressed, and to_format
01524          * doesn't want compression, decompress it */
01525         if ((this->m_format & phImageZlib) &&
01526             (!(to_format & phImageZlib)))
01527         {
01528             /* decompress */
01529             zlib_compress = -1;
01530             
01531             /* Conversion happened */
01532             retrc = phSUCCESS;
01533             send_notify = 1;
01534         }
01535         /* if this isn't compressed, and to_format 
01536          * wants compression, then compress it */
01537         else if ((!(this->m_format & phImageZlib)) &&
01538                  (to_format & phImageZlib))
01539         {
01540             /* compress */
01541             zlib_compress = 1;
01542 
01543             /* Conversion happened */
01544             retrc = phSUCCESS;
01545             send_notify = 1;
01546         }
01547 
01548         /* These are in a specific order to prevent an invalid
01549          * compress/decompress combination */
01550         if (zlib_compress == -1)
01551         {
01552             rc = this->decompress();
01553             phPRINT_RC(rc,NULL,"decompress");
01554         }
01555         if (jpeg_compress == -1)
01556         {
01557             /* jpeg will force a zlib decompress */
01558             rc = this->jpegDecompress();
01559             phPRINT_RC(rc,NULL,"jpegDecompress");
01560         }
01561         if (jpeg_compress == 1)
01562         {
01563             /* jpeg will force a zlib decompress */
01564             rc = this->jpegCompress();
01565             phPRINT_RC(rc,NULL,"jpegCompress");
01566         }
01567         if (zlib_compress == 1)
01568         {
01569             rc = this->compress();
01570             phPRINT_RC(rc,NULL,"compress");
01571         }
01572     }
01573     /* if the data isn't NULL and the image needs to be converted */
01574     else if (this->m_data != NULL)
01575     {
01576         /* Set the format default for error checking */
01577         this->m_conv_dst_format = phImageNOFORMAT;
01578         
01579         /* if a force_format value is valid, then
01580          * set the to_format to it */
01581         if (force_format != phImageNOFORMAT)
01582         {
01583             to_format = force_format;
01584         }
01585             
01586         /* filter out special flags */
01587         if (to_format & phImageSpecialMask)
01588         {
01589             special_format_flags |= to_format & phImageSpecialMask;
01590             to_format &= ~phImageSpecialMask;
01591         }
01592         
01593         /* decompress the image; 
01594          * These methods won't decompress if it isn't necessary */
01595         rc = this->decompress();
01596         phPRINT_RC(rc,NULL,"this->decompress()");
01597         if (rc == phSUCCESS) zlib_decompressed = 1;
01598         rc = this->jpegDecompress();
01599         phPRINT_RC(rc,NULL,"this->jpegDecompress()");
01600         if (rc == phSUCCESS) jpeg_decompressed = 1;
01601 
01602         /*
01603          *  int convert(uint32_t    width,
01604          *              uint32_t    height,
01605          *              uint8_t     *data,
01606          *              uint8_t     **dst,
01607          *              uint32_t    *dst_size,
01608          *              uint32_t    *dst_format,
01609          *              int32_t     in_format, 
01610          *              int32_t     out_format );
01611         */ 
01612         rc = ::ph_image_convert( this->m_width,
01613                                  this->m_height,
01614                                  (uint8_t*)this->m_data,
01615                                  &(this->m_conv_dst),
01616                                  &(this->m_conv_dstsize),
01617                                  &(this->m_conv_dst_format),
01618                                  this->m_format,
01619                                  to_format,
01620                                  &conversion_type );
01621         phCHECK_RC(rc,NULL,"::ph_image_convert failed [%s:%d to %s:%d].",
01622                   phImageFormatToString(this->m_format),
01623                   this->m_format,
01624                   phImageFormatToString(to_format),
01625                   to_format
01626                   );
01627         /* if a conversion happened... */
01628         if ((rc == phSUCCESS) && (conversion_type != phImageCONVERT_FAIL))
01629         {
01630             /* return to a higher level that the conversion happened */
01631             retrc = phSUCCESS;
01632             
01633             /* the data was altered in place, just change the format */
01634             if (conversion_type == phImageCONVERT_INPLACE)
01635             {
01636                 this->m_format = this->m_conv_dst_format;
01637             }
01638             /* if the data wasn't altered in place and we need to swap */
01639             else if ((this->m_conv_dst_format != phImageNOFORMAT) &&
01640                      (this->m_conv_dst != NULL) &&
01641                      (conversion_type == phImageCONVERT_COPY))
01642             {
01643                 uint32_t w = this->m_width;
01644                 uint32_t h = this->m_height;
01645                 
01646                 rc = this->swapData(&w, &h,
01647                         &(this->m_conv_dst_format),
01648                         &(this->m_conv_dst),
01649                         &(this->m_conv_dstsize));
01650                 phCHECK_RC(rc,NULL,"this->swapData failed.");
01651             }
01652 
01653             /* this fixes a bug where a notify wasn't sent in the "else"
01654              * clause of the above block */
01655             send_notify = 1;
01656         }
01657        
01658         /* Handle JPEG first */
01659         if (special_format_flags & phImageJPEG)
01660         {
01661             /* A conversion happened, return to the higher level */
01662             if (!jpeg_decompressed) retrc = phSUCCESS;
01663             
01664             /* compress will set the phImageJPEG compress flag bit */
01665             rc = this->jpegCompress();
01666             phPRINT_RC(rc,NULL,"jpegCompress()");
01667 
01668             send_notify = 1;
01669         }
01670         
01671         /* handle Zlib last */
01672         /* Won't compress if compression isn't available */
01673         if (special_format_flags & phImageZlib)
01674         {
01675             /* return to a higher level that a conversion happened */
01676             if (!zlib_decompressed) retrc = phSUCCESS;
01677             
01678             /* compress will set the phImageZlib compress flag bit */
01679             rc = this->compress();
01680             phPRINT_RC(rc,NULL,"compress()");
01681 
01682             send_notify = 1;
01683         }
01684         /* TODO: Add other if statements, i.e. PNG compression */
01685     }
01686     else if (this->m_data == NULL)
01687     {
01688         goto error;
01689     }
01690 
01691     /* If we should notify, then do it */
01692     /* first, re-enable notifications... */
01693     if (reenable_notify)
01694     {
01695         this->enableNotify();
01696         reenable_notify = 0;
01697     }    
01698 
01699     /* Then send the notification so we don't have to force it */
01700     if (send_notify)
01701     {
01702         rc = this->notify();
01703         phPRINT_RC(rc,NULL,"notify() failed.");
01704     }
01705     
01706     phTHIS_RWUNLOCK(locked);
01707 
01708     return retrc;
01709 error:
01710     if (reenable_notify)
01711     {
01712         this->enableNotify();
01713     }
01714     phTHIS_RWUNLOCK_ERROR(locked);
01715 
01716     return phFAIL;
01717 }
01718 
01719 /* ---------------------------------------------------------------------- */
01720 /* Simple ZLib compression support */
01721 /* ---------------------------------------------------------------------- */
01722 /* From the zlib documentation:
01723  * 
01724  * int compress (   Bytef *dest, 
01725  *                  uLongf *destLen, 
01726  *                  const Bytef *source, 
01727  *                  uLong sourceLen);
01728  *  Compresses the source buffer into the destination buffer. sourceLen is 
01729  *  the byte length of the source buffer. Upon entry, destLen is the total 
01730  *  size of the destination buffer, which must be at least 0.1% larger than 
01731  *  sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the 
01732  *  compressed buffer.
01733  *  
01734  *  This function can be used to compress a whole file at once if the input 
01735  *  file is mmap'ed.
01736  *  
01737  *  compress returns 
01738  *      Z_OK if success, 
01739  *      Z_MEM_ERROR if there was not enough memory, 
01740  *      Z_BUF_ERROR if there was not enough room in the output buffer.
01741  *      
01742  * int compress2 (  Bytef *dest, 
01743  *                  uLongf *destLen, 
01744  *                  const Bytef *source, 
01745  *                  uLong sourceLen, 
01746  *                  int level);
01747  *                  
01748  * Compresses the source buffer into the destination buffer. The level 
01749  * parameter has the same meaning as in deflateInit. sourceLen is the 
01750  * byte length of the source buffer. Upon entry, destLen is the total 
01751  * size of the destination buffer, which must be at least 0.1% larger 
01752  * than sourceLen plus 12 bytes. Upon exit, destLen is the actual size 
01753  * of the compressed buffer.
01754  * 
01755  * compress2 returns 
01756  *      Z_OK if success, 
01757  *      Z_MEM_ERROR if there was not enough memory, 
01758  *      Z_BUF_ERROR if there was not enough room in the output buffer, 
01759  *      Z_STREAM_ERROR if the level parameter is invalid.
01760  * ---------------------------------------------------------------------- */
01761 #if HAVE_LIBZ
01762 #include <zlib.h>
01763 
01764 /* ---------------------------------------------------------------------- */
01765 #define Z_CHECK_RC(rc,pmsg,fmt,...) \
01766 {\
01767     if (rc != Z_OK) {\
01768         phERROR_PRINT(pmsg,"*** ERROR (rc:%d)*** " fmt "\n",rc,## __VA_ARGS__); \
01769         goto error; \
01770     }\
01771 }
01772 #endif /* HAVE_LIBZ */
01773 
01774 /* ---------------------------------------------------------------------- */
01775 int phImage::initZlibCompression()
01776 {
01777     phFUNCTION("phImage::initZlibCompression")
01778 
01779     /* compression temporary variables */
01780     this->m_compressed              = 0;
01781     this->m_compress_level          = 2;
01782     this->m_compress_buffer         = NULL;
01783     this->m_compress_buffer_size    = 0;
01784     this->m_decompress_buffer       = NULL;
01785     this->m_decompress_buffer_size  = 0;
01786  
01787     return phSUCCESS;
01788 }
01789 
01790 /* ---------------------------------------------------------------------- */
01791 int phImage::resetZlibCompression()
01792 {
01793     phFUNCTION("phImage::resetZlibCompression")
01794 
01795     this->m_compressed = 0;
01796     
01797     phFree(this->m_compress_buffer);
01798     this->m_compress_buffer_size = 0;
01799     
01800     phFree(this->m_decompress_buffer);
01801     this->m_decompress_buffer_size = 0;
01802 
01803     return phSUCCESS;
01804 }
01805 
01806 /* ---------------------------------------------------------------------- */
01807 int phImage::compress(  )
01808 {
01809     phFUNCTION("phImage::compress")
01810 #if HAVE_LIBZ
01811     int locked = 0;
01812     int retrc  = phSUCCESS;
01813 
01814     phTHIS_WRITELOCK(locked);
01815 
01816     /* Make sure the data isn't already compressed */
01817     if (this->isZlibAvailable() && (this->m_compressed == 0))
01818     {
01819         double          d_zero_point_one_percent = 0.0;
01820         uint32_t        i_zero_point_one_percent = 0;
01821         uint32_t        new_compress_buffer_size = 0; 
01822 
01823         /* ----------------------------------------------------------
01824          * Step 1:
01825          *
01826          *  Calculate the size of the temporary compression buffer to be
01827          *  size + (size * 0.1%) + 12 bytes(at least)
01828          *
01829          */
01830         d_zero_point_one_percent = (((double)this->m_size) / ((double)1000.0));
01831         if (d_zero_point_one_percent < 1.0) 
01832         {
01833             d_zero_point_one_percent = 1.0;
01834         }
01835         
01836         i_zero_point_one_percent = (uint32_t)ceil(d_zero_point_one_percent);
01837         
01838         /* compressed buffer size will never be 0 */
01839         new_compress_buffer_size = 
01840             this->m_size + 
01841             i_zero_point_one_percent + 
01842             24;
01843         
01844         /* ----------------------------------------------------------
01845          * Step 2: Make sure there is appropriate buffer space 
01846          */
01847     
01848         /* Check to see if the compressed buffer exists; malloc
01849          * enough data for compression to.*/
01850         phDALLOC_SIZE(  this->m_compress_buffer,
01851                         this->m_compress_buffer_size,
01852                         new_compress_buffer_size,
01853                         void );
01854         /* ----------------------------------------------------------
01855          * Step 3: Compress the data into the compress buffer 
01856          */
01857         if (this->m_compress_level == -1)
01858         {
01859             /*
01860              * int ::compress( Bytef *dest, uLongf *destLen, 
01861              *                 const Bytef *source, uLong sourceLen);
01862              */
01863             DEBUG_PRINT("compress-in(%p,%p:%ld,%p,%ld)\n",
01864                         (Bytef *)this->m_compress_buffer, 
01865                         (uLongf *)&new_compress_buffer_size,
01866                         new_compress_buffer_size,
01867                         (const Bytef *)this->m_data,
01868                         (uLong )this->m_size       );
01869             
01870             rc = ::compress((Bytef *)this->m_compress_buffer, 
01871                     /* use the new_ var so the member buffer size var isn't
01872                      * altered */
01873                             (uLongf *)&new_compress_buffer_size,
01874                             (const Bytef *)this->m_data,
01875                             (uLong )this->m_size);
01876             Z_CHECK_RC(rc,NULL,"::compress failed");
01877             
01878             DEBUG_PRINT("compress-out(%p,%p:%ld,%p,%ld)\n",
01879                         (Bytef *)this->m_compress_buffer, 
01880                         (uLongf *)&new_compress_buffer_size,
01881                         new_compress_buffer_size,
01882                         (const Bytef *)this->m_data,
01883                         (uLong )this->m_size       );
01884         }
01885         else
01886         {
01887             /*
01888              * int ::compress( Bytef *dest, uLongf *destLen, 
01889              *                 const Bytef *source, uLong sourceLen);
01890              */
01891             DEBUG_PRINT("compress2-in(%p,%p:%ld,%p,%ld,%d)\n",
01892                         (Bytef *)this->m_compress_buffer, 
01893                         (uLongf *)&new_compress_buffer_size,
01894                         new_compress_buffer_size,
01895                         (const Bytef *)this->m_data,
01896                         (uLong )this->m_size,
01897                         this->m_compress_level);
01898             
01899             rc = ::compress2((Bytef *)this->m_compress_buffer, 
01900                     /* use the new_ var so the member buffer size var isn't
01901                      * altered */
01902                             (uLongf *)&new_compress_buffer_size,
01903                             (const Bytef *)this->m_data,
01904                             (uLong )this->m_size,
01905                             this->m_compress_level);
01906             Z_CHECK_RC(rc,NULL,"::compress2 failed");
01907             
01908             DEBUG_PRINT("compress2-out(%p,%p:%ld,%p,%ld,%d)\n",
01909                         (Bytef *)this->m_compress_buffer, 
01910                         (uLongf *)&new_compress_buffer_size,
01911                         new_compress_buffer_size,
01912                         (const Bytef *)this->m_data,
01913                         (uLong )this->m_size,
01914                         this->m_compress_level );
01915         }
01916         /* ----------------------------------------------------------
01917          * Step 4: Copy the compressed data into the data buffer 
01918          */
01919         /* Copy the compressed data into the this->m_data memory by way
01920          * of the phDataObject. */
01921 #if 0 /* TODO */
01922         rc = this->phDataObject::swapData(  &(new_compress_buffer_size),
01923                                             &(this->m_compress_buffer) );
01924         phCHECK_RC(rc,NULL,"phDataObject::swapData()");
01925 #else
01926         rc = this->phDataObject::setData(   new_compress_buffer_size,
01927                                             this->m_compress_buffer );
01928         phCHECK_RC(rc,NULL,"phDataObject::setData()");
01929 #endif
01930    
01931         this->m_compressed = 1;
01932         this->m_format |= phImageZlib;
01933     } 
01934     else
01935     {
01936         /* no conversion */
01937         retrc = 1;
01938     }
01939 
01940     phTHIS_RWUNLOCK(locked);
01941     
01942     return retrc;
01943 error:
01944     this->m_compressed = 0;
01945 
01946     phTHIS_RWUNLOCK_ERROR(locked);
01947     
01948     return phFAIL;
01949 #else
01950     /* Return success to keep code running; 
01951      * Zlib's unavailability is a non-fatal error */
01952     return 1;
01953 #endif /* HAVE_LIBZ */    
01954 }
01955 
01956 /* ---------------------------------------------------------------------- */
01957 /* From the zlib documentation:
01958  * 
01959  * int uncompress ( Bytef *dest, 
01960  *                  uLongf *destLen, 
01961  *                  const Bytef *source, 
01962  *                  uLong sourceLen);
01963  *                  
01964  * Decompresses the source buffer into the destination buffer. sourceLen 
01965  * is the byte length of the source buffer. Upon entry, destLen is the 
01966  * total size of the destination buffer, which must be large enough to 
01967  * hold the entire uncompressed data. (The size of the uncompressed data 
01968  * must have been saved previously by the compressor and transmitted to 
01969  * the decompressor by some mechanism outside the scope of this 
01970  * compression library.) Upon exit, destLen is the actual size of the 
01971  * compressed buffer.
01972  * 
01973  * This function can be used to decompress a whole file at once if the 
01974  * input file is mmap'ed.
01975  * 
01976  * uncompress returns 
01977  *      Z_OK if success, 
01978  *      Z_MEM_ERROR if there was not enough memory, 
01979  *      Z_BUF_ERROR if there was not enough room in the output buffer, or 
01980  *      Z_DATA_ERROR if the input data was corrupted. 
01981 */
01982 
01983 /* ---------------------------------------------------------------------- */
01984 int phImage::decompress(  )
01985 {
01986     phFUNCTION("phImage::decompress")
01987 #if HAVE_LIBZ
01988     int locked  = 0;
01989     int retrc   = phSUCCESS;
01990 
01991     phTHIS_WRITELOCK(locked);
01992     
01993     /* int uncompress ( Bytef *dest, 
01994      *                  uLongf *destLen, 
01995      *                  const Bytef *source, 
01996      *                  uLong sourceLen);
01997      */
01998 
01999     /* Check to see if compression is available */
02000     /* and check to see if we need to decompress */
02001     /* Only decompress if the data is compressed, otherwise,
02002      * just return with success since the data is already decompressed */
02003     if (this->isZlibAvailable() && (this->m_compressed == 1))
02004     {
02005         /* The phImageZlib bit won't interfere with the format size
02006          * calculation */
02007         uint32_t new_decompress_buffer_size = 
02008                     this->calculateSize(this->m_width,
02009                                         this->m_height,
02010                                         this->m_format);
02011 
02012         /* Check the size of the decompress buffer for room to 
02013          * decompress */
02014         /* Checks to see if the decompress buffer exists; malloc
02015          * enough data for compression to.*/
02016         phDALLOC_SIZE(this->m_decompress_buffer,
02017                       this->m_decompress_buffer_size,
02018                       new_decompress_buffer_size,
02019                       void);
02020                       
02021         /* int uncompress ( Bytef *dest, uLongf *destLen, 
02022          *                  const Bytef *source, uLong sourceLen); */
02023         /* decompress the image */
02024         DEBUG_PRINT("decompress(%p,%p:%ld,%p,%ld)\n",
02025                 (Bytef *)this->m_decompress_buffer,                            
02026                 (uLongf *)&new_decompress_buffer_size,
02027                 new_decompress_buffer_size,
02028                 (const Bytef *)this->m_data,
02029                 (uLong)this->m_size);
02030         rc = ::uncompress((Bytef *)this->m_decompress_buffer,                            
02031                           (uLongf *)&new_decompress_buffer_size,
02032                           (const Bytef *)this->m_data,
02033                           (uLong)this->m_size);
02034                     this->m_compressed = 0;
02035         Z_CHECK_RC(rc,NULL,"::uncompress");
02036         DEBUG_PRINT("decompress(%p,%p:%ld,%p,%ld)\n",
02037                 (Bytef *)this->m_decompress_buffer,                            
02038                 (uLongf *)&new_decompress_buffer_size,
02039                 new_decompress_buffer_size,
02040                 (const Bytef *)this->m_data,
02041                 (uLong)this->m_size);
02042 
02043         /* ----------------------------------------------------------
02044          * Step 4: Copy the decompressed data into the data buffer 
02045          */
02046         /* Copy the decompressed data into the this->m_data memory by way
02047          * of the phDataObject. */
02048 #if 0 /* TODO */
02049         rc = this->phDataObject::swapData(  &(new_decompress_buffer_size),
02050                                             &(this->m_decompress_buffer) );
02051         phCHECK_RC(rc,NULL,"phDataObject::swapData()");
02052 #else
02053         rc = this->phDataObject::setData(   new_decompress_buffer_size,
02054                                             this->m_decompress_buffer );
02055         phCHECK_RC(rc,NULL,"phDataObject::setData()");
02056 #endif
02057         /* Set the compressed variable and remove the Zlib flag from the format */
02058         this->m_compressed = 0;
02059         this->m_format &= ~phImageZlib;
02060     }
02061     else
02062     {
02063         /* no conversion */
02064         retrc = 1;
02065     }
02066     
02067     phTHIS_RWUNLOCK(locked);
02068     
02069     return retrc;
02070 error:
02071     phTHIS_RWUNLOCK_ERROR(locked);
02072     return phFAIL;
02073 #else
02074     /* Return success to keep code running; 
02075      * Zlib's unavailability is a non-fatal error */
02076     return 1; /* no conversion */
02077 #endif /* HAVE_LIBZ */
02078 }
02079 
02080 /* ---------------------------------------------------------------------- */
02081 int phImage::isCompressed(  )
02082 {
02083     phFUNCTION("phImage::isCompressed")
02084     int retrc   = 0;
02085     int locked  = 0;
02086 
02087     phTHIS_READLOCK(locked);
02088     
02089     retrc = this->m_compressed;
02090 
02091     phTHIS_RWUNLOCK(locked);
02092     
02093     return retrc;
02094 error:
02095     return 0;
02096 }
02097 
02098 /* ---------------------------------------------------------------------- */
02099 int phImage::setCompressionLevel( int level )
02100 {
02101     phFUNCTION("phImage::setCompressionLevel")
02102     int locked = 0;
02103 
02104     phTHIS_WRITELOCK(locked);
02105 
02106     this->m_compress_level = (((level > 0) && (level < 10)) ? level : -1 );
02107 
02108     phTHIS_RWUNLOCK(locked);
02109     
02110 error:
02111     return phSUCCESS;
02112 }
02113 
02114 /* ---------------------------------------------------------------------- */
02115 int phImage::isZlibAvailable(  )
02116 {
02117 #if HAVE_LIBZ
02118     return 1;
02119 #else
02120     return 0;
02121 #endif /* HAVE_LIBZ */
02122 }
02123 
02124 
02125 /* ---------------------------------------------------------------------- */
02126 #if HAVE_LIBJPEG
02127 #include <ImageJPEG.h>
02128 #endif
02129 
02130 /* ---------------------------------------------------------------------- */
02131 int phImage::initJPEGCompression()
02132 {
02133     phFUNCTION("phImage::initJPEGCompression")
02134 
02135     this->m_jpegCompressed              = 0;
02136     this->m_jpegQuality                 = 80; /* TODO */
02137     this->m_jpegCompress_handle         = NULL;
02138     this->m_jpegCompress_buffer         = NULL;
02139     this->m_jpegCompress_buffer_size    = 0;
02140     this->m_jpegDecompress_handle       = NULL;
02141     this->m_jpegDecompress_buffer       = NULL;
02142     this->m_jpegDecompress_buffer_size  = 0;
02143 
02144     return phSUCCESS;
02145 }
02146 
02147 /* ---------------------------------------------------------------------- */
02148 int phImage::resetJPEGCompression()
02149 {
02150     phFUNCTION("phImage::resetJPEGCompression")
02151 
02152     this->m_jpegCompressed              = 0;
02153     this->m_jpegQuality                 = 80; /* TODO */
02154     
02155     if (this->m_jpegCompress_handle != NULL)
02156     {
02157 #if HAVE_LIBJPEG
02158         ph_jpeg_free_compress(&this->m_jpegCompress_handle);
02159 #endif
02160         this->m_jpegCompress_handle         = NULL;
02161     }
02162     
02163     if (this->m_jpegDecompress_handle != NULL)
02164     {
02165 #if HAVE_LIBJPEG
02166         ph_jpeg_free_decompress(&this->m_jpegDecompress_handle);
02167 #endif
02168         this->m_jpegDecompress_handle       = NULL;
02169     }
02170     
02171     phFree(this->m_jpegCompress_buffer);
02172     this->m_jpegCompress_buffer_size    = 0;
02173     
02174     
02175     phFree(this->m_jpegDecompress_buffer);
02176     this->m_jpegDecompress_buffer_size  = 0;
02177 
02178     return phSUCCESS;
02179 }
02180 
02181 /* ---------------------------------------------------------------------- */
02182 int phImage::isJPEGCompressed(  )
02183 {
02184     phFUNCTION("phImage::isJPEGCompressed")
02185     int retrc   = 0;
02186     int locked  = 0;
02187 
02188     phTHIS_READLOCK(locked);
02189     
02190     retrc = this->m_jpegCompressed;
02191 
02192     phTHIS_RWUNLOCK(locked);
02193     
02194     return retrc;
02195 error:
02196     return 0;
02197 }
02198 
02199 /* ---------------------------------------------------------------------- */
02200 int phImage::jpegCompress(  )
02201 {
02202     phFUNCTION("phImage::jpegCompress")
02203 #if HAVE_LIBJPEG
02204     int locked  = 0;
02205     int retrc   = phSUCCESS;
02206 
02207     phTHIS_WRITELOCK(locked);
02208 
02209     /* Make sure the data isn't already compressed */
02210     if (this->isJPEGAvailable() && (this->m_jpegCompressed == 0) &&
02211         (this->m_jpegQuality > 0))
02212     {
02213         /* Make sure the image isn't compressed by Zlib */
02214         rc = this->decompress();
02215         phPRINT_RC(rc,NULL,"this->decompress()");                
02216         
02217         if (this->m_jpegCompress_handle == NULL)
02218         {
02219             rc = ph_jpeg_new_compress(&this->m_jpegCompress_handle);
02220         }
02221         
02222         /*
02223          int ph_jpeg_compress( ph_cinfo_handle   compress_info,
02224                                 uint8_t           *src,
02225                                 uint32_t          srcsize,
02226                                 uint32_t          width,
02227                                 uint32_t          height,
02228                                 uint32_t          format,
02229                                 uint8_t           **pdst,
02230                                 uint32_t          *pdstsize );
02231          */
02232         rc = ::ph_jpeg_compress(
02233                 this->m_jpegCompress_handle,
02234                 (uint8_t *)this->m_data,
02235                 this->m_size,
02236                 this->m_width, 
02237                 this->m_height, 
02238                 this->m_format,
02239                 this->m_jpegQuality,
02240                 (uint8_t **)&(this->m_jpegCompress_buffer),
02241                 &(this->m_jpegCompress_buffer_size) );
02242         phPRINT_RC(rc,NULL,"ph_jpeg_compress");
02243         
02244         /* ----------------------------------------------------------
02245          * Copy the compressed data into the data buffer 
02246          * ------------------------------------------------------- */
02247         /* Copy the compressed data into the this->m_data memory by way
02248          * of the phDataObject. */
02249 #if 0 /* TODO */
02250         rc = this->phDataObject::swapData(  &(this->m_jpegDecompress_buffer_size),
02251                                             &(this->m_jpegDecompress_buffer) );
02252         phCHECK_RC(rc,NULL,"phDataObject::swapData()");
02253 #else
02254         DEBUG_PRINT("%d:%p\n",
02255                 this->m_jpegCompress_buffer_size,
02256                 this->m_jpegCompress_buffer );
02257         rc = this->phDataObject::setData(   this->m_jpegCompress_buffer_size,
02258                                             this->m_jpegCompress_buffer );
02259         phCHECK_RC(rc,NULL,"phDataObject::setData()");
02260 #endif
02261    
02262         this->m_jpegCompressed = 1;
02263         this->m_format |= phImageJPEG;
02264     } 
02265     else
02266     {
02267         /* no conversion */
02268         retrc = 1;
02269     }
02270 
02271     phTHIS_RWUNLOCK(locked);
02272     
02273     return retrc;
02274 error:
02275     this->m_jpegCompressed = 0;
02276 
02277     phTHIS_RWUNLOCK_ERROR(locked);
02278     
02279     return phFAIL;
02280 #else /* HAVE_LIBJPEG */    
02281     /* Return success to keep code running; 
02282      * JPEG's unavailability is a non-fatal error */
02283     return 1; /* no conversion */
02284 #endif /* HAVE_LIBJPEG */    
02285 }
02286 
02287 /* ---------------------------------------------------------------------- */
02288 int phImage::jpegDecompress(  )
02289 {
02290     phFUNCTION("phImage::jpegDecompress")
02291 #if HAVE_LIBJPEG
02292     int locked = 0;
02293     uint32_t w = 0;
02294     uint32_t h = 0;
02295     int32_t  f = 0;
02296     int      retrc = phSUCCESS;
02297 
02298     phTHIS_WRITELOCK(locked);
02299     
02300     /* Check to see if JPEG compression is available */
02301     /* and check to see if we need to decompress the JPEG data */
02302     /* Only decompress if the data is compressed, otherwise,
02303      * just return with success since the data is already decompressed */
02304     if (this->isJPEGAvailable() && (this->m_jpegCompressed == 1))
02305     {
02306         /* The phImageJPEG bit won't interfere with the format size
02307          * calculation */
02308         uint32_t new_decompress_buffer_size = 
02309                     this->calculateSize(this->m_width,
02310                                         this->m_height,
02311                                         this->m_format);
02312 
02313         /* Make sure the image isn't compressed by Zlib */
02314         rc = this->decompress();
02315         phPRINT_RC(rc,NULL,"this->decompress()");                
02316         
02317         if (this->m_jpegDecompress_handle == NULL)
02318         {
02319             rc = ph_jpeg_new_decompress(&this->m_jpegDecompress_handle);
02320         }
02321         
02322         /* Check the size of the decompress buffer for room to 
02323          * decompress */
02324         /* Checks to see if the decompress buffer exists; malloc
02325          * enough data for compression to.*/
02326         /* The ph_jpeg_ code will also change the size of the 
02327          * buffer if it is required, but let's try to prevent 
02328          * that necessity */
02329         phDALLOC_SIZE(this->m_jpegDecompress_buffer,
02330                       this->m_jpegDecompress_buffer_size,
02331                       new_decompress_buffer_size,
02332                       void);
02333 
02334         /*
02335          int ph_jpeg_decompress( ph_cinfo_handle decompress_info,
02336                                  uint8_t         *src,
02337                                  uint32_t        srcsize,
02338                                  uint8_t         **pdst,
02339                                  uint32_t        *pdstsize,
02340                                  uint32_t        *pwidth,
02341                                  uint32_t        *pheight,
02342                                  uint32_t        *pformat );
02343          */
02344         w = this->m_width;
02345         h = this->m_height;
02346         f = this->m_format;
02347         
02348         rc = ::ph_jpeg_decompress(
02349                 this->m_jpegDecompress_handle,
02350                 (uint8_t *)this->m_data,
02351                 this->m_size,
02352                 (uint8_t **)&(this->m_jpegDecompress_buffer),
02353                 &(this->m_jpegDecompress_buffer_size),
02354                 &(w), 
02355                 &(h), 
02356                 &(f)
02357                 );
02358         phPRINT_RC(rc,NULL,"ph_jpeg_decompress");
02359 
02360         this->m_width = w;
02361         this->m_height = h;
02362         
02363         /* ----------------------------------------------------------
02364          * Copy the decompressed data into the data buffer 
02365          * ------------------------------------------------------- */
02366         /* Copy the decompressed data into the this->m_data memory by way
02367          * of the phDataObject. */
02368 #if 0 /* TODO */
02369         rc = this->phDataObject::swapData(  &(this->m_jpegDecompress_buffer_size),
02370                                             &(this->m_jpegDecompress_buffer) );
02371         phCHECK_RC(rc,NULL,"phDataObject::swapData()");
02372 #else
02373         rc = this->phDataObject::setData(   this->m_jpegDecompress_buffer_size,
02374                                             this->m_jpegDecompress_buffer );
02375         phCHECK_RC(rc,NULL,"phDataObject::setData()");
02376 #endif
02377 
02378 
02379         /* Set the compressed variable and remove the JPEG flag from the format */
02380         this->m_jpegCompressed = 0;
02381         this->m_format &= ~phImageJPEG;
02382     }
02383     else
02384     {
02385         /* return to a higher level that the decompression didn't happen */
02386         retrc = 1;
02387     }
02388     
02389     phTHIS_RWUNLOCK(locked);
02390     
02391     return retrc;
02392 error:
02393     phTHIS_RWUNLOCK_ERROR(locked);
02394     
02395     return phFAIL;
02396 #else /* HAVE_LIBJPEG */    
02397 
02398     /* Return success to keep code running; 
02399      * JPEG's unavailability is a non-fatal error */
02400     return 1;
02401 #endif /* HAVE_LIBJPEG */
02402 }
02403 /* ---------------------------------------------------------------------- */
02404 int phImage::setJPEGQuality( int q )
02405 {
02406     phFUNCTION("phImage::setJPEGQuality")
02407     int locked = 0;
02408 
02409     phTHIS_WRITELOCK(locked);
02410 
02411     this->m_jpegQuality = (((q > 0) && (q <= 100)) ? q : 80 );
02412 
02413     phTHIS_RWUNLOCK(locked);
02414     
02415 error:
02416     return phSUCCESS;
02417 }
02418 
02419 /* ---------------------------------------------------------------------- */
02420 int phImage::getJPEGQuality( )
02421 {
02422     phFUNCTION("phImage::setJPEGQuality")
02423     int locked  = 0;
02424     int q       = 0;
02425 
02426     phTHIS_READLOCK(locked);
02427 
02428     q = this->m_jpegQuality;
02429 
02430     phTHIS_RWUNLOCK(locked);
02431     
02432 error:
02433     return q;
02434 }
02435 
02436 /* ---------------------------------------------------------------------- */
02437 int phImage::isJPEGAvailable(  )
02438 {
02439 #if HAVE_LIBJPEG
02440     return 1;
02441 #else
02442     return 0;
02443 #endif /* HAVE_LIBJPEG */
02444 }
02445 
02446 /* ---------------------------------------------------------------------- */
02447 int phImage::saveJPEG( char *filename )
02448 {
02449     phFUNCTION("phImage::saveJPEG")
02450 #if HAVE_LIBJPEG && HAVE_FOPEN
02451     int         locked      = 0;
02452     uint8_t     *imgdata    = NULL;
02453     int         imgsize     = 0;
02454     uint8_t     *ptr        = NULL;
02455     int         data_left   = 0;
02456     FILE        *fp         = NULL;
02457     
02458     phTHIS_READLOCK(locked);
02459 
02460     if (!(this->m_format & phImageJPEG))
02461     {
02462         /* This will lessen the overhead of saving an image often.
02463          * The whole inherited class line won't need to be constructed
02464          * again everytime this function is called.
02465          * The first time the image is saved for "this", the buffer will
02466          * be allocated and used for every successive save call. */
02467         if (this->m_saveImageBuf == NULL)
02468         {
02469             this->m_saveImageBuf = new phImage();
02470         }
02471         this->m_saveImageBuf->setJPEGQuality(m_jpegQuality);
02472         this->m_saveImageBuf->setImage(this->m_width,
02473                                         this->m_height,
02474                                         this->m_format,
02475                                         this->m_size,
02476                                         (uint8_t *)this->m_data);
02477         rc = this->m_saveImageBuf->convert(phImageRGB24|phImageJPEG);
02478         phCHECK_RC(rc,NULL,"converting of image failed.");
02479         
02480         imgdata = (uint8_t *)this->m_saveImageBuf->getData(); 
02481         imgsize = (int)this->m_saveImageBuf->getSize();
02482     }
02483     else
02484     {
02485         imgdata = (uint8_t *)this->m_data;
02486         imgsize = (int)this->m_size;
02487     }
02488     
02489     phCHECK_NULLPTR(this->m_data,NULL,"data == NULL");
02490     
02491     /* open the output file */
02492     fp = fopen(filename, "wb");
02493     phCHECK_PTR(fp,"fopen","fopen(%s,\"wb\")",filename);
02494 
02495     rc = ph_file_lock(fp);
02496     phPRINT_RC(rc,"ph_file_lock","ph_file_lock(%p)",fp);
02497 
02498     /* write the image data */
02499     data_left   = imgsize;
02500     ptr         = imgdata;
02501 
02502     do 
02503     {
02504         rc = fwrite(ptr, 1, data_left, fp);
02505         if (rc <= 0)
02506         {
02507            phCHECK_RC(-1,"fwrite","bytes written %d != buffer bytes %d",
02508                       rc,data_left);
02509         }
02510 
02511         data_left   -= rc;
02512         ptr         += rc;
02513     } 
02514     while ((data_left > 0) && (rc > 0));
02515 
02516     fflush(fp);
02517 
02518     rc = ph_file_unlock(fp);
02519     phPRINT_RC(rc,"ph_file_unlock","ph_file_unlock(%p)",fp);
02520 
02521     fclose(fp);
02522     fp = NULL;
02523 
02524     phTHIS_RWUNLOCK(locked);
02525 
02526     return phSUCCESS;
02527 
02528 error:
02529     if (fp != NULL)
02530     {
02531         fclose(fp);
02532     }
02533     
02534     phTHIS_RWUNLOCK_ERROR(locked);
02535 #endif /* HAVE_LIBJPEG */
02536     return phFAIL;
02537 }
02538 /* ---------------------------------------------------------------------- */
02539 int phImage::loadJPEG( char *filename ) 
02540 {
02541     phFUNCTION("phImage::saveJPEG")
02542 #if HAVE_LIBJPEG && HAVE_FOPEN
02543     int         locked      = 0;
02544     uint8_t    *imgdata     = NULL;
02545     int         imgsize     = 0;
02546     uint8_t    *readptr     = NULL;
02547     int         data_left   = 0;
02548     uint32_t    pwidth      = NULL;
02549     uint32_t    pheight     = NULL;
02550 
02551     FILE            *fp         = NULL;
02552     struct stat     stat_buf;
02553     void            *decompress_handle = NULL;
02554      
02555     phTHIS_WRITELOCK(locked);
02556 
02557     /* open the output file */
02558     fp = fopen(filename, "rb");
02559     phCHECK_PTR(fp,"fopen","fopen(%s,\"rb\")",filename);
02560 
02561     rc = ph_file_lock(fp);
02562     phPRINT_RC(rc,"ph_file_lock","ph_file_lock(%p)",fp);
02563 
02564     /* Get the file size info */
02565     /* int fstat(int filedes, struct stat *buf); */
02566     rc = fstat( fileno( fp ), &stat_buf );
02567     phCHECK_RC(rc,"fstat","fstat failed");
02568 
02569     /* Check to make sure the size is good */
02570     imgsize = (uint32_t)stat_buf.st_size;
02571     if (stat_buf.st_size <= 0) 
02572     {
02573         phCHECK_RC(-1,NULL,"stat_buf.st_size <= 0 : %d",(int32_t)stat_buf.st_size);
02574     }
02575 #if 0
02576     fseek(fp,0,SEEK_END);
02577     imgsize = ftell(fp);
02578     rewind(fp);
02579 #endif
02580     /* Allocate the buffer */
02581     imgdata = (uint8_t *)phCalloc(imgsize,sizeof(uint8_t));
02582     phCHECK_PTR(imgdata,"phCalloc","phCalloc failed to alloc buffer");
02583 
02584     /* Read in the info */
02585     data_left   = imgsize;
02586     readptr     = imgdata;
02587 
02588     do
02589     {
02590         rc = fread(readptr,1,data_left,fp);
02591         if (rc <= 0)
02592         {
02593             phCHECK_RC(-1,"fread","bytes written %d != buffer bytes %d",
02594                        rc,data_left);
02595         }
02596         data_left   -= rc;
02597         readptr     += rc;
02598     }
02599     while ((data_left > 0) && (rc > 0));
02600 
02601     /* Set up the decompressor and load the JPEG dimensions */
02602     rc = ph_jpeg_new_decompress(&decompress_handle); /* TODO */
02603     phCHECK_RC(rc,NULL,"ph_jpeg_new_decompress failed");
02604     
02605     /* Set the width, height, depth, format parameters */
02606     rc = ::ph_jpeg_decompress( decompress_handle,
02607                                imgdata,
02608                                imgsize,
02609                                NULL,
02610                                NULL,
02611                                &pwidth, 
02612                                &pheight, 
02613                                NULL
02614                              );
02615     phPRINT_RC(rc,NULL,"ph_jpeg_decompress");
02616 
02617     this->m_width   = pwidth;
02618     this->m_height  = pheight;
02619     this->m_format  = phImageRGB24 | phImageJPEG; 
02620         
02621     /* ----------------------------------------------------------
02622      * Copy the JPEG data into the data buffer 
02623      * ------------------------------------------------------- */
02624     rc = this->phDataObject::setData(imgsize, imgdata );
02625     phCHECK_RC(rc,NULL,"phDataObject::setData()");
02626 
02627     /* Set the compressed variable and the JPEG flag in the format */
02628     this->m_jpegCompressed = 1;
02629 
02630     /* Unlock the file */
02631     rc = ph_file_unlock(fp);
02632     phPRINT_RC(rc,"ph_file_unlock","ph_file_unlock(%p)",fp);
02633 
02634     /* Close the file */
02635     fclose(fp);
02636     fp = NULL;
02637 
02638     phTHIS_RWUNLOCK(locked);
02639 
02640     /* Free the buffer */
02641     phFree(imgdata);
02642     
02643     if (decompress_handle != NULL)
02644     {
02645         rc = ph_jpeg_free_decompress( &decompress_handle );
02646         decompress_handle = NULL;
02647         phCHECK_RC(rc,NULL,"ph_jpeg_free_decompress failed.");
02648     }
02649     
02650     return phSUCCESS;
02651 
02652 error:
02653     phFree(imgdata);
02654     
02655     if (fp != NULL)
02656     {
02657         fclose(fp);
02658     }
02659     
02660     if (decompress_handle != NULL)
02661     {
02662         rc = ph_jpeg_free_decompress( &decompress_handle );
02663         decompress_handle = NULL;
02664         phPRINT_RC(rc,NULL,"ph_jpeg_free_decompress failed.");
02665     }
02666 
02667     phTHIS_RWUNLOCK_ERROR(locked);
02668 #endif /* HAVE_LIBJPEG */
02669     return phFAIL;
02670 }
02671 




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:02 2007 for phission by  doxygen 1.4.4