_u32 _imageFile::getPageDelay( _u32 page ) { // Check if not-existing if( !this->isExisting() ) return 0; if( this->getRealMime() == _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 ); } // Limit Page Number if( gifAnim->frame_count <= page ) page = gifAnim->frame_count - 1; _u32 pageDelay = gifAnim->frames[page].frame_delay; // Clean temps if( this->buffer ) this->bufferedGif = gifAnim; else { delete[] gifAnim->gif_data; delete gifAnim; } return pageDelay; } return 0; }
/* 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; }
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(); }
_u32 _imageFile::getNumPages() { // Check if not-existing if( !this->isExisting() ) return 0; _mimeType mimeType = this->getRealMime(); 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 pages = GenericIcoDecoder::getNumPages( (const unsigned char*) this->bufferedData ); if( this->buffer ) this->bufferedData = data; else delete[] data; return pages; } 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 ); } _u32 pageCount = gifAnim->frame_count; // Clean temps if( this->buffer ) this->bufferedGif = gifAnim; else { delete[] gifAnim->gif_data; delete gifAnim; } return pageCount; } return 1; }
static bool nsgif_convert(struct content *c) { nsgif_content *gif = (nsgif_content *) c; int res; union content_msg_data msg_data; const char *data; unsigned long size; char *title; /* Get the animation */ data = content__get_source_data(c, &size); /* Initialise the GIF */ do { res = gif_initialise(gif->gif, size, (unsigned char *) data); if (res != GIF_OK && res != GIF_WORKING && res != GIF_INSUFFICIENT_FRAME_DATA) { switch (res) { case GIF_FRAME_DATA_ERROR: case GIF_INSUFFICIENT_DATA: case GIF_DATA_ERROR: msg_data.error = messages_get("BadGIF"); break; case GIF_INSUFFICIENT_MEMORY: msg_data.error = messages_get("NoMemory"); break; } content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } } while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA); /* Abort on bad GIFs */ if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) || (gif->gif->height == 0)) { msg_data.error = messages_get("BadGIF"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* Store our content width, height and calculate size */ c->width = gif->gif->width; c->height = gif->gif->height; c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44; /* set title text */ title = messages_get_buff("GIFTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } /* Schedule the animation if we have one */ gif->current_frame = 0; if (gif->gif->frame_count_partial > 1) guit->browser->schedule(gif->gif->frames[0].frame_delay * 10, nsgif_animate, c); /* Exit as a success */ content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
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; }