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