Main Page   Modules   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages   Examples  

misc/image.cpp

Go to the documentation of this file.
00001 #include "image.h"
00002 
00008 #include <misc/endian.h>
00009 #include <glt/color.h>
00010 
00011 #include <cassert>
00012 #include <cstring>
00013 #include <cstdio>
00014 #include <cmath>
00015 
00016 #include <set>
00017 #include <map>
00018 #include <list>
00019 #include <iostream>
00020 using namespace std;
00021 
00022 bool isGreyscale(const string &rgb)
00023 {
00024     assert(rgb.size()%3==0);
00025 
00026     if (rgb.size()%3)
00027         return false;
00028 
00029     for (size_t i=0; i<rgb.size(); i+=3)
00030         if (rgb[i]!=rgb[i+1] || rgb[i]!=rgb[i+2])
00031             return false;
00032 
00033     return true;
00034 }
00035 
00036 bool is256Colors(const string &rgb)
00037 {
00038     assert(rgb.size()%3==0);
00039 
00040     if (rgb.size()%3)
00041         return false;
00042 
00043     set<uint32> colors;
00044 
00045     for (size_t i=0; i<rgb.size(); i+=3)
00046     {
00047         const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00048 
00049         colors.insert(col);
00050 
00051         if (colors.size()>256)
00052             return false;
00053     }
00054 
00055     return true;
00056 }
00057 
00058 void getChannel(string &dest,const string &rgb,const uint32 size,const uint32 channel)
00059 {
00060     assert(rgb.size()%size==0);
00061     assert(channel<size);
00062 
00063     if (rgb.size()%size || channel>=size)
00064         return;
00065 
00066     dest.resize(rgb.size()/size);
00067 
00068     for (size_t i=channel,j=0; i<rgb.size(); i+=size,j++)
00069         dest[j] = rgb[i];
00070 }
00071 
00072 void rgb2Indexed(string &dest,const string &rgb)
00073 {
00074     assert(rgb.size()%3==0);
00075 
00076     if (rgb.size()%3)
00077         return;
00078 
00079     // Output buffer will begin with lookup-table, 
00080     // followed by pixel indexes
00081 
00082     const int tableSize = 256*3;
00083     dest.resize(tableSize+rgb.size()/3);
00084 
00085     // First find the first 256 unique colors
00086     // we initialise lookup-table as we go
00087 
00088     map<uint32,byte> colors;
00089 
00090     for (size_t i=0,j=0; i<rgb.size();)
00091     {
00092         const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00093         
00094         // Is this a new colour?
00095 
00096         if (colors.find(col)==colors.end())
00097         {
00098             // Add it
00099             colors.insert(make_pair(col,j/3));
00100 
00101             // Copy it into lookup-table
00102             dest[j++] = rgb[i++];
00103             dest[j++] = rgb[i++];
00104             dest[j++] = rgb[i++];
00105 
00106             // Stop if we've found them all
00107             if (colors.size()==256)
00108                 break;
00109         }
00110         else
00111             i += 3;
00112     }
00113 
00114     // Now use map to convert pixels to indexes
00115 
00116     {
00117         for (size_t i=0,j=tableSize; i<rgb.size(); i+=3,j++)
00118         {
00119             const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00120             assert(colors.find(col)!=colors.end());
00121             dest[j] = colors[col];
00122         }
00123     }
00124 }
00125 
00126 void indexed2rgb(string &dest,const string &indexed)
00127 {
00128     const int tableSize = 256*3;
00129     const int pixels = indexed.size()-tableSize;
00130 
00131     assert(pixels>=0);
00132     if (pixels<0)
00133         return;
00134 
00135     dest.resize(pixels*3);
00136 
00137     for (size_t i=tableSize,j=0; i<indexed.size(); i++,j+=3)
00138     {
00139         const size_t p = 3*(byte)(indexed[i]);
00140 
00141         dest[j]   = indexed[p];
00142         dest[j+1] = indexed[p+1];
00143         dest[j+2] = indexed[p+2];
00144     }
00145 }
00146 
00147 void flipImage(string &dest,const string &src,const int width,const int height)
00148 {
00149     const int lineSize = src.size()/height;
00150 
00151     assert(lineSize>0);
00152     assert(src.size()%lineSize==0);
00153 
00154     if (lineSize==0 || src.size()%lineSize!=0)
00155         return;
00156 
00157     dest.resize(src.size());
00158 
00159     const char *i = src.c_str();
00160     const char *j = dest.c_str()+dest.size()-lineSize;
00161 
00162     for (int k=0; k<height; i+=lineSize,j-=lineSize,k++)
00163         memcpy((void *)j,i,lineSize);
00164 }
00165 
00166 void 
00167 mirrorImage(std::string &dest,const std::string &src,const int width,const int height)
00168 {
00169     const int lineSize = static_cast<int>(src.size())/height;
00170     const int channels = lineSize/width;
00171 
00172     assert(channels>0);
00173     assert(src.size()%lineSize==0);
00174     assert(src.size()==width*height*channels);
00175 
00176     if (channels==0 || src.size()%lineSize!=0 || src.size()!=width*height*channels)
00177         return;
00178 
00179     dest.resize(src.size());
00180 
00181     const char *i = src.c_str();
00182     const char *j = dest.c_str()+lineSize-channels;
00183 
00184     for (int k=0; k<height; j+=lineSize*2,k++)
00185         for (int l=0; l<width; i+=channels,j-=channels,l++)
00186             memcpy((void *)j,i,channels);
00187 }
00188 
00189 void adjustGamma(std::string &image,const double gamma)
00190 {
00191     byte table[256];
00192     for (int i=0; i<256; i++)
00193         table[i] = (byte) floor( pow(double(i)/255.0, 1.0/gamma)*255.0 + 0.5);
00194 
00195           byte *j   =       (byte *) image.c_str();
00196     const byte *end = (const byte *) image.c_str() + image.size();
00197 
00198     for (;j<end;j++)
00199         *j = table[*j];
00200 }
00201 
00202 void 
00203 adjustHSV
00204 (
00205     std::string &image,
00206     const int width,
00207     const int height,
00208     const real hue,
00209     const real saturation,
00210     const real value
00211 )
00212 {
00213     const int channels = image.size()/(width*height);
00214     assert(channels*width*height==image.size());
00215 
00216           byte *i   =       (byte *) image.data();
00217     const byte *end = (const byte *) image.data() + image.size();
00218 
00219     for (;i<end;i+=channels)
00220     {
00221         GltColor col(*i/255.0,*(i+1)/255.0,*(i+2)/255.0);
00222         
00223         real h,s,v;
00224         col.toHSV(h,s,v);
00225 
00226         h = fmod(h+hue+360.0,360.0);
00227         s = CLAMP(s+saturation,0.0,1.0);
00228         v = CLAMP(v+value,0.0,1.0);
00229 
00230         col.fromHSV(h,s,v);
00231 
00232         *i     = (byte) floor(col.red()  *255.0+0.5);
00233         *(i+1) = (byte) floor(col.green()*255.0+0.5);
00234         *(i+2) = (byte) floor(col.blue() *255.0+0.5);
00235     }
00236 }
00237 
00238 bool stitchImages(string &image,const int dx,const int dy,const vector<string> &src,const int lineSize)
00239 {
00240     const int n=src.size();
00241 
00242     if (dx<1 || dy<1 || dx*dy!=n)
00243         return false;
00244 
00245     const int tileSize = src[0].size();
00246 
00247     // Allocate size of output image
00248     image.resize(n*tileSize);
00249 
00250     // Process each input in turn
00251 
00252     for (int y=0; y<dy; y++)
00253         for (int x=0; x<dx; x++)
00254         {
00255             const int k = x+y*dx;
00256 
00257                   byte *i    =       (byte *) image.data()+x*lineSize+y*dx*tileSize;
00258             const byte *iMax = (const byte *) image.data()+image.size();
00259             const byte *j    = (const byte *) src[k].data();
00260             const byte *jMax = (const byte *) src[k].data() + src[k].size(); 
00261 
00262             while (i<iMax && j<jMax)
00263             {
00264                 memcpy(i,j,lineSize);
00265                 i += lineSize*dx;
00266                 j += lineSize;
00267             }
00268         }
00269 
00270     return true;
00271 }
00272 
00273 //
00274 // Image decoding
00275 //
00276 
00277 bool decode(uint32 &width,uint32 &height,std::string &image,const std::string &data)
00278 {
00279     string type;
00280 
00281     // PPM
00282 
00283     if (decodePPM(type,width,height,image,data))
00284         return true;
00285     
00286     // BMP
00287 
00288     if (decodeBMP(width,height,image,data))
00289         return true;
00290 
00291     // PNG
00292 
00293     #ifdef GLT_PNG
00294     if (decodePNG(width,height,image,data))
00295         return true;
00296     #endif
00297 
00298     // TGA
00299 
00300     return decodeTGA(width,height,image,data);
00301 }
00302 
00303 bool decodePPM(string &type,uint32 &width,uint32 &height,string &image,const string &data)
00304 {
00305     if (data.size()<1 || data[0]!='P')
00306         return false;
00307 
00308     //
00309 
00310     size_t channels = 0;
00311 
00312     if (data[1]=='6')   // 24-bit binary RGB PPM file
00313     {
00314         channels = 3;
00315         type = "P6";
00316     }
00317     else
00318         if (data[1]=='5')   // 8-bit binary greyscale PGM file 
00319         {
00320             channels = 1;
00321             type = "P5";
00322         }
00323         else
00324             return false;
00325 
00326     //
00327 
00328     const string eol("\n");
00329     const string digits("0123456789");
00330 
00331     size_t i = 0;
00332     
00333     int depth = 0;
00334 
00335     for (;;)
00336     {
00337         // Find end-of-line
00338 
00339         i = data.find_first_of(eol,i);
00340         if (i==string::npos)
00341             break;
00342         else
00343             i++;
00344 
00345         // If this line is a comment, try next line
00346 
00347         if (data[i]=='#')
00348             continue;
00349         
00350         // Get width
00351 
00352         width = atoi(data.c_str()+i);
00353         i = data.find_first_not_of(digits,i); if (i==string::npos) break;
00354         i = data.find_first_of(digits,i);     if (i==string::npos) break;
00355 
00356         // Get height
00357 
00358         height = atoi(data.c_str()+i);
00359         i = data.find_first_not_of(digits,i); if (i==string::npos) break;
00360         i = data.find_first_of(digits,i);     if (i==string::npos) break;
00361 
00362         // Get depth
00363 
00364         depth = atoi(data.c_str()+i);
00365         i = data.find(eol,i); 
00366         if (i!=string::npos) 
00367             i++;
00368 
00369         break;
00370     }
00371 
00372     // Check that PPM seems to be valid
00373 
00374     const uint32 imageSize = width*height*channels;
00375     const uint32 rowSize   = width*channels;
00376 
00377     if (width!=0 && height!=0 && depth==255 && imageSize==data.size()-i)
00378     {
00379         // Extract image from input & flip
00380         flipImage(image,data.substr(i),width,height);
00381     }
00382 
00383     return true;
00384 }
00385 
00386 bool decodeBMP(uint32 &width,uint32 &height,string &image,const string &data)
00387 {
00388     //
00389     // For information about the BMP File Format:
00390     //
00391     // http://www.daubnet.com/formats/BMP.html
00392     // http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/BMP.txt
00393     //
00394 
00395     const uint32 fileHeaderSize = 14;
00396     if (data.size()<fileHeaderSize)
00397         return false;
00398 
00399     // Check for "BM" 
00400 
00401     if (data[0]!='B' || data[1]!='M') 
00402         return false;
00403 
00404     // Check the filesize matches string size
00405 
00406     const uint32 fileSize = littleEndian((uint32 *)(data.data()+2));
00407     if (data.size()!=fileSize)
00408         return false;
00409 
00410     // Get the size of the image header
00411 
00412     const uint32 imageHeaderSize = littleEndian((uint32 *)(data.data()+fileHeaderSize));
00413     if (fileHeaderSize+imageHeaderSize>data.size())
00414         return false;
00415 
00416     // Get some image info
00417 
00418     const uint32 imageWidth    = littleEndian((uint32 *)(data.data()+fileHeaderSize+4 ));
00419     const uint32 imageHeight   = littleEndian((uint32 *)(data.data()+fileHeaderSize+8 ));
00420     const uint16 imageBits     = littleEndian((uint16 *)(data.data()+fileHeaderSize+14));
00421     const uint32 imageCompress = littleEndian((uint32 *)(data.data()+fileHeaderSize+16));
00422 
00423     // Do some checking
00424 
00425     // We support only RGB images
00426 
00427     if (imageBits!=24)
00428         return false;       
00429 
00430     // We don't support compressed BMP.
00431     //
00432     // According to the specs, 4-bit and 8-bit RLE
00433     // compression is used only for indexed images.
00434 
00435     if (imageCompress!=0)
00436         return false;       
00437 
00438     const uint32 imagePos    = littleEndian((uint32 *)(data.data()+10));
00439     const uint32 imagePixels = imageWidth*imageHeight;
00440     const uint32 lineBytes   = (imageWidth*3+3)&~3;
00441     const uint32 imageBytes  = lineBytes*imageHeight;
00442 
00443     if (imagePos+imageBytes!=data.size())
00444         return false;
00445 
00446     // Extract the image
00447 
00448     width  = imageWidth;
00449     height = imageHeight;
00450     image.resize(imagePixels*3);
00451     
00452     // Destination iterator
00453 
00454     byte *i = (byte *) image.data();
00455 
00456     for (uint32 y=0; y<imageHeight; y++)
00457     {
00458         // Source iterator, beginning of y-th scanline
00459 
00460         const byte *j = (const byte *) data.data()+imagePos+lineBytes*y;
00461 
00462         // Copy the scanline, swapping red and blue channels
00463         // as we go...
00464 
00465         for (uint32 x=0; x<imageWidth; x++)
00466         {
00467             *(i++) = *(j++ + 2);        
00468             *(i++) = *(j++);
00469             *(i++) = *(j++ - 2);
00470         }
00471     }
00472 
00473     return true;
00474 }
00475 
00476 bool 
00477 decodeTGA(uint32 &width,uint32 &height,string &image,const string &data)
00478 {
00479     // Check that header appears to be valid
00480 
00481     const uint32 tgaHeaderSize = 18;
00482     if (data.size()<tgaHeaderSize)
00483     {
00484         cerr << "TGA Header seems to be invalid." << endl;
00485         return false;
00486     }
00487 
00488     // We only handle type 1, 2 and 10, for the moment
00489 
00490     const uint32 tgaType = data[2];
00491 
00492     if (tgaType!=1 && tgaType!=2 && tgaType!=10)
00493     {
00494         cerr << "Found TGA type: " << tgaType << endl;
00495         return false;
00496     }
00497 
00498     // There should be a color map for type 1
00499 
00500     if (tgaType==1 && data[1]!=1)
00501     {
00502         cerr << "Expecting color map in type 1 TGA." << endl;
00503         return false;
00504     }
00505     
00506     // We only handle 24 bit or 32 bit images, for the moment
00507 
00508     uint32 bytesPerPixel=0;
00509 
00510     if (tgaType==1)
00511         bytesPerPixel = data[7]==24 ? 3 : 4;    // Color mapped
00512     else
00513         bytesPerPixel = data[16]==24 ? 3 : 4;   // Unmapped
00514     
00515     if (bytesPerPixel!=3 && bytesPerPixel!=4)
00516     {
00517         cerr << "Found TGA pixel depth: " << bytesPerPixel << endl;
00518         return false;
00519     }
00520 
00521     // Color map information
00522 
00523     const byte idSize = data[0];    // Upto 255 characters of text
00524 
00525     const uint16 origin   = littleEndian((uint16 *)(data.data()+3));
00526     const uint16 length   = littleEndian((uint16 *)(data.data()+5));
00527     const byte   size     = data[7]>>3;
00528     const uint32 mapSize  = length*size;
00529     const byte   *mapData = (const byte *) data.data()+tgaHeaderSize+idSize;
00530 
00531     //
00532 
00533     width  = littleEndian((uint16 *)(data.data()+12));
00534     height = littleEndian((uint16 *)(data.data()+14));
00535 
00536     // Check if TGA file seems to be the right size
00537     // (TGA allows for descriptive junk at the end of the
00538     //  file, we just ignore it)
00539 
00540     switch (tgaType)
00541     {
00542     case 1:     // Indexed
00543         {
00544             // TODO 
00545         }
00546         break;
00547 
00548     case 2:     // Unmapped RGB(A)
00549         {
00550             if (data.size()<tgaHeaderSize+idSize+width*height*bytesPerPixel)
00551                 return false;
00552         }
00553         break;
00554 
00555     case 10:    // Compressed RGB(A)
00556         {
00557             // TODO
00558         }
00559         break;
00560     }
00561 
00562 
00563     image.resize(width*height*bytesPerPixel);
00564 
00565     // Destination iterator
00566 
00567           byte *i = (byte *) image.data();                           // Destination
00568     const byte *j = (const byte *) data.data()+tgaHeaderSize+idSize+mapSize;     // Source
00569 
00570     switch (tgaType)
00571     {
00572 
00573         // Indexed
00574 
00575         case 1:
00576             {
00577                 const uint32 pixels = width*height;
00578 
00579                 for (uint32 p=0; p<pixels; p++)
00580                 {
00581                     const byte *entry = mapData+(*(j++))*bytesPerPixel;
00582 
00583                     *(i++) = entry[2];
00584                     *(i++) = entry[1];
00585                     *(i++) = entry[0];
00586 
00587                     if (bytesPerPixel==4)
00588                         *(i++) = entry[3];
00589                 }
00590             }
00591             break;
00592 
00593         // Unmapped RGB(A)
00594 
00595         case 2: 
00596             {
00597                 for (uint32 y=0; y<height; y++)
00598                 {
00599                     // Copy the scanline, swapping red and blue channels
00600                     // as we go...
00601 
00602                     for (int x=0; x<width; x++)
00603                     {
00604                         *(i++) = *(j++ + 2);        
00605                         *(i++) = *(j++);
00606                         *(i++) = *(j++ - 2);
00607 
00608                         if (bytesPerPixel==4)
00609                             *(i++) = *(j++);    // Copy alpha
00610                     }
00611                 }
00612             }
00613             break;
00614 
00615         // Run Length Encoded, RGB(A) images 
00616 
00617         case 10:
00618             {
00619                 const byte *iMax = (const byte *) image.data()+image.size();
00620                 const byte *jMax = (const byte *) data.data()+data.size();
00621 
00622                 while (i<iMax && j<jMax)
00623                 {
00624                     const bool rle   = ((*j)&128)==128;
00625                     const int  count = ((*j)&127) + 1;
00626 
00627                     j++;
00628 
00629                     // Check if we're running out of output buffer
00630                     if (i+count*bytesPerPixel>iMax)
00631                         return false;
00632 
00633                     if (rle)
00634                     {
00635                         // Check if we're running out of input data
00636                         if (j+bytesPerPixel>jMax)
00637                             return false;
00638 
00639                         byte *pixel = i;
00640 
00641                         // Get the next pixel, swapping red and blue
00642 
00643                         *(i++) = *(j++ + 2);        
00644                         *(i++) = *(j++);
00645                         *(i++) = *(j++ - 2);
00646 
00647                         if (bytesPerPixel==4)
00648                             *(i++) = *(j++);    // Copy alpha
00649 
00650                         // Now duplicate for rest of the run
00651 
00652                         for (int k=0; k<count-1; k++,i+=bytesPerPixel)
00653                             memcpy(i,pixel,bytesPerPixel);
00654                     }
00655                     else
00656                     {
00657                         // Check if we're running out of input data
00658                         if (j+count*bytesPerPixel>jMax)
00659                             return false;
00660 
00661                         // Copy pixels, swapping red and blue as
00662                         // we go...
00663 
00664                         for (int k=0; k<count; k++)
00665                         {
00666                             *(i++) = *(j++ + 2);        
00667                             *(i++) = *(j++);
00668                             *(i++) = *(j++ - 2);
00669 
00670                             if (bytesPerPixel==4)
00671                                 *(i++) = *(j++);    // Copy alpha
00672                         }
00673 
00674                     }
00675                 }
00676 
00677                 if (i!=iMax)
00678                     return false;
00679             }   
00680             break;
00681     }
00682 
00683     // If the TGA origin is top-right
00684     // flip image
00685 
00686     if ((data[17]&32)==32)
00687     {
00688         // TODO - in-place flip
00689         string tmp = image;
00690         flipImage(image,tmp,width,height);
00691     }
00692 
00693     return true;
00694 }
00695 
00696 //
00697 
00698 #ifdef GLT_PNG
00699 
00700 #include <png.h>
00701 
00702 class GltPngReader
00703 {
00704 public:
00705 
00706     GltPngReader(const std::string &data,png_structp png_ptr)
00707     : pos(data.c_str()), end(data.c_str()+data.size())
00708     {
00709         png_set_read_fn(png_ptr,this,(png_rw_ptr) &GltPngReader::read);
00710     }
00711 
00712     size_t remaining() const { return end-pos; }
00713 
00714 private:
00715 
00716     static void read(png_structp png_ptr, png_bytep data, png_uint_32 length)
00717     {
00718         GltPngReader *reader = (GltPngReader *) png_get_io_ptr(png_ptr); 
00719 
00720         assert(reader);
00721         if (!reader)
00722             return;
00723 
00724         const char *&pos = reader->pos;
00725         const char *&end = reader->end;
00726 
00727         assert(pos);
00728         assert(end);
00729     
00730         if (pos && end)
00731         {
00732             if (pos+length<=end)
00733             {
00734                 memcpy(data,pos,length);
00735                 pos += length;
00736             }
00737             else
00738             {
00739                 memcpy(data,pos,end-pos);
00740                 pos = end = NULL;
00741             }
00742         }
00743     }
00744 
00745     const char *pos;
00746     const char *end;
00747 };
00748 
00749 class GltPngWriter
00750 {
00751 public:
00752 
00753     GltPngWriter(std::string &data,png_structp png_ptr)
00754     : _png(png_ptr), _data(data), _size(0)
00755     {
00756         png_set_write_fn(_png,this,(png_rw_ptr) &GltPngWriter::write,(png_flush_ptr) &GltPngWriter::flush);
00757     }
00758 
00759     ~GltPngWriter()
00760     {
00761         GltPngWriter::flush(_png);
00762         png_set_write_fn(_png,NULL,NULL,NULL);
00763     }
00764 
00765 private:
00766 
00767     static void write(png_structp png_ptr, png_bytep data, png_uint_32 length)
00768     {
00769         GltPngWriter *writer = (GltPngWriter *) png_get_io_ptr(png_ptr); 
00770 
00771         assert(writer);
00772         if (!writer)
00773             return;
00774 
00775         list<string> &blocks = writer->_blocks;
00776         size_t       &size   = writer->_size;
00777     
00778         if (length>0)
00779         {
00780             blocks.push_back(string());
00781             string &block = blocks.back();
00782             block.resize(length);
00783             memcpy((void *) block.data(),data,length);
00784             size += length;
00785         }
00786     }
00787 
00788     static void flush(png_structp png_ptr)
00789     {
00790         GltPngWriter *writer = (GltPngWriter *) png_get_io_ptr(png_ptr); 
00791 
00792         assert(writer);
00793         if (!writer)
00794             return;
00795 
00796         string       &data   = writer->_data;
00797         list<string> &blocks = writer->_blocks;
00798         size_t       &size   = writer->_size;
00799 
00800         if (size>0)
00801         {
00802             size_t begin = data.size();
00803             data.resize(begin+size);
00804             for (list<string>::iterator i=blocks.begin(); i!=blocks.end(); i++)
00805             {
00806                 memcpy((void *)(data.data()+begin),(void *) i->data(),i->size());
00807                 begin += i->size();
00808             }
00809             blocks.clear();
00810             size = 0;
00811         }
00812     }
00813 
00814     png_structp   _png;
00815     string       &_data;
00816     list<string>  _blocks;
00817     size_t        _size;
00818 };
00819 
00820 //
00821 
00822 bool
00823 decodePNG(uint32 &width,uint32 &height,std::string &image,const std::string &data)
00824 {
00825     const char *pngSignature = "\211PNG\r\n\032\n";
00826     if (data.size()<8 || strncmp(data.c_str(),pngSignature,8))
00827         return false;
00828 
00829     png_structp png_ptr = 
00830         png_create_read_struct(PNG_LIBPNG_VER_STRING,(png_voidp) NULL,NULL,NULL);
00831 
00832     if (!png_ptr)
00833         return false;
00834 
00835     png_infop info_ptr = png_create_info_struct(png_ptr);
00836 
00837     if (!info_ptr)
00838     {
00839         png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
00840             return false;
00841     }
00842 
00843 //  png_init_io(png_ptr, fp);
00844 
00845     GltPngReader read(data,png_ptr);
00846 
00847     png_read_info(png_ptr, info_ptr);
00848 
00849     int bit_depth, color_type, interlace_type,
00850         compression_type, filter_type;
00851 
00852     png_uint_32 w,h;
00853 
00854     png_get_IHDR(png_ptr, info_ptr, &w, &h,
00855                  &bit_depth, &color_type, &interlace_type,
00856                  &compression_type, &filter_type);
00857 
00858     width = w;
00859     height = h;
00860 
00861     // TODO - Handle other bit-depths
00862 
00863     if (bit_depth<8)
00864         png_set_packing(png_ptr);
00865 
00866     if (bit_depth==16)
00867         png_set_strip_16(png_ptr);
00868 
00869     int channels = png_get_channels(png_ptr,info_ptr);
00870 
00871     switch (color_type)
00872     {
00873         case PNG_COLOR_TYPE_GRAY:       image.resize(width*height);   break;
00874         case PNG_COLOR_TYPE_GRAY_ALPHA: image.resize(width*height*2); break;
00875         case PNG_COLOR_TYPE_RGB:        image.resize(width*height*3); break;
00876         case PNG_COLOR_TYPE_RGB_ALPHA:  image.resize(width*height*4); break;
00877         case PNG_COLOR_TYPE_PALETTE:    
00878             image.resize(width*height*3); 
00879             png_set_palette_to_rgb(png_ptr);
00880             break;
00881     }
00882 
00883     int rowbytes = image.size()/height;
00884     assert(image.size()==rowbytes*height);
00885 
00886     const char **row_pointers = (const char **) malloc(height*sizeof(char *));
00887     for(int i=0;i<height;i++)
00888         row_pointers[i] = image.c_str() + rowbytes*(height-1-i);
00889 
00890     png_read_image(png_ptr, (png_bytepp)row_pointers);
00891 
00892     free(row_pointers);
00893     free(info_ptr);
00894     free(png_ptr);
00895 
00896     return true;
00897 }
00898 
00899 bool 
00900 encodePNG(std::string &data,const uint32 &width,const uint32 &height,const std::string &image)
00901 {
00902     png_structp png_ptr =
00903         png_create_write_struct(PNG_LIBPNG_VER_STRING,(png_voidp) NULL,NULL,NULL);
00904     
00905     if (!png_ptr)
00906         return false;
00907 
00908     png_infop info_ptr = png_create_info_struct(png_ptr);
00909 
00910     if (!info_ptr)
00911     {
00912         png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
00913             return false;
00914     }
00915 
00916     {
00917         GltPngWriter write(data,png_ptr);
00918     
00919         const int channels   = image.size()/(width*height);
00920         const int bit_depth  = 8;
00921               int color_type = 0; 
00922 
00923         switch (channels)
00924         {
00925             case 1: color_type = PNG_COLOR_TYPE_GRAY;       break;
00926             case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
00927             case 3: color_type = PNG_COLOR_TYPE_RGB;        break;
00928             case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA;  break;
00929         }
00930 
00931         assert(color_type);
00932 
00933         png_set_IHDR(
00934             png_ptr,info_ptr,width,height,bit_depth,color_type,
00935             PNG_INTERLACE_ADAM7,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00936     
00937         png_set_strip_16(png_ptr);
00938         png_set_packing(png_ptr);
00939 
00940         int rowbytes = image.size()/height;
00941         assert(image.size()==rowbytes*height);
00942 
00943         const char **row_pointers = (const char **) malloc(height*sizeof(char *));
00944         for(int i=0;i<height;i++)
00945             row_pointers[i] = image.c_str() + rowbytes*(height-1-i);
00946 
00947         png_write_info(png_ptr, info_ptr);
00948         png_write_image(png_ptr,(png_bytepp) row_pointers);
00949         png_write_end(png_ptr,info_ptr);
00950 
00951         free(row_pointers);
00952     }
00953 
00954     free(info_ptr);
00955     free(png_ptr);
00956                 
00957     return true;
00958 }
00959 
00960 #endif
00961 
00962 //
00963 // Image encoding
00964 //
00965 
00966 bool 
00967 encodePPM(string &data,const uint32 width,const uint32 height,const string &image)
00968 {
00969     const bool ppm = width*height*3==image.size();
00970     const bool pgm = width*height  ==image.size();
00971 
00972     // Check that image data matches the dimensions
00973 
00974     if (!ppm && !pgm)
00975         return false;
00976 
00977     // PPM P6/P5 header 
00978 
00979     char header[100];
00980     sprintf(header,"%s\n%u %u\n255\n",ppm ? "P6" : "P5",width,height);
00981 
00982     // Assemble PPM file
00983 
00984     data.resize(strlen(header)+image.size());
00985     assert(data.size()==strlen(header)+image.size());
00986     strcpy((char *) data.data(),header);
00987 
00988     // Copy and flip
00989 
00990     const uint32 lineSize = ppm ? width*3 : width;
00991 
00992     // Destination pointer in data buffer
00993     byte *i = (byte *) data.data() + strlen(header);
00994 
00995     // Source pointer in image buffer
00996     const byte *j = (const byte *) image.data() + image.size() - lineSize;
00997 
00998     // Copy scan-lines until finished
00999     for (int k=0; k<height; i+=lineSize, j-=lineSize, k++)
01000         memcpy(i,j,lineSize);
01001 
01002     return true;
01003 }
01004 
01005 bool 
01006 eencodeBMP(string &data,const uint32 width,const uint32 height,const string &image)
01007 {
01008     // TODO
01009     return false;
01010 }
01011 
01012 bool 
01013 encodeTGA(string &data,const uint32 width,const uint32 height,const string &image)
01014 {
01015     // Check that image data matches the
01016     // dimensions
01017 
01018     if (width*height*3!=image.size())
01019         return false;
01020 
01021     // Allocate space for header and image
01022     data.resize(18+image.size());
01023 
01024     data[0] = 0;
01025     data[1] = 0;
01026     data[2] = 2;
01027     data[3] = 0;
01028     data[4] = 0;
01029     data[5] = 0;
01030     data[6] = 0;
01031     data[7] = 0;
01032     data[8] = 0;
01033     data[9] = 0;
01034     data[10] = 0;
01035     data[11] = 0;
01036     *(uint16 *) (data.data()+12) = littleEndian(uint16(width));
01037     *(uint16 *) (data.data()+14) = littleEndian(uint16(height));
01038     data[16] = 24;
01039     data[17] = 0;
01040 
01041     // Destination iterator
01042 
01043           byte *i = (byte *) data.data()+18;                // Destination
01044     const byte *j = (const byte *) image.data();            // Source
01045 
01046     for (int y=0; y<height; y++)
01047     {
01048         // Copy the scanline, swapping red and blue channels
01049         // as we go...
01050 
01051         for (int x=0; x<width; x++)
01052         {
01053             *(i++) = *(j++ + 2);        
01054             *(i++) = *(j++);
01055             *(i++) = *(j++ - 2);
01056         }
01057     }
01058 
01059 //-------------------------------------------------------------------------------
01060 //DATA TYPE 2:  Unmapped RGB images.                                             |
01061 //_______________________________________________________________________________|
01062 //| Offset | Length |                     Description                            |
01063 //|--------|--------|------------------------------------------------------------|
01064 //|--------|--------|------------------------------------------------------------|
01065 //|    0   |     1  |  Number of Characters in Identification Field.             |
01066 //|        |        |                                                            |
01067 //|        |        |  This field is a one-byte unsigned integer, specifying     |
01068 //|        |        |  the length of the Image Identification Field.  Its value  |
01069 //|        |        |  is 0 to 255.  A value of 0 means that no Image            |
01070 //|        |        |  Identification Field is included.                         |
01071 //|        |        |                                                            |
01072 //|--------|--------|------------------------------------------------------------|
01073 //|    1   |     1  |  Color Map Type.                                           |
01074 //|        |        |                                                            |
01075 //|        |        |  This field contains either 0 or 1.  0 means no color map  |
01076 //|        |        |  is included.  1 means a color map is included, but since  |
01077 //|        |        |  this is an unmapped image it is usually ignored.  TIPS    |
01078 //|        |        |  ( a Targa paint system ) will set the border color        |
01079 //|        |        |  the first map color if it is present.                     |
01080 //|        |        |                                                            |
01081 //|--------|--------|------------------------------------------------------------|
01082 //|    2   |     1  |  Image Type Code.                                          |
01083 //|        |        |                                                            |
01084 //|        |        |  This field will always contain a binary 2.                |
01085 //|        |        |  ( That's what makes it Data Type 2 ).                     |
01086 //|        |        |                                                            |
01087 //|--------|--------|------------------------------------------------------------|
01088 //|    3   |     5  |  Color Map Specification.                                  |
01089 //|        |        |                                                            |
01090 //|        |        |  Ignored if Color Map Type is 0; otherwise, interpreted    |
01091 //|        |        |  as follows:                                               |
01092 //|        |        |                                                            |
01093 //|    3   |     2  |  Color Map Origin.                                         |
01094 //|        |        |  Integer ( lo-hi ) index of first color map entry.         |
01095 //|        |        |                                                            |
01096 //|    5   |     2  |  Color Map Length.                                         |
01097 //|        |        |  Integer ( lo-hi ) count of color map entries.             |
01098 //|        |        |                                                            |
01099 //|    7   |     1  |  Color Map Entry Size.                                     |
01100 //|        |        |  Number of bits in color map entry.  16 for the Targa 16,  |
01101 //|        |        |  24 for the Targa 24, 32 for the Targa 32.                 |
01102 //|        |        |                                                            |
01103 //|--------|--------|------------------------------------------------------------|
01104 //|    8   |    10  |  Image Specification.                                      |
01105 //|        |        |                                                            |
01106 //|    8   |     2  |  X Origin of Image.                                        |
01107 //|        |        |  Integer ( lo-hi ) X coordinate of the lower left corner   |
01108 //|        |        |  of the image.                                             |
01109 //|        |        |                                                            |
01110 //|   10   |     2  |  Y Origin of Image.                                        |
01111 //|        |        |  Integer ( lo-hi ) Y coordinate of the lower left corner   |
01112 //|        |        |  of the image.                                             |
01113 //|        |        |                                                            |
01114 //|   12   |     2  |  Width of Image.                                           |
01115 //|        |        |  Integer ( lo-hi ) width of the image in pixels.           |
01116 //|        |        |                                                            |
01117 //|   14   |     2  |  Height of Image.                                          |
01118 //|        |        |  Integer ( lo-hi ) height of the image in pixels.          |
01119 //|        |        |                                                            |
01120 //|   16   |     1  |  Image Pixel Size.                                         |
01121 //|        |        |  Number of bits in a pixel.  This is 16 for Targa 16,      |
01122 //|        |        |  24 for Targa 24, and .... well, you get the idea.         |
01123 //|        |        |                                                            |
01124 //|   17   |     1  |  Image Descriptor Byte.                                    |
01125 //|        |        |  Bits 3-0 - number of attribute bits associated with each  |
01126 //|        |        |             pixel.  For the Targa 16, this would be 0 or   |
01127 //|        |        |             1.  For the Targa 24, it should be 0.  For     |
01128 //|        |        |             Targa 32, it should be 8.                      |
01129 //|        |        |  Bit 4    - reserved.  Must be set to 0.                   |
01130 //|        |        |  Bit 5    - screen origin bit.                             |
01131 //|        |        |             0 = Origin in lower left-hand corner.          |
01132 //|        |        |             1 = Origin in upper left-hand corner.          |
01133 //|        |        |             Must be 0 for Truevision images.               |
01134 //|        |        |  Bits 7-6 - Data storage interleaving flag.                |
01135 //|        |        |             00 = non-interleaved.                          |
01136 //|        |        |             01 = two-way (even/odd) interleaving.          |
01137 //|        |        |             10 = four way interleaving.                    |
01138 //|        |        |             11 = reserved.                                 |
01139 //|        |        |                                                            |
01140 //|--------|--------|------------------------------------------------------------|
01141 //|   18   | varies |  Image Identification Field.                               |
01142 //|        |        |  Contains a free-form identification field of the length   |
01143 //|        |        |  specified in byte 1 of the image record.  It's usually    |
01144 //|        |        |  omitted ( length in byte 1 = 0 ), but can be up to 255    |
01145 //|        |        |  characters.  If more identification information is        |
01146 //|        |        |  required, it can be stored after the image data.          |
01147 //|        |        |                                                            |
01148 //|--------|--------|------------------------------------------------------------|
01149 //| varies | varies |  Color map data.                                           |
01150 //|        |        |                                                            |
01151 //|        |        |  If the Color Map Type is 0, this field doesn't exist.     |
01152 //|        |        |  Otherwise, just read past it to get to the image.         |
01153 //|        |        |  The Color Map Specification describes the size of each    |
01154 //|        |        |  entry, and the number of entries you'll have to skip.     |
01155 //|        |        |  Each color map entry is 2, 3, or 4 bytes.                 |
01156 //|        |        |                                                            |
01157 //|--------|--------|------------------------------------------------------------|
01158 //| varies | varies |  Image Data Field.                                         |
01159 //|        |        |                                                            |
01160 //|        |        |  This field specifies (width) x (height) pixels.  Each     |
01161 //|        |        |  pixel specifies an RGB color value, which is stored as    |
01162 //|        |        |  an integral number of bytes.                              |
01163 //|        |        |                                                            |
01164 //|        |        |  The 2 byte entry is broken down as follows:               |
01165 //|        |        |  ARRRRRGG GGGBBBBB, where each letter represents a bit.    |
01166 //|        |        |  But, because of the lo-hi storage order, the first byte   |
01167 //|        |        |  coming from the file will actually be GGGBBBBB, and the   |
01168 //|        |        |  second will be ARRRRRGG. "A" represents an attribute bit. |
01169 //|        |        |                                                            |
01170 //|        |        |  The 3 byte entry contains 1 byte each of blue, green,     |
01171 //|        |        |  and red.                                                  |
01172 //|        |        |                                                            |
01173 //|        |        |  The 4 byte entry contains 1 byte each of blue, green,     |
01174 //|        |        |  red, and attribute.  For faster speed (because of the     |
01175 //|        |        |  hardware of the Targa board itself), Targa 24 images are  |
01176 //|        |        |  sometimes stored as Targa 32 images.                      |
01177 //|        |        |                                                            |
01178 //--------------------------------------------------------------------------------
01179 
01180     return true;
01181 }

Generated on Tue Nov 5 11:11:05 2002 for GLT by doxygen1.2.18