Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/plugins/ioTGA.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include "ioTGA.hpp"
00033 #include <vlCore/LoadWriterManager.hpp>
00034 #include <vlCore/VisualizationLibrary.hpp>
00035 #include <vlCore/VisualizationLibrary.hpp>
00036 #include <vlCore/FileSystem.hpp>
00037 #include <vlCore/DiskFile.hpp>
00038 #include <vlCore/Image.hpp>
00039 
00040 using namespace vl;
00041 
00042 #include <vlCore/ImageTools.hpp>
00043 
00044 //-----------------------------------------------------------------------------
00045 namespace
00046 {
00047   const unsigned long TGA_NO_IMAGE_DATA = 0;
00048   const unsigned long TGA_8BIT_UNCOMPRESSED = 1;
00049   const unsigned long TGA_RGB_UNCOMPRESSED  = 2;
00050   const unsigned long TGA_GRAYSCALE_UNCOMPRESSED  = 3;
00051   const unsigned long TGA_8BIT_COMPRESSED   = 9;
00052   const unsigned long TGA_RGB_COMPRESSED    = 10;
00053   const unsigned long TGA_GRAYSCALE_COMPRESSED = 11;
00054 
00055   typedef struct
00056   {
00057     unsigned char IdFieldSize; /* at offset 18 it starts, usually 0 */
00058     unsigned char HasColMap;   /* 1 for indexed images, 0 otherwise */
00059     unsigned char ImageType;   /* see defines above */
00060     unsigned char ColMapOrigin[2];
00061     unsigned char ColMapCount_lo;
00062     unsigned char ColMapCount_hi;
00063     unsigned char ColMapEntrySize; /* 16, 24, 32 */
00064     unsigned char ImageOrigins[4]; /* lo/hi bytes for x/y origins */
00065     unsigned char Width_lo;
00066     unsigned char Width_hi;
00067     unsigned char Height_lo;
00068     unsigned char Height_hi;
00069     unsigned char BitsPerPixel;  /* 8/16(?), 16, 24, 32 */
00070     unsigned char ImageDescriptor; /* origin | alpha channel bits */
00071   } STGAHeader;
00072 }
00073 //-----------------------------------------------------------------------------
00088 ref<Image> vl::loadTGA( const String& path )
00089 {
00090   ref<VirtualFile> file = defFileSystem()->locateFile(path);
00091   if ( !file )
00092   {
00093     Log::error( Say("File '%s' not found.\n") << path );
00094     return NULL;
00095   }
00096 
00097   return loadTGA( file.get() );
00098 }
00099 //-----------------------------------------------------------------------------
00100 ref<Image> vl::loadTGA( VirtualFile* file )
00101 {
00102   if ( !file->open(OM_ReadOnly) )
00103   {
00104     Log::error( Say("loadTGA: cannot load TGA file '%s'\n") << file->path() );
00105     return NULL;
00106   }
00107 
00108   ref<Image> img = new Image;
00109   img->setObjectName(file->path().toStdString().c_str());
00110 
00111   STGAHeader header;
00112   memset(&header, 0, sizeof(header));
00113   file->read( &header, sizeof(STGAHeader) );
00114 
00115   unsigned int colmap_offset = 18 + header.IdFieldSize;
00116   unsigned int pixels_offset = colmap_offset +
00117     (header.ColMapCount_lo + header.ColMapCount_hi*256)*header.ColMapEntrySize/8;
00118   unsigned int w = header.Width_lo  + header.Width_hi*256;
00119   unsigned int h = header.Height_lo + header.Height_hi*256;
00120 
00121   #ifndef NDEBUG
00122     unsigned int bpp = header.BitsPerPixel;
00123     const char *type = "";
00124     switch(header.ImageType)
00125     {
00126       case TGA_NO_IMAGE_DATA:          type = "TGA_NO_IMAGE_DATA"; break;
00127       case TGA_8BIT_UNCOMPRESSED:      type = "TGA_8BIT_UNCOMPRESSED"; break;
00128       case TGA_RGB_UNCOMPRESSED:       type = "TGA_RGB_UNCOMPRESSED"; break;
00129       case TGA_GRAYSCALE_UNCOMPRESSED: type = "TGA_GRAYSCALE_UNCOMPRESSED"; break;
00130       case TGA_8BIT_COMPRESSED:        type = "TGA_8BIT_COMPRESSED"; break;
00131       case TGA_RGB_COMPRESSED:         type = "TGA_RGB_COMPRESSED"; break;
00132       case TGA_GRAYSCALE_COMPRESSED:   type = "TGA_GRAYSCALE_COMPRESSED"; break;
00133     }
00134     Log::debug( Say("TGA %s: w=%n, h=%n, bpp=%n/%n %s\n") << file->path() << w << h << bpp << header.ColMapEntrySize << type);
00135   #endif
00136 
00137   if (header.ImageType == TGA_NO_IMAGE_DATA)
00138     return NULL;
00139 
00140   if (header.ImageType == TGA_RGB_COMPRESSED)
00141   {
00142     int pixsize = 0;
00143     switch(header.BitsPerPixel)
00144     {
00145       case 32: pixsize = 4; break;
00146       case 24: pixsize = 3; break;
00147       case 16: pixsize = 2; break;
00148     }
00149 
00150     if (pixsize)
00151     {
00152       img->allocate2D(w, h, 4, IF_RGBA, IT_UNSIGNED_BYTE);
00153 
00154       file->seekSet(pixels_offset);
00155       int pixcount = w*h;
00156       int pix = 0;
00157       while(pix < pixcount)
00158       {
00159         unsigned char header_ch = 0;
00160         file->read(&header_ch, 1);
00161         if (header_ch >= 128)
00162         {
00163           int count = header_ch - 128 + 1;
00164           unsigned char bgra[4];
00165           file->read(bgra, pixsize);
00166           while(count--)
00167           {
00168             memcpy((unsigned char*)img->pixels() + pix*pixsize, bgra, pixsize);
00169             pix++;
00170           }
00171         }
00172         else
00173         {
00174           int count = header_ch + 1;
00175           file->read((unsigned char*)img->pixels() + pix*pixsize, pixsize*count);
00176           pix += count;
00177         }
00178       }
00179 
00180       switch(header.BitsPerPixel)
00181       {
00182         case 24: convertRGBToRGBA(img->pixels(), img->width(), img->height(), 0xFF); // break;
00183         case 32: swapBytes32_BGRA_RGBA(img->pixels(), img->requiredMemory()); break;
00184         case 16: convertA1R5G5B5ToRGBA(img->pixels(), w*h, 0xFF); break;
00185       }
00186 
00187     }
00188     else
00189     {
00190       Log::error( Say("TGA ERROR: TGA_RGB_COMPRESSED %nbpp not supported.\n") << header.BitsPerPixel );
00191       file->close();
00192       return NULL;
00193     }
00194 
00195   }
00196   else
00197   if (header.ImageType == TGA_RGB_UNCOMPRESSED)
00198   {
00199     int pixsize = 0;
00200 
00201     switch(header.BitsPerPixel)
00202     {
00203       case 32: pixsize = 4; break;
00204       case 24: pixsize = 3; break;
00205       case 16: pixsize = 2; break;
00206     }
00207 
00208     if (pixsize)
00209     {
00210       file->seekSet(pixels_offset);
00211       img->allocate2D(w, h, 4, IF_RGBA, IT_UNSIGNED_BYTE);
00212       file->read(img->pixels(), w*h*pixsize);
00213       switch(header.BitsPerPixel)
00214       {
00215         case 24: convertRGBToRGBA(img->pixels(), img->width(), img->height(), 0xFF); // break;
00216         case 32: swapBytes32_BGRA_RGBA(img->pixels(), img->requiredMemory()); break;
00217         case 16: convertA1R5G5B5ToRGBA(img->pixels(), w*h, 0xFF); break;
00218       }
00219     }
00220     else
00221     {
00222       Log::error( Say("TGA ERROR: TGA_RGB_UNCOMPRESSED %nbpp not supported.\n") << header.BitsPerPixel );
00223       file->close();
00224       return NULL;
00225     }
00226 
00227   }
00228   else
00229   if (header.ImageType == TGA_8BIT_UNCOMPRESSED || header.ImageType == TGA_8BIT_COMPRESSED)
00230   {
00231     if (header.BitsPerPixel == 8)
00232     {
00233 
00234       unsigned int colmap_count = header.ColMapCount_lo + header.ColMapCount_hi*256;
00235       VL_CHECK(colmap_count<=256);
00236       if (header.ColMapEntrySize == 24)
00237       {
00238         TPalette3x256 palette;
00239         file->seekSet(colmap_offset);
00240         file->read(palette, colmap_count*3);
00241 
00242         file->seekSet(pixels_offset);
00243 
00244         img->allocate2D(w, h, 4, IF_RGBA, IT_UNSIGNED_BYTE);
00245         if (header.ImageType == TGA_8BIT_UNCOMPRESSED)
00246         {
00247           file->read(img->pixels(), w*h*1);
00248         }
00249         else // TGA_8BIT_UNCOMPRESSED
00250         {
00251           int pixsize = 1;
00252           int pixcount = w*h;
00253           int pix = 0;
00254           while(pix < pixcount)
00255           {
00256             unsigned char header_ch = 0;
00257             file->read(&header_ch, 1);
00258             if (header_ch >= 128)
00259             {
00260               int count = header_ch - 128 + 1;
00261               unsigned char bgra[4];
00262               file->read(bgra, pixsize);
00263               while(count--)
00264               {
00265                 memcpy((unsigned char*)img->pixels() + pix*pixsize, bgra, pixsize);
00266                 pix++;
00267               }
00268             }
00269             else
00270             {
00271               int count = header_ch + 1;
00272               file->read((unsigned char*)img->pixels() + pix*pixsize, pixsize*count);
00273               pix += count;
00274             }
00275           }
00276         }
00277 
00278         convert8ToRGBA(palette, img->pixels(), img->width(), img->height(), 0xFF);
00279         swapBytes32_BGRA_RGBA(img->pixels(), img->requiredMemory());
00280       }
00281       else if (header.ColMapEntrySize == 32)
00282       {
00283         TPalette4x256 palette;
00284         file->seekSet(colmap_offset);
00285         file->read(palette, colmap_count*4);
00286 
00287         file->seekSet( pixels_offset );
00288         img->allocate2D(w, h, 4, IF_RGBA, IT_UNSIGNED_BYTE);
00289         if (header.ImageType == TGA_8BIT_UNCOMPRESSED)
00290         {
00291           file->read(img->pixels(), w*h*1);
00292         }
00293         else // TGA_8BIT_UNCOMPRESSED
00294         {
00295           int pixsize = 1;
00296           int pixcount = w*h;
00297           int pix = 0;
00298           while(pix < pixcount)
00299           {
00300             unsigned char header_ch = 0;
00301             file->read(&header_ch, 1);
00302             if (header_ch >= 128)
00303             {
00304               int count = header_ch - 128 + 1;
00305               unsigned char bgra[4];
00306               file->read(bgra, pixsize);
00307               while(count--)
00308               {
00309                 memcpy((unsigned char*)img->pixels() + pix*pixsize, bgra, pixsize);
00310                 pix++;
00311               }
00312             }
00313             else
00314             {
00315               int count = header_ch + 1;
00316               file->read((unsigned char*)img->pixels() + pix*pixsize, pixsize*count);
00317               pix += count;
00318             }
00319           }
00320         }
00321 
00322         convert8ToRGBA(palette, img->pixels(), img->width(), img->height());
00323         swapBytes32_BGRA_RGBA(img->pixels(), img->requiredMemory());
00324       }
00325       else
00326       {
00327         Log::error( Say("TGA ERROR: TGA_8BIT_UNCOMPRESSED entry size = %n not supported.\n") << header.ColMapEntrySize );
00328         file->close();
00329         return NULL;
00330       }
00331     }
00332     else
00333     {
00334       Log::error( Say("TGA ERROR: TGA_8BIT_UNCOMPRESSED %nbpp bit not supported.\n") << header.BitsPerPixel );
00335       file->close();
00336       return NULL;
00337     }
00338   }
00339   else
00340   if (header.ImageType == TGA_GRAYSCALE_UNCOMPRESSED || header.ImageType == TGA_GRAYSCALE_COMPRESSED)
00341   {
00342     if (header.BitsPerPixel == 8)
00343     {
00344       file->seekSet(pixels_offset);
00345       img->allocate2D(w, h, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE);
00346       if (header.ImageType == TGA_GRAYSCALE_UNCOMPRESSED)
00347       {
00348         file->read(img->pixels(), w*h);
00349       }
00350       else  // TGA_GRAYSCALE_COMPRESSED
00351       {
00352         int pixsize = 1;
00353         int pixcount = w*h;
00354         int pix = 0;
00355         while(pix < pixcount)
00356         {
00357           unsigned char header_ch = 0;
00358           file->read(&header_ch, 1);
00359           if (header_ch >= 128)
00360           {
00361             int count = header_ch - 128 + 1;
00362             unsigned char bgra[4];
00363             file->read(bgra, pixsize);
00364             while(count--)
00365             {
00366               memcpy((unsigned char*)img->pixels() + pix*pixsize, bgra, pixsize);
00367               pix++;
00368             }
00369           }
00370           else
00371           {
00372             int count = header_ch + 1;
00373             file->read((unsigned char*)img->pixels() + pix*pixsize, pixsize*count);
00374             pix += count;
00375           }
00376         }
00377       }
00378     }
00379     else
00380     {
00381       Log::error( Say("TGA ERROR: TGA_GRAYSCALE_UNCOMPRESSED %nbpp not supported.\n") << header.BitsPerPixel );
00382       file->close();
00383       return NULL;
00384     }
00385 
00386   }
00387   else
00388   {
00389     Log::error( Say("TGA ERROR: this type %n not supported.\n") << header.ImageType);
00390     file->close();
00391     return NULL;
00392   }
00393 
00394   if ((header.ImageDescriptor & (1<<5)))
00395     img->flipVertically();
00396 
00397   file->close();
00398   return img;
00399 }
00400 //-----------------------------------------------------------------------------
00401 bool vl::saveTGA(const Image* src, const String& path)
00402 {
00403   ref<DiskFile> file = new DiskFile(path);
00404   return saveTGA(src, file.get());
00405 }
00406 //-----------------------------------------------------------------------------
00407 bool vl::saveTGA(const Image* src, VirtualFile* fout)
00408 {
00409   //if (src->dimension() != ID_2D )
00410   //{
00411   //  Log::error( Say("saveTGA('%s'): can save only 2D images.\n") << fout->path() );
00412   //  return false;
00413   //}
00414 
00415   int w = src->width();
00416   int h = src->height();
00417   int d = src->depth();
00418   if (h == 0) h=1;
00419   if (d == 0) d=1;
00420   if (src->isCubemap()) d=6;
00421   h = h*d;
00422 
00423   // convert src to IT_UNSIGNED_BYTE / IF_RGBA
00424   ref<Image> cimg;
00425   if (src->type() != IT_UNSIGNED_BYTE)
00426   {
00427     cimg = src->convertType(IT_UNSIGNED_BYTE);
00428     src = cimg.get();
00429     if (!cimg)
00430     {
00431       Log::error( Say("saveTGA('%s'): could not convert image to IT_UNSIGNED_BYTE.\n") << fout->path() );
00432       return false;
00433     }
00434   }
00435   if (src->format() != IF_BGRA)
00436   {
00437     cimg = src->convertFormat(IF_BGRA);
00438     src = cimg.get();
00439     if (!cimg)
00440     {
00441       Log::error( Say("saveTGA('%s'): could not convert image to IF_BGRA.\n") << fout->path() );
00442       return false;
00443     }
00444   }
00445 
00446   if(!fout->open(OM_WriteOnly))
00447   {
00448     Log::error( Say("TGA: could not write to '%s'.\n") << fout->path() );
00449     return false;
00450   }
00451 
00452   STGAHeader header;
00453   memset(&header, 0, sizeof(STGAHeader));
00454   // flip vertically
00455   // header.ImageDescriptor |= 1<<5;
00456   header.ImageType = TGA_RGB_UNCOMPRESSED;
00457   header.Width_lo  = (unsigned char)(w & 0x00FF);
00458   header.Width_hi  = (unsigned char)(w >> 8);
00459   header.Height_lo = (unsigned char)(h & 0x00FF);
00460   header.Height_hi = (unsigned char)(h >> 8);
00461   header.BitsPerPixel = 32;
00462   fout->write(&header, sizeof(header));
00463 
00464   fout->write(src->pixels(), src->requiredMemory());
00465 
00466   // TGA footer
00467 
00468   // extension area offset
00469   fout->writeUInt32(0);
00470   // developer directory offset
00471   fout->writeUInt32(0);
00472   // signature + "." + "0"
00473   fout->write("TRUEVISION-XFILE.", 18);
00474 
00475   fout->close();
00476   return true;
00477 }
00478 //-----------------------------------------------------------------------------
00480 bool vl::isTGA( VirtualFile* file )
00481 {
00482   if (!file->open(OM_ReadOnly))
00483     return false;
00484 
00485   STGAHeader header;
00486   memset(&header, 0, sizeof(header));
00487   file->read(&header, sizeof(STGAHeader) );
00488 
00489   char signature[17];
00490   memset(signature, 0, 17);
00491   file->seekEnd(-18);
00492   file->read(signature, 16);
00493   file->close();
00494 
00495   // unfortunately many TGA files are without this field
00496 
00497   if (strcmp("TRUEVISION-XFILE", signature) == 0)
00498     return true;
00499 
00500   // do some heuristic checks
00501 
00502   switch( header.ImageType )
00503   {
00504     case 0:
00505     case 1:
00506     case 2:
00507     case 3:
00508     case 9:
00509     case 10:
00510     case 11:
00511       break;
00512     default:
00513       return false;
00514   }
00515 
00516   // unsigned int colmap_offset = 18 + header.IdFieldSize;
00517   // unsigned int pixels_offset = colmap_offset + (header.ColMapCount_lo + header.ColMapCount_hi*256)*header.ColMapEntrySize/8;
00518   unsigned int width  = header.Width_lo  + header.Width_hi*256;
00519   unsigned int height = header.Height_lo + header.Height_hi*256;
00520   unsigned int bpp = header.BitsPerPixel;
00521 
00522   if (width * height == 0)
00523     return false;
00524 
00525   switch( bpp )
00526   {
00527     case 1:
00528     case 4:
00529     case 8:
00530     case 16:
00531     case 24:
00532     case 32:
00533       break;
00534     default:
00535       return false;
00536   }
00537 
00538   // ends with .tga
00539   if ( !file->path().toLowerCase().endsWith(".tga") )
00540     return false;
00541 
00542   Log::warning( Say("isTGA: the file '%s' looks like a TGA but is missing the 'TRUEVISION-XFILE' signature.\n") << file->path() );
00543   return true;
00544 }
00545 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:30.
Permission is granted to use this page to write and publish articles regarding Visualization Library.