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

ImageTIFF.cpp

Go to the documentation of this file.
00001 /*
00002  * ImageTIFF.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00032 #include "../Include/FlyLegacy.h"
00033 #include "../Include/Utility.h"
00034 #include "../Include/Globals.h"
00035 #include "../Include/Endian.h"
00036 
00037 
00038 /*
00039  * Libtiff implementation
00040  *
00041 extern "C" {
00042  #include <tiffio.h>
00043 }
00044 #include <stdarg.h>
00045 
00046 
00047 static void tiffError (const char* module, const char* fmt, va_list va)
00048 {
00049   gtfo (fmt, va);
00050 }
00051 
00052 static tsize_t tiffRead (thandle_t handle, tdata_t data, tsize_t size)
00053 {
00054   PODFILE *p = (PODFILE *)handle;
00055   return pread (data, 1, size, p);
00056 }
00057 
00058 static tsize_t tiffWrite (thandle_t handle, tdata_t data, tsize_t size)
00059 {
00060   gtfo ("tiffWrite : Cannot write to POD file");
00061   return 0;
00062 }
00063 
00064 static toff_t tiffSeek (thandle_t handle, toff_t offset, int origin)
00065 {
00066   PODFILE *p = (PODFILE *) handle;
00067   pseek (p, offset, origin);
00068   return offset;
00069 }
00070 
00071 static int tiffClose (thandle_t handle)
00072 {
00073   PODFILE *p = (PODFILE *) handle;
00074   pclose (p);
00075   return 1;
00076 }
00077 
00078 static toff_t tiffSize (thandle_t handle)
00079 {
00080   PODFILE *p = (PODFILE *) handle;
00081   return p->size;
00082 }
00083 
00084 static int tiffMap (thandle_t handle, tdata_t* data, toff_t* offset)
00085 {
00086 //  gtfo ("tiffMap : Unimplemented");
00087   return 0;
00088 }
00089 
00090 static void tiffUnmap (thandle_t handle, tdata_t data, toff_t offset)
00091 {
00092 //  gtfo ("tiffUnmap : Unimplemented");
00093 }
00094 
00095 
00096 CImageTIFF::CImageTIFF (const char* tifFilename)
00097 {
00098   // Initialize class members
00099   image = NULL;
00100   width = height = 0;
00101   depth = 4;
00102   texid = 0;
00103 
00104   // Open POD file
00105   PODFILE *p = popen (&globals->pfs, tifFilename);
00106   if (p == NULL) {
00107     gtfo ("CImageTIFF : Failed to open file %s", tifFilename);
00108   }
00109 
00112   TIFFSetErrorHandler(tiffError);
00113   TIFF *tiff = TIFFClientOpen(p->pPod->name, "rb", (thandle_t) p,
00114     tiffRead, tiffWrite, tiffSeek, tiffClose, tiffSize, tiffMap, tiffUnmap);
00115 
00116   if (tiff) {
00117     TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
00118     TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
00119     size_t nPixels = width * height;
00120     image = (unsigned char *) _TIFFmalloc (nPixels * sizeof(unsigned long));
00121     if (image != NULL) {
00122       if (!TIFFReadRGBAImage (tiff, width, height, (unsigned long *)image, 0)) {
00123         // Error during read
00124         gtfo ("CImageTIFF : Error reading image data from %s", tifFilename);
00125       }
00126     } else {
00127       gtfo ("CImageTIFF : Error allocating memory for %s", tifFilename);
00128     }
00129   } else {
00130     gtfo ("CImageTIFF : Error opening TIFF* for %s", tifFilename);
00131   }
00132 
00133   pclose (p);
00134 }
00135 
00136 CImageTIFF::~CImageTIFF (void)
00137 {
00138   if (image != NULL) _TIFFfree(image);
00139 }
00140 
00141   */
00142 
00143 
00144 GLuint CImageTIFF::CreateTexture (bool mipmap)
00145 {
00146   // Create the OpenGL texture
00147   glGenTextures (1, &texid);
00148   glBindTexture (GL_TEXTURE_2D, texid);
00149   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
00150   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00151   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00152   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00153   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00154   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00155 
00156   GLenum format = GL_RGBA;
00157   switch (depth) {
00158   case 4:
00159     // RGBA image with opacity data
00160     format = GL_RGBA;
00161     break;
00162   }
00163 
00164   if (mipmap) {
00165     // Generate mipmapped texture
00166     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00167     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00168 
00169     gluBuild2DMipmaps (GL_TEXTURE_2D, depth, width, height, format,
00170       GL_UNSIGNED_BYTE, image);
00171   } else {
00172     // Generate non-mipmapped texture
00173     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00174     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00175 
00176     glTexImage2D (GL_TEXTURE_2D, 0, depth, width, height, 0,
00177       format, GL_UNSIGNED_BYTE, image);
00178   }
00179 
00180   return texid;
00181 }
00182 
00183 int CImageTIFF::GetWidth (void)
00184 {
00185   return width;
00186 }
00187 
00188 int CImageTIFF::GetHeight (void)
00189 {
00190   return height;
00191 }
00192 
00193 
00194 //
00195 // Read data from the TIF stream.  The bigEndian argument is true if
00196 //   data is stored in the file as big-Endian
00197 //
00198 static short tifRead16 (PODFILE *p, bool bigEndian)
00199 {
00200   short s;
00201   pread (&s, sizeof(short), 1, p);
00202   if (bigEndian) {
00203     s = BigEndian (s);
00204   } else {
00205     s = LittleEndian (s);
00206   }
00207   return s;
00208 }
00209 
00210 static long tifRead32 (PODFILE *p, bool bigEndian)
00211 {
00212   long v;
00213   pread (&v, sizeof(long), 1, p);
00214   if (bigEndian) {
00215     v = BigEndian (v);
00216   } else {
00217     v = LittleEndian (v);
00218   }
00219   return v;
00220 }
00221 
00222 typedef struct {
00223   unsigned short    endian;     // 'II' (Little Endian) or 'MM' (Big-Endian)
00224   unsigned short    signature;  // 0x0042 in appropriate endian-ness
00225   long              ifd;        // Image File Directory offset
00226 } TIFF_IFH;
00227 
00228 typedef struct {
00229   unsigned short    tag;
00230   unsigned short    type;
00231   unsigned long   count;
00232   unsigned long   offset;
00233 } TIFF_IFD_ENTRY;
00234 
00235 
00236 #define TIFF_TYPE_BYTE    (1)
00237 #define TIFF_TYPE_ASCII   (2)
00238 #define TIFF_TYPE_SHORT   (3)
00239 #define TIFF_TYPE_LONG    (4)
00240 #define TIFF_TYPE_RATIONAL  (5)
00241 
00242 #define TIFF_LITTLE_ENDIAN  (0x4949)
00243 #define TIFF_BIG_ENDIAN   (0x4D4D)
00244 #define TIFF_SIGNATURE    (42)
00245 
00246 #define TIFF_TAG_IMAGEWIDTH       (0x0100)
00247 #define TIFF_TAG_IMAGELENGTH      (0x0101)
00248 #define TIFF_TAG_BITSPERSAMPLE      (0x0102)
00249 #define TIFF_TAG_COMPRESSION      (0x0103)
00250 #define TIFF_TAG_INTERPRETATION     (0x0106)
00251 #define TIFF_TAG_STRIPOFFSETS     (0x0111)
00252 #define TIFF_TAG_SAMPLESPERPIXEL    (0x0115)
00253 #define TIFF_TAG_ROWSPERSTRIP     (0x0116)
00254 #define TIFF_TAG_STRIPBYTECOUNTS    (0x0117)
00255 #define TIFF_TAG_PLANARCONFIGURATION  (0x011C)
00256 #define TIFF_TAG_COLORMAP       (0x0140)
00257 
00258 
00259 typedef enum {
00260   TIFF_UNKNOWN,
00261   TIFF_RGB,
00262   TIFF_CMAP
00263 } ETiffImageType;
00264 
00265 
00266 CImageTIFF::CImageTIFF (const char* tifFilename)
00267 {
00268   int i, j, k;
00269  
00270   // Locals for image information
00271   unsigned long   bps = 0;
00272   unsigned long   spp = 0;
00273   ETiffImageType  type = TIFF_UNKNOWN;
00274   unsigned short  num_strips = 0;
00275   unsigned long  *strip_offsets = NULL;
00276   unsigned long   rows_per_strip = 0;
00277   unsigned long  *bytes_per_strip = NULL;
00278   unsigned long   cmap_size = 0;
00279   unsigned long   cmap_offset = 0;
00280 
00281   // Initialize class members
00282   image = NULL;
00283   width = height = 0;
00284   texid = 0;
00285 
00286   // Open POD file
00287   PODFILE *p = popen (&globals->pfs, tifFilename);
00288   if (p == NULL) {
00289     gtfo ("CImageTIFF : Failed to open file %s", tifFilename);
00290   }
00291 
00292   // Read image file header
00293   TIFF_IFH ifh;
00294   pread (&ifh, sizeof(TIFF_IFH), 1, p);
00295   bool bigEndian = false;
00296   switch (ifh.endian) {
00297   case TIFF_LITTLE_ENDIAN:
00298     ifh.signature = LittleEndian (ifh.signature);
00299     ifh.ifd = LittleEndian (ifh.ifd);
00300     break;
00301 
00302   case TIFF_BIG_ENDIAN:
00303     bigEndian = true;
00304     ifh.signature = BigEndian (ifh.signature);
00305     ifh.ifd = BigEndian (ifh.ifd);
00306     break;
00307 
00308   default:
00309     // Error
00310     gtfo ("ssgLoadTIF : Invalid endian tag 0x%04X in image file header", ifh.endian);
00311   }
00312 
00313   // Double-check signature
00314   if (ifh.signature != TIFF_SIGNATURE) {
00315     // Error
00316     gtfo ("ssgLoadTIF : Incorrect TIFF signature");
00317   }
00318 
00319   // Read number of directory entries
00320   pseek (p, ifh.ifd, SEEK_SET);
00321   unsigned short nEntries = (unsigned short) tifRead16 (p, bigEndian);
00322 
00323   // Read directory entries
00324   TIFF_IFD_ENTRY *entry = new TIFF_IFD_ENTRY[nEntries];
00325   for (i=0; i<nEntries; i++) {
00326     TIFF_IFD_ENTRY* ifd = &entry[i];
00327     ifd->tag = tifRead16 (p, bigEndian);
00328     ifd->type = tifRead16 (p, bigEndian);
00329     ifd->count = tifRead32 (p, bigEndian);
00330     ifd->offset = tifRead32 (p, bigEndian);
00331 
00332     // Parse tag
00333     switch (ifd->tag) {
00334     case TIFF_TAG_IMAGEWIDTH:
00335       // Image width
00336       switch (ifd->type) {
00337       case TIFF_TYPE_SHORT:
00338         width = (short)ifd->offset;
00339         break;
00340       case TIFF_TYPE_LONG:
00341         width = (long)ifd->offset;
00342         break;
00343       }
00344       break;
00345 
00346     case TIFF_TAG_IMAGELENGTH:
00347       // Image height
00348       switch (ifd->type) {
00349       case TIFF_TYPE_SHORT:
00350         height = (unsigned short)ifd->offset;
00351         break;
00352       case TIFF_TYPE_LONG:
00353         height = (unsigned long)ifd->offset;
00354         break;
00355       }
00356       break;
00357 
00358     case TIFF_TAG_BITSPERSAMPLE:
00359       // Bits per sample.  For palette images this is typically 8.  For RGB,
00360       //   it may be 8,8,8 or some other combination of bits for the red,
00361       //   green and blue channels.
00362       bps = ifd->offset;
00363       break;
00364 
00365     case TIFF_TAG_COMPRESSION:
00366       // Only uncompressed images are supported
00367       if (ifd->offset != 1) {
00368         gtfo ("ssgLoadTIF : Compressed images not supported");
00369       }
00370       break;
00371 
00372     case TIFF_TAG_INTERPRETATION:
00373       switch (ifd->offset) {
00374       case 0:
00375         // Monochrome, 0 is White
00376         gtfo ("ssgLoadTIF : Monochrome images not supported");
00377         break;
00378 
00379       case 1:
00380         // Monochrome, 0 is Black
00381         gtfo ("ssgLoadTIF : Monochrome images not supported");
00382         break;
00383 
00384       case 2:
00385         // RGB
00386         type = TIFF_RGB;
00387         break;
00388 
00389       case 3:
00390         // Palette color
00391         type = TIFF_CMAP;
00392         break;
00393 
00394       case 4:
00395         // Transparency mask
00396         gtfo ("ssgLoadTIF : Transparency mask not supported");
00397         break;
00398       }
00399       break;
00400 
00401     case TIFF_TAG_STRIPOFFSETS:
00402       {
00403         // Data offsets for each strip
00404         num_strips = ifd->count;
00405         strip_offsets = new unsigned long[num_strips];
00406 
00407         if (num_strips == 1) {
00408           strip_offsets[0] = ifd->offset;
00409         } else {
00410           long tell = ptell (p);
00411           // Set file pointer to read strip offset data
00412           pseek (p, ifd->offset, SEEK_SET);
00413           switch (ifd->type) {
00414           case TIFF_TYPE_SHORT:
00415             // Offsets are short integers, must be read one at a time and converted to long
00416             for (j=0; j<num_strips; j++) {
00417               short s = tifRead16 (p, bigEndian);
00418               strip_offsets[j] = (long)s;
00419             }
00420             break;
00421           case TIFF_TYPE_LONG:
00422             // Offsets are long integers
00423             for (j=0; j<num_strips; j++) {
00424               strip_offsets[j] = tifRead32 (p, bigEndian);
00425             }
00426           }
00427           // Restore file pointer to read next directory entry
00428           pseek (p, tell, SEEK_SET);
00429         }
00430       }
00431       break;
00432 
00433     case TIFF_TAG_ROWSPERSTRIP:
00434       // Number of rows represented by each strip
00435       rows_per_strip = ifd->offset;
00436       break;
00437 
00438     case TIFF_TAG_STRIPBYTECOUNTS:
00439       {
00440         // Number of bytes in each strip
00441         num_strips = ifd->count;
00442         bytes_per_strip = new unsigned long[num_strips];
00443 
00444         if (num_strips == 1) {
00445           bytes_per_strip[0] = ifd->offset;
00446         } else {
00447           long tell = ptell (p);
00448           pseek (p, ifd->offset, SEEK_SET);
00449           switch (ifd->type) {
00450           case TIFF_TYPE_SHORT:
00451             for (j=0; j<(int)ifd->count; j++) {
00452               short s = tifRead16 (p, bigEndian);
00453               bytes_per_strip[j] = (long)s;
00454             }
00455             break;
00456           case TIFF_TYPE_LONG:
00457             for (j=0; j<(int)ifd->count; j++) {
00458               bytes_per_strip[j] = tifRead32 (p, bigEndian);
00459             }
00460             break;
00461           }
00462           // Restore file pointer to read next directory entry
00463           pseek (p, tell, SEEK_SET);
00464         }
00465       }
00466       break;
00467 
00468     case TIFF_TAG_SAMPLESPERPIXEL:
00469       // Samples per pixel, only used for RGB images
00470       spp = ifd->offset;
00471       break;
00472 
00473     case TIFF_TAG_PLANARCONFIGURATION:
00474       // Planar configuration for RGB images
00475       switch (ifd->offset) {
00476       case 1:
00477         // Chunky configuration, RGBRGBRGB...
00478         break;
00479 
00480       case 2:
00481         // Planar format, not supported
00482         gtfo ("ssgLoadTIF : Planar format not supported");
00483         break;
00484       }
00485       break;
00486 
00487     case TIFF_TAG_COLORMAP:
00488       // Color map, only used for palettized images
00489       // Color map is a table of shorts, all R followed by all G then all B
00490       cmap_size = ifd->count;
00491       cmap_offset = ifd->offset;
00492       break;
00493     }
00494   }
00495 
00496   // Verify that an image format was included in the directory entries
00497   if (type == TIFF_UNKNOWN) {
00498     gtfo ("ssgLoadTIF : No photometric interpretation type");
00499   }
00500 
00501   // Allocate storage for the image
00502   depth = 4;
00503   image = new GLubyte[width*height*depth];
00504   memset (image, 0, width*height*depth);
00505 
00506   // Allocate storage for colormap; this is only used if the image is TIFF_CMAP
00507   typedef struct {
00508     GLubyte r, g, b;
00509   } RGB;
00510   RGB *pal = new RGB[0x100];
00511 
00512   // Read the image data
00513   switch (type) {
00514   case TIFF_CMAP:
00515     {
00516       // Read the colormap
00517       pseek (p, cmap_offset, SEEK_SET);
00518 //      long tell = ftell (p->pFile);
00519       
00520       // First come all red values
00521       for (i=0; i<0x100; i++) {
00522         short s;
00523         pread (&s, sizeof(short), 1, p);
00524         pal[i].r = (GLubyte)s;
00525       }
00526 
00527       // Next all green values
00528       for (i=0; i<0x100; i++) {
00529         short s;
00530         pread (&s, sizeof(short), 1, p);
00531         pal[i].g = (GLubyte)s;
00532       }
00533 
00534       // Last all blue values
00535       for (i=0; i<0x100; i++) {
00536         short s;
00537         pread (&s, sizeof(short), 1, p);
00538         pal[i].b = (GLubyte)s;
00539       }
00540 
00541       // Read the strip data
00542       for (i=0; i<num_strips; i++) {
00543         GLubyte *strip_data = new GLubyte[bytes_per_strip[i]];
00544         pseek (p, strip_offsets[i], SEEK_SET);
00545         pread (strip_data, sizeof(GLubyte), bytes_per_strip[i], p);
00546 
00547 //        unsigned long bytes_per_row = bytes_per_strip[i] / rows_per_strip;
00548 //        unsigned long pixels_per_strip = bytes_per_strip[i] / spp;
00549         int iData = 0;
00550         for (j=0; j<(int)rows_per_strip; j++) {
00551           for (k=0; k<width; k++) {
00552             unsigned long imageRow = (i * rows_per_strip) + j;
00553             unsigned long imageCol = k;
00554             unsigned long iImage = ((imageRow * width) + imageCol) * depth;
00555 
00556             // Read RGB sample per pixel
00557             GLubyte pi = strip_data[iData++];
00558             image [iImage + 0] = pal[pi].r;
00559             image [iImage + 1] = pal[pi].g;
00560             image [iImage + 2] = pal[pi].b;
00561 
00562             // If two samples per pixel, read alpha channel
00563             if (spp == 2) {
00564               GLubyte a = strip_data[iData++];
00565               image [iImage + 3] = a;
00566             } else {
00567               // No alpha channel
00568               image [iImage + 3] = 0;
00569             }
00570           }
00571         }
00572         delete strip_data;
00573       }
00574     }
00575 
00576     break;
00577 
00578   case TIFF_RGB:
00579     // This an RBG image, read the strip data
00580     break;
00581     
00582   default:
00583     // Unsupported TIF image type
00584     gtfo ("CImageTIFF : Unsupported TIF image type %d in %s", type, tifFilename);
00585   }
00586 
00587   // Clean up temporary storage
00588   delete entry;
00589   delete pal;
00590   delete strip_offsets;
00591   delete bytes_per_strip;
00592 
00593   pclose (p);
00594 }
00595 
00596 CImageTIFF::~CImageTIFF (void)
00597 {
00598   if (image != NULL) delete image;
00599 }
00600 
SourceForge.net Logo Documentation generated by doxygen