LCOV - code coverage report
Current view: directory - frmts/gif - gifdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 312 224 71.8 %
Date: 2010-01-09 Functions: 21 19 90.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: gifdataset.cpp 17689 2009-09-25 17:23:37Z rouault $
       3                 :  *
       4                 :  * Project:  GIF Driver
       5                 :  * Purpose:  Implement GDAL GIF Support using libungif code.  
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2001, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "cpl_string.h"
      32                 : 
      33                 : CPL_CVSID("$Id: gifdataset.cpp 17689 2009-09-25 17:23:37Z rouault $");
      34                 : 
      35                 : CPL_C_START
      36                 : #include "gif_lib.h"
      37                 : CPL_C_END
      38                 : 
      39                 : CPL_C_START
      40                 : void  GDALRegister_GIF(void);
      41                 : 
      42                 : // This prototype seems to have been messed up!
      43                 : GifFileType * EGifOpen(void* userData, OutputFunc writeFunc);
      44                 : CPL_C_END
      45                 : 
      46                 : static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
      47                 : static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
      48                 : 
      49                 : static int VSIGIFReadFunc( GifFileType *, GifByteType *, int);
      50                 : static int VSIGIFWriteFunc( GifFileType *, const GifByteType *, int );
      51                 : 
      52                 : /************************************************************************/
      53                 : /* ==================================================================== */
      54                 : /*        GIFDataset        */
      55                 : /* ==================================================================== */
      56                 : /************************************************************************/
      57                 : 
      58                 : class GIFRasterBand;
      59                 : 
      60                 : class GIFDataset : public GDALPamDataset
      61                 : {
      62                 :     friend class GIFRasterBand;
      63                 : 
      64                 :     FILE        *fp;
      65                 : 
      66                 :     GifFileType *hGifFile;
      67                 : 
      68                 :     char        *pszProjection;
      69                 :     int         bGeoTransformValid;
      70                 :     double      adfGeoTransform[6];
      71                 : 
      72                 :     int         nGCPCount;
      73                 :     GDAL_GCP  *pasGCPList;
      74                 : 
      75                 :   public:
      76                 :                  GIFDataset();
      77                 :                  ~GIFDataset();
      78                 : 
      79                 :     virtual const char *GetProjectionRef();
      80                 :     virtual CPLErr GetGeoTransform( double * );
      81                 :     virtual int    GetGCPCount();
      82                 :     virtual const char *GetGCPProjection();
      83                 :     virtual const GDAL_GCP *GetGCPs();
      84                 :     static GDALDataset *Open( GDALOpenInfo * );
      85                 :     static int          Identify( GDALOpenInfo * );
      86                 : };
      87                 : 
      88                 : /************************************************************************/
      89                 : /* ==================================================================== */
      90                 : /*                            GIFRasterBand                             */
      91                 : /* ==================================================================== */
      92                 : /************************************************************************/
      93                 : 
      94                 : class GIFRasterBand : public GDALPamRasterBand
      95                 : {
      96                 :     friend class GIFDataset;
      97                 : 
      98                 :     SavedImage  *psImage;
      99                 : 
     100                 :     int   *panInterlaceMap;
     101                 :     
     102                 :     GDALColorTable *poColorTable;
     103                 : 
     104                 :     int   nTransparentColor;
     105                 : 
     106                 :   public:
     107                 : 
     108                 :                    GIFRasterBand( GIFDataset *, int, SavedImage *, int );
     109                 :     virtual       ~GIFRasterBand();
     110                 : 
     111                 :     virtual CPLErr IReadBlock( int, int, void * );
     112                 : 
     113                 :     virtual double GetNoDataValue( int *pbSuccess = NULL );
     114                 :     virtual GDALColorInterp GetColorInterpretation();
     115                 :     virtual GDALColorTable *GetColorTable();
     116                 : };
     117                 : 
     118                 : /************************************************************************/
     119                 : /*                           GIFRasterBand()                            */
     120                 : /************************************************************************/
     121                 : 
     122              23 : GIFRasterBand::GIFRasterBand( GIFDataset *poDS, int nBand, 
     123              23 :                               SavedImage *psSavedImage, int nBackground )
     124                 : 
     125                 : {
     126              23 :     this->poDS = poDS;
     127              23 :     this->nBand = nBand;
     128                 : 
     129              23 :     eDataType = GDT_Byte;
     130                 : 
     131              23 :     nBlockXSize = poDS->nRasterXSize;
     132              23 :     nBlockYSize = 1;
     133                 : 
     134              23 :     psImage = psSavedImage;
     135                 : 
     136                 : /* -------------------------------------------------------------------- */
     137                 : /*      Setup interlacing map if required.                              */
     138                 : /* -------------------------------------------------------------------- */
     139              23 :     panInterlaceMap = NULL;
     140              23 :     if( psImage->ImageDesc.Interlace )
     141                 :     {
     142               8 :         int i, j, iLine = 0;
     143                 : 
     144               8 :         panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
     145                 : 
     146              40 :   for (i = 0; i < 4; i++)
     147                 :         {
     148            6432 :       for (j = InterlacedOffset[i]; 
     149                 :                  j < poDS->nRasterYSize;
     150            3200 :                  j += InterlacedJumps[i]) 
     151            3200 :                 panInterlaceMap[j] = iLine++;
     152                 :         }
     153                 :     }
     154                 : 
     155                 : /* -------------------------------------------------------------------- */
     156                 : /*      Check for transparency.  We just take the first graphic         */
     157                 : /*      control extension block we find, if any.                        */
     158                 : /* -------------------------------------------------------------------- */
     159                 :     int iExtBlock;
     160                 : 
     161              23 :     nTransparentColor = -1;
     162              26 :     for( iExtBlock = 0; iExtBlock < psImage->ExtensionBlockCount; iExtBlock++ )
     163                 :     {
     164                 :         unsigned char *pExtData;
     165                 : 
     166               3 :         if( psImage->ExtensionBlocks[iExtBlock].Function != 0xf9 )
     167               0 :             continue;
     168                 : 
     169               3 :         pExtData = (unsigned char *) psImage->ExtensionBlocks[iExtBlock].Bytes;
     170                 : 
     171                 :         /* check if transparent color flag is set */
     172               3 :         if( !(pExtData[0] & 0x1) )
     173               0 :             continue;
     174                 : 
     175               3 :         nTransparentColor = pExtData[3];
     176                 :     }
     177                 : 
     178                 : /* -------------------------------------------------------------------- */
     179                 : /*      Setup colormap.                                                 */
     180                 : /* -------------------------------------------------------------------- */
     181              23 :     ColorMapObject  *psGifCT = psImage->ImageDesc.ColorMap;
     182              23 :     if( psGifCT == NULL )
     183              23 :         psGifCT = poDS->hGifFile->SColorMap;
     184                 : 
     185              23 :     poColorTable = new GDALColorTable();
     186            3143 :     for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
     187                 :     {
     188                 :         GDALColorEntry  oEntry;
     189                 : 
     190            3120 :         oEntry.c1 = psGifCT->Colors[iColor].Red;
     191            3120 :         oEntry.c2 = psGifCT->Colors[iColor].Green;
     192            3120 :         oEntry.c3 = psGifCT->Colors[iColor].Blue;
     193                 : 
     194            3120 :         if( iColor == nTransparentColor )
     195               3 :             oEntry.c4 = 0;
     196                 :         else
     197            3117 :             oEntry.c4 = 255;
     198                 : 
     199            3120 :         poColorTable->SetColorEntry( iColor, &oEntry );
     200                 :     }
     201                 : 
     202                 : /* -------------------------------------------------------------------- */
     203                 : /*      If we have a background value, return it here.  Some            */
     204                 : /*      applications might want to treat this as transparent, but in    */
     205                 : /*      many uses this is inappropriate so we don't return it as        */
     206                 : /*      nodata or transparent.                                          */
     207                 : /* -------------------------------------------------------------------- */
     208              23 :     if( nBackground != 255 )
     209                 :     {
     210                 :         char szBackground[10];
     211                 :         
     212              13 :         sprintf( szBackground, "%d", nBackground );
     213              13 :         SetMetadataItem( "GIF_BACKGROUND", szBackground );
     214                 :     }
     215              23 : }
     216                 : 
     217                 : /************************************************************************/
     218                 : /*                           ~GIFRasterBand()                           */
     219                 : /************************************************************************/
     220                 : 
     221              46 : GIFRasterBand::~GIFRasterBand()
     222                 : 
     223                 : {
     224              23 :     if( poColorTable != NULL )
     225              23 :         delete poColorTable;
     226                 : 
     227              23 :     CPLFree( panInterlaceMap );
     228              46 : }
     229                 : 
     230                 : /************************************************************************/
     231                 : /*                             IReadBlock()                             */
     232                 : /************************************************************************/
     233                 : 
     234            3089 : CPLErr GIFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     235                 :                                   void * pImage )
     236                 : 
     237                 : {
     238                 :     CPLAssert( nBlockXOff == 0 );
     239                 : 
     240            3089 :     if( panInterlaceMap != NULL )
     241            1600 :         nBlockYOff = panInterlaceMap[nBlockYOff];
     242                 : 
     243                 :     memcpy( pImage, psImage->RasterBits + nBlockYOff * nBlockXSize, 
     244            3089 :             nBlockXSize );
     245                 : 
     246            3089 :     return CE_None;
     247                 : }
     248                 : 
     249                 : /************************************************************************/
     250                 : /*                       GetColorInterpretation()                       */
     251                 : /************************************************************************/
     252                 : 
     253              11 : GDALColorInterp GIFRasterBand::GetColorInterpretation()
     254                 : 
     255                 : {
     256              11 :     return GCI_PaletteIndex;
     257                 : }
     258                 : 
     259                 : /************************************************************************/
     260                 : /*                           GetColorTable()                            */
     261                 : /************************************************************************/
     262                 : 
     263            1622 : GDALColorTable *GIFRasterBand::GetColorTable()
     264                 : 
     265                 : {
     266            1622 :     return poColorTable;
     267                 : }
     268                 : 
     269                 : /************************************************************************/
     270                 : /*                           GetNoDataValue()                           */
     271                 : /************************************************************************/
     272                 : 
     273              16 : double GIFRasterBand::GetNoDataValue( int *pbSuccess )
     274                 : 
     275                 : {
     276              16 :     if( pbSuccess != NULL )
     277              16 :         *pbSuccess = nTransparentColor != -1;
     278                 : 
     279              16 :     return nTransparentColor;
     280                 : }
     281                 : 
     282                 : /************************************************************************/
     283                 : /* ==================================================================== */
     284                 : /*                             GIFDataset                               */
     285                 : /* ==================================================================== */
     286                 : /************************************************************************/
     287                 : 
     288                 : 
     289                 : /************************************************************************/
     290                 : /*                            GIFDataset()                            */
     291                 : /************************************************************************/
     292                 : 
     293              23 : GIFDataset::GIFDataset()
     294                 : 
     295                 : {
     296              23 :     hGifFile = NULL;
     297              23 :     fp = NULL;
     298                 : 
     299              23 :     pszProjection = NULL;
     300              23 :     bGeoTransformValid = FALSE;
     301              23 :     adfGeoTransform[0] = 0.0;
     302              23 :     adfGeoTransform[1] = 1.0;
     303              23 :     adfGeoTransform[2] = 0.0;
     304              23 :     adfGeoTransform[3] = 0.0;
     305              23 :     adfGeoTransform[4] = 0.0;
     306              23 :     adfGeoTransform[5] = 1.0;
     307                 : 
     308              23 :     nGCPCount = 0;
     309              23 :     pasGCPList = NULL;
     310              23 : }
     311                 : 
     312                 : /************************************************************************/
     313                 : /*                           ~GIFDataset()                            */
     314                 : /************************************************************************/
     315                 : 
     316              46 : GIFDataset::~GIFDataset()
     317                 : 
     318                 : {
     319              23 :     FlushCache();
     320                 : 
     321              23 :     if ( pszProjection )
     322               0 :         CPLFree( pszProjection );
     323                 : 
     324              23 :     if ( nGCPCount > 0 )
     325                 :     {
     326               0 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     327               0 :         CPLFree( pasGCPList );
     328                 :     }
     329                 : 
     330              23 :     if( hGifFile )
     331              23 :         DGifCloseFile( hGifFile );
     332                 : 
     333              23 :     if( fp != NULL )
     334              23 :         VSIFCloseL( fp );
     335              46 : }
     336                 : 
     337                 : /************************************************************************/
     338                 : /*                        GetProjectionRef()                            */
     339                 : /************************************************************************/
     340                 : 
     341              16 : const char *GIFDataset::GetProjectionRef()
     342                 : 
     343                 : {
     344              16 :     if ( pszProjection && bGeoTransformValid )
     345               0 :         return pszProjection;
     346                 :     else
     347              16 :         return GDALPamDataset::GetProjectionRef();
     348                 : }
     349                 : 
     350                 : /************************************************************************/
     351                 : /*                          GetGeoTransform()                           */
     352                 : /************************************************************************/
     353                 : 
     354              21 : CPLErr GIFDataset::GetGeoTransform( double * padfTransform )
     355                 : 
     356                 : {
     357              21 :     if( bGeoTransformValid )
     358                 :     {
     359               0 :         memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
     360               0 :         return CE_None;
     361                 :     }
     362                 :     else
     363              21 :         return GDALPamDataset::GetGeoTransform( padfTransform );
     364                 : }
     365                 : 
     366                 : /************************************************************************/
     367                 : /*                            GetGCPCount()                             */
     368                 : /************************************************************************/
     369                 : 
     370               5 : int GIFDataset::GetGCPCount()
     371                 : 
     372                 : {
     373               5 :     if (nGCPCount > 0)
     374               0 :         return nGCPCount;
     375                 :     else
     376               5 :         return GDALPamDataset::GetGCPCount();
     377                 : }
     378                 : 
     379                 : /************************************************************************/
     380                 : /*                          GetGCPProjection()                          */
     381                 : /************************************************************************/
     382                 : 
     383               0 : const char *GIFDataset::GetGCPProjection()
     384                 : 
     385                 : {
     386               0 :     if ( pszProjection && nGCPCount > 0 )
     387               0 :         return pszProjection;
     388                 :     else
     389               0 :         return GDALPamDataset::GetGCPProjection();
     390                 : }
     391                 : 
     392                 : /************************************************************************/
     393                 : /*                               GetGCPs()                              */
     394                 : /************************************************************************/
     395                 : 
     396               0 : const GDAL_GCP *GIFDataset::GetGCPs()
     397                 : 
     398                 : {
     399               0 :     if (nGCPCount > 0)
     400               0 :         return pasGCPList;
     401                 :     else
     402               0 :         return GDALPamDataset::GetGCPs();
     403                 : }
     404                 : 
     405                 : /************************************************************************/
     406                 : /*                                Open()                                */
     407                 : /************************************************************************/
     408                 : 
     409            9381 : int GIFDataset::Identify( GDALOpenInfo * poOpenInfo )
     410                 : 
     411                 : {
     412            9381 :     if( poOpenInfo->nHeaderBytes < 8 )
     413            8589 :         return FALSE;
     414                 : 
     415             792 :     if( strncmp((const char *) poOpenInfo->pabyHeader, "GIF87a",5) != 0
     416                 :         && strncmp((const char *) poOpenInfo->pabyHeader, "GIF89a",5) != 0 )
     417             768 :         return FALSE;
     418                 : 
     419              24 :     return TRUE;
     420                 : }
     421                 : 
     422                 : /************************************************************************/
     423                 : /*                                Open()                                */
     424                 : /************************************************************************/
     425                 : 
     426            1658 : GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
     427                 : 
     428                 : {
     429            1658 :     if( !Identify( poOpenInfo ) )
     430            1634 :         return NULL;
     431                 : 
     432              24 :     if( poOpenInfo->eAccess == GA_Update )
     433                 :     {
     434                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     435                 :                   "The GIF driver does not support update access to existing"
     436               0 :                   " files.\n" );
     437               0 :         return NULL;
     438                 :     }
     439                 : 
     440                 : /* -------------------------------------------------------------------- */
     441                 : /*      Open the file and ingest.                                       */
     442                 : /* -------------------------------------------------------------------- */
     443                 :     GifFileType   *hGifFile;
     444                 :     FILE                *fp;
     445                 :     int                  nGifErr;
     446                 : 
     447              24 :     fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
     448              24 :     if( fp == NULL )
     449               0 :         return NULL;
     450                 : 
     451              24 :     hGifFile = DGifOpen( fp, VSIGIFReadFunc );
     452              24 :     if( hGifFile == NULL )
     453                 :     {
     454               0 :         VSIFCloseL( fp );
     455                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     456                 :                   "DGifOpen() failed for %s.\n"
     457                 :                   "Perhaps the gif file is corrupt?\n",
     458               0 :                   poOpenInfo->pszFilename );
     459                 : 
     460               0 :         return NULL;
     461                 :     }
     462                 : 
     463                 :     /* The following code enables us to detect GIF datasets eligible */
     464                 :     /* for BIGGIF driver even with an unpatched giflib  */
     465                 : 
     466                 :     /* -------------------------------------------------------------------- */
     467                 :     /*      Find the first image record.                                    */
     468                 :     /* -------------------------------------------------------------------- */
     469              24 :     GifRecordType RecordType = TERMINATE_RECORD_TYPE;
     470                 : 
     471              27 :     while( DGifGetRecordType(hGifFile, &RecordType) != GIF_ERROR
     472                 :         && RecordType != TERMINATE_RECORD_TYPE
     473                 :         && RecordType != IMAGE_DESC_RECORD_TYPE ) {}
     474                 : 
     475              24 :     if( RecordType == IMAGE_DESC_RECORD_TYPE  &&
     476                 :         DGifGetImageDesc(hGifFile) != GIF_ERROR)
     477                 :     {
     478              21 :         int width = hGifFile->SavedImages[0].ImageDesc.Width;
     479              21 :         int height = hGifFile->SavedImages[0].ImageDesc.Height;
     480              21 :         if ((double) width * (double) height > 100000000.0 )
     481                 :         {
     482                 :             CPLDebug( "GIF",
     483                 :                       "Due to limitations of the GDAL GIF driver we deliberately avoid\n"
     484               1 :                       "opening large GIF files (larger than 100 megapixels).");
     485               1 :             DGifCloseFile( hGifFile );
     486               1 :             VSIFCloseL( fp );
     487               1 :             return NULL;
     488                 :         }
     489                 :     }
     490                 : 
     491              23 :     DGifCloseFile( hGifFile );
     492                 : 
     493              23 :     VSIFSeekL( fp, 0, SEEK_SET);
     494              23 :     hGifFile = DGifOpen( fp, VSIGIFReadFunc );
     495              23 :     if( hGifFile == NULL )
     496                 :     {
     497               0 :         VSIFCloseL( fp );
     498                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     499                 :                   "DGifOpen() failed for %s.\n"
     500                 :                   "Perhaps the gif file is corrupt?\n",
     501               0 :                   poOpenInfo->pszFilename );
     502                 : 
     503               0 :         return NULL;
     504                 :     }
     505                 : 
     506              23 :     nGifErr = DGifSlurp( hGifFile );
     507                 : 
     508              23 :     if( nGifErr != GIF_OK )
     509                 :     {
     510               0 :         VSIFCloseL( fp );
     511               0 :         DGifCloseFile(hGifFile);
     512                 : 
     513               0 :         if( nGifErr == D_GIF_ERR_DATA_TOO_BIG )
     514                 :         {
     515                 :              CPLDebug( "GIF",
     516                 :                        "DGifSlurp() failed for %s because it was too large.\n"
     517                 :                        "Due to limitations of the GDAL GIF driver we deliberately avoid\n"
     518                 :                        "opening large GIF files (larger than 100 megapixels).",
     519               0 :                        poOpenInfo->pszFilename );
     520               0 :             return NULL;
     521                 :          }
     522                 :          else
     523                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     524                 :                         "DGifSlurp() failed for %s.\n"
     525                 :                         "Perhaps the gif file is corrupt?\n",
     526               0 :                         poOpenInfo->pszFilename );
     527                 : 
     528               0 :         return NULL;
     529                 :     }
     530                 : 
     531                 : /* -------------------------------------------------------------------- */
     532                 : /*      Create a corresponding GDALDataset.                             */
     533                 : /* -------------------------------------------------------------------- */
     534                 :     GIFDataset  *poDS;
     535                 : 
     536              23 :     poDS = new GIFDataset();
     537                 : 
     538              23 :     poDS->fp = fp;
     539              23 :     poDS->eAccess = GA_ReadOnly;
     540              23 :     poDS->hGifFile = hGifFile;
     541                 : 
     542                 : /* -------------------------------------------------------------------- */
     543                 : /*      Capture some information from the file that is of interest.     */
     544                 : /* -------------------------------------------------------------------- */
     545              23 :     poDS->nRasterXSize = hGifFile->SavedImages[0].ImageDesc.Width;
     546              23 :     poDS->nRasterYSize = hGifFile->SavedImages[0].ImageDesc.Height;
     547                 : 
     548                 : /* -------------------------------------------------------------------- */
     549                 : /*      Create band information objects.                                */
     550                 : /* -------------------------------------------------------------------- */
     551              46 :     for( int iImage = 0; iImage < hGifFile->ImageCount; iImage++ )
     552                 :     {
     553              23 :         SavedImage  *psImage = hGifFile->SavedImages + iImage;
     554                 : 
     555              23 :         if( psImage->ImageDesc.Width != poDS->nRasterXSize
     556                 :             || psImage->ImageDesc.Height != poDS->nRasterYSize )
     557               0 :             continue;
     558                 : 
     559                 :         poDS->SetBand( poDS->nBands+1, 
     560                 :                        new GIFRasterBand( poDS, poDS->nBands+1, psImage,
     561              23 :                                           hGifFile->SBackGroundColor ));
     562                 :     }
     563                 : 
     564                 : /* -------------------------------------------------------------------- */
     565                 : /*      Check for world file.                                           */
     566                 : /* -------------------------------------------------------------------- */
     567                 :     poDS->bGeoTransformValid = 
     568                 :         GDALReadWorldFile( poOpenInfo->pszFilename, NULL, 
     569              23 :                            poDS->adfGeoTransform );
     570              23 :     if ( !poDS->bGeoTransformValid )
     571                 :     {
     572                 :         poDS->bGeoTransformValid =
     573                 :             GDALReadWorldFile( poOpenInfo->pszFilename, ".wld", 
     574              23 :                                poDS->adfGeoTransform );
     575                 : 
     576              23 :         if ( !poDS->bGeoTransformValid )
     577                 :         {
     578                 :             int bOziFileOK = 
     579                 :                 GDALReadOziMapFile( poOpenInfo->pszFilename,
     580                 :                                     poDS->adfGeoTransform, 
     581                 :                                     &poDS->pszProjection,
     582              23 :                                     &poDS->nGCPCount, &poDS->pasGCPList );
     583                 : 
     584              23 :             if ( bOziFileOK && poDS->nGCPCount == 0 )
     585               0 :                  poDS->bGeoTransformValid = TRUE;
     586                 :         }
     587                 :     }
     588                 : 
     589                 : /* -------------------------------------------------------------------- */
     590                 : /*      Initialize any PAM information.                                 */
     591                 : /* -------------------------------------------------------------------- */
     592              23 :     poDS->SetDescription( poOpenInfo->pszFilename );
     593              23 :     poDS->TryLoadXML();
     594                 : 
     595                 : /* -------------------------------------------------------------------- */
     596                 : /*      Support overviews.                                              */
     597                 : /* -------------------------------------------------------------------- */
     598              23 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     599                 : 
     600              23 :     return poDS;
     601                 : }
     602                 : 
     603                 : /************************************************************************/
     604                 : /*                           GIFCreateCopy()                            */
     605                 : /************************************************************************/
     606                 : 
     607                 : static GDALDataset *
     608              19 : GIFCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     609                 :                int bStrict, char ** papszOptions, 
     610                 :                GDALProgressFunc pfnProgress, void * pProgressData )
     611                 : 
     612                 : {
     613              19 :     int  nBands = poSrcDS->GetRasterCount();
     614              19 :     int  nXSize = poSrcDS->GetRasterXSize();
     615              19 :     int  nYSize = poSrcDS->GetRasterYSize();
     616              19 :     int  bInterlace = FALSE;
     617                 : 
     618                 : /* -------------------------------------------------------------------- */
     619                 : /*      Check for interlaced option.                                    */
     620                 : /* -------------------------------------------------------------------- */
     621              19 :     bInterlace = CSLFetchBoolean(papszOptions, "INTERLACING", FALSE);
     622                 : 
     623                 : /* -------------------------------------------------------------------- */
     624                 : /*      Some some rudimentary checks                                    */
     625                 : /* -------------------------------------------------------------------- */
     626              19 :     if( nBands != 1 )
     627                 :     {
     628                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     629               5 :                   "GIF driver only supports one band images.\n" );
     630                 : 
     631               5 :         return NULL;
     632                 :     }
     633                 : 
     634              14 :     if (nXSize > 65535 || nYSize > 65535)
     635                 :     {
     636                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     637               0 :                   "GIF driver only supports datasets up to 65535x65535 size.\n" );
     638                 : 
     639               0 :         return NULL;
     640                 :     }
     641                 : 
     642              14 :     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
     643                 :         && bStrict )
     644                 :     {
     645                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     646                 :                   "GIF driver doesn't support data type %s. "
     647                 :                   "Only eight bit bands supported.\n", 
     648                 :                   GDALGetDataTypeName( 
     649              10 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     650                 : 
     651              10 :         return NULL;
     652                 :     }
     653                 : 
     654                 : /* -------------------------------------------------------------------- */
     655                 : /*      Open the output file.                                           */
     656                 : /* -------------------------------------------------------------------- */
     657                 :     GifFileType *hGifFile;
     658                 :     FILE *fp;
     659                 : 
     660               4 :     fp = VSIFOpenL( pszFilename, "w" );
     661               4 :     if( fp == NULL )
     662                 :     {
     663                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     664                 :                   "Failed to create %s:\n%s", 
     665               0 :                   pszFilename, VSIStrerror( errno ) );
     666               0 :         return NULL;
     667                 :     }
     668                 : 
     669               4 :     hGifFile = EGifOpen( fp, VSIGIFWriteFunc );
     670               4 :     if( hGifFile == NULL )
     671                 :     {
     672               0 :         VSIFCloseL( fp );
     673                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     674                 :                   "EGifOpenFilename(%s) failed.  Does file already exist?",
     675               0 :                   pszFilename );
     676                 : 
     677               0 :         return NULL;
     678                 :     }
     679                 : 
     680                 : /* -------------------------------------------------------------------- */
     681                 : /*      Prepare colortable.                                             */
     682                 : /* -------------------------------------------------------------------- */
     683               4 :     GDALRasterBand  *poBand = poSrcDS->GetRasterBand(1);
     684                 :     ColorMapObject  *psGifCT;
     685                 :     int     iColor;
     686                 : 
     687               4 :     if( poBand->GetColorTable() == NULL )
     688                 :     {
     689               3 :         psGifCT = MakeMapObject( 256, NULL );
     690             771 :         for( iColor = 0; iColor < 256; iColor++ )
     691                 :         {
     692             768 :             psGifCT->Colors[iColor].Red = (GifByteType) iColor;
     693             768 :             psGifCT->Colors[iColor].Green = (GifByteType) iColor;
     694             768 :             psGifCT->Colors[iColor].Blue = (GifByteType) iColor;
     695                 :         }
     696                 :     }
     697                 :     else
     698                 :     {
     699               1 :         GDALColorTable  *poCT = poBand->GetColorTable();
     700               1 :         int nFullCount = 1;
     701                 : 
     702               6 :         while( nFullCount < poCT->GetColorEntryCount() )
     703               4 :             nFullCount = nFullCount * 2;
     704                 : 
     705               1 :         psGifCT = MakeMapObject( nFullCount, NULL );
     706              17 :         for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ )
     707                 :         {
     708                 :             GDALColorEntry  sEntry;
     709                 : 
     710              16 :             poCT->GetColorEntryAsRGB( iColor, &sEntry );
     711              16 :             psGifCT->Colors[iColor].Red = (GifByteType) sEntry.c1;
     712              16 :             psGifCT->Colors[iColor].Green = (GifByteType) sEntry.c2;
     713              16 :             psGifCT->Colors[iColor].Blue = (GifByteType) sEntry.c3;
     714                 :         }
     715               1 :         for( ; iColor < nFullCount; iColor++ )
     716                 :         {
     717               0 :             psGifCT->Colors[iColor].Red = 0;
     718               0 :             psGifCT->Colors[iColor].Green = 0;
     719               0 :             psGifCT->Colors[iColor].Blue = 0;
     720                 :         }
     721                 :     }
     722                 : 
     723                 : /* -------------------------------------------------------------------- */
     724                 : /*      Setup parameters.                                               */
     725                 : /* -------------------------------------------------------------------- */
     726               4 :     if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 
     727                 :                           psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR)
     728                 :     {
     729               0 :         FreeMapObject(psGifCT);
     730               0 :         PrintGifError();
     731                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     732               0 :                   "Error writing gif file." );
     733               0 :         EGifCloseFile(hGifFile);
     734               0 :         VSIFCloseL( fp );
     735               0 :         return NULL;
     736                 :     }
     737                 :     
     738               4 :     FreeMapObject(psGifCT);
     739               4 :     psGifCT = NULL;
     740                 : 
     741                 :     /* Support for transparency */
     742                 :     int bNoDataValue;
     743               4 :     double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
     744               4 :     if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
     745                 :     {
     746                 :         unsigned char extensionData[4];
     747               1 :         extensionData[0] = 1; /*  Transparent Color Flag */
     748               1 :         extensionData[1] = 0;
     749               1 :         extensionData[2] = 0;
     750               1 :         extensionData[3] = (unsigned char)noDataValue;
     751               1 :         EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
     752                 :     }
     753                 : 
     754               4 :     if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, NULL) == GIF_ERROR )
     755                 :     {
     756               0 :         PrintGifError();
     757                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     758               0 :                   "Error writing gif file." );
     759               0 :         EGifCloseFile(hGifFile);
     760               0 :         VSIFCloseL( fp );
     761               0 :         return NULL;
     762                 :     }
     763                 : 
     764                 : /* -------------------------------------------------------------------- */
     765                 : /*      Loop over image, copying image data.                            */
     766                 : /* -------------------------------------------------------------------- */
     767                 :     CPLErr      eErr;
     768                 :     GDALPamDataset *poDS;
     769                 :     GByte      *pabyScanline;
     770                 : 
     771               4 :     pabyScanline = (GByte *) CPLMalloc( nXSize );
     772                 : 
     773               4 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
     774               0 :         eErr = CE_Failure;
     775                 : 
     776               4 :     if( !bInterlace )
     777                 :     {
     778             454 :         for( int iLine = 0; iLine < nYSize; iLine++ )
     779                 :         {
     780                 :             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
     781                 :                                      pabyScanline, nXSize, 1, GDT_Byte,
     782             450 :                                      nBands, nBands * nXSize );
     783                 : 
     784             450 :             if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR )
     785                 :             {
     786                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     787               0 :                           "Error writing gif file." );
     788               0 :                 goto error;
     789                 :             }
     790                 : 
     791             450 :             if( !pfnProgress( (iLine + 1) * 1.0 / nYSize, NULL, pProgressData ) )
     792                 :             {
     793               0 :                 goto error;
     794                 :             }
     795                 : 
     796                 :         }
     797                 :     }
     798                 :     else
     799                 :     {
     800                 :         int   i, j;
     801               0 :         int nLinesRead = 0;
     802               0 :         int nLinesToRead = 0;
     803               0 :         for ( i = 0; i < 4; i++)
     804                 :         {
     805               0 :             for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
     806                 :             {
     807               0 :                 nLinesToRead ++;
     808                 :             }
     809                 :         }
     810                 : 
     811                 :         /* Need to perform 4 passes on the images: */
     812               0 :         for ( i = 0; i < 4; i++)
     813                 :         {
     814               0 :             for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
     815                 :             {
     816                 :                 eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, 
     817                 :                                         pabyScanline, nXSize, 1, GDT_Byte,
     818               0 :                                         1, nXSize );
     819                 : 
     820               0 :                 if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
     821                 :                 {
     822                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     823               0 :                             "Error writing gif file." );
     824               0 :                     goto error;
     825                 :                 }
     826                 : 
     827               0 :                 nLinesRead ++;
     828               0 :                 if( !pfnProgress( nLinesRead * 1.0 / nYSize, NULL, pProgressData ) )
     829                 :                 {
     830               0 :                     goto error;
     831                 :                 }
     832                 :             }
     833                 :         }
     834                 :     }
     835                 : 
     836               4 :     CPLFree( pabyScanline );
     837               4 :     pabyScanline = NULL;
     838                 : 
     839                 : /* -------------------------------------------------------------------- */
     840                 : /*      cleanup                                                         */
     841                 : /* -------------------------------------------------------------------- */
     842               4 :     if (EGifCloseFile(hGifFile) == GIF_ERROR)
     843                 :     {
     844                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     845               0 :                   "EGifCloseFile() failed.\n" );
     846               0 :         hGifFile = NULL;
     847               0 :         goto error;
     848                 :     }
     849               4 :     hGifFile = NULL;
     850                 : 
     851                 :     /* This is a hack to write a GIF89a instead of GIF87a */
     852                 :     /* (we have to, since we are using graphical extension block) */
     853                 :     /* EGifSpew would write GIF89a when it detects an extension block if we were using it */
     854                 :     /* As we don't, we could have used EGifSetGifVersion instead, but the version of libungif */
     855                 :     /* in GDAL has a bug : it writes on read-only memory ! */
     856                 :     /* (this is a well-known problem. Just google for "EGifSetGifVersion segfault") */
     857                 :     /* Most readers don't even care if it is GIF87a or GIF89a, but it is */
     858                 :     /* better to write the right version */
     859                 : 
     860               4 :     VSIFSeekL(fp, 0, SEEK_SET);
     861               4 :     if (VSIFWriteL("GIF89a", 1, 6, fp) != 6)
     862                 :     {
     863                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     864               0 :                   "Error writing gif file." );
     865               0 :         goto error;
     866                 :     }
     867                 : 
     868               4 :     VSIFCloseL( fp );
     869               4 :     fp = NULL;
     870                 : 
     871                 : /* -------------------------------------------------------------------- */
     872                 : /*      Do we need a world file?                                          */
     873                 : /* -------------------------------------------------------------------- */
     874               4 :     if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
     875                 :     {
     876                 :       double      adfGeoTransform[6];
     877                 :   
     878               0 :   if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
     879               0 :             GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
     880                 :     }
     881                 : 
     882                 : /* -------------------------------------------------------------------- */
     883                 : /*      Re-open dataset, and copy any auxilary pam information.         */
     884                 : /* -------------------------------------------------------------------- */
     885                 :     poDS = (GDALPamDataset *) 
     886               4 :         GDALOpen( pszFilename, GA_ReadOnly );
     887                 : 
     888               4 :     if( poDS )
     889               4 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
     890                 : 
     891               4 :     return poDS;
     892                 : 
     893                 : error:
     894               0 :     if (hGifFile)
     895               0 :         EGifCloseFile(hGifFile);
     896               0 :     if (fp)
     897               0 :         VSIFCloseL( fp );
     898               0 :     if (pabyScanline)
     899               0 :         CPLFree( pabyScanline );
     900               0 :     return NULL;
     901                 : }
     902                 : 
     903                 : /************************************************************************/
     904                 : /*                           VSIGIFReadFunc()                           */
     905                 : /*                                                                      */
     906                 : /*      Proxy function for reading from GIF file.                       */
     907                 : /************************************************************************/
     908                 : 
     909            8513 : static int VSIGIFReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
     910                 :                            int nBytesToRead )
     911                 : 
     912                 : {
     913                 :     return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
     914            8513 :                       (FILE *) psGFile->UserData );
     915                 : }
     916                 : 
     917                 : /************************************************************************/
     918                 : /*                          VSIGIFWriteFunc()                           */
     919                 : /*                                                                      */
     920                 : /*      Proxy write function.                                           */
     921                 : /************************************************************************/
     922                 : 
     923             872 : static int VSIGIFWriteFunc( GifFileType *psGFile, 
     924                 :                             const GifByteType *pabyBuffer, int nBytesToWrite )
     925                 : 
     926                 : {
     927                 :     return VSIFWriteL( (void *) pabyBuffer, 1, nBytesToWrite, 
     928             872 :                        (FILE *) psGFile->UserData );
     929                 : }
     930                 : 
     931                 : /************************************************************************/
     932                 : /*                          GDALRegister_GIF()                        */
     933                 : /************************************************************************/
     934                 : 
     935             338 : void GDALRegister_GIF()
     936                 : 
     937                 : {
     938                 :     GDALDriver  *poDriver;
     939                 : 
     940             338 :     if( GDALGetDriverByName( "GIF" ) == NULL )
     941                 :     {
     942             336 :         poDriver = new GDALDriver();
     943                 :         
     944             336 :         poDriver->SetDescription( "GIF" );
     945                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     946             336 :                                    "Graphics Interchange Format (.gif)" );
     947                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     948             336 :                                    "frmt_gif.html" );
     949             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gif" );
     950             336 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/gif" );
     951                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
     952             336 :                                    "Byte" );
     953                 : 
     954                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
     955                 : "<CreationOptionList>\n"
     956                 : "   <Option name='INTERLACING' type='boolean'/>\n"
     957                 : "   <Option name='WORLDFILE' type='boolean'/>\n"
     958             336 : "</CreationOptionList>\n" );
     959                 : 
     960             336 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     961                 : 
     962             336 :         poDriver->pfnOpen = GIFDataset::Open;
     963             336 :         poDriver->pfnCreateCopy = GIFCreateCopy;
     964             336 :         poDriver->pfnIdentify = GIFDataset::Identify;
     965                 : 
     966             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     967                 :     }
     968             338 : }
     969                 : 

Generated by: LCOV version 1.7