diff options
author | Martijn Kaijser <martijn@xbmc.org> | 2016-01-10 07:29:26 -0800 |
---|---|---|
committer | Martijn Kaijser <martijn@xbmc.org> | 2016-01-10 07:29:26 -0800 |
commit | 252aceae210e385a32270bcde9c38cc8599fd203 (patch) | |
tree | ea9c74afa444d8b4ce10b71fc5028a10b7f7da06 | |
parent | c0541b52d6652f95dc966681ea72cfa0f8fddb77 (diff) | |
parent | c3710ddd26195250bbebbb9bdc6970c313f684e4 (diff) |
Merge pull request #8823 from ace20022/tp_jarvis
[tools][texturepacker] Fix gif decoding and packaging
5 files changed, 379 insertions, 328 deletions
diff --git a/project/BuildDependencies/scripts/0_package.list b/project/BuildDependencies/scripts/0_package.list index b89826dab7..4ce1934db7 100644 --- a/project/BuildDependencies/scripts/0_package.list +++ b/project/BuildDependencies/scripts/0_package.list @@ -14,7 +14,7 @@ dnssd-541-win32.zip doxygen-1.8.2-win32.7z fontconfig-2.8.0-win32.7z freetype-2.4.6-win32-3.7z -giflib-5.1.0-win32.7z +giflib-5.1.1-win32.7z gnutls-3.2.3-win32.zip jsonschemabuilder-1.0.0-win32-3.7z libass-0.12.1-win32.7z @@ -49,5 +49,5 @@ python-2.7.8-win32.7z sqlite-3.8.6-win32-vc120.7z swig-2.0.7-win32-1.7z taglib-1.9.1-patched-win32-vc120.7z -texturepacker-1.0.4-win32.7z +texturepacker-1.0.5-win32.7z tinyxml-2.6.2_3-win32-vc120.7z diff --git a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp index 67e6d24389..f970793d02 100644 --- a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp +++ b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp @@ -34,26 +34,25 @@ bool GIFDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) GifHelper *gifImage = new GifHelper(); if (gifImage->LoadGif(filename.c_str())) { - std::vector<GifFrame> extractedFrames = gifImage->GetFrames(); + auto extractedFrames = gifImage->GetFrames(); n = extractedFrames.size(); if (n > 0) { + unsigned int height = gifImage->GetHeight(); + unsigned int width = gifImage->GetWidth(); + unsigned int pitch = gifImage->GetPitch(); + unsigned int frameSize = pitch * height; for (unsigned int i = 0; i < extractedFrames.size(); i++) { DecodedFrame frame; - frame.rgbaImage.pixels = (char *)new char[extractedFrames[i].m_imageSize]; - memcpy(frame.rgbaImage.pixels, extractedFrames[i].m_pImage, extractedFrames[i].m_imageSize); - frame.rgbaImage.height = extractedFrames[i].m_height; - frame.rgbaImage.width = extractedFrames[i].m_width; + frame.rgbaImage.pixels = (char *)new char[frameSize]; + memcpy(frame.rgbaImage.pixels, extractedFrames[i]->m_pImage, frameSize); + frame.rgbaImage.height = height; + frame.rgbaImage.width = width; frame.rgbaImage.bbp = 32; - frame.rgbaImage.pitch = extractedFrames[i].m_pitch; - - frame.delay = extractedFrames[i].m_delay; - frame.disposal = extractedFrames[i].m_disposal; - frame.x = extractedFrames[i].m_left; - frame.y = extractedFrames[i].m_top; - + frame.rgbaImage.pitch = pitch; + frame.delay = extractedFrames[i]->m_delay; frames.frameList.push_back(frame); } diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp index 45a5a5e784..d629844399 100644 --- a/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp @@ -33,134 +33,134 @@ public: unsigned int buffSize; unsigned int readPosition; - Gifreader() : buffer(NULL), buffSize(0), readPosition(0) {} + Gifreader() : buffer(nullptr), buffSize(0), readPosition(0) {} }; -int ReadFromMemory(GifFileType* gif, GifByteType* gifbyte, int len) -{ - unsigned int alreadyRead = ((Gifreader*)gif->UserData)->readPosition; - unsigned int buffSizeLeft = ((Gifreader*)gif->UserData)->buffSize - alreadyRead; - int readBytes = len; - - if (len <= 0) - readBytes = 0; - - if ((unsigned int)len > buffSizeLeft) - readBytes = buffSizeLeft; - - if (readBytes > 0) - { - unsigned char* src = ((Gifreader*)gif->UserData)->buffer + alreadyRead; - memcpy(gifbyte, src, readBytes); - ((Gifreader*)gif->UserData)->readPosition += readBytes; - } - return readBytes; -} - int ReadFromVfs(GifFileType* gif, GifByteType* gifbyte, int len) { - CFile *gifFile = (CFile *)gif->UserData; - return (int)gifFile->Read(gifbyte, len); + CFile *gifFile = static_cast<CFile*>(gif->UserData); + return gifFile->Read(gifbyte, len); } - GifHelper::GifHelper() : m_imageSize(0), m_pitch(0), m_loops(0), m_numFrames(0), m_filename(""), - m_gif(NULL), - m_hasBackground(false), - m_pTemplate(NULL), + m_gif(nullptr), + m_pTemplate(nullptr), m_isAnimated(-1) { - m_backColor = new COLOR(); - memset(m_backColor, 0, sizeof(COLOR)); - m_frames.clear(); + m_gifFile = new CFile(); } GifHelper::~GifHelper() { - int err; -#if GIFLIB_MAJOR >= 5 && GIFLIB_MINOR >= 1 - DGifCloseFile(m_gif, &err); + Close(m_gif); + Release(); + delete m_gifFile; +} + +bool GifHelper::Open(GifFileType*& gif, void *dataPtr, InputFunc readFunc) +{ + int err = 0; +#if GIFLIB_MAJOR == 5 + gif = DGifOpen(dataPtr, readFunc, &err); +#else + gif = DGifOpen(dataPtr, readFunc); + if (!gif) + err = GifLastError(); +#endif + + if (!gif) + { + fprintf(stderr, "Gif::Open(): Could not open file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(err)); + return false; + } + + return true; +} + +void GifHelper::Close(GifFileType* gif) +{ + int err = 0; + int reason = 0; +#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 + err = DGifCloseFile(gif, &reason); #else - err = DGifCloseFile(m_gif); + err = DGifCloseFile(gif); +#if GIFLIB_MAJOR < 5 + reason = GifLastError(); #endif - if (err == D_GIF_ERR_CLOSE_FAILED) + if (err == GIF_ERROR) + free(gif); +#endif + if (err == GIF_ERROR) { - fprintf(stderr, "Gif::~Gif(): D_GIF_ERR_CLOSE_FAILED\n"); - free(m_gif); + fprintf(stderr, "GifHelper::Close(): closing file %s failed. Reason: %s\n", m_filename.c_str(), Reason(reason)); } - Release(); - delete m_backColor; +} + +const char* GifHelper::Reason(int reason) +{ + const char* err = GifErrorString(reason); + if (err) + return err; + + return "unknown"; + } void GifHelper::Release() { delete[] m_pTemplate; - m_pTemplate = NULL; + m_pTemplate = nullptr; m_globalPalette.clear(); m_frames.clear(); } -void GifHelper::ConvertColorTable(std::vector<COLOR> &dest, ColorMapObject* src, unsigned int size) +void GifHelper::ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size) { for (unsigned int i = 0; i < size; ++i) { - COLOR c; + GifColor c; c.r = src->Colors[i].Red; c.g = src->Colors[i].Green; c.b = src->Colors[i].Blue; - c.x = 0xff; + c.a = 0xff; dest.push_back(c); } } -bool GifHelper::LoadGifMetaData(GifFileType* file) +bool GifHelper::LoadGifMetaData(GifFileType* gif) { - if (DGifSlurp(m_gif) == GIF_ERROR) - { -#if GIFLIB_MAJOR >= 5 - const char* error = GifErrorString(m_gif->Error); - if (error) - fprintf(stderr, "Gif::LoadGif(): Could not read file %s - %s\n", m_filename.c_str(), error); -#else - int error = GifLastError(); - if (error) - fprintf(stderr, "Gif::LoadGif(): Could not read file %s - %d\n", m_filename.c_str(), error); -#endif - else - fprintf(stderr, "Gif::LoadGif(): Could not read file %s (reasons unknown)\n", m_filename.c_str()); + if (!Slurp(gif)) return false; - } - m_height = m_gif->SHeight; - m_width = m_gif->SWidth; + m_height = gif->SHeight; + m_width = gif->SWidth; if (!m_height || !m_width) { fprintf(stderr, "Gif::LoadGif(): Zero sized image. File %s\n", m_filename.c_str()); return false; } - m_numFrames = m_gif->ImageCount; + m_numFrames = gif->ImageCount; if (m_numFrames > 0) { -#if GIFLIB_MAJOR >= 5 - GraphicsControlBlock GCB; - DGifSavedExtensionToGCB(m_gif, 0, &GCB); - ExtensionBlock* extb = m_gif->SavedImages[0].ExtensionBlocks; + ExtensionBlock* extb = gif->SavedImages[0].ExtensionBlocks; if (extb && extb->Function == APPLICATION_EXT_FUNC_CODE) { // Read number of loops - if(++extb && extb->Function == CONTINUE_EXT_FUNC_CODE) + if (++extb && extb->Function == CONTINUE_EXT_FUNC_CODE) { - m_loops = UNSIGNED_LITTLE_ENDIAN(extb->Bytes[1],extb->Bytes[2]); + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + m_loops = UNSIGNED_LITTLE_ENDIAN(low, high); } } -#endif } else { @@ -168,7 +168,7 @@ bool GifHelper::LoadGifMetaData(GifFileType* file) return false; } - m_pitch = m_width * sizeof(COLOR); + m_pitch = m_width * sizeof(GifColor); m_imageSize = m_pitch * m_height; unsigned long memoryUsage = m_numFrames * m_imageSize; if (memoryUsage > GIF_MAX_MEMORY) @@ -183,31 +183,28 @@ bool GifHelper::LoadGifMetaData(GifFileType* file) bool GifHelper::LoadGifMetaData(const char* file) { - int err = 0; - - if (m_gifFile.Open(file)) -#if GIFLIB_MAJOR >= 5 - m_gif = DGifOpen(&m_gifFile, ReadFromVfs, &err); -#else - m_gif = DGifOpen(&m_gifFile, ReadFromVfs); -#endif + m_gifFile->Close(); + if (!m_gifFile->Open(file) || !Open(m_gif, m_gifFile, ReadFromVfs)) + return false; - if (!m_gif) + return LoadGifMetaData(m_gif); +} + +bool GifHelper::Slurp(GifFileType* gif) +{ + if (DGifSlurp(gif) == GIF_ERROR) { -#if GIFLIB_MAJOR >= 5 - const char* error = GifErrorString(err); - if (error) - fprintf(stderr, "Gif::LoadGif(): Could not open file %s - %s\n", m_filename.c_str(), error); + int reason = 0; +#if GIFLIB_MAJOR == 5 + reason = gif->Error; #else - int error = GifLastError(); - if (error) - fprintf(stderr, "Gif::LoadGif(): Could not open file %s - %d\n", m_filename.c_str(), error); + reason = GifLastError(); #endif - else - fprintf(stderr, "Gif::LoadGif(): Could not open file %s (reasons unknown)\n", m_filename.c_str()); + fprintf(stderr, "Gif::LoadGif(): Could not read file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(reason)); return false; } - return LoadGifMetaData(m_gif); + + return true; } bool GifHelper::LoadGif(const char* file) @@ -220,7 +217,19 @@ bool GifHelper::LoadGif(const char* file) { InitTemplateAndColormap(); - return ExtractFrames(m_numFrames); + int extractedFrames = ExtractFrames(m_numFrames); + if (extractedFrames < 0) + { + fprintf(stderr, "Gif::LoadGif(): Could not extract any frame. File %s\n", m_filename.c_str()); + return false; + } + else if (extractedFrames < (int)m_numFrames) + { + fprintf(stderr, "Gif::LoadGif(): Could only extract %d/%d frames. File %s\n", extractedFrames, m_numFrames, m_filename.c_str()); + m_numFrames = extractedFrames; + } + + return true; } catch (std::bad_alloc& ba) { @@ -230,40 +239,6 @@ bool GifHelper::LoadGif(const char* file) } } -bool GifHelper::IsAnimated(const char* file) -{ - if (m_isAnimated < 0) - { - m_isAnimated = 0; - - GifFileType *gif = NULL; - FILE *gifFile; - int err = 0; - gifFile = fopen(file, "rb"); - if (gifFile != NULL) - { -#if GIFLIB_MAJOR >= 5 - gif = DGifOpen(&gifFile, ReadFromVfs, &err); -#else - gif = DGifOpen(&gifFile, ReadFromVfs); -#endif - } - - if (gif) - { - if (DGifSlurp(gif) && gif->ImageCount > 1) - m_isAnimated = 1; -#if GIFLIB_MAJOR >= 5 && GIFLIB_MINOR >= 1 - DGifCloseFile(gif, NULL); -#else - DGifCloseFile(gif); -#endif - fclose(gifFile); - } - } - return m_isAnimated > 0; -} - void GifHelper::InitTemplateAndColormap() { m_pTemplate = new unsigned char[m_imageSize]; @@ -273,155 +248,166 @@ void GifHelper::InitTemplateAndColormap() { m_globalPalette.clear(); ConvertColorTable(m_globalPalette, m_gif->SColorMap, m_gif->SColorMap->ColorCount); - - // draw the canvas - *m_backColor = m_globalPalette[m_gif->SBackGroundColor]; - m_hasBackground = true; - - for (unsigned int i = 0; i < m_height * m_width; ++i) - { - unsigned char *dest = m_pTemplate + (i *sizeof(COLOR)); - memcpy(dest, m_backColor, sizeof(COLOR)); - } } else m_globalPalette.clear(); } -bool GifHelper::gcbToFrame(GifFrame &frame, unsigned int imgIdx) +bool GifHelper::GcbToFrame(GifFrame &frame, unsigned int imgIdx) { int transparent = -1; frame.m_delay = 0; frame.m_disposal = 0; -#if GIFLIB_MAJOR >= 5 + if (m_gif->ImageCount > 0) { +#if GIFLIB_MAJOR == 5 GraphicsControlBlock gcb; if (!DGifSavedExtensionToGCB(m_gif, imgIdx, &gcb)) { - const char* error = GifErrorString(m_gif->Error); - if (error) - fprintf(stderr, "Gif::ExtractFrames(): Could not read GraphicsControlBlock of frame %d - %s\n", imgIdx, error); - else - fprintf(stderr, "Gif::ExtractFrames(): Could not read GraphicsControlBlock of frame %d (reasons unknown)\n", imgIdx); + fprintf(stderr, "Gif::GcbToFrame(): Could not read GraphicsControlBlock of frame %d in file %s\n", + imgIdx, m_filename.c_str()), GifErrorString(m_gif->Error); return false; } // delay in ms frame.m_delay = gcb.DelayTime * 10; frame.m_disposal = gcb.DisposalMode; transparent = gcb.TransparentColor; - } #else - if (m_gif->ImageCount > 0) - { ExtensionBlock* extb = m_gif->SavedImages[imgIdx].ExtensionBlocks; while (extb && extb->Function != GRAPHICS_EXT_FUNC_CODE) extb++; - if (extb) + if (!extb || extb->ByteCount != 4) + { + fprintf(stderr, "Gif::GcbToFrame() : Could not read GraphicsControlBlock of frame %d in file %s\n", + imgIdx, m_filename.c_str()); + return false; + } + else { - frame.m_delay = UNSIGNED_LITTLE_ENDIAN(extb->Bytes[1], extb->Bytes[2]) * 10; - frame.m_disposal = (extb->Bytes[0] >> 2) & 0x7; - if (extb->Bytes[0] & 0x1) - transparent = extb->Bytes[3]; + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + frame.m_delay = UNSIGNED_LITTLE_ENDIAN(low, high) * 10; + frame.m_disposal = (extb->Bytes[0] >> 2) & 0x07; + if (extb->Bytes[0] & 0x01) + { + transparent = static_cast<uint8_t>(extb->Bytes[3]); + } else transparent = -1; } - } + #endif + } if (transparent >= 0 && (unsigned)transparent < frame.m_palette.size()) - frame.m_palette[transparent].x = 0; + frame.m_palette[transparent].a = 0; return true; } -bool GifHelper::ExtractFrames(unsigned int count) +int GifHelper::ExtractFrames(unsigned int count) { if (!m_gif) - return false; + return -1; if (!m_pTemplate) { fprintf(stderr, "Gif::ExtractFrames(): No frame template available\n"); - return false; + return -1; } + int extracted = 0; for (unsigned int i = 0; i < count; i++) { - GifFrame frame; + FramePtr frame(new GifFrame); SavedImage savedImage = m_gif->SavedImages[i]; GifImageDesc imageDesc = m_gif->SavedImages[i].ImageDesc; - frame.m_height = imageDesc.Height; - frame.m_width = imageDesc.Width; - frame.m_top = imageDesc.Top; - frame.m_left = imageDesc.Left; - frame.m_pitch = m_pitch; - - if (frame.m_top + frame.m_height > m_height || frame.m_left + frame.m_width > m_width - || !frame.m_width || !frame.m_height) + frame->m_height = imageDesc.Height; + frame->m_width = imageDesc.Width; + frame->m_top = imageDesc.Top; + frame->m_left = imageDesc.Left; + + if (frame->m_top + frame->m_height > m_height || frame->m_left + frame->m_width > m_width + || !frame->m_width || !frame->m_height + || frame->m_width > m_width || frame->m_height > m_height) { - fprintf(stderr, "Gif::ExtractFrames(): Illegal frame dimensions: width: %d, height: %d, left: %d, top: %d instead of (%d,%d)\n", - frame.m_width, frame.m_height, frame.m_left, frame.m_top, m_width, m_height); - return false; + fprintf(stderr, "Gif::ExtractFrames(): Illegal frame dimensions: width: %d, height: %d, left: %d, top: %d instead of (%d,%d), skip it\n", + frame->m_width, frame->m_height, frame->m_left, frame->m_top, m_width, m_height); + continue; } if (imageDesc.ColorMap) { - frame.m_palette.clear(); - ConvertColorTable(frame.m_palette, imageDesc.ColorMap, imageDesc.ColorMap->ColorCount); - // TODO save a backup of the palette for frames without a table in case there's no gloabl table. + frame->m_palette.clear(); + ConvertColorTable(frame->m_palette, imageDesc.ColorMap, imageDesc.ColorMap->ColorCount); + // TODO save a backup of the palette for frames without a table in case there's no global table. } else if (m_gif->SColorMap) { - frame.m_palette = m_globalPalette; + frame->m_palette = m_globalPalette; + } + else + { + fprintf(stderr, "Gif::ExtractFrames(): No color map found for frame %d, skip it\n", i); + continue; } // fill delay, disposal and transparent color into frame - if (!gcbToFrame(frame, i)) - return false; + if (!GcbToFrame(*frame, i)) + { + fprintf(stderr, "Gif::ExtractFrames(): Corrupted Graphics Control Block for frame %d, skip it\n", i); + continue; + } - frame.m_pImage = new unsigned char[m_imageSize]; - frame.m_imageSize = m_imageSize; - memcpy(frame.m_pImage, m_pTemplate, m_imageSize); + frame->m_pImage = new unsigned char[m_imageSize]; + frame->m_imageSize = m_imageSize; + memcpy(frame->m_pImage, m_pTemplate, m_imageSize); - ConstructFrame(frame, savedImage.RasterBits); + ConstructFrame(*frame, savedImage.RasterBits); - if(!PrepareTemplate(frame)) - return false; + if (!PrepareTemplate(*frame)) + { + fprintf(stderr, "Gif::ExtractFrames(): Could not prepare template after frame %d, skip it\n", i); + continue; + } + extracted++; m_frames.push_back(frame); } - return true; + return extracted; } void GifHelper::ConstructFrame(GifFrame &frame, const unsigned char* src) const { + size_t paletteSize = frame.m_palette.size(); + for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) { - unsigned char *to = frame.m_pImage + (dest_y * m_pitch) + (frame.m_left * sizeof(COLOR)); + unsigned char *to = frame.m_pImage + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); const unsigned char *from = src + (src_y * frame.m_width); for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) { - COLOR col = frame.m_palette[*from++]; - if (col.x != 0) - { - *to++ = col.b; - *to++ = col.g; - *to++ = col.r; - *to++ = col.x; - } - else + unsigned char index = *from++; + + if (index >= paletteSize) { - to += 4; + fprintf(stderr, "Gif::ConstructFrame(): Pixel (%d,%d) has no valid palette entry, skip it\n", src_x, src_y); + continue; } + + GifColor col = frame.m_palette[index]; + if (col.a != 0) + memcpy(to, &col, sizeof(GifColor)); + + to += 4; } } } -bool GifHelper::PrepareTemplate(const GifFrame &frame) +bool GifHelper::PrepareTemplate(GifFrame &frame) { -#if GIFLIB_MAJOR >= 5 switch (frame.m_disposal) { /* No disposal specified. */ @@ -431,140 +417,92 @@ bool GifHelper::PrepareTemplate(const GifFrame &frame) memcpy(m_pTemplate, frame.m_pImage, m_imageSize); break; - /* Set area too background color */ + /* + Clear the frame's area to transparency. + The disposal names is misleading. Do not restore to the background color because + this part of the specification is ignored by all browsers/image viewers. + */ case DISPOSE_BACKGROUND: - { - if (!m_hasBackground) - { - fprintf(stderr, "Gif::PrepareTemplate(): Disposal method DISPOSE_BACKGROUND encountered, but the gif has no background.\n"); - return false; - } - SetFrameAreaToBack(m_pTemplate, frame); - break; - } - /* Restore to previous content */ + { + ClearFrameAreaToTransparency(m_pTemplate, frame); + break; + } + /* Restore to previous content */ case DISPOSE_PREVIOUS: + { + + /* + * This disposal method makes no sense for the first frame + * Since browsers etc. handle that too, we'll fall back to DISPOSE_DO_NOT + */ + if (m_frames.empty()) { - bool valid = false; + frame.m_disposal = DISPOSE_DO_NOT; + return PrepareTemplate(frame); + } - for (int i = m_frames.size() - 1 ; i >= 0; --i) - { - if (m_frames[i].m_disposal != DISPOSE_PREVIOUS) - { - memcpy(m_pTemplate, m_frames[i].m_pImage, m_imageSize); - valid = true; - break; - } - } - if (!valid) + bool valid = false; + + for (int i = m_frames.size() - 1; i >= 0; --i) + { + if (m_frames[i]->m_disposal != DISPOSE_PREVIOUS) { - fprintf(stderr, "Gif::PrepareTemplate(): Disposal method DISPOSE_PREVIOUS encountered, but could not find a suitable frame.\n"); - return false; + memcpy(m_pTemplate, m_frames[i]->m_pImage, m_imageSize); + valid = true; + break; } - break; } - default: + if (!valid) { - fprintf(stderr, "Gif::PrepareTemplate(): Unknown disposal method: %d\n", frame.m_disposal); + fprintf(stderr, "Gif::PrepareTemplate(): Disposal method DISPOSE_PREVIOUS encountered, but could not find a suitable frame.\n"); return false; } + break; + } + default: + { + fprintf(stderr, "Gif::PrepareTemplate(): Unknown disposal method: %d. Using DISPOSAL_UNSPECIFIED, the animation might be wrong now.\n", frame.m_disposal); + frame.m_disposal = DISPOSAL_UNSPECIFIED; + return PrepareTemplate(frame); + } } -#endif return true; } -void GifHelper::SetFrameAreaToBack(unsigned char* dest, const GifFrame &frame) +void GifHelper::ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame) { for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) { - unsigned char *to = dest + (dest_y * m_pitch) + (frame.m_left * sizeof(COLOR)); + unsigned char *to = dest + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) { - memcpy(to, m_backColor, sizeof(COLOR)); - to += 4; + to += 3; + *to++ = 0; } } } -bool GifHelper::LoadImageFromMemory(unsigned char* buffer, unsigned int bufSize, unsigned int width, unsigned int height) -{ - if (!buffer || !bufSize || !width || !height) - return false; - - Gifreader reader; - reader.buffer = buffer; - reader.buffSize = bufSize; - - int err = 0; -#if GIFLIB_MAJOR >= 5 - m_gif = DGifOpen((void *)&reader, (InputFunc)&ReadFromMemory, &err); -#else - m_gif = DGifOpen((void *)&reader, (InputFunc)&ReadFromMemory); -#endif - if (!m_gif) - { -#if GIFLIB_MAJOR >= 5 - const char* error = GifErrorString(err); - if (error) - fprintf(stderr, "Gif::LoadImageFromMemory(): Could not open gif from memory - %s\n", error); -#else - int error = GifLastError(); - if (error) - fprintf(stderr, "Gif::LoadImageFromMemory(): Could not open gif from memory - %d\n", error); -#endif - else - fprintf(stderr, "Gif::LoadImageFromMemory(): Could not open gif from memory (reasons unknown)\n"); - return false; - } - - if (!LoadGifMetaData(m_gif)) - return false; - - m_originalWidth = m_width; - m_originalHeight = m_height; - - try - { - InitTemplateAndColormap(); - - if (!ExtractFrames(m_numFrames)) - return false; - } - catch (std::bad_alloc& ba) - { - fprintf(stderr, "Gif::LoadImageFromMemory(): Out of memory while extracting gif frames - %s\n", ba.what()); - Release(); - return false; - } - - return true; -} - GifFrame::GifFrame() : - m_pImage(NULL), + m_pImage(nullptr), m_delay(0), m_imageSize(0), m_height(0), m_width(0), m_top(0), m_left(0), - m_disposal(0), - m_transparent(0), - m_pitch(0) + m_disposal(0) {} GifFrame::GifFrame(const GifFrame& src) : - m_pImage(NULL), + m_pImage(nullptr), m_delay(src.m_delay), m_imageSize(src.m_imageSize), m_height(src.m_height), m_width(src.m_width), m_top(src.m_top), m_left(src.m_left), - m_disposal(src.m_disposal), - m_transparent(src.m_transparent), - m_pitch(src.m_pitch) + m_disposal(src.m_disposal) { if (src.m_pImage) { @@ -581,5 +519,5 @@ GifFrame::GifFrame(const GifFrame& src) : GifFrame::~GifFrame() { delete[] m_pImage; - m_pImage = NULL; + m_pImage = nullptr; } diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.h b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h index dae24589e0..02fe25bbb4 100644 --- a/tools/depends/native/TexturePacker/src/decoder/GifHelper.h +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h @@ -21,13 +21,36 @@ #pragma once #include "gif_lib.h" +#ifndef CONTINUE_EXT_FUNC_CODE +#define CONTINUE_EXT_FUNC_CODE 0 +#endif + +#ifndef DISPOSAL_UNSPECIFIED +#define DISPOSAL_UNSPECIFIED 0 +#endif + +#ifndef DISPOSE_DO_NOT +#define DISPOSE_DO_NOT 1 +#endif + +#ifndef DISPOSE_BACKGROUND +#define DISPOSE_BACKGROUND 2 +#endif + +#ifndef DISPOSE_PREVIOUS +#define DISPOSE_PREVIOUS 3 +#endif + #include <vector> #include <string> +#include <memory> #include "SimpleFS.h" - #pragma pack(1) -struct COLOR { unsigned char b, g, r, x; }; // Windows GDI expects 4bytes per color +struct GifColor +{ + uint8_t b, g, r, a; +}; #pragma pack() class CFile; @@ -39,12 +62,13 @@ public: GifFrame(); virtual ~GifFrame(); - void Release(); - - GifFrame(const GifFrame& src); unsigned char* m_pImage; unsigned int m_delay; + +private: + GifFrame(const GifFrame& src); + unsigned int m_top; unsigned int m_left; unsigned int m_disposal; @@ -52,10 +76,7 @@ public: unsigned int m_width; unsigned int m_pitch; unsigned int m_imageSize; - -private: - - std::vector<COLOR> m_palette; + std::vector<GifColor> m_palette; int m_transparent; }; @@ -64,22 +85,24 @@ private: class GifHelper { friend class GifFrame; + + typedef std::shared_ptr<GifFrame> FramePtr; + public: GifHelper(); virtual ~GifHelper(); - bool LoadGifMetaData(const char* file); + bool LoadGif(const char* file); - virtual bool LoadImageFromMemory(unsigned char* buffer, unsigned int bufSize, unsigned int width, unsigned int height); - //virtual bool Decode(const unsigned char *pixels, unsigned int pitch, unsigned int format); - bool IsAnimated(const char* file); - std::vector<GifFrame>& GetFrames() { return m_frames; } + std::vector<FramePtr>& GetFrames() { return m_frames; } unsigned int GetPitch() const { return m_pitch; } unsigned int GetNumLoops() const { return m_loops; } + unsigned int GetWidth() const { return m_width; } + unsigned int GetHeight() const { return m_height; } private: - std::vector<GifFrame> m_frames; + std::vector<FramePtr> m_frames; unsigned int m_imageSize; unsigned int m_pitch; unsigned int m_loops; @@ -88,11 +111,11 @@ private: std::string m_filename; GifFileType* m_gif; bool m_hasBackground; - COLOR* m_backColor; - std::vector<COLOR> m_globalPalette; + GifColor* m_backColor; + std::vector<GifColor> m_globalPalette; unsigned char* m_pTemplate; int m_isAnimated; - CFile m_gifFile; + CFile* m_gifFile; unsigned int m_width; unsigned int m_height; @@ -101,13 +124,106 @@ private: unsigned int m_orientation; bool m_hasAlpha; + bool Open(GifFileType *& gif, void * dataPtr, InputFunc readFunc); + void Close(GifFileType * gif); + + const char* Reason(int reason); + + bool LoadGifMetaData(const char* file); + bool Slurp(GifFileType* gif); void InitTemplateAndColormap(); - bool LoadGifMetaData(GifFileType* file); - static void ConvertColorTable(std::vector<COLOR> &dest, ColorMapObject* src, unsigned int size); - bool gcbToFrame(GifFrame &frame, unsigned int imgIdx); - bool ExtractFrames(unsigned int count); - void SetFrameAreaToBack(unsigned char* dest, const GifFrame &frame); + bool LoadGifMetaData(GifFileType* gif); + static void ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size); + bool GcbToFrame(GifFrame &frame, unsigned int imgIdx); + int ExtractFrames(unsigned int count); + void ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame); void ConstructFrame(GifFrame &frame, const unsigned char* src) const; - bool PrepareTemplate(const GifFrame &frame); + bool PrepareTemplate(GifFrame &frame); void Release(); + +#if GIFLIB_MAJOR != 5 + /* + taken from giflib 5.1.0 + */ + const char* GifErrorString(int ErrorCode) + { + const char *Err; + + switch (ErrorCode) { + case E_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case E_GIF_ERR_WRITE_FAILED: + Err = "Failed to write to given file"; + break; + case E_GIF_ERR_HAS_SCRN_DSCR: + Err = "Screen descriptor has already been set"; + break; + case E_GIF_ERR_HAS_IMAG_DSCR: + Err = "Image descriptor is still active"; + break; + case E_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case E_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case E_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case E_GIF_ERR_DISK_IS_FULL: + Err = "Write failed (disk full?)"; + break; + case E_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case E_GIF_ERR_NOT_WRITEABLE: + Err = "Given file was not opened for write"; + break; + case D_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case D_GIF_ERR_READ_FAILED: + Err = "Failed to read from given file"; + break; + case D_GIF_ERR_NOT_GIF_FILE: + Err = "Data is not in GIF format"; + break; + case D_GIF_ERR_NO_SCRN_DSCR: + Err = "No screen descriptor detected"; + break; + case D_GIF_ERR_NO_IMAG_DSCR: + Err = "No Image Descriptor detected"; + break; + case D_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case D_GIF_ERR_WRONG_RECORD: + Err = "Wrong record type detected"; + break; + case D_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case D_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case D_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case D_GIF_ERR_NOT_READABLE: + Err = "Given file was not opened for read"; + break; + case D_GIF_ERR_IMAGE_DEFECT: + Err = "Image is defective, decoding aborted"; + break; + case D_GIF_ERR_EOF_TOO_SOON: + Err = "Image EOF detected before image complete"; + break; + default: + Err = NULL; + break; + } + return Err; + } +#endif }; diff --git a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h index def1eca8b1..25363c7be1 100644 --- a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h +++ b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h @@ -37,10 +37,8 @@ public: class DecodedFrame { public: - DecodedFrame() : x(0), y(0), disposal(0), delay(0) { } + DecodedFrame() : delay(0) { } RGBAImage rgbaImage; /* rgbaimage for this frame */ - int x, y; /* Frame offset position */ - int disposal; /* Disposal code */ int delay; /* Frame delay in ms */ }; |