基于giflib实现gif读写功能
This commit is contained in:
parent
89e8be4374
commit
f0b1c48ea9
|
@ -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
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\modules\imgfmt\HGBmp.cpp" />
|
||||
<ClCompile Include="..\..\..\modules\imgfmt\HGGif.cpp" />
|
||||
<ClCompile Include="..\..\..\modules\imgfmt\HGImgFmt.cpp" />
|
||||
<ClCompile Include="..\..\..\modules\imgfmt\HGJpeg.cpp" />
|
||||
<ClCompile Include="..\..\..\modules\imgfmt\HGOfd.cpp" />
|
||||
|
@ -35,6 +36,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\modules\imgfmt\HGBmp.h" />
|
||||
<ClInclude Include="..\..\..\modules\imgfmt\HGGif.h" />
|
||||
<ClInclude Include="..\..\..\modules\imgfmt\HGImgFmt.h" />
|
||||
<ClInclude Include="..\..\..\modules\imgfmt\HGImgFmtErr.h" />
|
||||
<ClInclude Include="..\..\..\modules\imgfmt\HGJpeg.h" />
|
||||
|
@ -119,7 +121,7 @@
|
|||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<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>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -127,7 +129,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<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>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -142,7 +144,7 @@
|
|||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<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>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -151,7 +153,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<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>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
|
@ -170,7 +172,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
|
|||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<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>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
|
@ -179,7 +181,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<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>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
@ -194,7 +196,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
|
|||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<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>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -203,7 +205,7 @@ copy $(OutDir)HGImgFmt.dll $(SolutionDir)..\..\..\release\win\x86\Release\</Comm
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<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>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
Loading…
Reference in New Issue