From f0b1c48ea993e7c4aafae871571bc0f667a09190 Mon Sep 17 00:00:00 2001 From: luoliangyi <87842688@qq.com> Date: Fri, 8 Jul 2022 17:36:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E4=BA=8Egiflib=E5=AE=9E=E7=8E=B0gif?= =?UTF-8?q?=E8=AF=BB=E5=86=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/windows/HGImgFmt/HGImgFmt.def | 10 + build/windows/HGImgFmt/HGImgFmt.vcxproj | 18 +- build/windows/HGTest/HGTestDlg.cpp | 37 + build/windows/HGTest/pch.h | 1 + modules/imgfmt/HGGif.cpp | 904 ++++++++++++++++++++++++ modules/imgfmt/HGGif.h | 46 ++ 6 files changed, 1008 insertions(+), 8 deletions(-) create mode 100644 modules/imgfmt/HGGif.cpp create mode 100644 modules/imgfmt/HGGif.h diff --git a/build/windows/HGImgFmt/HGImgFmt.def b/build/windows/HGImgFmt/HGImgFmt.def index 796a3f58..1de5a7b9 100644 --- a/build/windows/HGImgFmt/HGImgFmt.def +++ b/build/windows/HGImgFmt/HGImgFmt.def @@ -40,6 +40,16 @@ HGImgFmt_CloseTiffWriter HGImgFmt_SaveImageToTiffWriter HGImgFmt_SaveTiffImage +HGImgFmt_CheckGifFile +HGImgFmt_OpenGifReader +HGImgFmt_CloseGifReader +HGImgFmt_LoadImageFromGifReader +HGImgFmt_LoadGifImage +HGImgFmt_OpenGifWriter +HGImgFmt_CloseGifWriter +HGImgFmt_SaveImageToGifWriter +HGImgFmt_SaveGifImage + HGImgFmt_CheckPdfFile HGImgFmt_OpenPdfReader HGImgFmt_ClosePdfReader diff --git a/build/windows/HGImgFmt/HGImgFmt.vcxproj b/build/windows/HGImgFmt/HGImgFmt.vcxproj index 419a33c3..208fe11c 100644 --- a/build/windows/HGImgFmt/HGImgFmt.vcxproj +++ b/build/windows/HGImgFmt/HGImgFmt.vcxproj @@ -23,6 +23,7 @@ + @@ -35,6 +36,7 @@ + @@ -119,7 +121,7 @@ NotUsing pch.h MultiThreadedDebug - ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) + ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/giflib/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) %(DisableSpecificWarnings) @@ -127,7 +129,7 @@ true false HGImgFmt.def - ../Debug/HGBase.lib;../../../third_party/libjpeg/windows/lib/x86/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x86/libnsbmp.lib;../../../third_party/libpng/windows/lib/x86/libpng16.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libtiff/windows/lib/x86/tiff.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2d.lib;%(AdditionalDependencies) + ../Debug/HGBase.lib;../../../third_party/libjpeg/windows/lib/x86/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x86/libnsbmp.lib;../../../third_party/libpng/windows/lib/x86/libpng16.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libtiff/windows/lib/x86/tiff.lib;../../../third_party/giflib/windows/lib/x86/giflib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2d.lib;%(AdditionalDependencies) /ignore:4098,4099,4075 /LTCG %(AdditionalOptions) @@ -142,7 +144,7 @@ NotUsing pch.h MultiThreaded - ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) + ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/giflib/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) Windows @@ -151,7 +153,7 @@ true false HGImgFmt.def - ../Release/HGBase.lib;../../../third_party/libjpeg/windows/lib/x86/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x86/libnsbmp.lib;../../../third_party/libpng/windows/lib/x86/libpng16.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libtiff/windows/lib/x86/tiff.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2.lib;%(AdditionalDependencies) + ../Release/HGBase.lib;../../../third_party/libjpeg/windows/lib/x86/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x86/libnsbmp.lib;../../../third_party/libpng/windows/lib/x86/libpng16.lib;../../../third_party/zlib/windows/lib/x86/zlib.lib;../../../third_party/libtiff/windows/lib/x86/tiff.lib;../../../third_party/giflib/windows/lib/x86/giflib.lib;../../../third_party/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2.lib;%(AdditionalDependencies) /ignore:4099 /LTCG %(AdditionalOptions) @@ -170,7 +172,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\NotUsing pch.h MultiThreadedDebug - ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) + ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/giflib/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) %(DisableSpecificWarnings) false @@ -179,7 +181,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\true false HGImgFmt.def - ../x64/Debug/HGBase.lib;../../../third_party/libjpeg/windows/lib/x64/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x64/libnsbmp.lib;../../../third_party/libpng/windows/lib/x64/libpng16.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libtiff/windows/lib/x64/tiff.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2d.lib;%(AdditionalDependencies) + ../x64/Debug/HGBase.lib;../../../third_party/libjpeg/windows/lib/x64/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x64/libnsbmp.lib;../../../third_party/libpng/windows/lib/x64/libpng16.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libtiff/windows/lib/x64/tiff.lib;../../../third_party/giflib/windows/lib/x64/giflib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2d.lib;%(AdditionalDependencies) /ignore:4098,4099,4075 /LTCG %(AdditionalOptions) @@ -194,7 +196,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\NotUsing pch.h MultiThreaded - ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) + ../../../third_party/libjpeg/windows/include;../../../third_party/libnsbmp/windows/include;../../../third_party/libpng/windows/include;../../../third_party/zlib/windows/include;../../../third_party/libtiff/windows/include;../../../third_party/giflib/windows/include;../../../third_party/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories) Windows @@ -203,7 +205,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\true false HGImgFmt.def - ../x64/Release/HGBase.lib;../../../third_party/libjpeg/windows/lib/x64/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x64/libnsbmp.lib;../../../third_party/libpng/windows/lib/x64/libpng16.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libtiff/windows/lib/x64/tiff.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2.lib;%(AdditionalDependencies) + ../x64/Release/HGBase.lib;../../../third_party/libjpeg/windows/lib/x64/jpeg.lib;../../../third_party/libnsbmp/windows/lib/x64/libnsbmp.lib;../../../third_party/libpng/windows/lib/x64/libpng16.lib;../../../third_party/zlib/windows/lib/x64/zlib.lib;../../../third_party/libtiff/windows/lib/x64/tiff.lib;../../../third_party/giflib/windows/lib/x64/giflib.lib;../../../third_party/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2.lib;%(AdditionalDependencies) /ignore:4099 /LTCG %(AdditionalOptions) diff --git a/build/windows/HGTest/HGTestDlg.cpp b/build/windows/HGTest/HGTestDlg.cpp index d35c44a6..84717a87 100644 --- a/build/windows/HGTest/HGTestDlg.cpp +++ b/build/windows/HGTest/HGTestDlg.cpp @@ -104,6 +104,43 @@ BOOL CHGTestDlg::OnInitDialog() SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 + HGGifLoadInfo loadInfo; + HGGifReader gifReader = NULL; + HGImgFmt_OpenGifReader("D:\\1.gif", &loadInfo, &gifReader); + if (NULL != gifReader) + { + HGGifSaveInfo saveInfo; + saveInfo.width = loadInfo.width; + saveInfo.height = loadInfo.height; + + HGGifWriter gifWriter = NULL; + HGImgFmt_OpenGifWriter("D:\\2.gif", &saveInfo, &gifWriter); + if (NULL != gifWriter) + { + while (1) + { + HGUInt index = 0xFFFFFFFF; + HGUInt interval = 0xFFFFFFFF; + HGImage image = NULL; + HGImgFmt_LoadImageFromGifReader(gifReader, &index, &interval, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_BOTTOM, &image); + if (NULL != image) + { + HGImgFmt_SaveImageToGifWriter(gifWriter, interval, image); + HGBase_DestroyImage(image); + } + + if (index == loadInfo.imageCount - 1) + { + break; + } + } + + HGImgFmt_CloseGifWriter(gifWriter); + } + + HGImgFmt_CloseGifReader(gifReader); + } + return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } diff --git a/build/windows/HGTest/pch.h b/build/windows/HGTest/pch.h index cf27d615..8b76e55e 100644 --- a/build/windows/HGTest/pch.h +++ b/build/windows/HGTest/pch.h @@ -15,6 +15,7 @@ #include "imgfmt/HGBmp.h" #include "imgfmt/HGPng.h" #include "imgfmt/HGTiff.h" +#include "imgfmt/HGGif.h" #include "imgfmt/HGPdf.h" #include "imgfmt/HGOfd.h" #include "imgfmt/HGImgFmt.h" diff --git a/modules/imgfmt/HGGif.cpp b/modules/imgfmt/HGGif.cpp new file mode 100644 index 00000000..fa2dfaba --- /dev/null +++ b/modules/imgfmt/HGGif.cpp @@ -0,0 +1,904 @@ +#include "HGGif.h" +#include "../base/HGInc.h" +#include "gif_lib.h" + +struct HGGifReaderImpl +{ + HGGifReaderImpl() + { + m_gifFile = NULL; + m_curIndex = 0xFFFFFFFF; + m_screenBuffer = NULL; + m_imageBuffer = NULL; + } + + ~HGGifReaderImpl() + { + if (NULL != m_imageBuffer) + { + free(m_imageBuffer); + m_imageBuffer = NULL; + } + if (NULL != m_screenBuffer) + { + free(m_screenBuffer); + m_screenBuffer = NULL; + } + if (NULL != m_gifFile) + { + int err; + DGifCloseFile(m_gifFile, &err); + m_gifFile = NULL; + } + } + + GifFileType* m_gifFile; + HGUInt m_curIndex; + uint8_t* m_screenBuffer; + uint8_t* m_imageBuffer; +}; + +struct HGGifWriterImpl +{ + HGGifWriterImpl() + { + m_gifFile = NULL; + m_curIndex = 0xFFFFFFFF; + m_redBuffer = NULL; + m_greenBuffer = NULL; + m_blueBuffer = NULL; + } + + ~HGGifWriterImpl() + { + if (NULL != m_blueBuffer) + { + free(m_blueBuffer); + m_blueBuffer = NULL; + } + if (NULL != m_greenBuffer) + { + free(m_greenBuffer); + m_greenBuffer = NULL; + } + if (NULL != m_redBuffer) + { + free(m_redBuffer); + m_redBuffer = NULL; + } + if (NULL != m_gifFile) + { + int savedCount = m_gifFile->ImageCount; + SavedImage* savedImages = m_gifFile->SavedImages; + //关闭GIF并释放相关存储。 + EGifSpew(m_gifFile); + + for (SavedImage *sp = savedImages; sp < savedImages + savedCount; sp++) + { + if (sp->ImageDesc.ColorMap != NULL) + { + GifFreeMapObject(sp->ImageDesc.ColorMap); + sp->ImageDesc.ColorMap = NULL; + } + + if (sp->RasterBits != NULL) + free((char*)sp->RasterBits); + + GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks); + } + + free((char*)savedImages); + savedImages = NULL; + } + } + + GifFileType* m_gifFile; + HGUInt m_curIndex; + uint8_t* m_redBuffer; + uint8_t* m_greenBuffer; + uint8_t* m_blueBuffer; +}; + +#define ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define COLOR_ARRAY_SIZE 32768 +#define BITS_PER_PRIM_COLOR 5 +#define MAX_PRIM_COLOR 0x1f + +static int SortRGBAxis; + +typedef struct QuantizedColorType { + GifByteType RGB[3]; + GifByteType NewColorIndex; + long Count; + struct QuantizedColorType* Pnext; +} QuantizedColorType; + +typedef struct NewColorMapType { + GifByteType RGBMin[3], RGBWidth[3]; + unsigned int NumEntries; /* # of QuantizedColorType in linked list below */ + unsigned long Count; /* Total number of pixels in all the entries */ + QuantizedColorType* QuantizedColors; +} NewColorMapType; + +static int SortCmpRtn(const void* Entry1, + const void* Entry2) { + QuantizedColorType* entry1 = (*((QuantizedColorType**)Entry1)); + QuantizedColorType* entry2 = (*((QuantizedColorType**)Entry2)); + + /* sort on all axes of the color space! */ + int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256 + + entry1->RGB[(SortRGBAxis + 1) % 3] * 256 + + entry1->RGB[(SortRGBAxis + 2) % 3]; + int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256 + + entry2->RGB[(SortRGBAxis + 1) % 3] * 256 + + entry2->RGB[(SortRGBAxis + 2) % 3]; + + return hash1 - hash2; +} + +static int SubdivColorMap(NewColorMapType* NewColorSubdiv, + unsigned int ColorMapSize, + unsigned int* NewColorMapSize) { + + unsigned int i, j, Index = 0; + QuantizedColorType* QuantizedColor, ** SortArray; + + while (ColorMapSize > *NewColorMapSize) { + /* Find candidate for subdivision: */ + long Sum, Count; + int MaxSize = -1; + unsigned int NumEntries, MinColor, MaxColor; + for (i = 0; i < *NewColorMapSize; i++) { + for (j = 0; j < 3; j++) { + if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) && + (NewColorSubdiv[i].NumEntries > 1)) { + MaxSize = NewColorSubdiv[i].RGBWidth[j]; + Index = i; + SortRGBAxis = j; + } + } + } + + if (MaxSize == -1) + return GIF_OK; + + /* Split the entry Index into two along the axis SortRGBAxis: */ + + /* Sort all elements in that entry along the given axis and split at + * the median. */ + SortArray = (QuantizedColorType**)malloc( + sizeof(QuantizedColorType*) * + NewColorSubdiv[Index].NumEntries); + if (SortArray == NULL) + return GIF_ERROR; + for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors; + j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL; + j++, QuantizedColor = QuantizedColor->Pnext) + SortArray[j] = QuantizedColor; + + /* + * Because qsort isn't stable, this can produce differing + * results for the order of tuples depending on platform + * details of how qsort() is implemented. + * + * We mitigate this problem by sorting on all three axes rather + * than only the one specied by SortRGBAxis; that way the instability + * can only become an issue if there are multiple color indices + * referring to identical RGB tuples. Older versions of this + * sorted on only the one axis. + */ + qsort(SortArray, NewColorSubdiv[Index].NumEntries, + sizeof(QuantizedColorType*), SortCmpRtn); + + /* Relink the sorted list into one: */ + for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++) + SortArray[j]->Pnext = SortArray[j + 1]; + SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL; + NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0]; + free((char*)SortArray); + + /* Now simply add the Counts until we have half of the Count: */ + Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count; + NumEntries = 1; + Count = QuantizedColor->Count; + while (QuantizedColor->Pnext != NULL && + (Sum -= QuantizedColor->Pnext->Count) >= 0 && + QuantizedColor->Pnext->Pnext != NULL) { + QuantizedColor = QuantizedColor->Pnext; + NumEntries++; + Count += QuantizedColor->Count; + } + /* Save the values of the last color of the first half, and first + * of the second half so we can update the Bounding Boxes later. + * Also as the colors are quantized and the BBoxes are full 0..255, + * they need to be rescaled. + */ + MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */ + /* coverity[var_deref_op] */ + MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */ + MaxColor <<= (8 - BITS_PER_PRIM_COLOR); + MinColor <<= (8 - BITS_PER_PRIM_COLOR); + + /* Partition right here: */ + NewColorSubdiv[*NewColorMapSize].QuantizedColors = + QuantizedColor->Pnext; + QuantizedColor->Pnext = NULL; + NewColorSubdiv[*NewColorMapSize].Count = Count; + NewColorSubdiv[Index].Count -= Count; + NewColorSubdiv[*NewColorMapSize].NumEntries = + NewColorSubdiv[Index].NumEntries - NumEntries; + NewColorSubdiv[Index].NumEntries = NumEntries; + for (j = 0; j < 3; j++) { + NewColorSubdiv[*NewColorMapSize].RGBMin[j] = + NewColorSubdiv[Index].RGBMin[j]; + NewColorSubdiv[*NewColorMapSize].RGBWidth[j] = + NewColorSubdiv[Index].RGBWidth[j]; + } + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] = + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] + + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor; + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor; + + NewColorSubdiv[Index].RGBWidth[SortRGBAxis] = + MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis]; + + (*NewColorMapSize)++; + } + + return GIF_OK; +} + +static int GifQuantizeBuffer(unsigned int Width, + unsigned int Height, + int* ColorMapSize, + GifByteType* RedInput, + GifByteType* GreenInput, + GifByteType* BlueInput, + GifByteType* OutputBuffer, + GifColorType* OutputColorMap) { + + unsigned int Index, NumOfEntries; + int i, j, MaxRGBError[3]; + unsigned int NewColorMapSize; + long Red, Green, Blue; + NewColorMapType NewColorSubdiv[256]; + QuantizedColorType* ColorArrayEntries, * QuantizedColor; + + ColorArrayEntries = (QuantizedColorType*)malloc( + sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE); + if (ColorArrayEntries == NULL) { + return GIF_ERROR; + } + + for (i = 0; i < COLOR_ARRAY_SIZE; i++) { + ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR); + ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & + MAX_PRIM_COLOR; + ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR; + ColorArrayEntries[i].Count = 0; + } + + /* Sample the colors and their distribution: */ + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + ColorArrayEntries[Index].Count++; + } + + /* Put all the colors in the first entry of the color map, and call the + * recursive subdivision process. */ + for (i = 0; i < 256; i++) { + NewColorSubdiv[i].QuantizedColors = NULL; + NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0; + for (j = 0; j < 3; j++) { + NewColorSubdiv[i].RGBMin[j] = 0; + NewColorSubdiv[i].RGBWidth[j] = 255; + } + } + + /* Find the non empty entries in the color table and chain them: */ + for (i = 0; i < COLOR_ARRAY_SIZE; i++) + if (ColorArrayEntries[i].Count > 0) + break; + QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i]; + NumOfEntries = 1; + while (++i < COLOR_ARRAY_SIZE) + if (ColorArrayEntries[i].Count > 0) { + QuantizedColor->Pnext = &ColorArrayEntries[i]; + QuantizedColor = &ColorArrayEntries[i]; + NumOfEntries++; + } + QuantizedColor->Pnext = NULL; + + NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */ + NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */ + NewColorMapSize = 1; + if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) != + GIF_OK) { + free((char*)ColorArrayEntries); + return GIF_ERROR; + } + if ((int)NewColorMapSize < *ColorMapSize) { + /* And clear rest of color map: */ + for (i = NewColorMapSize; i < *ColorMapSize; i++) + OutputColorMap[i].Red = OutputColorMap[i].Green = + OutputColorMap[i].Blue = 0; + } + + /* Average the colors in each entry to be the color to be used in the + * output color map, and plug it into the output color map itself. */ + for (i = 0; i < (int)NewColorMapSize; i++) { + if ((j = NewColorSubdiv[i].NumEntries) > 0) { + QuantizedColor = NewColorSubdiv[i].QuantizedColors; + Red = Green = Blue = 0; + while (QuantizedColor) { + QuantizedColor->NewColorIndex = i; + Red += QuantizedColor->RGB[0]; + Green += QuantizedColor->RGB[1]; + Blue += QuantizedColor->RGB[2]; + QuantizedColor = QuantizedColor->Pnext; + } + OutputColorMap[i].Red = (GifByteType)((Red << (8 - BITS_PER_PRIM_COLOR)) / j); + OutputColorMap[i].Green = (GifByteType)((Green << (8 - BITS_PER_PRIM_COLOR)) / j); + OutputColorMap[i].Blue = (GifByteType)((Blue << (8 - BITS_PER_PRIM_COLOR)) / j); + } + } + + /* Finally scan the input buffer again and put the mapped index in the + * output buffer. */ + MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0; + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + Index = ColorArrayEntries[Index].NewColorIndex; + OutputBuffer[i] = Index; + if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i])) + MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]); + if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i])) + MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]); + if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i])) + MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]); + } + +#ifdef DEBUG + fprintf(stderr, + "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n", + MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]); +#endif /* DEBUG */ + + free((char*)ColorArrayEntries); + + *ColorMapSize = NewColorMapSize; + + return GIF_OK; +} + +HGResult HGAPI HGImgFmt_CheckGifFile(const HGChar* fileName, HGBool* isGif) +{ + if (NULL == fileName || NULL == isGif) + { + return HGBASE_ERR_INVALIDARG; + } + + *isGif = HGFALSE; + HGGifReader reader = NULL; + HGImgFmt_OpenGifReader(fileName, NULL, &reader); + if (NULL != reader) + { + *isGif = HGTRUE; + HGImgFmt_CloseGifReader(reader); + } + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_OpenGifReader(const HGChar* fileName, HGGifLoadInfo* info, HGGifReader* reader) +{ + if (NULL == fileName || NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + int err; + GifFileType* gifFile = DGifOpenFileName(fileName, &err); + if (NULL == gifFile) + { + return HGBASE_ERR_ACCESSDENIED; + } + + DGifSlurp(gifFile); + if (gifFile->ImageCount <= 0) + { + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_FAIL; + } + + uint8_t* screenBuffer = (uint8_t*)malloc(gifFile->SWidth * gifFile->SHeight); + if (NULL == screenBuffer) + { + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + uint8_t* imageBuffer = (uint8_t *)malloc(gifFile->SWidth * gifFile->SHeight * 4); + if (NULL == imageBuffer) + { + free(screenBuffer); + screenBuffer = NULL; + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + // 设置底色 + memset(screenBuffer, gifFile->SBackGroundColor, gifFile->SWidth * gifFile->SHeight); + + if (NULL != info) + { + info->width = gifFile->SWidth; + info->height = gifFile->SHeight; + info->colors = (1 << gifFile->SColorResolution); + info->imageCount = gifFile->ImageCount; + } + + HGGifReaderImpl* gifReaderImpl = new HGGifReaderImpl; + gifReaderImpl->m_gifFile = gifFile; + gifReaderImpl->m_curIndex = 0; + gifReaderImpl->m_screenBuffer = screenBuffer; + gifReaderImpl->m_imageBuffer = imageBuffer; + + *reader = (HGGifReader)gifReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseGifReader(HGGifReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifReaderImpl* gifReaderImpl = (HGGifReaderImpl*)reader; + delete gifReaderImpl; + return HGBASE_ERR_OK; +} + +static HGResult LoadGifImage(HGGifReaderImpl* gifReaderImpl, HGUInt &interval) +{ + assert(NULL != gifReaderImpl); + + int transColor = -1; + unsigned int loopCount = 0; + + SavedImage* image = &gifReaderImpl->m_gifFile->SavedImages[gifReaderImpl->m_curIndex]; + + //获取间隔、TransparentColor等信息 + for (ExtensionBlock* ep = image->ExtensionBlocks; ep < image->ExtensionBlocks + image->ExtensionBlockCount; ep++) + { + bool last = (ep - image->ExtensionBlocks == (image->ExtensionBlockCount - 1)); + if (ep->Function == GRAPHICS_EXT_FUNC_CODE) + { + GraphicsControlBlock gcb; + if (DGifExtensionToGCB(ep->ByteCount, ep->Bytes, &gcb) == GIF_ERROR) + { + return HGBASE_ERR_FAIL; + } + + transColor = gcb.TransparentColor; + //DelayTime的单位为10 ms + interval = gcb.DelayTime * 10; + } + else if (!last + && ep->Function == APPLICATION_EXT_FUNC_CODE + && ep->ByteCount >= 11 + && (ep + 1)->ByteCount >= 3 + && memcmp(ep->Bytes, "NETSCAPE2.0", 11) == 0) + { + unsigned char* params = (++ep)->Bytes; + loopCount = params[1] | (params[2] << 8); + } + else + { + //其他信息暂不处理 + while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) + { + ++ep; + last = (ep - image->ExtensionBlocks == (image->ExtensionBlockCount - 1)); + } + } + } + + if (image->ImageDesc.Interlace) + { + // + } + + ColorMapObject* colorMap = (image->ImageDesc.ColorMap ? image->ImageDesc.ColorMap : gifReaderImpl->m_gifFile->SColorMap); + if (colorMap == NULL) + { + return HGBASE_ERR_FAIL; + } + + for (int h = image->ImageDesc.Top; h < image->ImageDesc.Top + image->ImageDesc.Height; ++h) + { + uint8_t* p1 = gifReaderImpl->m_screenBuffer + h * gifReaderImpl->m_gifFile->SWidth + image->ImageDesc.Left; + uint8_t* p2 = image->RasterBits + (h - image->ImageDesc.Top) * image->ImageDesc.Width; + memcpy(p1, p2, image->ImageDesc.Width); + } + + for (int h = 0; h < gifReaderImpl->m_gifFile->SHeight; ++h) + { + uint8_t* p1 = gifReaderImpl->m_imageBuffer + h * gifReaderImpl->m_gifFile->SWidth * 4; + uint8_t* p2 = gifReaderImpl->m_screenBuffer + h * gifReaderImpl->m_gifFile->SWidth; + for (int w = 0; w < gifReaderImpl->m_gifFile->SWidth; ++w) + { + if (transColor != -1 && transColor == p2[w]) + continue; + + GifColorType* colorMapEntry = &colorMap->Colors[p2[w]]; + p1[w * 4] = colorMapEntry->Red; + p1[w * 4 + 1] = colorMapEntry->Green; + p1[w * 4 + 2] = colorMapEntry->Blue; + p1[w * 4 + 3] = 0xFF; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadImageFromGifReader(HGGifReader reader, HGUInt* index, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifReaderImpl* gifReaderImpl = (HGGifReaderImpl*)reader; + if (gifReaderImpl->m_curIndex >= (HGUInt)gifReaderImpl->m_gifFile->ImageCount) + { + gifReaderImpl->m_curIndex = 0; + // 设置底色 + memset(gifReaderImpl->m_screenBuffer, gifReaderImpl->m_gifFile->SBackGroundColor, + gifReaderImpl->m_gifFile->SWidth * gifReaderImpl->m_gifFile->SHeight); + } + + HGUInt interval2; + HGResult ret = LoadGifImage(gifReaderImpl, interval2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + } + + HGImageInfo gifImageInfo; + gifImageInfo.width = gifReaderImpl->m_gifFile->SWidth; + gifImageInfo.height = gifReaderImpl->m_gifFile->SHeight; + gifImageInfo.type = HGBASE_IMGTYPE_RGBA; + gifImageInfo.widthStep = gifReaderImpl->m_gifFile->SWidth * 4; + gifImageInfo.origin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + ret = HGBase_CreateImageWithData((HGByte*)gifReaderImpl->m_imageBuffer, &gifImageInfo, &image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != index) + *index = gifReaderImpl->m_curIndex; + if (NULL != interval) + *interval = interval2; + + ++gifReaderImpl->m_curIndex; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadGifImage(const HGChar* fileName, HGGifLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + + HGGifReader reader = NULL; + HGResult ret = HGImgFmt_OpenGifReader(fileName, info, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != image) + { + HGImgFmt_LoadImageFromGifReader(reader, NULL, NULL, imgType, imgOrigin, image); + } + + HGImgFmt_CloseGifReader(reader); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_OpenGifWriter(const HGChar* fileName, const HGGifSaveInfo* info, HGGifWriter* writer) +{ + if (NULL == fileName || NULL == info || NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == info->width || 0 == info->height) + { + return HGBASE_ERR_INVALIDARG; + } + + int err; + GifFileType* gifFile = EGifOpenFileName(fileName, false, &err); + if (NULL == gifFile) + { + return HGBASE_ERR_ACCESSDENIED; + } + + gifFile->SWidth = info->width; + gifFile->SHeight = info->height; + gifFile->SColorResolution = 8; + gifFile->SBackGroundColor = 0; + gifFile->SColorMap = NULL; + gifFile->SavedImages = NULL; + gifFile->ImageCount = 0; + gifFile->ExtensionBlockCount = 0; + gifFile->ExtensionBlocks = NULL; + + uint8_t* redBuffer = (uint8_t*)malloc(gifFile->SWidth * gifFile->SHeight); + if (NULL == redBuffer) + { + EGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + uint8_t* greenBuffer = (uint8_t*)malloc(gifFile->SWidth * gifFile->SHeight); + if (NULL == greenBuffer) + { + free(redBuffer); + redBuffer = NULL; + EGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + uint8_t* blueBuffer = (uint8_t*)malloc(gifFile->SWidth * gifFile->SHeight); + if (NULL == blueBuffer) + { + free(greenBuffer); + greenBuffer = NULL; + free(redBuffer); + redBuffer = NULL; + EGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + HGGifWriterImpl* gifWriterImpl = new HGGifWriterImpl; + gifWriterImpl->m_gifFile = gifFile; + gifWriterImpl->m_curIndex = 0; + gifWriterImpl->m_redBuffer = redBuffer; + gifWriterImpl->m_greenBuffer = greenBuffer; + gifWriterImpl->m_blueBuffer = blueBuffer; + + *writer = (HGGifWriter)gifWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseGifWriter(HGGifWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifWriterImpl* gifWriterImpl = (HGGifWriterImpl*)writer; + delete gifWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveImageToGifWriter(HGGifWriter writer, HGUInt interval, HGImage image) +{ + if (NULL == writer || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGBase_ResetImageROI(image); + + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgFmt_SaveImageToGifWriter(writer, interval, imageTmp); + HGBase_DestroyImage(imageTmp); + } + + HGBase_SetImageROI(image, &roi); + return ret; + } + + HGGifWriterImpl* gifWriterImpl = (HGGifWriterImpl*)writer; + GifFileType* gifFile = gifWriterImpl->m_gifFile; + GifWord gifWidth = gifWriterImpl->m_gifFile->SWidth; + GifWord gifHeight = gifWriterImpl->m_gifFile->SHeight; + uint8_t* redBuffer = gifWriterImpl->m_redBuffer; + uint8_t* greenBuffer = gifWriterImpl->m_greenBuffer; + uint8_t* blueBuffer = gifWriterImpl->m_blueBuffer; + + if (imgInfo.width < (HGUInt)gifWidth || imgInfo.height < (HGUInt)gifHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* imgData = NULL; + HGBase_GetImageData(image, &imgData); + + int channels = 1; + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_BGR == imgInfo.type) + channels = 3; + else if (HGBASE_IMGTYPE_RGBA == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + channels = 4; + + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + { + for (GifWord row = 0; row < gifHeight; row++) + { + uint8_t* pr = redBuffer + row * gifWidth; + uint8_t* pg = greenBuffer + row * gifWidth; + uint8_t* pb = blueBuffer + row * gifWidth; + uint8_t* pData = imgData + row * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (gifHeight - row - 1) * imgInfo.widthStep; + + for (GifWord col = 0; col < gifWidth; col++) + { + pr[col] = pData[col * channels]; + pg[col] = pData[col * channels + 1]; + pb[col] = pData[col * channels + 2]; + } + } + } + else if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + for (GifWord row = 0; row < gifHeight; row++) + { + uint8_t* pr = redBuffer + row * gifWidth; + uint8_t* pg = greenBuffer + row * gifWidth; + uint8_t* pb = blueBuffer + row * gifWidth; + uint8_t* pData = imgData + row * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (gifHeight - row - 1) * imgInfo.widthStep; + + for (GifWord col = 0; col < gifWidth; col++) + { + pb[col] = pData[col * channels]; + pg[col] = pData[col * channels + 1]; + pr[col] = pData[col * channels + 2]; + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == imgInfo.type); + + for (GifWord row = 0; row < gifHeight; row++) + { + uint8_t* pr = redBuffer + row * gifWidth; + uint8_t* pg = greenBuffer + row * gifWidth; + uint8_t* pb = blueBuffer + row * gifWidth; + uint8_t* pData = imgData + row * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (gifHeight - row - 1) * imgInfo.widthStep; + + for (GifWord col = 0; col < gifWidth; col++) + { + pr[col] = pData[col]; + pg[col] = pData[col]; + pb[col] = pData[col]; + } + } + } + + SavedImage* gifImage = GifMakeSavedImage(gifFile, NULL); + + int mapSize = (1 << gifFile->SColorResolution); + if ((gifImage->ImageDesc.ColorMap = GifMakeMapObject(mapSize, NULL)) == NULL) + { + return HGBASE_ERR_FAIL; + } + + gifImage->RasterBits = (GifPixelType*)malloc(sizeof(GifPixelType) * gifWidth * gifHeight); + //5.2.0 GifQuantizeBuffer函数已移除 + //但是自己去做rgb转256色太麻烦,所以我又加上了 + //mapSize调用后会被修改为实际值 + if (GifQuantizeBuffer(gifWidth, gifHeight, &mapSize, redBuffer, greenBuffer, blueBuffer, + gifImage->RasterBits, gifImage->ImageDesc.ColorMap->Colors) == GIF_ERROR) + { + return HGBASE_ERR_FAIL; + } + + gifImage->ImageDesc.Left = 0; + gifImage->ImageDesc.Top = 0; + gifImage->ImageDesc.Width = gifWidth; + gifImage->ImageDesc.Height = gifHeight; + gifImage->ImageDesc.Interlace = false; + + GraphicsControlBlock gcb; + gcb.DisposalMode = DISPOSAL_UNSPECIFIED; + gcb.DelayTime = interval / 10; + gcb.UserInputFlag = false; + gcb.TransparentColor = NO_TRANSPARENT_COLOR; + EGifGCBToSavedExtension(&gcb, gifFile, gifWriterImpl->m_curIndex); + + //把循环次数写到第一帧对应的扩展块 + if (0 == gifWriterImpl->m_curIndex) + { + unsigned char params[3] = { 1, 0, 0 }; + //Create a Netscape 2.0 loop block + if (GifAddExtensionBlock(&gifImage->ExtensionBlockCount, &gifImage->ExtensionBlocks, APPLICATION_EXT_FUNC_CODE, + 11, (unsigned char*)"NETSCAPE2.0") == GIF_ERROR) + { + return HGBASE_ERR_FAIL; + } + + if (GifAddExtensionBlock(&gifImage->ExtensionBlockCount, &gifImage->ExtensionBlocks, 0, sizeof(params), params) == GIF_ERROR) + { + return HGBASE_ERR_FAIL; + } + } + + ++gifWriterImpl->m_curIndex; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveGifImage(HGImage image, const HGGifSaveInfo* info, const HGChar* fileName) +{ + HGGifWriter writer = NULL; + HGResult ret = HGImgFmt_OpenGifWriter(fileName, info, &writer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveImageToGifWriter(writer, 100, image); + HGImgFmt_CloseGifWriter(writer); + return ret; +} \ No newline at end of file diff --git a/modules/imgfmt/HGGif.h b/modules/imgfmt/HGGif.h new file mode 100644 index 00000000..58495851 --- /dev/null +++ b/modules/imgfmt/HGGif.h @@ -0,0 +1,46 @@ +#ifndef __HGGIF_H__ +#define __HGGIF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGGifReader); +HG_DECLARE_HANDLE(HGGifWriter); + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt colors; /* 颜色数量 */ + HGUInt imageCount; /* 图像数量 */ +}HGGifLoadInfo; + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ +}HGGifSaveInfo; + +HGEXPORT HGResult HGAPI HGImgFmt_CheckGifFile(const HGChar* fileName, HGBool* isGif); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifReader(const HGChar* fileName, HGGifLoadInfo* info, HGGifReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifReader(HGGifReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromGifReader(HGGifReader reader, HGUInt *index, HGUInt *interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadGifImage(const HGChar* fileName, HGGifLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifWriter(const HGChar* fileName, const HGGifSaveInfo* info, HGGifWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifWriter(HGGifWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToGifWriter(HGGifWriter writer, HGUInt interval, HGImage image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveGifImage(HGImage image, const HGGifSaveInfo* info, const HGChar* fileName); + +#endif /* __HGGIF_H__ */ \ No newline at end of file