void DDGifSlurp(GifInfo *info, bool shouldDecode) { GifRecordType RecordType; GifByteType *ExtData; int codeSize; int ExtFunction; do { if (DGifGetRecordType(info->gifFilePtr, &RecordType) == GIF_ERROR) return; switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(info->gifFilePtr, !shouldDecode) == GIF_ERROR) return; const uint_fast16_t requiredScreenWidth = info->gifFilePtr->Image.Left + info->gifFilePtr->Image.Width; const uint_fast16_t requiredScreenHeight = info->gifFilePtr->Image.Top + info->gifFilePtr->Image.Height; if (requiredScreenWidth > info->gifFilePtr->SWidth || requiredScreenHeight > info->gifFilePtr->SHeight) { if (shouldDecode) { void *tmpRasterBits = realloc(info->rasterBits, requiredScreenWidth * requiredScreenHeight * sizeof(GifPixelType)); if (tmpRasterBits == NULL) { info->gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; return; } info->rasterBits = tmpRasterBits; } else { info->gifFilePtr->SWidth = requiredScreenWidth; info->gifFilePtr->SHeight = requiredScreenHeight; } } if (shouldDecode) { if (info->gifFilePtr->Image.Interlace) { uint_fast16_t i, j; /* * The way an interlaced image should be read - * offsets and jumps... */ uint_fast8_t InterlacedOffset[] = {0, 4, 2, 1}; uint_fast8_t InterlacedJumps[] = {8, 8, 4, 2}; /* Need to perform 4 passes on the image */ for (i = 0; i < 4; i++) for (j = InterlacedOffset[i]; j < info->gifFilePtr->Image.Height; j += InterlacedJumps[i]) { if (DGifGetLine(info->gifFilePtr, info->rasterBits + j * info->gifFilePtr->Image.Width, info->gifFilePtr->Image.Width) == GIF_ERROR) return; } } else { if (DGifGetLine( info->gifFilePtr, info->rasterBits, info->gifFilePtr->Image.Width * info->gifFilePtr->Image.Height) == GIF_ERROR) return; } return; } else { if (DGifGetCode(info->gifFilePtr, &codeSize, &ExtData) == GIF_ERROR) return; while (ExtData != NULL) { if (DGifGetCodeNext(info->gifFilePtr, &ExtData) == GIF_ERROR) return; } } break; case EXTENSION_RECORD_TYPE: if (DGifGetExtension(info->gifFilePtr, &ExtFunction, &ExtData) == GIF_ERROR) return; if (!shouldDecode) { GraphicsControlBlock *tmpInfos = realloc(info->controlBlock, (info->gifFilePtr->ImageCount + 1) * sizeof(GraphicsControlBlock)); if (tmpInfos == NULL) { info->gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; return; } info->controlBlock = tmpInfos; info->controlBlock[info->gifFilePtr->ImageCount].DelayTime = DEFAULT_FRAME_DURATION_MS; if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) return; } while (ExtData != NULL) { if (DGifGetExtensionNext(info->gifFilePtr, &ExtData, &ExtFunction) == GIF_ERROR) return; if (!shouldDecode) { if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) return; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); info->rewindFunction(info); }
void DDGifSlurp(GifInfo *info, bool decode, bool exitAfterFrame) { GifRecordType RecordType; GifByteType *ExtData; int ExtFunction; GifFileType *gifFilePtr; gifFilePtr = info->gifFilePtr; uint_fast32_t lastAllocatedGCBIndex = 0; do { if (DGifGetRecordType(gifFilePtr, &RecordType) == GIF_ERROR) return; bool isInitialPass = !decode && !exitAfterFrame; switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(gifFilePtr, isInitialPass) == GIF_ERROR) return; if (isInitialPass) { int_fast32_t widthOverflow = gifFilePtr->Image.Width - gifFilePtr->SWidth; int_fast32_t heightOverflow = gifFilePtr->Image.Height - gifFilePtr->SHeight; if (widthOverflow > 0 || heightOverflow > 0) { gifFilePtr->SWidth += widthOverflow; gifFilePtr->SHeight += heightOverflow; } SavedImage *sp = &gifFilePtr->SavedImages[gifFilePtr->ImageCount - 1]; int_fast32_t topOverflow = gifFilePtr->Image.Top + gifFilePtr->Image.Height - gifFilePtr->SHeight; if (topOverflow > 0) { sp->ImageDesc.Top -= topOverflow; } int_fast32_t leftOverflow = gifFilePtr->Image.Left + gifFilePtr->Image.Width - gifFilePtr->SWidth; if (leftOverflow > 0) { sp->ImageDesc.Left -= leftOverflow; } if (!updateGCB(info, &lastAllocatedGCBIndex)) { return; } } if (decode) { int_fast32_t widthOverflow = gifFilePtr->Image.Width - info->originalWidth; int_fast32_t heightOverflow = gifFilePtr->Image.Height - info->originalHeight; if (widthOverflow > 0 || heightOverflow > 0) { void *tmpRasterBits = reallocarray(info->rasterBits, info->originalWidth * info->originalHeight, sizeof(GifPixelType)); if (tmpRasterBits == NULL) { gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; return; } info->rasterBits = tmpRasterBits; } if (gifFilePtr->Image.Interlace) { uint_fast16_t i, j; /* * The way an interlaced image should be read - * offsets and jumps... */ uint_fast8_t InterlacedOffset[] = {0, 4, 2, 1}; uint_fast8_t InterlacedJumps[] = {8, 8, 4, 2}; /* Need to perform 4 passes on the image */ for (i = 0; i < 4; i++) for (j = InterlacedOffset[i]; j < gifFilePtr->Image.Height; j += InterlacedJumps[i]) { if (DGifGetLine(gifFilePtr, info->rasterBits + j * gifFilePtr->Image.Width, gifFilePtr->Image.Width) == GIF_ERROR) return; } } else { if (DGifGetLine(gifFilePtr, info->rasterBits, gifFilePtr->Image.Width * gifFilePtr->Image.Height) == GIF_ERROR) { return; } } if (info->sampleSize > 1) { unsigned char *dst = info->rasterBits; unsigned char *src = info->rasterBits; unsigned char *const srcEndImage = info->rasterBits + gifFilePtr->Image.Width * gifFilePtr->Image.Height; do { unsigned char *srcNextLineStart = src + gifFilePtr->Image.Width * info->sampleSize; unsigned char *const srcEndLine = src + gifFilePtr->Image.Width; unsigned char *dstEndLine = dst + gifFilePtr->Image.Width / info->sampleSize; do { *dst = *src; dst++; src += info->sampleSize; } while (src < srcEndLine); dst = dstEndLine; src = srcNextLineStart; } while (src < srcEndImage); } return; } else { do { if (DGifGetCodeNext(gifFilePtr, &ExtData) == GIF_ERROR) { return; } } while (ExtData != NULL); if (exitAfterFrame) { return; } } break; case EXTENSION_RECORD_TYPE: if (DGifGetExtension(gifFilePtr, &ExtFunction, &ExtData) == GIF_ERROR) { return; } if (isInitialPass) { updateGCB(info, &lastAllocatedGCBIndex); if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) { return; } } while (ExtData != NULL) { if (DGifGetExtensionNext(gifFilePtr, &ExtData) == GIF_ERROR) { return; } if (isInitialPass) { if (readExtensions(ExtFunction, ExtData, info) == GIF_ERROR) return; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be trapped by DGifGetRecordType */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); info->rewindFunction(info); }