LCOV - code coverage report
Current view: directory - frmts/gif - gifdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 283 211 74.6 %
Date: 2012-12-26 Functions: 19 13 68.4 %

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

Generated by: LCOV version 1.7