static void decode_new_frame(gs_image_file_t *image, int new_frame) { if (!image->animation_frame_cache[new_frame]) { int last_frame; /* if looped, decode frame 0 */ last_frame = (new_frame < image->last_decoded_frame) ? 0 : image->last_decoded_frame + 1; /* decode missed frames */ for (int i = last_frame; i < new_frame; i++) { if (gif_decode_frame(&image->gif, i) != GIF_OK) return; } /* decode actual desired frame */ if (gif_decode_frame(&image->gif, new_frame) == GIF_OK) { size_t pos = new_frame * image->gif.width * image->gif.height * 4; image->animation_frame_cache[new_frame] = image->animation_frame_data + pos; memcpy(image->animation_frame_cache[new_frame], image->gif.frame_image, image->gif.width * image->gif.height * 4); image->last_decoded_frame = new_frame; } } image->cur_frame = new_frame; }
/* gifReadImage: Reads an image from a memory buffer. Returns: non-zero if successful. */ int gifReadImage(int w, int h, int d, char* bits, char *data, int nBytes) { gif_bitmap_callback_vt bitmap_callbacks = { bitmap_create, bitmap_destroy, bitmap_get_buffer, bitmap_set_opaque, bitmap_test_opaque, bitmap_modified }; gif_animation gif; gif_result code; formWidth = w; formHeight = h; formBits = bits; /* create our gif animation */ gif_create(&gif, &bitmap_callbacks); /* begin decoding */ do { code = gif_initialise(&gif, nBytes, data); if (code != GIF_OK && code != GIF_WORKING) { DBG("gif_initialise failure"); return 0; } } while (code != GIF_OK); if(gif.width != w || gif.height != h || gif.frame_count != 1 || d != 32) { DBG("image format mismatch"); return 0; } code = gif_decode_frame(&gif, 0); if (code != GIF_OK) { DBG("gif_decode_frame error"); return 0; } /* clean up */ gif_finalise(&gif); return 1; }
/** * Updates the GIF bitmap to display the current frame * * \param c the content to update */ static gif_result nsgif_get_frame(nsgif_content *gif) { int previous_frame, current_frame, frame; gif_result res = GIF_OK; current_frame = gif->current_frame; if (!nsoption_bool(animate_images)) { current_frame = 0; } if (current_frame < gif->gif->decoded_frame) previous_frame = 0; else previous_frame = gif->gif->decoded_frame + 1; for (frame = previous_frame; frame <= current_frame; frame++) { res = gif_decode_frame(gif->gif, frame); } return res; }
static bool init_animated_gif(gs_image_file_t *image, const char *path) { bool is_animated_gif = true; gif_result result; uint64_t max_size; size_t size; FILE *file; image->bitmap_callbacks.bitmap_create = bi_def_bitmap_create; image->bitmap_callbacks.bitmap_destroy = bi_def_bitmap_destroy; image->bitmap_callbacks.bitmap_get_buffer = bi_def_bitmap_get_buffer; image->bitmap_callbacks.bitmap_modified = bi_def_bitmap_modified; image->bitmap_callbacks.bitmap_set_opaque = bi_def_bitmap_set_opaque; image->bitmap_callbacks.bitmap_test_opaque = bi_def_bitmap_test_opaque; gif_create(&image->gif, &image->bitmap_callbacks); file = os_fopen(path, "rb"); if (!file) { blog(LOG_WARNING, "Failed to open file '%s'", path); goto fail; } fseek(file, 0, SEEK_END); size = (size_t)os_ftelli64(file); fseek(file, 0, SEEK_SET); image->gif_data = bmalloc(size); fread(image->gif_data, 1, size, file); do { result = gif_initialise(&image->gif, size, image->gif_data); if (result < 0) { blog(LOG_WARNING, "Failed to initialize gif '%s', " "possible file corruption", path); goto fail; } } while (result != GIF_OK); if (image->gif.width > 4096 || image->gif.height > 4096) { blog(LOG_WARNING, "Bad texture dimensions (%dx%d) in '%s'", image->gif.width, image->gif.height, path); goto fail; } max_size = (uint64_t)image->gif.width * (uint64_t)image->gif.height * (uint64_t)image->gif.frame_count * 4LLU; if ((uint64_t)get_full_decoded_gif_size(image) != max_size) { blog(LOG_WARNING, "Gif '%s' overflowed maximum pointer size", path); goto fail; } image->is_animated_gif = (image->gif.frame_count > 1 && result >= 0); if (image->is_animated_gif) { gif_decode_frame(&image->gif, 0); image->animation_frame_cache = bzalloc( image->gif.frame_count * sizeof(uint8_t*)); image->animation_frame_data = bzalloc( get_full_decoded_gif_size(image)); for (unsigned int i = 0; i < image->gif.frame_count; i++) { if (gif_decode_frame(&image->gif, i) != GIF_OK) blog(LOG_WARNING, "Couldn't decode frame %u " "of '%s'", i, path); } gif_decode_frame(&image->gif, 0); image->cx = (uint32_t)image->gif.width; image->cy = (uint32_t)image->gif.height; image->format = GS_RGBA; } else { gif_finalise(&image->gif); bfree(image->gif_data); image->gif_data = NULL; is_animated_gif = false; goto not_animated; } image->loaded = true; fail: if (!image->loaded) gs_image_file_free(image); not_animated: if (file) fclose(file); return is_animated_gif; }
_bitmap _imageFile::readBitmap( _optValue<_u32> page ) { // Check if not-existing if( !this->isExisting() ) return _bitmap(); _mimeType mimeType = this->getRealMime(); if( mimeType == _mime::image_png ) { if( this->bufferedImage ) return *bufferedImage; _bitmap result; YsRawPngDecoder* pngDecoder = new YsRawPngDecoder; pngDecoder->Decode( this->filename.c_str() ); if( pngDecoder->wid > 0 && pngDecoder->hei > 0 && pngDecoder->rgba != NULL ) { // Allocate bitmap result = _bitmap( pngDecoder->wid , pngDecoder->hei ); // Get size of Data (in bytes)(every pixel consists of u8 red, u8 green, u8 blue, u8 alpha) _u32 size = pngDecoder->wid * pngDecoder->hei; _pixelArray base = result.getBitmap(); _u8* source = pngDecoder->rgba; do { _u8 r = *source++; _u8 g = *source++; _u8 b = *source++; bool a = *source++ > 127; *base++ = _color::fromRGB8(r,g,b,a); } while( --size > 0 ); } // Delete the decoder delete pngDecoder; if( this->buffer ) { this->bufferedImage = new _bitmap( move(result) ); return *this->bufferedImage; } return move(result); } else if( mimeType == _mime::image_jpeg ) { if( this->bufferedImage ) return *bufferedImage; _bitmap result; _u32 size = this->getSize(); _byte* data = new _byte[size]; this->read( data , size ); Jpeg::Decoder* jpgDecoder = new Jpeg::Decoder( data , size ); if ( jpgDecoder->GetResult() == Jpeg::Decoder::OK ) { result = _bitmap( jpgDecoder->GetWidth() , jpgDecoder->GetHeight() ); if( jpgDecoder->IsColor() ) { _u32 size = jpgDecoder->GetImageSize(); _u8* rgb = jpgDecoder->GetImage(); _pixelArray dest = result.getBitmap(); do { _u8 r = *rgb++; _u8 g = *rgb++; _u8 b = *rgb++; *dest++ = _color::fromRGB8(r,g,b); size -= 3; } while( size > 0 ); } else { _u32 size = jpgDecoder->GetImageSize(); _u8* rgb = jpgDecoder->GetImage(); _pixelArray dest = result.getBitmap(); do { *dest++ = _color::fromBW8( *rgb++ ); } while( --size > 0 ); } } delete[] data; delete jpgDecoder; if( this->buffer ) { this->bufferedImage = new _bitmap( move(result) ); return *this->bufferedImage; } return move(result); } else if( mimeType == _mime::image_bmp ) { if( this->bufferedImage ) return *bufferedImage; _bitmap result; _u32 size = this->getSize(); _byte* data = new _byte[size]; this->read( data , size ); _u32 width; _u32 height; _pixelArray pixeldata = GenericBMPDecoder::decode( data , size , width , height ); if ( pixeldata != nullptr ) { result = _bitmap( width , height ); memcpy16( result.getBitmap() , pixeldata , width * height ); delete[] pixeldata; } delete[] data; if( this->buffer ) { this->bufferedImage = new _bitmap( move(result) ); return *this->bufferedImage; } return move(result); } else if( mimeType == _mime::image_ico ) { _byte* data; if( this->bufferedData ) data = this->bufferedData; else { _u32 size = this->getSize(); data = new _byte[size]; this->read( data , size ); } _u32 width; _u32 height; _bitmap result; _u8* pixeldata = GenericIcoDecoder::decode( data , width , height , page ); if ( pixeldata != nullptr ) { // Allocate bitmap result = _bitmap( width , height ); // Get size of Data (in bytes)(every pixel consists of u8 red, u8 green, u8 blue, u8 alpha) _u32 size = width * height; _pixelArray base = result.getBitmap(); _u8* source = pixeldata; do { _u8 r = *source++; _u8 g = *source++; _u8 b = *source++; bool a = *source++ > 127; *base++ = _color::fromRGB8(r,g,b,a); } while( --size > 0 ); delete[] pixeldata; } if( !this->buffer ) delete[] data; else this->bufferedData = data; return result; } else if( mimeType == _mime::image_gif ) { gif_animation* gifAnim; gif_result statusCode = GIF_OK; // Allocate Decoder if( this->bufferedGif ) gifAnim = this->bufferedGif; else { // Read file content to buffer _u32 size = this->getSize(); _byte* data = new _byte[size]; this->read( data , size ); // Allocate Decoder gifAnim = new gif_animation; // Initialize Decoder gif_create( gifAnim ); // Partly Decode the gif do { statusCode = gif_initialise( gifAnim , size , data ); if (statusCode != GIF_OK && statusCode != GIF_WORKING) { _imageFile::outputGifWarning( "gif_initialise" , statusCode); break; } } while( statusCode != GIF_OK ); } if( !this->bufferedGifBitmap ) this->bufferedGifBitmap = new _bitmap( gifAnim->width , gifAnim->height , _color::transparent ); // Limit Page Number if( gifAnim->frame_count <= page ) page = gifAnim->frame_count -1; // Decode... statusCode = gif_decode_frame(gifAnim, page); // ... and Check if everything went ok if (statusCode != GIF_OK) _imageFile::outputGifWarning( "gif_decode_frame" , statusCode ); // Get destination bitmap _pixelArray dest = this->bufferedGifBitmap->getBitmap(); // Get Source bitmap _u8* source = (_u8*)gifAnim->frame_image; // Copy source bitmap to destination _length numPixels = gifAnim->height * gifAnim->width; do { *dest++ = _color::fromRGB8( source[0] , source[1] , source[2] , source[3] ); source += 4; } while( --numPixels > 0 ); // Clean temps if( this->buffer ) this->bufferedGif = gifAnim; else { delete[] gifAnim->gif_data; delete gifAnim; } return *this->bufferedGifBitmap; } return _bitmap(); }
int main(int argc, char *argv[]) { gif_bitmap_callback_vt bitmap_callbacks = { bitmap_create, bitmap_destroy, bitmap_get_buffer, bitmap_set_opaque, bitmap_test_opaque, bitmap_modified }; gif_animation gif; size_t size; gif_result code; unsigned int i; if (argc != 2) { fprintf(stderr, "Usage: %s image.gif\n", argv[0]); return 1; } /* create our gif animation */ gif_create(&gif, &bitmap_callbacks); /* load file into memory */ unsigned char *data = load_file(argv[1], &size); /* begin decoding */ do { code = gif_initialise(&gif, size, data); if (code != GIF_OK && code != GIF_WORKING) { warning("gif_initialise", code); exit(1); } } while (code != GIF_OK); printf("P3\n"); printf("# %s\n", argv[1]); printf("# width %u \n", gif.width); printf("# height %u \n", gif.height); printf("# frame_count %u \n", gif.frame_count); printf("# frame_count_partial %u \n", gif.frame_count_partial); printf("# loop_count %u \n", gif.loop_count); printf("%u %u 256\n", gif.width, gif.height * gif.frame_count); /* decode the frames */ for (i = 0; i != gif.frame_count; i++) { unsigned int row, col; unsigned char *image; code = gif_decode_frame(&gif, i); if (code != GIF_OK) warning("gif_decode_frame", code); printf("# frame %u:\n", i); image = (unsigned char *) gif.frame_image; for (row = 0; row != gif.height; row++) { for (col = 0; col != gif.width; col++) { size_t z = (row * gif.width + col) * 4; printf("%u %u %u ", (unsigned char) image[z], (unsigned char) image[z + 1], (unsigned char) image[z + 2]); } printf("\n"); } } /* clean up */ gif_finalise(&gif); free(data); return 0; }