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