diff --git a/src/savers/gif/gif.h b/src/savers/gif/gif.h index d89ffc38..16c577b5 100644 --- a/src/savers/gif/gif.h +++ b/src/savers/gif/gif.h @@ -205,7 +205,7 @@ void GifPartitionByMedian(uint8_t* image, int left, int right, int com, int need } // Builds a palette by creating a balanced k-d tree of all pixels in the image -void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal) +void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, GifPalette* pal) { if(lastElt <= firstElt || numPixels == 0) return; @@ -213,48 +213,6 @@ void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, i // base case, bottom of the tree if(lastElt == firstElt+1) { - if(buildForDither) - { - // Dithering needs at least one color as dark as anything - // in the image and at least one brightest color - - // otherwise it builds up error and produces strange artifacts - if( firstElt == 1 ) - { - // special case: the darkest color in the image - uint32_t r=255, g=255, b=255; - for(int ii=0; iir[firstElt] = (uint8_t)r; - pal->g[firstElt] = (uint8_t)g; - pal->b[firstElt] = (uint8_t)b; - - return; - } - - if( firstElt == (1 << pal->bitDepth)-1 ) - { - // special case: the lightest color in the image - uint32_t r=0, g=0, b=0; - for(int ii=0; iir[firstElt] = (uint8_t)r; - pal->g[firstElt] = (uint8_t)g; - pal->b[firstElt] = (uint8_t)b; - - return; - } - } - // otherwise, take the average of all colors in this subcube uint64_t r=0, g=0, b=0; for(int ii=0; iitreeSplitElt[treeNode] = (uint8_t)splitCom; pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom]; - GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal); - GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2+1, buildForDither, pal); + GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, pal); + GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2+1, pal); } // Finds all pixels that have changed from the previous image and @@ -350,7 +308,7 @@ int GifPickChangedPixels( const uint8_t* lastFrame, uint8_t* frame, int numPixel // Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom. // This is known as the "modified median split" technique -void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, bool buildForDither, GifPalette* pPal ) +void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, GifPalette* pPal ) { pPal->bitDepth = bitDepth; @@ -368,7 +326,7 @@ void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_ const int splitElt = lastElt/2; const int splitDist = splitElt/2; - GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal); + GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, pPal); GIF_TEMP_FREE(destroyableImage); @@ -379,115 +337,6 @@ void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_ pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; } -// Implements Floyd-Steinberg dithering, writes palette value to alpha -void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal ) -{ - int numPixels = (int)(width * height); - - // quantPixels initially holds color*256 for all pixels - // The extra 8 bits of precision allow for sub-single-color error values - // to be propagated - int32_t *quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4); - - for( int ii=0; iir[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]; - nextPix[2] = pPal->b[bestInd]; - nextPix[3] = bestInd; - - // Propagate the error to the four adjacent locations - // that we haven't touched yet - int quantloc_7 = (int)(yy * width + xx + 1); - int quantloc_3 = (int)(yy * width + width + xx - 1); - int quantloc_5 = (int)(yy * width + width + xx); - int quantloc_1 = (int)(yy * width + width + xx + 1); - - if(quantloc_7 < numPixels) - { - int32_t* pix7 = quantPixels+4*quantloc_7; - pix7[0] += GifIMax( -pix7[0], r_err * 7 / 16 ); - pix7[1] += GifIMax( -pix7[1], g_err * 7 / 16 ); - pix7[2] += GifIMax( -pix7[2], b_err * 7 / 16 ); - } - - if(quantloc_3 < numPixels) - { - int32_t* pix3 = quantPixels+4*quantloc_3; - pix3[0] += GifIMax( -pix3[0], r_err * 3 / 16 ); - pix3[1] += GifIMax( -pix3[1], g_err * 3 / 16 ); - pix3[2] += GifIMax( -pix3[2], b_err * 3 / 16 ); - } - - if(quantloc_5 < numPixels) - { - int32_t* pix5 = quantPixels+4*quantloc_5; - pix5[0] += GifIMax( -pix5[0], r_err * 5 / 16 ); - pix5[1] += GifIMax( -pix5[1], g_err * 5 / 16 ); - pix5[2] += GifIMax( -pix5[2], b_err * 5 / 16 ); - } - - if(quantloc_1 < numPixels) - { - int32_t* pix1 = quantPixels+4*quantloc_1; - pix1[0] += GifIMax( -pix1[0], r_err / 16 ); - pix1[1] += GifIMax( -pix1[1], g_err / 16 ); - pix1[2] += GifIMax( -pix1[2], b_err / 16 ); - } - } - } - - // Copy the palettized result to the output buffer - for( int ii=0; ii= 1400) writer->f = 0; fopen_s(&writer->f, filename, "wb"); @@ -796,7 +644,7 @@ bool GifBegin( GifWriter* writer, const char* filename, uint32_t width, uint32_t // The GIFWriter should have been created by GIFBegin. // AFAIK, it is legal to use different bit depths for different frames of an image - // this may be handy to save bits in animations that don't change much. -bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false ) +bool GifWriteFrame(GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8) { if(!writer->f) return false; @@ -804,12 +652,9 @@ bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uin writer->firstFrame = false; GifPalette pal; - GifMakePalette((dither? NULL : oldImage), image, width, height, bitDepth, dither, &pal); + GifMakePalette(oldImage, image, width, height, bitDepth, &pal); - if(dither) - GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal); - else - GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); + GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);