LCOV - code coverage report
Current view: directory - frmts/gif - gifdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 281 211 75.1 %
Date: 2012-04-28 Functions: 18 13 72.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: gifdataset.cpp 23621 2011-12-20 23:26:56Z 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                 : #include "gifabstractdataset.h"
      33                 : 
      34                 : CPL_CVSID("$Id: gifdataset.cpp 23621 2011-12-20 23:26:56Z rouault $");
      35                 : 
      36                 : CPL_C_START
      37                 : void  GDALRegister_GIF(void);
      38                 : 
      39                 : // This prototype seems to have been messed up!
      40                 : GifFileType * EGifOpen(void* userData, OutputFunc writeFunc);
      41                 : CPL_C_END
      42                 : 
      43                 : static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
      44                 : static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
      45                 : 
      46                 : static int VSIGIFReadFunc( GifFileType *, GifByteType *, int);
      47                 : static int VSIGIFWriteFunc( GifFileType *, const GifByteType *, int );
      48                 : 
      49                 : /************************************************************************/
      50                 : /* ==================================================================== */
      51                 : /*                              GIFDataset                              */
      52                 : /* ==================================================================== */
      53                 : /************************************************************************/
      54                 : 
      55                 : class GIFRasterBand;
      56                 : 
      57                 : class GIFDataset : public GIFAbstractDataset
      58              58 : {
      59                 :     friend class GIFRasterBand;
      60                 : 
      61                 :   public:
      62                 :                  GIFDataset();
      63                 : 
      64                 :     static GDALDataset *Open( GDALOpenInfo * );
      65                 : 
      66                 :     static GDALDataset* CreateCopy( const char * pszFilename,
      67                 :                                     GDALDataset *poSrcDS,
      68                 :                                     int bStrict, char ** papszOptions,
      69                 :                                     GDALProgressFunc pfnProgress,
      70                 :                                     void * pProgressData );
      71                 : 
      72                 : };
      73                 : 
      74                 : /************************************************************************/
      75                 : /* ==================================================================== */
      76                 : /*                            GIFRasterBand                             */
      77                 : /* ==================================================================== */
      78                 : /************************************************************************/
      79                 : 
      80                 : class GIFRasterBand : public GDALPamRasterBand
      81                 : {
      82                 :     friend class GIFDataset;
      83                 : 
      84                 :     SavedImage  *psImage;
      85                 : 
      86                 :     int   *panInterlaceMap;
      87                 :     
      88                 :     GDALColorTable *poColorTable;
      89                 : 
      90                 :     int   nTransparentColor;
      91                 : 
      92                 :   public:
      93                 : 
      94                 :                    GIFRasterBand( GIFDataset *, int, SavedImage *, int );
      95                 :     virtual       ~GIFRasterBand();
      96                 : 
      97                 :     virtual CPLErr IReadBlock( int, int, void * );
      98                 : 
      99                 :     virtual double GetNoDataValue( int *pbSuccess = NULL );
     100                 :     virtual GDALColorInterp GetColorInterpretation();
     101                 :     virtual GDALColorTable *GetColorTable();
     102                 : };
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                           GIFRasterBand()                            */
     106                 : /************************************************************************/
     107                 : 
     108              58 : GIFRasterBand::GIFRasterBand( GIFDataset *poDS, int nBand, 
     109              58 :                               SavedImage *psSavedImage, int nBackground )
     110                 : 
     111                 : {
     112              58 :     this->poDS = poDS;
     113              58 :     this->nBand = nBand;
     114                 : 
     115              58 :     eDataType = GDT_Byte;
     116                 : 
     117              58 :     nBlockXSize = poDS->nRasterXSize;
     118              58 :     nBlockYSize = 1;
     119                 : 
     120              58 :     psImage = psSavedImage;
     121                 : 
     122              58 :     poColorTable = NULL;
     123              58 :     panInterlaceMap = NULL;
     124              58 :     nTransparentColor = 0;
     125                 : 
     126              58 :     if (psImage == NULL)
     127               2 :         return;
     128                 : 
     129                 : /* -------------------------------------------------------------------- */
     130                 : /*      Setup interlacing map if required.                              */
     131                 : /* -------------------------------------------------------------------- */
     132              56 :     panInterlaceMap = NULL;
     133              56 :     if( psImage->ImageDesc.Interlace )
     134                 :     {
     135              22 :         int i, j, iLine = 0;
     136                 : 
     137              22 :         panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
     138                 : 
     139             110 :   for (i = 0; i < 4; i++)
     140                 :         {
     141           17688 :       for (j = InterlacedOffset[i]; 
     142                 :                  j < poDS->nRasterYSize;
     143            8800 :                  j += InterlacedJumps[i]) 
     144            8800 :                 panInterlaceMap[j] = iLine++;
     145                 :         }
     146                 :     }
     147                 : 
     148                 : /* -------------------------------------------------------------------- */
     149                 : /*      Check for transparency.  We just take the first graphic         */
     150                 : /*      control extension block we find, if any.                        */
     151                 : /* -------------------------------------------------------------------- */
     152                 :     int iExtBlock;
     153                 : 
     154              56 :     nTransparentColor = -1;
     155             240 :     for( iExtBlock = 0; iExtBlock < psImage->ExtensionBlockCount; iExtBlock++ )
     156                 :     {
     157                 :         unsigned char *pExtData;
     158                 : 
     159             184 :         if( psImage->ExtensionBlocks[iExtBlock].Function != 0xf9 )
     160             178 :             continue;
     161                 : 
     162               6 :         pExtData = (unsigned char *) psImage->ExtensionBlocks[iExtBlock].Bytes;
     163                 : 
     164                 :         /* check if transparent color flag is set */
     165               6 :         if( !(pExtData[0] & 0x1) )
     166               0 :             continue;
     167                 : 
     168               6 :         nTransparentColor = pExtData[3];
     169                 :     }
     170                 : 
     171                 : /* -------------------------------------------------------------------- */
     172                 : /*      Setup colormap.                                                 */
     173                 : /* -------------------------------------------------------------------- */
     174              56 :     ColorMapObject  *psGifCT = psImage->ImageDesc.ColorMap;
     175              56 :     if( psGifCT == NULL )
     176              56 :         psGifCT = poDS->hGifFile->SColorMap;
     177                 : 
     178              56 :     poColorTable = new GDALColorTable();
     179            7416 :     for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
     180                 :     {
     181                 :         GDALColorEntry  oEntry;
     182                 : 
     183            7360 :         oEntry.c1 = psGifCT->Colors[iColor].Red;
     184            7360 :         oEntry.c2 = psGifCT->Colors[iColor].Green;
     185            7360 :         oEntry.c3 = psGifCT->Colors[iColor].Blue;
     186                 : 
     187            7360 :         if( iColor == nTransparentColor )
     188               6 :             oEntry.c4 = 0;
     189                 :         else
     190            7354 :             oEntry.c4 = 255;
     191                 : 
     192            7360 :         poColorTable->SetColorEntry( iColor, &oEntry );
     193                 :     }
     194                 : 
     195                 : /* -------------------------------------------------------------------- */
     196                 : /*      If we have a background value, return it here.  Some            */
     197                 : /*      applications might want to treat this as transparent, but in    */
     198                 : /*      many uses this is inappropriate so we don't return it as        */
     199                 : /*      nodata or transparent.                                          */
     200                 : /* -------------------------------------------------------------------- */
     201              56 :     if( nBackground != 255 )
     202                 :     {
     203                 :         char szBackground[10];
     204                 :         
     205              32 :         sprintf( szBackground, "%d", nBackground );
     206              32 :         SetMetadataItem( "GIF_BACKGROUND", szBackground );
     207                 :     }
     208               0 : }
     209                 : 
     210                 : /************************************************************************/
     211                 : /*                           ~GIFRasterBand()                           */
     212                 : /************************************************************************/
     213                 : 
     214              58 : GIFRasterBand::~GIFRasterBand()
     215                 : 
     216                 : {
     217              58 :     if( poColorTable != NULL )
     218              56 :         delete poColorTable;
     219                 : 
     220              58 :     CPLFree( panInterlaceMap );
     221              58 : }
     222                 : 
     223                 : /************************************************************************/
     224                 : /*                             IReadBlock()                             */
     225                 : /************************************************************************/
     226                 : 
     227            7058 : CPLErr GIFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     228                 :                                   void * pImage )
     229                 : 
     230                 : {
     231            7058 :     CPLAssert( nBlockXOff == 0 );
     232                 : 
     233            7058 :     if (psImage == NULL)
     234                 :     {
     235              40 :         memset(pImage, 0, nBlockXSize);
     236              40 :         return CE_None;
     237                 :     }
     238                 : 
     239            7018 :     if( panInterlaceMap != NULL )
     240            4000 :         nBlockYOff = panInterlaceMap[nBlockYOff];
     241                 : 
     242                 :     memcpy( pImage, psImage->RasterBits + nBlockYOff * nBlockXSize, 
     243            7018 :             nBlockXSize );
     244                 : 
     245            7018 :     return CE_None;
     246                 : }
     247                 : 
     248                 : /************************************************************************/
     249                 : /*                       GetColorInterpretation()                       */
     250                 : /************************************************************************/
     251                 : 
     252              30 : GDALColorInterp GIFRasterBand::GetColorInterpretation()
     253                 : 
     254                 : {
     255              30 :     return GCI_PaletteIndex;
     256                 : }
     257                 : 
     258                 : /************************************************************************/
     259                 : /*                           GetColorTable()                            */
     260                 : /************************************************************************/
     261                 : 
     262            3242 : GDALColorTable *GIFRasterBand::GetColorTable()
     263                 : 
     264                 : {
     265            3242 :     return poColorTable;
     266                 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                           GetNoDataValue()                           */
     270                 : /************************************************************************/
     271                 : 
     272              46 : double GIFRasterBand::GetNoDataValue( int *pbSuccess )
     273                 : 
     274                 : {
     275              46 :     if( pbSuccess != NULL )
     276              46 :         *pbSuccess = nTransparentColor != -1;
     277                 : 
     278              46 :     return nTransparentColor;
     279                 : }
     280                 : 
     281                 : /************************************************************************/
     282                 : /* ==================================================================== */
     283                 : /*                             GIFDataset                               */
     284                 : /* ==================================================================== */
     285                 : /************************************************************************/
     286                 : 
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                            GIFDataset()                            */
     290                 : /************************************************************************/
     291                 : 
     292              58 : GIFDataset::GIFDataset()
     293                 : {
     294              58 : }
     295                 : 
     296                 : /************************************************************************/
     297                 : /*                                Open()                                */
     298                 : /************************************************************************/
     299                 : 
     300            5108 : GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
     301                 : 
     302                 : {
     303            5108 :     if( !Identify( poOpenInfo ) )
     304            5050 :         return NULL;
     305                 : 
     306              58 :     if( poOpenInfo->eAccess == GA_Update )
     307                 :     {
     308                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     309                 :                   "The GIF driver does not support update access to existing"
     310               0 :                   " files.\n" );
     311               0 :         return NULL;
     312                 :     }
     313                 : 
     314                 : /* -------------------------------------------------------------------- */
     315                 : /*      Open the file and ingest.                                       */
     316                 : /* -------------------------------------------------------------------- */
     317                 :     GifFileType   *hGifFile;
     318                 :     VSILFILE                *fp;
     319                 :     int                  nGifErr;
     320                 : 
     321              58 :     fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
     322              58 :     if( fp == NULL )
     323               0 :         return NULL;
     324                 : 
     325              58 :     hGifFile = DGifOpen( fp, VSIGIFReadFunc );
     326              58 :     if( hGifFile == NULL )
     327                 :     {
     328               0 :         VSIFCloseL( fp );
     329                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     330                 :                   "DGifOpen() failed for %s.\n"
     331                 :                   "Perhaps the gif file is corrupt?\n",
     332               0 :                   poOpenInfo->pszFilename );
     333                 : 
     334               0 :         return NULL;
     335                 :     }
     336                 : 
     337                 :     /* The following code enables us to detect GIF datasets eligible */
     338                 :     /* for BIGGIF driver even with an unpatched giflib  */
     339                 : 
     340                 :     /* -------------------------------------------------------------------- */
     341                 :     /*      Find the first image record.                                    */
     342                 :     /* -------------------------------------------------------------------- */
     343              58 :     GifRecordType RecordType = TERMINATE_RECORD_TYPE;
     344                 : 
     345             124 :     while( DGifGetRecordType(hGifFile, &RecordType) != GIF_ERROR
     346                 :         && RecordType != TERMINATE_RECORD_TYPE
     347                 :         && RecordType != IMAGE_DESC_RECORD_TYPE )
     348                 :     {
     349                 :         /* Skip extension records found before IMAGE_DESC_RECORD_TYPE */
     350               8 :         if (RecordType == EXTENSION_RECORD_TYPE)
     351                 :         {
     352                 :             int nFunction;
     353                 :             GifByteType *pExtData;
     354               8 :             if (DGifGetExtension(hGifFile, &nFunction, &pExtData) == GIF_ERROR)
     355               0 :                 break;
     356             200 :             while (pExtData != NULL)
     357                 :             {
     358             184 :                 if (DGifGetExtensionNext(hGifFile, &pExtData) == GIF_ERROR)
     359               0 :                     break;
     360                 :             }
     361                 :         }
     362                 :     }
     363                 : 
     364              58 :     if( RecordType == IMAGE_DESC_RECORD_TYPE  &&
     365                 :         DGifGetImageDesc(hGifFile) != GIF_ERROR)
     366                 :     {
     367              58 :         int width = hGifFile->SavedImages[0].ImageDesc.Width;
     368              58 :         int height = hGifFile->SavedImages[0].ImageDesc.Height;
     369              58 :         if ((double) width * (double) height > 100000000.0 )
     370                 :         {
     371                 :             CPLDebug( "GIF",
     372                 :                       "Due to limitations of the GDAL GIF driver we deliberately avoid\n"
     373               2 :                       "opening large GIF files (larger than 100 megapixels).");
     374               2 :             DGifCloseFile( hGifFile );
     375               2 :             VSIFCloseL( fp );
     376               2 :             return NULL;
     377                 :         }
     378                 :     }
     379                 : 
     380              56 :     DGifCloseFile( hGifFile );
     381                 : 
     382              56 :     VSIFSeekL( fp, 0, SEEK_SET);
     383              56 :     hGifFile = DGifOpen( fp, VSIGIFReadFunc );
     384              56 :     if( hGifFile == NULL )
     385                 :     {
     386               0 :         VSIFCloseL( fp );
     387                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     388                 :                   "DGifOpen() failed for %s.\n"
     389                 :                   "Perhaps the gif file is corrupt?\n",
     390               0 :                   poOpenInfo->pszFilename );
     391                 : 
     392               0 :         return NULL;
     393                 :     }
     394                 : 
     395              56 :     nGifErr = DGifSlurp( hGifFile );
     396                 : 
     397              56 :     if( nGifErr != GIF_OK || hGifFile->SavedImages == NULL )
     398                 :     {
     399               0 :         VSIFCloseL( fp );
     400               0 :         DGifCloseFile(hGifFile);
     401                 : 
     402               0 :         if( nGifErr == D_GIF_ERR_DATA_TOO_BIG )
     403                 :         {
     404                 :              CPLDebug( "GIF",
     405                 :                        "DGifSlurp() failed for %s because it was too large.\n"
     406                 :                        "Due to limitations of the GDAL GIF driver we deliberately avoid\n"
     407                 :                        "opening large GIF files (larger than 100 megapixels).",
     408               0 :                        poOpenInfo->pszFilename );
     409               0 :             return NULL;
     410                 :          }
     411                 :          else
     412                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     413                 :                         "DGifSlurp() failed for %s.\n"
     414                 :                         "Perhaps the gif file is corrupt?\n",
     415               0 :                         poOpenInfo->pszFilename );
     416                 : 
     417               0 :         return NULL;
     418                 :     }
     419                 : 
     420                 : /* -------------------------------------------------------------------- */
     421                 : /*      Create a corresponding GDALDataset.                             */
     422                 : /* -------------------------------------------------------------------- */
     423                 :     GIFDataset  *poDS;
     424                 : 
     425              56 :     poDS = new GIFDataset();
     426                 : 
     427              56 :     poDS->fp = fp;
     428              56 :     poDS->eAccess = GA_ReadOnly;
     429              56 :     poDS->hGifFile = hGifFile;
     430                 : 
     431                 : /* -------------------------------------------------------------------- */
     432                 : /*      Capture some information from the file that is of interest.     */
     433                 : /* -------------------------------------------------------------------- */
     434              56 :     poDS->nRasterXSize = hGifFile->SavedImages[0].ImageDesc.Width;
     435              56 :     poDS->nRasterYSize = hGifFile->SavedImages[0].ImageDesc.Height;
     436                 : 
     437                 : /* -------------------------------------------------------------------- */
     438                 : /*      Create band information objects.                                */
     439                 : /* -------------------------------------------------------------------- */
     440             112 :     for( int iImage = 0; iImage < hGifFile->ImageCount; iImage++ )
     441                 :     {
     442              56 :         SavedImage  *psImage = hGifFile->SavedImages + iImage;
     443                 : 
     444              56 :         if( psImage->ImageDesc.Width != poDS->nRasterXSize
     445                 :             || psImage->ImageDesc.Height != poDS->nRasterYSize )
     446               0 :             continue;
     447                 : 
     448                 :         poDS->SetBand( poDS->nBands+1, 
     449                 :                        new GIFRasterBand( poDS, poDS->nBands+1, psImage,
     450              56 :                                           hGifFile->SBackGroundColor ));
     451                 :     }
     452                 : 
     453                 : /* -------------------------------------------------------------------- */
     454                 : /*      Check for georeferencing.                                       */
     455                 : /* -------------------------------------------------------------------- */
     456              56 :     poDS->DetectGeoreferencing(poOpenInfo);
     457                 : 
     458                 : /* -------------------------------------------------------------------- */
     459                 : /*      Initialize any PAM information.                                 */
     460                 : /* -------------------------------------------------------------------- */
     461              56 :     poDS->SetDescription( poOpenInfo->pszFilename );
     462              56 :     poDS->TryLoadXML();
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      Support overviews.                                              */
     466                 : /* -------------------------------------------------------------------- */
     467              56 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     468                 : 
     469              56 :     return poDS;
     470                 : }
     471                 : 
     472                 : /************************************************************************/
     473                 : /*                             CreateCopy()                             */
     474                 : /************************************************************************/
     475                 : 
     476                 : GDALDataset *
     477              44 : GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     478                 :                int bStrict, char ** papszOptions, 
     479                 :                GDALProgressFunc pfnProgress, void * pProgressData )
     480                 : 
     481                 : {
     482              44 :     int  nBands = poSrcDS->GetRasterCount();
     483              44 :     int  nXSize = poSrcDS->GetRasterXSize();
     484              44 :     int  nYSize = poSrcDS->GetRasterYSize();
     485              44 :     int  bInterlace = FALSE;
     486                 : 
     487                 : /* -------------------------------------------------------------------- */
     488                 : /*      Check for interlaced option.                                    */
     489                 : /* -------------------------------------------------------------------- */
     490              44 :     bInterlace = CSLFetchBoolean(papszOptions, "INTERLACING", FALSE);
     491                 : 
     492                 : /* -------------------------------------------------------------------- */
     493                 : /*      Some some rudimentary checks                                    */
     494                 : /* -------------------------------------------------------------------- */
     495              44 :     if( nBands != 1 )
     496                 :     {
     497                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     498              10 :                   "GIF driver only supports one band images.\n" );
     499                 : 
     500              10 :         return NULL;
     501                 :     }
     502                 : 
     503              34 :     if (nXSize > 65535 || nYSize > 65535)
     504                 :     {
     505                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     506               0 :                   "GIF driver only supports datasets up to 65535x65535 size.\n" );
     507                 : 
     508               0 :         return NULL;
     509                 :     }
     510                 : 
     511              34 :     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
     512                 :         && bStrict )
     513                 :     {
     514                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     515                 :                   "GIF driver doesn't support data type %s. "
     516                 :                   "Only eight bit bands supported.\n", 
     517                 :                   GDALGetDataTypeName( 
     518              20 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     519                 : 
     520              20 :         return NULL;
     521                 :     }
     522                 : 
     523                 : /* -------------------------------------------------------------------- */
     524                 : /*      Open the output file.                                           */
     525                 : /* -------------------------------------------------------------------- */
     526                 :     GifFileType *hGifFile;
     527                 :     VSILFILE *fp;
     528                 : 
     529              14 :     fp = VSIFOpenL( pszFilename, "wb" );
     530              14 :     if( fp == NULL )
     531                 :     {
     532                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     533                 :                   "Failed to create %s:\n%s", 
     534               4 :                   pszFilename, VSIStrerror( errno ) );
     535               4 :         return NULL;
     536                 :     }
     537                 : 
     538              10 :     hGifFile = EGifOpen( fp, VSIGIFWriteFunc );
     539              10 :     if( hGifFile == NULL )
     540                 :     {
     541               0 :         VSIFCloseL( fp );
     542                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     543                 :                   "EGifOpenFilename(%s) failed.  Does file already exist?",
     544               0 :                   pszFilename );
     545                 : 
     546               0 :         return NULL;
     547                 :     }
     548                 : 
     549                 : /* -------------------------------------------------------------------- */
     550                 : /*      Prepare colortable.                                             */
     551                 : /* -------------------------------------------------------------------- */
     552              10 :     GDALRasterBand  *poBand = poSrcDS->GetRasterBand(1);
     553                 :     ColorMapObject  *psGifCT;
     554                 :     int     iColor;
     555                 : 
     556              10 :     if( poBand->GetColorTable() == NULL )
     557                 :     {
     558               8 :         psGifCT = MakeMapObject( 256, NULL );
     559            2056 :         for( iColor = 0; iColor < 256; iColor++ )
     560                 :         {
     561            2048 :             psGifCT->Colors[iColor].Red = (GifByteType) iColor;
     562            2048 :             psGifCT->Colors[iColor].Green = (GifByteType) iColor;
     563            2048 :             psGifCT->Colors[iColor].Blue = (GifByteType) iColor;
     564                 :         }
     565                 :     }
     566                 :     else
     567                 :     {
     568               2 :         GDALColorTable  *poCT = poBand->GetColorTable();
     569               2 :         int nFullCount = 1;
     570                 : 
     571              12 :         while( nFullCount < poCT->GetColorEntryCount() )
     572               8 :             nFullCount = nFullCount * 2;
     573                 : 
     574               2 :         psGifCT = MakeMapObject( nFullCount, NULL );
     575              34 :         for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ )
     576                 :         {
     577                 :             GDALColorEntry  sEntry;
     578                 : 
     579              32 :             poCT->GetColorEntryAsRGB( iColor, &sEntry );
     580              32 :             psGifCT->Colors[iColor].Red = (GifByteType) sEntry.c1;
     581              32 :             psGifCT->Colors[iColor].Green = (GifByteType) sEntry.c2;
     582              32 :             psGifCT->Colors[iColor].Blue = (GifByteType) sEntry.c3;
     583                 :         }
     584               2 :         for( ; iColor < nFullCount; iColor++ )
     585                 :         {
     586               0 :             psGifCT->Colors[iColor].Red = 0;
     587               0 :             psGifCT->Colors[iColor].Green = 0;
     588               0 :             psGifCT->Colors[iColor].Blue = 0;
     589                 :         }
     590                 :     }
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Setup parameters.                                               */
     594                 : /* -------------------------------------------------------------------- */
     595              10 :     if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 
     596                 :                           psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR)
     597                 :     {
     598               0 :         FreeMapObject(psGifCT);
     599               0 :         PrintGifError();
     600                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     601               0 :                   "Error writing gif file." );
     602               0 :         EGifCloseFile(hGifFile);
     603               0 :         VSIFCloseL( fp );
     604               0 :         return NULL;
     605                 :     }
     606                 :     
     607              10 :     FreeMapObject(psGifCT);
     608              10 :     psGifCT = NULL;
     609                 : 
     610                 :     /* Support for transparency */
     611                 :     int bNoDataValue;
     612              10 :     double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
     613              10 :     if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
     614                 :     {
     615                 :         unsigned char extensionData[4];
     616               2 :         extensionData[0] = 1; /*  Transparent Color Flag */
     617               2 :         extensionData[1] = 0;
     618               2 :         extensionData[2] = 0;
     619               2 :         extensionData[3] = (unsigned char)noDataValue;
     620               2 :         EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
     621                 :     }
     622                 : 
     623              10 :     if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, NULL) == GIF_ERROR )
     624                 :     {
     625               0 :         PrintGifError();
     626                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     627               0 :                   "Error writing gif file." );
     628               0 :         EGifCloseFile(hGifFile);
     629               0 :         VSIFCloseL( fp );
     630               0 :         return NULL;
     631                 :     }
     632                 : 
     633                 : /* -------------------------------------------------------------------- */
     634                 : /*      Loop over image, copying image data.                            */
     635                 : /* -------------------------------------------------------------------- */
     636                 :     CPLErr      eErr;
     637                 :     GDALPamDataset *poDS;
     638                 :     GByte      *pabyScanline;
     639                 : 
     640              10 :     pabyScanline = (GByte *) CPLMalloc( nXSize );
     641                 : 
     642              10 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
     643               0 :         eErr = CE_Failure;
     644                 : 
     645              10 :     if( !bInterlace )
     646                 :     {
     647             950 :         for( int iLine = 0; iLine < nYSize; iLine++ )
     648                 :         {
     649                 :             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
     650                 :                                      pabyScanline, nXSize, 1, GDT_Byte,
     651             940 :                                      nBands, nBands * nXSize );
     652                 : 
     653             940 :             if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR )
     654                 :             {
     655                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     656               0 :                           "Error writing gif file." );
     657               0 :                 goto error;
     658                 :             }
     659                 : 
     660             940 :             if( !pfnProgress( (iLine + 1) * 1.0 / nYSize, NULL, pProgressData ) )
     661                 :             {
     662               0 :                 goto error;
     663                 :             }
     664                 : 
     665                 :         }
     666                 :     }
     667                 :     else
     668                 :     {
     669                 :         int   i, j;
     670               0 :         int nLinesRead = 0;
     671               0 :         int nLinesToRead = 0;
     672               0 :         for ( i = 0; i < 4; i++)
     673                 :         {
     674               0 :             for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
     675                 :             {
     676               0 :                 nLinesToRead ++;
     677                 :             }
     678                 :         }
     679                 : 
     680                 :         /* Need to perform 4 passes on the images: */
     681               0 :         for ( i = 0; i < 4; i++)
     682                 :         {
     683               0 :             for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
     684                 :             {
     685                 :                 eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, 
     686                 :                                         pabyScanline, nXSize, 1, GDT_Byte,
     687               0 :                                         1, nXSize );
     688                 : 
     689               0 :                 if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
     690                 :                 {
     691                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     692               0 :                             "Error writing gif file." );
     693               0 :                     goto error;
     694                 :                 }
     695                 : 
     696               0 :                 nLinesRead ++;
     697               0 :                 if( !pfnProgress( nLinesRead * 1.0 / nYSize, NULL, pProgressData ) )
     698                 :                 {
     699               0 :                     goto error;
     700                 :                 }
     701                 :             }
     702                 :         }
     703                 :     }
     704                 : 
     705              10 :     CPLFree( pabyScanline );
     706              10 :     pabyScanline = NULL;
     707                 : 
     708                 : /* -------------------------------------------------------------------- */
     709                 : /*      cleanup                                                         */
     710                 : /* -------------------------------------------------------------------- */
     711              10 :     if (EGifCloseFile(hGifFile) == GIF_ERROR)
     712                 :     {
     713                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     714               0 :                   "EGifCloseFile() failed.\n" );
     715               0 :         hGifFile = NULL;
     716               0 :         goto error;
     717                 :     }
     718              10 :     hGifFile = NULL;
     719                 : 
     720              10 :     VSIFCloseL( fp );
     721              10 :     fp = NULL;
     722                 : 
     723                 : /* -------------------------------------------------------------------- */
     724                 : /*      Do we need a world file?                                          */
     725                 : /* -------------------------------------------------------------------- */
     726              10 :     if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
     727                 :     {
     728                 :       double      adfGeoTransform[6];
     729                 :   
     730               0 :   if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
     731               0 :             GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
     732                 :     }
     733                 : 
     734                 : /* -------------------------------------------------------------------- */
     735                 : /*      Re-open dataset, and copy any auxilary pam information.         */
     736                 : /* -------------------------------------------------------------------- */
     737                 : 
     738                 :     /* If outputing to stdout, we can't reopen it, so we'll return */
     739                 :     /* a fake dataset to make the caller happy */
     740              10 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     741              10 :     poDS = (GDALPamDataset*) GDALOpen(pszFilename, GA_ReadOnly);
     742              10 :     CPLPopErrorHandler();
     743              10 :     if (poDS)
     744                 :     {
     745               8 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
     746               8 :         return poDS;
     747                 :     }
     748                 :     else
     749                 :     {
     750               2 :         CPLErrorReset();
     751                 : 
     752               2 :         GIFDataset* poGIF_DS = new GIFDataset();
     753               2 :         poGIF_DS->nRasterXSize = nXSize;
     754               2 :         poGIF_DS->nRasterYSize = nYSize;
     755               8 :         for(int i=0;i<nBands;i++)
     756               2 :             poGIF_DS->SetBand( i+1, new GIFRasterBand( poGIF_DS, i+1, NULL, 0 ) );
     757               2 :         return poGIF_DS;
     758                 :     }
     759                 : 
     760                 : error:
     761               0 :     if (hGifFile)
     762               0 :         EGifCloseFile(hGifFile);
     763               0 :     if (fp)
     764               0 :         VSIFCloseL( fp );
     765               0 :     if (pabyScanline)
     766               0 :         CPLFree( pabyScanline );
     767               0 :     return NULL;
     768                 : }
     769                 : 
     770                 : /************************************************************************/
     771                 : /*                           VSIGIFReadFunc()                           */
     772                 : /*                                                                      */
     773                 : /*      Proxy function for reading from GIF file.                       */
     774                 : /************************************************************************/
     775                 : 
     776           20642 : static int VSIGIFReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
     777                 :                            int nBytesToRead )
     778                 : 
     779                 : {
     780                 :     return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
     781           20642 :                       (VSILFILE *) psGFile->UserData );
     782                 : }
     783                 : 
     784                 : /************************************************************************/
     785                 : /*                          VSIGIFWriteFunc()                           */
     786                 : /*                                                                      */
     787                 : /*      Proxy write function.                                           */
     788                 : /************************************************************************/
     789                 : 
     790            2286 : static int VSIGIFWriteFunc( GifFileType *psGFile, 
     791                 :                             const GifByteType *pabyBuffer, int nBytesToWrite )
     792                 : 
     793                 : {
     794            2286 :     VSILFILE* fp = (VSILFILE *) psGFile->UserData;
     795            2286 :     if ( VSIFTellL(fp) == 0 && nBytesToWrite >= 6 &&
     796                 :          memcmp(pabyBuffer, "GIF87a", 6) == 0 )
     797                 :     {
     798                 :         /* This is a hack to write a GIF89a instead of GIF87a */
     799                 :         /* (we have to, since we are using graphical extension block) */
     800                 :         /* EGifSpew would write GIF89a when it detects an extension block if we were using it */
     801                 :         /* As we don't, we could have used EGifSetGifVersion instead, but the version of libungif */
     802                 :         /* in GDAL has a bug : it writes on read-only memory ! */
     803                 :         /* (this is a well-known problem. Just google for "EGifSetGifVersion segfault") */
     804                 :         /* Most readers don't even care if it is GIF87a or GIF89a, but it is */
     805                 :         /* better to write the right version */
     806                 : 
     807              10 :         int nRet = VSIFWriteL("GIF89a", 1, 6, fp);
     808              10 :         nRet += VSIFWriteL( (char *) pabyBuffer + 6, 1, nBytesToWrite - 6, fp );
     809              10 :         return nRet;
     810                 :     }
     811                 :     else
     812            2276 :         return VSIFWriteL( (void *) pabyBuffer, 1, nBytesToWrite, fp );
     813                 : }
     814                 : 
     815                 : /************************************************************************/
     816                 : /*                          GDALRegister_GIF()                        */
     817                 : /************************************************************************/
     818                 : 
     819            1135 : void GDALRegister_GIF()
     820                 : 
     821                 : {
     822                 :     GDALDriver  *poDriver;
     823                 : 
     824            1135 :     if( GDALGetDriverByName( "GIF" ) == NULL )
     825                 :     {
     826            1093 :         poDriver = new GDALDriver();
     827                 :         
     828            1093 :         poDriver->SetDescription( "GIF" );
     829                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     830            1093 :                                    "Graphics Interchange Format (.gif)" );
     831                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     832            1093 :                                    "frmt_gif.html" );
     833            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gif" );
     834            1093 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/gif" );
     835                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
     836            1093 :                                    "Byte" );
     837                 : 
     838                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
     839                 : "<CreationOptionList>\n"
     840                 : "   <Option name='INTERLACING' type='boolean'/>\n"
     841                 : "   <Option name='WORLDFILE' type='boolean'/>\n"
     842            1093 : "</CreationOptionList>\n" );
     843                 : 
     844            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     845                 : 
     846            1093 :         poDriver->pfnOpen = GIFDataset::Open;
     847            1093 :         poDriver->pfnCreateCopy = GIFDataset::CreateCopy;
     848            1093 :         poDriver->pfnIdentify = GIFAbstractDataset::Identify;
     849                 : 
     850            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     851                 :     }
     852            1135 : }
     853                 : 

Generated by: LCOV version 1.7