Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PNGGenerator.cc

Go to the documentation of this file.
00001 #include "PNGGenerator.h"
00002 #include "InterleavedYUVGenerator.h"
00003 #include "Events/DataEvent.h"
00004 #include "Events/EventRouter.h"
00005 #include "Events/FilterBankEvent.h"
00006 #include "Shared/Profiler.h"
00007 #include "Wireless/Socket.h"
00008 
00009 //better to put this here instead of the header
00010 using namespace std; 
00011 
00012 extern "C" {
00013   //! stores progress of user_write_png_data() between calls
00014   struct png_write_mem_status {
00015     png_bytep buf;  //!< beginning of buffer being writen into (doesn't move with progress)
00016     size_t bufsize; //!< total size of buffer
00017     size_t offset;  //!< position within buffer, i.e. amount of buffer written so far
00018   };
00019   //! user callback function for writing a png at @a data into user parameters stored in @a png_ptr
00020   void user_write_png_data(png_structp png_ptr, png_bytep data, png_size_t length) {
00021     png_write_mem_status* status=(png_write_mem_status*)(png_get_io_ptr(png_ptr));
00022     size_t endoff=status->offset+length;
00023     if(endoff<=status->bufsize) {
00024       memcpy(status->buf+status->offset,data,length);
00025       status->offset=endoff;
00026     } else {
00027       png_error(png_ptr, "Write Error - ran out of file");
00028     }
00029   }
00030   //! user callback function for flushing results of user_write_png_data() (this is a no-op)
00031   void user_flush_png_data(png_structp /*png_ptr*/) {}
00032 }
00033 
00034 
00035 PNGGenerator::PNGGenerator(unsigned int mysid, FilterBankGenerator* fbg, EventBase::EventTypeID_t tid)
00036 : FilterBankGenerator("PNGGenerator","PNGGenerator",EventBase::visPNGEGID,mysid,fbg,tid), srcMode(SRC_AUTO), curMode(SRC_AUTO), bytesUsed(NULL)
00037 {
00038   if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00039     curMode=SRC_COLOR;
00040   else
00041     curMode=SRC_GRAYSCALE;
00042   
00043   //this part is only necessary if you override setNumImages yourself
00044   if(fbg!=NULL) {
00045     numLayers=numChannels=0; //this is to force setNumImages to override settings provided by FilterBankGenerator
00046     setNumImages(fbg->getNumLayers(),fbg->getNumChannels());
00047   }
00048 }
00049 
00050 PNGGenerator::PNGGenerator(unsigned int mysid, src_mode_t mode, FilterBankGenerator* fbg, EventBase::EventTypeID_t tid)
00051 : FilterBankGenerator("PNGGenerator","PNGGenerator",EventBase::visPNGEGID,mysid,fbg,tid), srcMode(mode), curMode(mode), bytesUsed(NULL)
00052 {
00053   if(srcMode==SRC_AUTO) {
00054     if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00055       curMode=SRC_COLOR;
00056     else
00057       curMode=SRC_GRAYSCALE;
00058   }
00059   
00060   //this part is only necessary if you override setNumImages yourself
00061   if(fbg!=NULL) {
00062     numLayers=numChannels=0; //this is to force setNumImages to override settings provided by FilterBankGenerator
00063     setNumImages(fbg->getNumLayers(),fbg->getNumChannels());
00064   }
00065 }
00066 
00067 PNGGenerator::~PNGGenerator() {
00068   freeCaches();
00069   destruct();
00070 }
00071 
00072 
00073 /*! The const casts in this function are regretable but necessary
00074 *  since the corresponding OPEN-R functions require mutable
00075 *  arguments, even though they shouldn't be modifying the data
00076 */
00077 void
00078 PNGGenerator::processEvent(const EventBase& event) {
00079   FilterBankGenerator::processEvent(event);
00080   if(event.getGeneratorID()==getListenGeneratorID() && event.getSourceID()==getListenSourceID()) {
00081     if(getSourceMode()==SRC_AUTO) { //if not auto, curMode was already set when srcMode was set
00082       if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00083         curMode=SRC_COLOR;
00084       else
00085         curMode=SRC_GRAYSCALE;
00086     }
00087     FilterBankEvent fbkev(this,getGeneratorID(),getSourceID(),EventBase::activateETID);
00088     erouter->postEvent(fbkev);
00089     fbkev.setTypeID(EventBase::statusETID);
00090     erouter->postEvent(fbkev);
00091     fbkev.setTypeID(EventBase::deactivateETID);
00092     erouter->postEvent(fbkev);
00093   }
00094 }
00095 
00096 unsigned int
00097 PNGGenerator::getBinSize() const {
00098   unsigned int used=FilterBankGenerator::getBinSize();
00099   char * type;
00100   if(getCurrentSourceFormat()==SRC_COLOR)
00101     type="PNGColor";
00102   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00103     type="PNGGrayscale";
00104   else {
00105     serr->printf("getBinSize failed - unsuitable or unknown mode/generator pair");
00106     return 0;
00107   }
00108   used+=strlen(type)+LoadSave::stringpad;
00109   if(bytesUsed[selectedSaveLayer][selectedSaveChannel]!=0)
00110     used+=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00111   else
00112     used+=widths[selectedSaveLayer]*heights[selectedSaveLayer]*3+PNG_HEADER_PAD;
00113   return used;
00114 }
00115 
00116 unsigned int
00117 PNGGenerator::loadBuffer(const char buf[], unsigned int len) {
00118   unsigned int origlen=len;
00119   if(!FilterBankGenerator::loadBuffer(buf,len)) return 0;
00120   std::string tmp;
00121   if(!decodeInc(tmp,buf,len)) return 0;
00122   if(tmp!="PNGColor" && tmp!="PNGGrayscale") {
00123     serr->printf("Unhandled image type for PNGGenerator: %s",tmp.c_str());
00124     return 0;
00125   } else {
00126     if(tmp=="PNGColor" && getCurrentSourceFormat()==SRC_GRAYSCALE)
00127       serr->printf("Warning: loading grayscale into color image");
00128     if(tmp=="PNGGrayscale" && getCurrentSourceFormat()==SRC_COLOR)
00129       serr->printf("Warning: loading color into grayscale image");
00130     unsigned int tmpL;
00131     if(!decodeInc(tmpL,buf,len)) return 0;
00132     if(tmpL>len)
00133       return 0;
00134     if(images[selectedSaveLayer][selectedSaveChannel]!=NULL)
00135       delete [] images[selectedSaveLayer][selectedSaveChannel];
00136     images[selectedSaveLayer][selectedSaveChannel]=createImageCache(selectedSaveLayer,selectedSaveChannel);
00137     unsigned int used=bytesUsed[selectedSaveLayer][selectedSaveChannel]=tmpL;
00138     unsigned char* img=getImage(selectedSaveLayer,selectedSaveChannel);
00139     if(img==NULL)
00140       return 0;
00141     memcpy(img,buf,used);
00142     len-=used; buf+=used;
00143     imageValids[selectedSaveLayer][selectedSaveChannel]=true;
00144     return origlen-len; 
00145   }
00146 }
00147 
00148 unsigned int
00149 PNGGenerator::saveBuffer(char buf[], unsigned int len) const {
00150   unsigned int origlen=len;
00151   if(!checkInc(FilterBankGenerator::saveBuffer(buf,len),buf,len)) return 0;
00152   
00153   char * type;
00154   if(getCurrentSourceFormat()==SRC_COLOR)
00155     type="PNGColor";
00156   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00157     type="PNGGrayscale";
00158   else {
00159     serr->printf("saveBuffer failed - unsuitable or unknown mode/generator pair");
00160     return 0;
00161   }
00162   if(!encodeInc(type,buf,len)) return 0;
00163   
00164   if(images[selectedSaveLayer][selectedSaveChannel]==NULL) {
00165     serr->printf("PNGGenerator::saveBuffer() failed because selected image is NULL -- call selectSaveImage first to make sure it's up to date\n");
00166     return 0;
00167   }
00168   if(!imageValids[selectedSaveLayer][selectedSaveChannel]) {
00169     serr->printf("PNGGenerator::saveBuffer() failed because selected image is invalid -- call selectSaveImage first to make sure it's up to date\n");
00170     return 0;
00171   }
00172   unsigned char* img=images[selectedSaveLayer][selectedSaveChannel];
00173   if(img==NULL)
00174     return 0;
00175   if(!encodeInc(bytesUsed[selectedSaveLayer][selectedSaveChannel],buf,len)) return 0;
00176   unsigned int used=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00177   if(used>len)
00178     return 0;
00179   memcpy(buf,img,used);
00180   len-=used;
00181   return origlen-len;
00182 }
00183 
00184 void
00185 PNGGenerator::setNumImages(unsigned int nLayers, unsigned int nChannels) {
00186   if(nLayers==numLayers && nChannels==numChannels)
00187     return;
00188   FilterBankGenerator::setNumImages(nLayers,nChannels);
00189   for(unsigned int i=0; i<numLayers; i++)
00190     strides[i]=skips[i]=0;
00191   bytesUsed=new unsigned int*[numLayers];
00192   for(unsigned int res=0; res<numLayers; res++) {
00193     increments[res]=3;
00194     bytesUsed[res]=new unsigned int[numChannels];
00195     for(unsigned int i=0; i<numChannels; i++)
00196       bytesUsed[res][i]=0;
00197   }
00198 }
00199 
00200 unsigned char *
00201 PNGGenerator::createImageCache(unsigned int layer, unsigned int /*chan*/) const {
00202   return new unsigned char[widths[layer]*heights[layer]*3+PNG_HEADER_PAD];
00203 }
00204 
00205 void
00206 PNGGenerator::calcImage(unsigned int layer, unsigned int chan) {
00207   PROFSECTION("PNGGenerator::calcImage(...)",*mainProfiler);
00208   
00209   png_structp  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00210   if (!png_ptr) {
00211     serr->printf("png_create_info_struct failed, %s unavailable.\n",getName().c_str());
00212     return;
00213   }
00214   png_infop  info_ptr = png_create_info_struct(png_ptr);
00215   if (!info_ptr) {
00216     png_destroy_write_struct(&png_ptr, NULL);
00217     serr->printf("png_create_info_struct failed, %s unavailable.\n",getName().c_str());
00218     return;
00219   }
00220   
00221   png_write_mem_status write_status;
00222   write_status.buf=images[layer][chan];
00223   write_status.bufsize=widths[layer]*heights[layer]*3+PNG_HEADER_PAD;
00224   write_status.offset=0;
00225   png_set_write_fn(png_ptr, &write_status, user_write_png_data, user_flush_png_data);
00226   
00227   if(setjmp(png_jmpbuf(png_ptr))) {
00228     serr->printf("An error occurred during PNG compression\n");
00229     png_destroy_write_struct(&png_ptr, &info_ptr);
00230     return;
00231   }
00232   int bit_depth=8;
00233   int color_type;
00234   if(getCurrentSourceFormat()==SRC_COLOR)
00235     color_type=PNG_COLOR_TYPE_RGB;
00236   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00237     color_type=PNG_COLOR_TYPE_GRAY;
00238   else {
00239     serr->printf("calcImage failed - unsuitable or unknown mode/generator pair\n");
00240     return;
00241   }
00242   png_set_IHDR(png_ptr, info_ptr, widths[layer], heights[layer], bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00243   png_write_info(png_ptr, info_ptr);
00244   png_bytep row=reinterpret_cast<png_bytep>(src->getImage(layer,chan));
00245   const unsigned int inc=src->getIncrement(layer);
00246 #ifdef DEBUG
00247   if(getCurrentSourceFormat()==SRC_COLOR && inc!=3 || getCurrentSourceFormat()==SRC_GRAYSCALE && inc!=1) {
00248     serr->printf("PNGGenerator only supports color mode from sources with interleaving of 3 samples (increment==3), or grayscale from \"pure\" sources (increment==1)\n");
00249     png_write_end(png_ptr, NULL);
00250     return;
00251   }
00252 #endif
00253   unsigned int row_stride = src->getStride(layer);
00254   png_bytep endp=reinterpret_cast<png_bytep>(row+row_stride*heights[layer]);
00255   for(unsigned int h=0; h<heights[layer]; ++h) {
00256     if(row+row_stride>endp) {
00257       serr->printf("Ran out of src image -- bad height?\n");
00258       break;
00259     }
00260     png_write_row(png_ptr, row);
00261     row+=row_stride;
00262   }
00263   png_write_end(png_ptr, NULL);
00264   png_destroy_write_struct(&png_ptr, &info_ptr);
00265   bytesUsed[layer][chan]=write_status.offset;
00266   imageValids[layer][chan]=true;
00267 }
00268 
00269 void
00270 PNGGenerator::destruct() {
00271   FilterBankGenerator::destruct();
00272   for(unsigned int res=0; res<numLayers; res++)
00273     delete [] bytesUsed[res];
00274   delete [] bytesUsed;
00275   bytesUsed=NULL;
00276 }
00277 
00278 /*! @file
00279  * @brief Implements PNGGenerator, which generates FilterBankEvents containing PNG compressed images
00280  * @author Ethan Tira-Thompson (ejt) (Creator)
00281  *
00282  * $Author: ejt $
00283  * $Name: tekkotsu-3_0 $
00284  * $Revision: 1.6 $
00285  * $State: Exp $
00286  * $Date: 2006/09/16 06:01:41 $
00287  */

Tekkotsu v3.0
Generated Wed Oct 4 00:03:45 2006 by Doxygen 1.4.7