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 : CPLError(CE_Failure, CPLE_NotSupported,
165 : "The GIF driver does not support update access to existing"
166 : " files.");
167 0 : return nullptr;
168 : }
169 :
170 : /* -------------------------------------------------------------------- */
171 : /* Ingest. */
172 : /* -------------------------------------------------------------------- */
173 35 : VSILFILE *fp = poOpenInfo->fpL;
174 35 : poOpenInfo->fpL = nullptr;
175 :
176 : GifFileType *hGifFile =
177 35 : GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
178 35 : if (hGifFile == nullptr)
179 : {
180 0 : VSIFCloseL(fp);
181 0 : CPLError(CE_Failure, CPLE_OpenFailed,
182 : "DGifOpen() failed for %s. "
183 : "Perhaps the gif file is corrupt?",
184 : poOpenInfo->pszFilename);
185 :
186 0 : return nullptr;
187 : }
188 :
189 : // The following code enables us to detect GIF datasets eligible
190 : // for BIGGIF driver even with an unpatched giflib.
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Find the first image record. */
194 : /* -------------------------------------------------------------------- */
195 35 : GifRecordType RecordType = FindFirstImage(hGifFile);
196 70 : if (RecordType == IMAGE_DESC_RECORD_TYPE &&
197 35 : DGifGetImageDesc(hGifFile) != GIF_ERROR)
198 : {
199 35 : const int width = hGifFile->SavedImages[0].ImageDesc.Width;
200 35 : const int height = hGifFile->SavedImages[0].ImageDesc.Height;
201 35 : if (static_cast<double>(width) * height > 100000000.0)
202 : {
203 2 : CPLDebug("GIF", "Due to limitations of the GDAL GIF driver we "
204 : "deliberately avoid opening large GIF files "
205 : "(larger than 100 megapixels).");
206 2 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
207 : // Reset poOpenInfo->fpL since BIGGIF may need it.
208 2 : poOpenInfo->fpL = fp;
209 2 : VSIFSeekL(fp, 0, SEEK_SET);
210 2 : return nullptr;
211 : }
212 : }
213 :
214 33 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
215 :
216 33 : VSIFSeekL(fp, 0, SEEK_SET);
217 :
218 33 : hGifFile = GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
219 33 : if (hGifFile == nullptr)
220 : {
221 0 : VSIFCloseL(fp);
222 0 : CPLError(CE_Failure, CPLE_OpenFailed,
223 : "DGifOpen() failed for %s. "
224 : "Perhaps the gif file is corrupt?",
225 : poOpenInfo->pszFilename);
226 :
227 0 : return nullptr;
228 : }
229 :
230 33 : const int nGifErr = DGifSlurp(hGifFile);
231 :
232 33 : if (nGifErr != GIF_OK || hGifFile->SavedImages == nullptr)
233 : {
234 0 : VSIFCloseL(fp);
235 0 : GIFAbstractDataset::myDGifCloseFile(hGifFile);
236 :
237 0 : if (nGifErr == D_GIF_ERR_DATA_TOO_BIG)
238 : {
239 0 : CPLDebug("GIF",
240 : "DGifSlurp() failed for %s because it was too large. "
241 : "Due to limitations of the GDAL GIF driver we "
242 : "deliberately avoid opening large GIF files "
243 : "(larger than 100 megapixels).",
244 : poOpenInfo->pszFilename);
245 0 : return nullptr;
246 : }
247 :
248 0 : CPLError(CE_Failure, CPLE_OpenFailed,
249 : "DGifSlurp() failed for %s. "
250 : "Perhaps the gif file is corrupt?",
251 : poOpenInfo->pszFilename);
252 :
253 0 : return nullptr;
254 : }
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Create a corresponding GDALDataset. */
258 : /* -------------------------------------------------------------------- */
259 33 : GIFDataset *poDS = new GIFDataset();
260 :
261 33 : poDS->fp = fp;
262 33 : poDS->eAccess = GA_ReadOnly;
263 33 : poDS->hGifFile = hGifFile;
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Capture some information from the file that is of interest. */
267 : /* -------------------------------------------------------------------- */
268 33 : poDS->nRasterXSize = hGifFile->SavedImages[0].ImageDesc.Width;
269 33 : poDS->nRasterYSize = hGifFile->SavedImages[0].ImageDesc.Height;
270 33 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
271 : {
272 0 : delete poDS;
273 0 : return nullptr;
274 : }
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Create band information objects. */
278 : /* -------------------------------------------------------------------- */
279 66 : for (int iImage = 0; iImage < hGifFile->ImageCount; iImage++)
280 : {
281 33 : SavedImage *psImage = hGifFile->SavedImages + iImage;
282 :
283 33 : if (psImage->ImageDesc.Width != poDS->nRasterXSize ||
284 33 : psImage->ImageDesc.Height != poDS->nRasterYSize)
285 0 : continue;
286 :
287 33 : if (psImage->ImageDesc.ColorMap == nullptr &&
288 33 : poDS->hGifFile->SColorMap == nullptr)
289 : {
290 0 : CPLDebug("GIF", "Skipping image without color table");
291 0 : continue;
292 : }
293 : #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
294 : // Since giflib 5, de-interlacing is done by DGifSlurp().
295 33 : psImage->ImageDesc.Interlace = false;
296 : #endif
297 33 : poDS->SetBand(poDS->nBands + 1,
298 33 : new GIFRasterBand(poDS, poDS->nBands + 1, psImage,
299 33 : hGifFile->SBackGroundColor));
300 : }
301 33 : if (poDS->nBands == 0)
302 : {
303 0 : delete poDS;
304 0 : return nullptr;
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Check for georeferencing. */
309 : /* -------------------------------------------------------------------- */
310 33 : poDS->DetectGeoreferencing(poOpenInfo);
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* Initialize any PAM information. */
314 : /* -------------------------------------------------------------------- */
315 33 : poDS->SetDescription(poOpenInfo->pszFilename);
316 33 : poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
317 :
318 : /* -------------------------------------------------------------------- */
319 : /* Support overviews. */
320 : /* -------------------------------------------------------------------- */
321 66 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
322 33 : poOpenInfo->GetSiblingFiles());
323 :
324 33 : return poDS;
325 : }
326 :
327 : /************************************************************************/
328 : /* GDALPrintGifError() */
329 : /************************************************************************/
330 :
331 0 : static void GDALPrintGifError(CPL_UNUSED GifFileType *hGifFile,
332 : const char *pszMsg)
333 : {
334 : // GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
335 : // libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
336 : #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && \
337 : ((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
338 : // Static string actually, hence the const char* cast.
339 :
340 : #if GIFLIB_MAJOR >= 5
341 0 : const char *pszGIFLIBError = GifErrorString(hGifFile->Error);
342 : #else
343 : // TODO(schwehr): Can we remove the cast for older libgif?
344 : const char *pszGIFLIBError = (const char *)GifErrorString();
345 : #endif
346 0 : if (pszGIFLIBError == nullptr)
347 0 : pszGIFLIBError = "Unknown error";
348 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s. GIFLib Error : %s", pszMsg,
349 : pszGIFLIBError);
350 : #else
351 : PrintGifError();
352 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
353 : #endif
354 0 : }
355 :
356 : /************************************************************************/
357 : /* CreateCopy() */
358 : /************************************************************************/
359 :
360 24 : GDALDataset *GIFDataset::CreateCopy(const char *pszFilename,
361 : GDALDataset *poSrcDS, int bStrict,
362 : char **papszOptions,
363 : GDALProgressFunc pfnProgress,
364 : void *pProgressData)
365 :
366 : {
367 : /* -------------------------------------------------------------------- */
368 : /* Check for interlaced option. */
369 : /* -------------------------------------------------------------------- */
370 24 : const bool bInterlace = CPLFetchBool(papszOptions, "INTERLACING", false);
371 :
372 : /* -------------------------------------------------------------------- */
373 : /* Some some rudimentary checks */
374 : /* -------------------------------------------------------------------- */
375 24 : const int nBands = poSrcDS->GetRasterCount();
376 24 : if (nBands != 1)
377 : {
378 5 : CPLError(CE_Failure, CPLE_NotSupported,
379 : "GIF driver only supports one band images.");
380 :
381 5 : return nullptr;
382 : }
383 :
384 19 : const int nXSize = poSrcDS->GetRasterXSize();
385 19 : const int nYSize = poSrcDS->GetRasterYSize();
386 19 : if (nXSize > 65535 || nYSize > 65535)
387 : {
388 0 : CPLError(CE_Failure, CPLE_NotSupported,
389 : "GIF driver only supports datasets up to 65535x65535 size.");
390 :
391 0 : return nullptr;
392 : }
393 :
394 19 : if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict)
395 : {
396 10 : CPLError(CE_Failure, CPLE_NotSupported,
397 : "GIF driver doesn't support data type %s. "
398 : "Only eight bit bands supported.",
399 : GDALGetDataTypeName(
400 : poSrcDS->GetRasterBand(1)->GetRasterDataType()));
401 :
402 10 : return nullptr;
403 : }
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Open the output file. */
407 : /* -------------------------------------------------------------------- */
408 9 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
409 9 : if (fp == nullptr)
410 : {
411 3 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
412 3 : pszFilename, VSIStrerror(errno));
413 3 : return nullptr;
414 : }
415 :
416 : #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
417 6 : int nError = 0;
418 6 : GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc, &nError);
419 : #else
420 : GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc);
421 : #endif
422 6 : if (hGifFile == nullptr)
423 : {
424 0 : VSIFCloseL(fp);
425 0 : CPLError(CE_Failure, CPLE_OpenFailed,
426 : "EGifOpenFilename(%s) failed. Does file already exist?",
427 : pszFilename);
428 :
429 0 : return nullptr;
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Prepare colortable. */
434 : /* -------------------------------------------------------------------- */
435 6 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
436 6 : ColorMapObject *psGifCT = nullptr;
437 :
438 6 : if (poBand->GetColorTable() == nullptr)
439 : {
440 5 : psGifCT = GifMakeMapObject(256, nullptr);
441 5 : if (psGifCT == nullptr)
442 : {
443 0 : CPLError(CE_Failure, CPLE_AppDefined,
444 : "Cannot allocate color table");
445 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
446 0 : VSIFCloseL(fp);
447 0 : return nullptr;
448 : }
449 1285 : for (int iColor = 0; iColor < 256; iColor++)
450 : {
451 1280 : psGifCT->Colors[iColor].Red = static_cast<GifByteType>(iColor);
452 1280 : psGifCT->Colors[iColor].Green = static_cast<GifByteType>(iColor);
453 1280 : psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(iColor);
454 : }
455 : }
456 : else
457 : {
458 1 : GDALColorTable *poCT = poBand->GetColorTable();
459 1 : int nFullCount = 2;
460 :
461 4 : while (nFullCount < poCT->GetColorEntryCount())
462 3 : nFullCount = nFullCount * 2;
463 :
464 1 : psGifCT = GifMakeMapObject(nFullCount, nullptr);
465 1 : if (psGifCT == nullptr)
466 : {
467 0 : CPLError(CE_Failure, CPLE_AppDefined,
468 : "Cannot allocate color table");
469 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
470 0 : VSIFCloseL(fp);
471 0 : return nullptr;
472 : }
473 1 : int iColor = 0;
474 17 : for (; iColor < poCT->GetColorEntryCount(); iColor++)
475 : {
476 : GDALColorEntry sEntry;
477 :
478 16 : poCT->GetColorEntryAsRGB(iColor, &sEntry);
479 16 : psGifCT->Colors[iColor].Red = static_cast<GifByteType>(sEntry.c1);
480 16 : psGifCT->Colors[iColor].Green = static_cast<GifByteType>(sEntry.c2);
481 16 : psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(sEntry.c3);
482 : }
483 1 : for (; iColor < nFullCount; iColor++)
484 : {
485 0 : psGifCT->Colors[iColor].Red = 0;
486 0 : psGifCT->Colors[iColor].Green = 0;
487 0 : psGifCT->Colors[iColor].Blue = 0;
488 : }
489 : }
490 :
491 : /* -------------------------------------------------------------------- */
492 : /* Setup parameters. */
493 : /* -------------------------------------------------------------------- */
494 6 : if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 8, /* ColorRes */
495 : 255, /* Background */
496 6 : psGifCT) == GIF_ERROR)
497 : {
498 0 : GifFreeMapObject(psGifCT);
499 0 : GDALPrintGifError(hGifFile, "Error writing gif file.");
500 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
501 0 : VSIFCloseL(fp);
502 0 : return nullptr;
503 : }
504 :
505 6 : GifFreeMapObject(psGifCT);
506 6 : psGifCT = nullptr;
507 :
508 : // Support for transparency.
509 6 : int bNoDataValue = 0;
510 6 : double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
511 6 : if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
512 : {
513 1 : unsigned char extensionData[4] = {
514 : 1, // Transparent Color Flag.
515 1 : 0, 0, static_cast<unsigned char>(noDataValue)};
516 1 : EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
517 : }
518 :
519 6 : if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, nullptr) ==
520 : GIF_ERROR)
521 : {
522 0 : GDALPrintGifError(hGifFile, "Error writing gif file.");
523 0 : GIFAbstractDataset::myEGifCloseFile(hGifFile);
524 0 : VSIFCloseL(fp);
525 0 : return nullptr;
526 : }
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* Loop over image, copying image data. */
530 : /* -------------------------------------------------------------------- */
531 6 : GDALPamDataset *poDS = nullptr;
532 6 : GByte *pabyScanline = static_cast<GByte *>(CPLMalloc(nXSize));
533 :
534 6 : if (!pfnProgress(0.0, nullptr, pProgressData))
535 : {
536 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to setup progress.");
537 : }
538 :
539 6 : if (!bInterlace)
540 : {
541 475 : for (int iLine = 0; iLine < nYSize; iLine++)
542 : {
543 940 : const CPLErr eErr = poBand->RasterIO(
544 : GF_Read, 0, iLine, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte,
545 470 : nBands, static_cast<GSpacing>(nBands) * nXSize, nullptr);
546 :
547 940 : if (eErr != CE_None ||
548 470 : EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
549 : {
550 0 : CPLError(CE_Failure, CPLE_AppDefined,
551 : "Error writing gif file.");
552 0 : goto error;
553 : }
554 :
555 470 : if (!pfnProgress((iLine + 1) * 1.0 / nYSize, nullptr,
556 : pProgressData))
557 : {
558 0 : goto error;
559 : }
560 : }
561 : }
562 : else
563 : {
564 1 : int nLinesRead = 0;
565 : // Need to perform 4 passes on the images:
566 5 : for (int i = 0; i < 4; i++)
567 : {
568 24 : for (int j = InterlacedOffset[i]; j < nYSize;
569 20 : j += InterlacedJumps[i])
570 : {
571 : const CPLErr eErr =
572 20 : poBand->RasterIO(GF_Read, 0, j, nXSize, 1, pabyScanline,
573 : nXSize, 1, GDT_Byte, 1, nXSize, nullptr);
574 :
575 40 : if (eErr != CE_None ||
576 20 : EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
577 : {
578 0 : CPLError(CE_Failure, CPLE_AppDefined,
579 : "Error writing gif file.");
580 0 : goto error;
581 : }
582 :
583 20 : nLinesRead++;
584 20 : if (!pfnProgress(nLinesRead * 1.0 / nYSize, nullptr,
585 : pProgressData))
586 : {
587 0 : goto error;
588 : }
589 : }
590 : }
591 : }
592 :
593 6 : CPLFree(pabyScanline);
594 6 : pabyScanline = nullptr;
595 :
596 : /* -------------------------------------------------------------------- */
597 : /* cleanup */
598 : /* -------------------------------------------------------------------- */
599 6 : if (GIFAbstractDataset::myEGifCloseFile(hGifFile) == GIF_ERROR)
600 : {
601 0 : CPLError(CE_Failure, CPLE_AppDefined, "EGifCloseFile() failed.");
602 0 : hGifFile = nullptr;
603 0 : goto error;
604 : }
605 6 : hGifFile = nullptr;
606 :
607 6 : VSIFCloseL(fp);
608 6 : fp = nullptr;
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* Do we need a world file? */
612 : /* -------------------------------------------------------------------- */
613 6 : if (CPLFetchBool(papszOptions, "WORLDFILE", false))
614 : {
615 0 : double adfGeoTransform[6] = {};
616 :
617 0 : if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
618 0 : GDALWriteWorldFile(pszFilename, "wld", adfGeoTransform);
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 : }
|