基于giflib实现gif读写功能

This commit is contained in:
luoliangyi 2022-07-08 17:36:13 +08:00
parent 89e8be4374
commit f0b1c48ea9
6 changed files with 1008 additions and 8 deletions

View File

@ -40,6 +40,16 @@ HGImgFmt_CloseTiffWriter
HGImgFmt_SaveImageToTiffWriter HGImgFmt_SaveImageToTiffWriter
HGImgFmt_SaveTiffImage HGImgFmt_SaveTiffImage
HGImgFmt_CheckGifFile
HGImgFmt_OpenGifReader
HGImgFmt_CloseGifReader
HGImgFmt_LoadImageFromGifReader
HGImgFmt_LoadGifImage
HGImgFmt_OpenGifWriter
HGImgFmt_CloseGifWriter
HGImgFmt_SaveImageToGifWriter
HGImgFmt_SaveGifImage
HGImgFmt_CheckPdfFile HGImgFmt_CheckPdfFile
HGImgFmt_OpenPdfReader HGImgFmt_OpenPdfReader
HGImgFmt_ClosePdfReader HGImgFmt_ClosePdfReader

View File

@ -23,6 +23,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\modules\imgfmt\HGBmp.cpp" /> <ClCompile Include="..\..\..\modules\imgfmt\HGBmp.cpp" />
<ClCompile Include="..\..\..\modules\imgfmt\HGGif.cpp" />
<ClCompile Include="..\..\..\modules\imgfmt\HGImgFmt.cpp" /> <ClCompile Include="..\..\..\modules\imgfmt\HGImgFmt.cpp" />
<ClCompile Include="..\..\..\modules\imgfmt\HGJpeg.cpp" /> <ClCompile Include="..\..\..\modules\imgfmt\HGJpeg.cpp" />
<ClCompile Include="..\..\..\modules\imgfmt\HGOfd.cpp" /> <ClCompile Include="..\..\..\modules\imgfmt\HGOfd.cpp" />
@ -35,6 +36,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\modules\imgfmt\HGBmp.h" /> <ClInclude Include="..\..\..\modules\imgfmt\HGBmp.h" />
<ClInclude Include="..\..\..\modules\imgfmt\HGGif.h" />
<ClInclude Include="..\..\..\modules\imgfmt\HGImgFmt.h" /> <ClInclude Include="..\..\..\modules\imgfmt\HGImgFmt.h" />
<ClInclude Include="..\..\..\modules\imgfmt\HGImgFmtErr.h" /> <ClInclude Include="..\..\..\modules\imgfmt\HGImgFmtErr.h" />
<ClInclude Include="..\..\..\modules\imgfmt\HGJpeg.h" /> <ClInclude Include="..\..\..\modules\imgfmt\HGJpeg.h" />
@ -119,7 +121,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<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/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
@ -127,7 +129,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile> <ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile>
<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/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2d.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<AdditionalOptions>/ignore:4098,4099,4075 /LTCG %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4098,4099,4075 /LTCG %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -142,7 +144,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<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/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -151,7 +153,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile> <ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile>
<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/libzip/windows/lib/x86/zip.lib;../../../third_party/tinyxml2/windows/lib/x86/tinyxml2.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<AdditionalOptions>/ignore:4099 /LTCG %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4099 /LTCG %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
@ -170,7 +172,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<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/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>%(DisableSpecificWarnings)</DisableSpecificWarnings>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile> </ClCompile>
@ -179,7 +181,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile> <ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile>
<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/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2d.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<AdditionalOptions>/ignore:4098,4099,4075 /LTCG %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4098,4099,4075 /LTCG %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -194,7 +196,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<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/mupdf/windows/include;../../../third_party/pdflib/windows/include;../../../third_party/libzip/windows/include;../../../third_party/tinyxml2/windows/include;../../../utility;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -203,7 +205,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile> <ModuleDefinitionFile>HGImgFmt.def</ModuleDefinitionFile>
<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/libzip/windows/lib/x64/zip.lib;../../../third_party/tinyxml2/windows/lib/x64/tinyxml2.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<AdditionalOptions>/ignore:4099 /LTCG %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4099 /LTCG %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>

View File

@ -104,6 +104,43 @@ BOOL CHGTestDlg::OnInitDialog()
SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 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 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} }

View File

@ -15,6 +15,7 @@
#include "imgfmt/HGBmp.h" #include "imgfmt/HGBmp.h"
#include "imgfmt/HGPng.h" #include "imgfmt/HGPng.h"
#include "imgfmt/HGTiff.h" #include "imgfmt/HGTiff.h"
#include "imgfmt/HGGif.h"
#include "imgfmt/HGPdf.h" #include "imgfmt/HGPdf.h"
#include "imgfmt/HGOfd.h" #include "imgfmt/HGOfd.h"
#include "imgfmt/HGImgFmt.h" #include "imgfmt/HGImgFmt.h"

904
modules/imgfmt/HGGif.cpp Normal file
View File

@ -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;
}

46
modules/imgfmt/HGGif.h Normal file
View File

@ -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__ */