Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GIF Driver
4 : * Purpose: Implement GDAL GIF Support using libungif code.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2001, Frank Warmerdam
9 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "gifabstractdataset.h"
15 :
16 : #include "cpl_string.h"
17 : #include "gdal_frmts.h"
18 : #include "gdal_pam.h"
19 : #include "gifdrivercore.h"
20 :
21 : CPL_C_START
22 : #if !(defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5)
23 :
24 : // This prototype seems to have been messed up!
25 : GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
26 :
27 : // Define alias compatible with giflib >= 5.0.0
28 : #define GifMakeMapObject MakeMapObject
29 : #define GifFreeMapObject FreeMapObject
30 :
31 : #endif // defined(GIFLIB_MAJOR) && GIFLIB_MAJOR < 5
32 :
33 : CPL_C_END
34 :
35 : /************************************************************************/
36 : /* VSIGIFWriteFunc() */
37 : /* */
38 : /* Proxy write function. */
39 : /************************************************************************/
40 :
41 1414 : static int VSIGIFWriteFunc(GifFileType *psGFile, const GifByteType *pabyBuffer,
42 : int nBytesToWrite)
43 :
44 : {
45 1414 : VSILFILE *fp = static_cast<VSILFILE *>(psGFile->UserData);
46 1420 : if (VSIFTellL(fp) == 0 && nBytesToWrite >= 6 &&
47 6 : memcmp(pabyBuffer, "GIF87a", 6) == 0)
48 : {
49 : // This is a hack to write a GIF89a instead of GIF87a (we have to, since
50 : // we are using graphical extension block). EGifSpew would write GIF89a
51 : // when it detects an extension block if we were using it As we don't,
52 : // we could have used EGifSetGifVersion instead, but the version of
53 : // libungif in GDAL has a bug: it writes on read-only memory!
54 : // This is a well-known problem. Just google for "EGifSetGifVersion
55 : // segfault".
56 : // Most readers don't even care if it is GIF87a or GIF89a, but it is
57 : // better to write the right version.
58 :
59 6 : size_t nRet = VSIFWriteL("GIF89a", 1, 6, fp);
60 12 : nRet += VSIFWriteL(reinterpret_cast<const char *>(pabyBuffer) + 6, 1,
61 6 : nBytesToWrite - 6, fp);
62 6 : return static_cast<int>(nRet);
63 : }
64 :
65 1408 : return static_cast<int>(VSIFWriteL(pabyBuffer, 1, nBytesToWrite, fp));
66 : }
67 :
68 : /************************************************************************/
69 : /* ==================================================================== */
70 : /* GIFDataset */
71 : /* ==================================================================== */
72 : /************************************************************************/
73 :
74 : class GIFRasterBand;
75 :
76 60 : class GIFDataset final : public GIFAbstractDataset
77 : {
78 : friend class GIFRasterBand;
79 :
80 : public:
81 : GIFDataset();
82 : ~GIFDataset() override;
83 :
84 : static GDALDataset *Open(GDALOpenInfo *);
85 :
86 : static GDALDataset *CreateCopy(const char *pszFilename,
87 : GDALDataset *poSrcDS, int bStrict,
88 : char **papszOptions,
89 : GDALProgressFunc pfnProgress,
90 : void *pProgressData);
91 : };
92 :
93 : GIFDataset::~GIFDataset() = default;
94 :
95 : /************************************************************************/
96 : /* ==================================================================== */
97 : /* GIFRasterBand */
98 : /* ==================================================================== */
99 : /************************************************************************/
100 :
101 : class GIFRasterBand final : public GIFAbstractRasterBand
102 : {
103 : public:
104 : GIFRasterBand(GIFDataset *, int, SavedImage *, int);
105 : CPLErr IReadBlock(int, int, void *) override;
106 : };
107 :
108 : /************************************************************************/
109 : /* GIFRasterBand() */
110 : /************************************************************************/
111 :
112 30 : GIFRasterBand::GIFRasterBand(GIFDataset *poDSIn, int nBandIn,
113 30 : SavedImage *psSavedImage, int nBackground)
114 30 : : GIFAbstractRasterBand(poDSIn, nBandIn, psSavedImage, nBackground, FALSE)
115 : {
116 30 : }
117 :
118 : /************************************************************************/
119 : /* IReadBlock() */
120 : /************************************************************************/
121 :
122 2960 : CPLErr GIFRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
123 : void *pImage)
124 : {
125 2960 : CPLAssert(nBlockXOff == 0);
126 :
127 2960 : if (psImage == nullptr)
128 : {
129 20 : memset(pImage, 0, nBlockXSize);
130 20 : return CE_None;
131 : }
132 :
133 2940 : if (panInterlaceMap != nullptr)
134 0 : nBlockYOff = panInterlaceMap[nBlockYOff];
135 :
136 2940 : memcpy(pImage, psImage->RasterBits + nBlockYOff * nBlockXSize, nBlockXSize);
137 :
138 2940 : return CE_None;
139 : }
140 :
141 : /************************************************************************/
142 : /* ==================================================================== */
143 : /* GIFDataset */
144 : /* ==================================================================== */
145 : /************************************************************************/
146 :
147 : /************************************************************************/
148 : /* GIFDataset() */
149 : /************************************************************************/
150 :
151 30 : GIFDataset::GIFDataset()
152 : {
153 30 : }
154 :
155 : /************************************************************************/
156 : /* Open() */
157 : /************************************************************************/
158 :
159 31 : GDALDataset *GIFDataset::Open(GDALOpenInfo *poOpenInfo)
160 :
161 : {
162 31 : if (!GIFDriverIdentify(poOpenInfo))
163 0 : return nullptr;
164 :
165 31 : if (poOpenInfo->eAccess == GA_Update)
166 : {
167 0 : ReportUpdateNotSupportedByDriver("GIF");
168 0 : return nullptr;
169 : }
170 :
171 : /* -------------------------------------------------------------------- */
172 : /* Ingest. */
173 : /* -------------------------------------------------------------------- */
174 31 : VSILFILE *fp = poOpenInfo->fpL;
175 31 : poOpenInfo->fpL = nullptr;
176 :
177 : GifFileType *hGifFile =
178 31 : GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
179 31 : if (hGifFile == nullptr)
180 : {
181 0 : VSIFCloseL(fp);
182 0 : CPLError(CE_Failure, CPLE_OpenFailed,
183 : "DGifOpen() failed for %s. "
184 : "Perhaps the gif file is corrupt?",
185 : poOpenInfo->pszFilename);
186 :
187 0 : return nullptr;
188 : }
189 :
190 : // The following code enables us to detect GIF datasets eligible
191 : // for BIGGIF driver even with an unpatched giflib.
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Find the first image record. */
195 : /* -------------------------------------------------------------------- */
196 31 : GifRecordType RecordType = FindFirstImage(hGifFile);
197 62 : if (RecordType == IMAGE_DESC_RECORD_TYPE &&
198 31 : DGifGetImageDesc(hGifFile) != GIF_ERROR)
199 : {
200 31 : const int width = hGifFile->SavedImages[0].ImageDesc.Width;
201 31 : const int height = hGifFile->SavedImages[0].ImageDesc.Height;
202 31 : if (static_cast<double>(width) * height > 100000000.0)
203 : {
204 2 : CPLDebug("GIF", "Due to limitations of the GDAL GIF driver we "
205 : "deliberately avoid opening large GIF files "
206 : "(larger than 100 megapixels).");
207 2 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
208 : // Reset poOpenInfo->fpL since BIGGIF may need it.
209 2 : poOpenInfo->fpL = fp;
210 2 : VSIFSeekL(fp, 0, SEEK_SET);
211 2 : return nullptr;
212 : }
213 : }
214 :
215 29 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
216 :
217 29 : VSIFSeekL(fp, 0, SEEK_SET);
218 :
219 29 : hGifFile = GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
220 29 : if (hGifFile == nullptr)
221 : {
222 0 : VSIFCloseL(fp);
223 0 : CPLError(CE_Failure, CPLE_OpenFailed,
224 : "DGifOpen() failed for %s. "
225 : "Perhaps the gif file is corrupt?",
226 : poOpenInfo->pszFilename);
227 :
228 0 : return nullptr;
229 : }
230 :
231 29 : const int nGifErr = DGifSlurp(hGifFile);
232 :
233 29 : if (nGifErr != GIF_OK || hGifFile->SavedImages == nullptr)
234 : {
235 0 : VSIFCloseL(fp);
236 0 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
237 :
238 0 : if (nGifErr == D_GIF_ERR_DATA_TOO_BIG)
239 : {
240 0 : CPLDebug("GIF",
241 : "DGifSlurp() failed for %s because it was too large. "
242 : "Due to limitations of the GDAL GIF driver we "
243 : "deliberately avoid opening large GIF files "
244 : "(larger than 100 megapixels).",
245 : poOpenInfo->pszFilename);
246 0 : return nullptr;
247 : }
248 :
249 0 : CPLError(CE_Failure, CPLE_OpenFailed,
250 : "DGifSlurp() failed for %s. "
251 : "Perhaps the gif file is corrupt?",
252 : poOpenInfo->pszFilename);
253 :
254 0 : return nullptr;
255 : }
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Create a corresponding GDALDataset. */
259 : /* -------------------------------------------------------------------- */
260 29 : GIFDataset *poDS = new GIFDataset();
261 :
262 29 : poDS->fp = fp;
263 29 : poDS->eAccess = GA_ReadOnly;
264 29 : poDS->hGifFile = hGifFile;
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Capture some information from the file that is of interest. */
268 : /* -------------------------------------------------------------------- */
269 29 : poDS->nRasterXSize = hGifFile->SavedImages[0].ImageDesc.Width;
270 29 : poDS->nRasterYSize = hGifFile->SavedImages[0].ImageDesc.Height;
271 29 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
272 : {
273 0 : delete poDS;
274 0 : return nullptr;
275 : }
276 :
277 : /* -------------------------------------------------------------------- */
278 : /* Create band information objects. */
279 : /* -------------------------------------------------------------------- */
280 58 : for (int iImage = 0; iImage < hGifFile->ImageCount; iImage++)
281 : {
282 29 : SavedImage *psImage = hGifFile->SavedImages + iImage;
283 :
284 29 : if (psImage->ImageDesc.Width != poDS->nRasterXSize ||
285 29 : psImage->ImageDesc.Height != poDS->nRasterYSize)
286 0 : continue;
287 :
288 29 : if (psImage->ImageDesc.ColorMap == nullptr &&
289 29 : poDS->hGifFile->SColorMap == nullptr)
290 : {
291 0 : CPLDebug("GIF", "Skipping image without color table");
292 0 : continue;
293 : }
294 : #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
295 : // Since giflib 5, de-interlacing is done by DGifSlurp().
296 29 : psImage->ImageDesc.Interlace = false;
297 : #endif
298 29 : poDS->SetBand(poDS->nBands + 1,
299 29 : new GIFRasterBand(poDS, poDS->nBands + 1, psImage,
300 29 : hGifFile->SBackGroundColor));
301 : }
302 29 : if (poDS->nBands == 0)
303 : {
304 0 : delete poDS;
305 0 : return nullptr;
306 : }
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Check for georeferencing. */
310 : /* -------------------------------------------------------------------- */
311 29 : poDS->DetectGeoreferencing(poOpenInfo);
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Initialize any PAM information. */
315 : /* -------------------------------------------------------------------- */
316 29 : poDS->SetDescription(poOpenInfo->pszFilename);
317 29 : poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Support overviews. */
321 : /* -------------------------------------------------------------------- */
322 58 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
323 29 : poOpenInfo->GetSiblingFiles());
324 :
325 29 : return poDS;
326 : }
327 :
328 : /************************************************************************/
329 : /* GDALPrintGifError() */
330 : /************************************************************************/
331 :
332 0 : static void GDALPrintGifError(CPL_UNUSED GifFileType *hGifFile,
333 : const char *pszMsg)
334 : {
335 : // GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
336 : // libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
337 : #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \
338 : ((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
339 : // Static string actually, hence the const char* cast.
340 :
341 : #if GIFLIB_MAJOR >= 5
342 0 : const char *pszGIFLIBError = GifErrorString(hGifFile->Error);
343 : #else
344 : // TODO(schwehr): Can we remove the cast for older libgif?
345 : const char *pszGIFLIBError = (const char *)GifErrorString();
346 : #endif
347 0 : if (pszGIFLIBError == nullptr)
348 0 : pszGIFLIBError = "Unknown error";
349 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s. GIFLib Error : %s", pszMsg,
350 : pszGIFLIBError);
351 : #else
352 : PrintGifError();
353 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
354 : #endif
355 0 : }
356 :
357 : /************************************************************************/
358 : /* CreateCopy() */
359 : /************************************************************************/
360 :
361 24 : GDALDataset *GIFDataset::CreateCopy(const char *pszFilename,
362 : GDALDataset *poSrcDS, int bStrict,
363 : char **papszOptions,
364 : GDALProgressFunc pfnProgress,
365 : void *pProgressData)
366 :
367 : {
368 : /* -------------------------------------------------------------------- */
369 : /* Check for interlaced option. */
370 : /* -------------------------------------------------------------------- */
371 24 : const bool bInterlace = CPLFetchBool(papszOptions, "INTERLACING", false);
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Some some rudimentary checks */
375 : /* -------------------------------------------------------------------- */
376 24 : const int nBands = poSrcDS->GetRasterCount();
377 24 : if (nBands != 1)
378 : {
379 5 : CPLError(CE_Failure, CPLE_NotSupported,
380 : "GIF driver only supports one band images.");
381 :
382 5 : return nullptr;
383 : }
384 :
385 19 : const int nXSize = poSrcDS->GetRasterXSize();
386 19 : const int nYSize = poSrcDS->GetRasterYSize();
387 19 : if (nXSize > 65535 || nYSize > 65535)
388 : {
389 0 : CPLError(CE_Failure, CPLE_NotSupported,
390 : "GIF driver only supports datasets up to 65535x65535 size.");
391 :
392 0 : return nullptr;
393 : }
394 :
395 19 : if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict)
396 : {
397 10 : CPLError(CE_Failure, CPLE_NotSupported,
398 : "GIF driver doesn't support data type %s. "
399 : "Only eight bit bands supported.",
400 : GDALGetDataTypeName(
401 : poSrcDS->GetRasterBand(1)->GetRasterDataType()));
402 :
403 10 : return nullptr;
404 : }
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Open the output file. */
408 : /* -------------------------------------------------------------------- */
409 9 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
410 9 : if (fp == nullptr)
411 : {
412 3 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
413 3 : pszFilename, VSIStrerror(errno));
414 3 : return nullptr;
415 : }
416 :
417 : #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
418 6 : int nError = 0;
419 6 : GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc, &nError);
420 : #else
421 : GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc);
422 : #endif
423 6 : if (hGifFile == nullptr)
424 : {
425 0 : VSIFCloseL(fp);
426 0 : CPLError(CE_Failure, CPLE_OpenFailed,
427 : "EGifOpenFilename(%s) failed. Does file already exist?",
428 : pszFilename);
429 :
430 0 : return nullptr;
431 : }
432 :
433 : /* -------------------------------------------------------------------- */
434 : /* Prepare colortable. */
435 : /* -------------------------------------------------------------------- */
436 6 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
437 6 : ColorMapObject *psGifCT = nullptr;
438 :
439 6 : if (poBand->GetColorTable() == nullptr)
440 : {
441 5 : psGifCT = GifMakeMapObject(256, nullptr);
442 5 : if (psGifCT == nullptr)
443 : {
444 0 : CPLError(CE_Failure, CPLE_AppDefined,
445 : "Cannot allocate color table");
446 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
447 0 : VSIFCloseL(fp);
448 0 : return nullptr;
449 : }
450 1285 : for (int iColor = 0; iColor < 256; iColor++)
451 : {
452 1280 : psGifCT->Colors[iColor].Red = static_cast<GifByteType>(iColor);
453 1280 : psGifCT->Colors[iColor].Green = static_cast<GifByteType>(iColor);
454 1280 : psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(iColor);
455 : }
456 : }
457 : else
458 : {
459 1 : GDALColorTable *poCT = poBand->GetColorTable();
460 1 : int nFullCount = 2;
461 :
462 4 : while (nFullCount < poCT->GetColorEntryCount())
463 3 : nFullCount = nFullCount * 2;
464 :
465 1 : psGifCT = GifMakeMapObject(nFullCount, nullptr);
466 1 : if (psGifCT == nullptr)
467 : {
468 0 : CPLError(CE_Failure, CPLE_AppDefined,
469 : "Cannot allocate color table");
470 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
471 0 : VSIFCloseL(fp);
472 0 : return nullptr;
473 : }
474 1 : int iColor = 0;
475 17 : for (; iColor < poCT->GetColorEntryCount(); iColor++)
476 : {
477 : GDALColorEntry sEntry;
478 :
479 16 : poCT->GetColorEntryAsRGB(iColor, &sEntry);
480 16 : psGifCT->Colors[iColor].Red = static_cast<GifByteType>(sEntry.c1);
481 16 : psGifCT->Colors[iColor].Green = static_cast<GifByteType>(sEntry.c2);
482 16 : psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(sEntry.c3);
483 : }
484 1 : for (; iColor < nFullCount; iColor++)
485 : {
486 0 : psGifCT->Colors[iColor].Red = 0;
487 0 : psGifCT->Colors[iColor].Green = 0;
488 0 : psGifCT->Colors[iColor].Blue = 0;
489 : }
490 : }
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Setup parameters. */
494 : /* -------------------------------------------------------------------- */
495 6 : if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 8, /* ColorRes */
496 : 255, /* Background */
497 6 : psGifCT) == GIF_ERROR)
498 : {
499 0 : GifFreeMapObject(psGifCT);
500 0 : GDALPrintGifError(hGifFile, "Error writing gif file.");
501 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
502 0 : VSIFCloseL(fp);
503 0 : return nullptr;
504 : }
505 :
506 6 : GifFreeMapObject(psGifCT);
507 6 : psGifCT = nullptr;
508 :
509 : // Support for transparency.
510 6 : int bNoDataValue = 0;
511 6 : double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
512 6 : if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
513 : {
514 1 : unsigned char extensionData[4] = {
515 : 1, // Transparent Color Flag.
516 1 : 0, 0, static_cast<unsigned char>(noDataValue)};
517 1 : EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
518 : }
519 :
520 6 : if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, nullptr) ==
521 : GIF_ERROR)
522 : {
523 0 : GDALPrintGifError(hGifFile, "Error writing gif file.");
524 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
525 0 : VSIFCloseL(fp);
526 0 : return nullptr;
527 : }
528 :
529 : /* -------------------------------------------------------------------- */
530 : /* Loop over image, copying image data. */
531 : /* -------------------------------------------------------------------- */
532 6 : GDALPamDataset *poDS = nullptr;
533 6 : GByte *pabyScanline = static_cast<GByte *>(CPLMalloc(nXSize));
534 :
535 6 : if (!pfnProgress(0.0, nullptr, pProgressData))
536 : {
537 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to setup progress.");
538 : }
539 :
540 6 : if (!bInterlace)
541 : {
542 475 : for (int iLine = 0; iLine < nYSize; iLine++)
543 : {
544 940 : const CPLErr eErr = poBand->RasterIO(
545 : GF_Read, 0, iLine, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte,
546 470 : nBands, static_cast<GSpacing>(nBands) * nXSize, nullptr);
547 :
548 940 : if (eErr != CE_None ||
549 470 : EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
550 : {
551 0 : CPLError(CE_Failure, CPLE_AppDefined,
552 : "Error writing gif file.");
553 0 : goto error;
554 : }
555 :
556 470 : if (!pfnProgress((iLine + 1) * 1.0 / nYSize, nullptr,
557 : pProgressData))
558 : {
559 0 : goto error;
560 : }
561 : }
562 : }
563 : else
564 : {
565 1 : int nLinesRead = 0;
566 : // Need to perform 4 passes on the images:
567 5 : for (int i = 0; i < 4; i++)
568 : {
569 24 : for (int j = InterlacedOffset[i]; j < nYSize;
570 20 : j += InterlacedJumps[i])
571 : {
572 : const CPLErr eErr =
573 20 : poBand->RasterIO(GF_Read, 0, j, nXSize, 1, pabyScanline,
574 : nXSize, 1, GDT_Byte, 1, nXSize, nullptr);
575 :
576 40 : if (eErr != CE_None ||
577 20 : EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
578 : {
579 0 : CPLError(CE_Failure, CPLE_AppDefined,
580 : "Error writing gif file.");
581 0 : goto error;
582 : }
583 :
584 20 : nLinesRead++;
585 20 : if (!pfnProgress(nLinesRead * 1.0 / nYSize, nullptr,
586 : pProgressData))
587 : {
588 0 : goto error;
589 : }
590 : }
591 : }
592 : }
593 :
594 6 : CPLFree(pabyScanline);
595 6 : pabyScanline = nullptr;
596 :
597 : /* -------------------------------------------------------------------- */
598 : /* cleanup */
599 : /* -------------------------------------------------------------------- */
600 6 : if (GIFAbstractDataset::myEGifCloseFile(hGifFile) == GIF_ERROR)
601 : {
602 0 : CPLError(CE_Failure, CPLE_AppDefined, "EGifCloseFile() failed.");
603 0 : hGifFile = nullptr;
604 0 : goto error;
605 : }
606 6 : hGifFile = nullptr;
607 :
608 6 : VSIFCloseL(fp);
609 6 : fp = nullptr;
610 :
611 : /* -------------------------------------------------------------------- */
612 : /* Do we need a world file? */
613 : /* -------------------------------------------------------------------- */
614 6 : if (CPLFetchBool(papszOptions, "WORLDFILE", false))
615 : {
616 0 : GDALGeoTransform gt;
617 0 : if (poSrcDS->GetGeoTransform(gt) == CE_None)
618 0 : GDALWriteWorldFile(pszFilename, "wld", gt.data());
619 : }
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* Re-open dataset, and copy any auxiliary pam information. */
623 : /* -------------------------------------------------------------------- */
624 :
625 : // If writing to stdout, we can't reopen it, so return
626 : // a fake dataset to make the caller happy.
627 6 : CPLPushErrorHandler(CPLQuietErrorHandler);
628 6 : poDS = static_cast<GDALPamDataset *>(GDALOpen(pszFilename, GA_ReadOnly));
629 6 : CPLPopErrorHandler();
630 6 : if (poDS)
631 : {
632 5 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
633 5 : return poDS;
634 : }
635 : else
636 : {
637 1 : CPLErrorReset();
638 :
639 1 : GIFDataset *poGIF_DS = new GIFDataset();
640 1 : poGIF_DS->nRasterXSize = nXSize;
641 1 : poGIF_DS->nRasterYSize = nYSize;
642 2 : for (int i = 0; i < nBands; i++)
643 1 : poGIF_DS->SetBand(i + 1,
644 1 : new GIFRasterBand(poGIF_DS, i + 1, nullptr, 0));
645 1 : return poGIF_DS;
646 : }
647 :
648 0 : error:
649 0 : if (hGifFile)
650 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
651 0 : if (fp)
652 0 : VSIFCloseL(fp);
653 0 : if (pabyScanline)
654 0 : CPLFree(pabyScanline);
655 0 : return nullptr;
656 : }
657 :
658 : /************************************************************************/
659 : /* GDALRegister_GIF() */
660 : /************************************************************************/
661 :
662 19 : void GDALRegister_GIF()
663 :
664 : {
665 19 : if (GDALGetDriverByName(GIF_DRIVER_NAME) != nullptr)
666 0 : return;
667 :
668 19 : GDALDriver *poDriver = new GDALDriver();
669 :
670 19 : GIFDriverSetCommonMetadata(poDriver);
671 19 : poDriver->pfnOpen = GIFDataset::Open;
672 19 : poDriver->pfnCreateCopy = GIFDataset::CreateCopy;
673 :
674 19 : GetGDALDriverManager()->RegisterDriver(poDriver);
675 :
676 : #ifdef GIF_PLUGIN
677 19 : GDALRegister_BIGGIF();
678 : #endif
679 : }
|