mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
saver/gif: up to date the gif encoder.
this fixes the memory sanitizer report: ../src/savers/gif/gif.h:315:31: runtime error: index 255 out of bounds for type 'unsigned char [255]' ../src/savers/gif/gif.h:113:54: runtime error: index 255 out of bounds for type 'unsigned char [255]' Issue: https://github.com/thorvg/thorvg/issues/1758
This commit is contained in:
parent
7bf958e913
commit
f71aa2e300
1 changed files with 47 additions and 46 deletions
|
@ -32,6 +32,7 @@
|
|||
#include <stdio.h> // for FILE*
|
||||
#include <string.h> // for memcpy and bzero
|
||||
#include <stdint.h> // for integer typedefs
|
||||
#include <stdbool.h> // for bool macros
|
||||
|
||||
// Define these macros to hook into a custom memory allocator.
|
||||
// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
|
||||
|
@ -61,7 +62,7 @@
|
|||
|
||||
const int kGifTransIndex = 0;
|
||||
|
||||
struct GifPalette
|
||||
typedef struct
|
||||
{
|
||||
int bitDepth;
|
||||
|
||||
|
@ -72,9 +73,9 @@ struct GifPalette
|
|||
// k-d tree over RGB space, organized in heap fashion
|
||||
// i.e. left child of node i is node i*2, right child is node i*2+1
|
||||
// nodes 256-511 are implicitly the leaves, containing a color
|
||||
uint8_t treeSplitElt[255];
|
||||
uint8_t treeSplit[255];
|
||||
};
|
||||
uint8_t treeSplitElt[256];
|
||||
uint8_t treeSplit[256];
|
||||
} GifPalette;
|
||||
|
||||
// max, min, and abs functions
|
||||
int GifIMax(int l, int r) { return l>r?l:r; }
|
||||
|
@ -85,7 +86,7 @@ int GifIAbs(int i) { return i<0?-i:i; }
|
|||
// Takes as in/out parameters the current best color and its error -
|
||||
// only changes them if it finds a better color in its subtree.
|
||||
// this is the major hotspot in the code at the moment.
|
||||
void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1)
|
||||
void GifGetClosestPaletteColor( GifPalette* pPal, int r, int g, int b, int* bestInd, int* bestDiff, int treeRoot )
|
||||
{
|
||||
// base case, reached the bottom of the tree
|
||||
if(treeRoot > (1<<pPal->bitDepth)-1)
|
||||
|
@ -99,10 +100,10 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI
|
|||
int b_err = b - ((int32_t)pPal->b[ind]);
|
||||
int diff = GifIAbs(r_err)+GifIAbs(g_err)+GifIAbs(b_err);
|
||||
|
||||
if(diff < bestDiff)
|
||||
if(diff < *bestDiff)
|
||||
{
|
||||
bestInd = ind;
|
||||
bestDiff = diff;
|
||||
*bestInd = ind;
|
||||
*bestDiff = diff;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -117,7 +118,7 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI
|
|||
{
|
||||
// check the left subtree
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
if( bestDiff > splitPos - splitComp )
|
||||
if( *bestDiff > splitPos - splitComp )
|
||||
{
|
||||
// cannot prove there's not a better value in the right subtree, check that too
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
|
@ -126,7 +127,7 @@ void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestI
|
|||
else
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
if( bestDiff > splitComp - splitPos )
|
||||
if( *bestDiff > splitComp - splitPos )
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
}
|
||||
|
@ -391,7 +392,7 @@ void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t
|
|||
for( int ii=0; ii<numPixels*4; ++ii )
|
||||
{
|
||||
uint8_t pix = nextFrame[ii];
|
||||
int32_t pix16 = int32_t(pix) * 256;
|
||||
int32_t pix16 = (int32_t)(pix) * 256;
|
||||
quantPixels[ii] = pix16;
|
||||
}
|
||||
|
||||
|
@ -425,12 +426,12 @@ void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t
|
|||
int32_t bestInd = kGifTransIndex;
|
||||
|
||||
// Search the palete
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, bestInd, bestDiff);
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the result to the temp buffer
|
||||
int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256;
|
||||
int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256;
|
||||
int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256;
|
||||
int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd]) * 256;
|
||||
int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd]) * 256;
|
||||
int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd]) * 256;
|
||||
|
||||
nextPix[0] = pPal->r[bestInd];
|
||||
nextPix[1] = pPal->g[bestInd];
|
||||
|
@ -510,7 +511,7 @@ void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint
|
|||
// palettize the pixel
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = 1;
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], bestInd, bestDiff);
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the resulting color to the output buffer
|
||||
outFrame[0] = pPal->r[bestInd];
|
||||
|
@ -527,52 +528,52 @@ void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint
|
|||
|
||||
// Simple structure to write out the LZW-compressed portion of the image
|
||||
// one bit at a time
|
||||
struct GifBitStatus
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bitIndex; // how many bits in the partial byte written so far
|
||||
uint8_t byte; // current partial byte
|
||||
|
||||
uint32_t chunkIndex;
|
||||
uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
|
||||
};
|
||||
} GifBitStatus;
|
||||
|
||||
// insert a single bit
|
||||
void GifWriteBit( GifBitStatus& stat, uint32_t bit )
|
||||
void GifWriteBit( GifBitStatus* stat, uint32_t bit )
|
||||
{
|
||||
bit = bit & 1;
|
||||
bit = bit << stat.bitIndex;
|
||||
stat.byte |= bit;
|
||||
bit = bit << stat->bitIndex;
|
||||
stat->byte |= bit;
|
||||
|
||||
++stat.bitIndex;
|
||||
if( stat.bitIndex > 7 )
|
||||
++stat->bitIndex;
|
||||
if( stat->bitIndex > 7 )
|
||||
{
|
||||
// move the newly-finished byte to the chunk buffer
|
||||
stat.chunk[stat.chunkIndex++] = stat.byte;
|
||||
stat->chunk[stat->chunkIndex++] = stat->byte;
|
||||
// and start a new byte
|
||||
stat.bitIndex = 0;
|
||||
stat.byte = 0;
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write all bytes so far to the file
|
||||
void GifWriteChunk( FILE* f, GifBitStatus& stat )
|
||||
void GifWriteChunk( FILE* f, GifBitStatus* stat )
|
||||
{
|
||||
fputc((int)stat.chunkIndex, f);
|
||||
fwrite(stat.chunk, 1, stat.chunkIndex, f);
|
||||
fputc((int)stat->chunkIndex, f);
|
||||
fwrite(stat->chunk, 1, stat->chunkIndex, f);
|
||||
|
||||
stat.bitIndex = 0;
|
||||
stat.byte = 0;
|
||||
stat.chunkIndex = 0;
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
stat->chunkIndex = 0;
|
||||
}
|
||||
|
||||
void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length )
|
||||
void GifWriteCode( FILE* f, GifBitStatus* stat, uint32_t code, uint32_t length )
|
||||
{
|
||||
for( uint32_t ii=0; ii<length; ++ii )
|
||||
{
|
||||
GifWriteBit(stat, code);
|
||||
code = code >> 1;
|
||||
|
||||
if( stat.chunkIndex == 255 )
|
||||
if( stat->chunkIndex == 255 )
|
||||
{
|
||||
GifWriteChunk(f, stat);
|
||||
}
|
||||
|
@ -581,10 +582,10 @@ void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length )
|
|||
|
||||
// The LZW dictionary is a 256-ary tree constructed as the file is encoded,
|
||||
// this is one node
|
||||
struct GifLzwNode
|
||||
typedef struct
|
||||
{
|
||||
uint16_t m_next[256];
|
||||
};
|
||||
} GifLzwNode;
|
||||
|
||||
// write a 256-color (8-bit) image palette to the file
|
||||
void GifWritePalette( const GifPalette* pPal, FILE* f )
|
||||
|
@ -653,7 +654,7 @@ void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uin
|
|||
stat.bitIndex = 0;
|
||||
stat.chunkIndex = 0;
|
||||
|
||||
GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
|
||||
for(uint32_t yy=0; yy<height; ++yy)
|
||||
{
|
||||
|
@ -684,7 +685,7 @@ void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uin
|
|||
else
|
||||
{
|
||||
// finish the current run, write a code
|
||||
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
|
||||
// insert the new run into the dictionary
|
||||
codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode;
|
||||
|
@ -698,7 +699,7 @@ void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uin
|
|||
if( maxCode == 4095 )
|
||||
{
|
||||
// the dictionary is full, clear it out and begin anew
|
||||
GifWriteCode(f, stat, clearCode, codeSize); // clear tree
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
codeSize = (uint32_t)(minCodeSize + 1);
|
||||
|
@ -711,25 +712,25 @@ void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uin
|
|||
}
|
||||
|
||||
// compression footer
|
||||
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, stat, clearCode, codeSize);
|
||||
GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1);
|
||||
GifWriteCode(f, &stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode + 1, (uint32_t)minCodeSize + 1);
|
||||
|
||||
// write out the last partial chunk
|
||||
while( stat.bitIndex ) GifWriteBit(stat, 0);
|
||||
if( stat.chunkIndex ) GifWriteChunk(f, stat);
|
||||
while( stat.bitIndex ) GifWriteBit(&stat, 0);
|
||||
if( stat.chunkIndex ) GifWriteChunk(f, &stat);
|
||||
|
||||
fputc(0, f); // image block terminator
|
||||
|
||||
GIF_TEMP_FREE(codetree);
|
||||
}
|
||||
|
||||
struct GifWriter
|
||||
typedef struct
|
||||
{
|
||||
FILE* f;
|
||||
uint8_t* oldImage;
|
||||
bool firstFrame;
|
||||
};
|
||||
} GifWriter;
|
||||
|
||||
// Creates a gif file.
|
||||
// The input GIFWriter is assumed to be uninitialized.
|
||||
|
|
Loading…
Add table
Reference in a new issue