uint32_t progressive_render(int32_t quality, int64_t bytes_read) { while (drawing) {SDL_Delay(50);} drawing = 1; printf("%lli bytes read, rendering at quality=%.2f%%\n",(unsigned long long int) bytes_read, 0.01*quality); animation = (flif_decoder_num_images(d) > 1); FLIF_IMAGE* image = flif_decoder_get_image(d, 0); if (!image) { printf("Error: No decoded image found\n"); return 1; } uint32_t w = flif_image_get_width(image); uint32_t h = flif_image_get_height(image); if (!window) { printf("Error: Could not create window\n"); return 2; } SDL_SetWindowSize(window,w,h); char title[100]; sprintf(title,"%ix%i FLIF image [read %lli bytes, quality=%.2f%%]",w,h,(unsigned long long int) bytes_read, 0.01*quality); SDL_SetWindowTitle(window,title); for (int f = 0; f< flif_decoder_num_images(d); f++) { FLIF_IMAGE* image = flif_decoder_get_image(d, f); if (!image) { printf("Error: No decoded image found\n"); return 1; } uint32_t w = flif_image_get_width(image); uint32_t h = flif_image_get_height(image); frame_delay[f] = flif_image_get_frame_delay(image); if (!surf[f]) surf[f] = SDL_CreateRGBSurface(0,w,h,32,0x000000FF,0x0000FF00,0x00FF0000,0xFF000000); if (!surf[f]) { printf("Error: Could not create surface\n"); return 1; } if (!tmpsurf) tmpsurf = SDL_CreateRGBSurface(0,w,h,32,0x000000FF,0x0000FF00,0x00FF0000,0xFF000000); if (!tmpsurf) { printf("Error: Could not create surface\n"); return 1; } char* pp =(char*) tmpsurf->pixels; for (uint32_t r=0; r<h; r++) { flif_image_read_row_RGBA8(image, r, pp, w * sizeof(RGBA)); pp += tmpsurf->pitch; } if (flif_image_get_nb_channels(image) > 3) { if (!bgsurf) { bgsurf = SDL_CreateRGBSurface(0,w,h,32,0x000000FF,0x0000FF00,0x00FF0000,0xFF000000); // Draw checkerboard background for image with alpha channel SDL_Rect sq; sq.w=20; sq.h=20; for (sq.y=0; sq.y<h; sq.y+=sq.h) for (sq.x=0; sq.x<w; sq.x+=sq.w) SDL_FillRect(bgsurf,&sq,((sq.y/sq.h + sq.x/sq.w)&1 ? 0xFF606060 : 0xFFA0A0A0)); } SDL_BlitSurface(bgsurf,NULL,surf[f],NULL); } SDL_BlitSurface(tmpsurf,NULL,surf[f],NULL); } drawing = 0; draw_image(); // SDL_Delay(1000); if (quit) return 0; // stop decoding return quality + 1000; // call me back when you have at least 10.00% better quality }
int main(int argc, char **argv) { if (argc < 2 || argc > 2) { printf("Usage: %s image.flif\n",argv[0]); return 0; } d = flif_create_decoder(); if (!d) return 1; SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow("FLIF Viewer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 200, 200, 0); flif_decoder_set_quality(d, 100); // this is the default flif_decoder_set_scale(d, 1); // this is the default #ifdef PROGRESSIVE_DECODING flif_decoder_set_callback(d, &(progressive_render)); flif_decoder_set_first_callback_quality(d, 500); // do the first callback when at least 5.00% quality has been decoded printf("Decoding progressively...\n"); SDL_Thread *decode_thread = SDL_CreateThread(decodeThread,"Decode_FLIF",argv); if (!decode_thread) { printf("Error: failed to create decode thread\n"); return 1; } #else printf("Decoding entire image...\n"); decodeThread(argv); progressive_render(10000,-1); #endif SDL_Event e; int result = 0; while (!quit) { draw_image(); if (animation) { SDL_Delay(frame_delay[frame]); frame++; frame %= flif_decoder_num_images(d); } else { SDL_WaitEvent(&e); if (!do_event(e)) break; SDL_Delay(100); } while (SDL_PollEvent(&e)) if (!do_event(e)) break; } #ifdef PROGRESSIVE_DECODING while(flif_abort_decoder(d)) SDL_Delay(100); SDL_WaitThread(decode_thread, &result); #endif flif_destroy_decoder(d); SDL_DestroyWindow(window); SDL_Quit(); return result; }
// Callback function: converts (partially) decoded image/animation to a/several SDL_Texture(s), // resizes the viewer window if needed, and calls draw_image() // Input arguments are: quality (0..10000), current position in the .flif file // Output is the desired minimal quality before doing the next callback uint32_t progressive_render(int32_t quality, int64_t bytes_read) { loading = 1; while (drawing) {SDL_Delay(50);} // don't touch the textures until we're done drawing printf("%lli bytes read, rendering at quality=%.2f%%\n",(long long int) bytes_read, 0.01*quality); FLIF_IMAGE* image = flif_decoder_get_image(d, 0); if (!image) { printf("Error: No decoded image found\n"); return 1; } uint32_t w = flif_image_get_width(image); uint32_t h = flif_image_get_height(image); // set the window title and size if (!window) { printf("Error: Could not create window\n"); return 2; } char title[100]; sprintf(title,"FLIF image decoded at %ix%i [read %lli bytes, quality=%.2f%%]",w,h,(long long int) bytes_read, 0.01*quality); SDL_SetWindowTitle(window,title); if (!window_size_set) { int ww = (w > dm.w ? dm.w : w); int wh = (h > dm.h ? dm.h : h); if (ww > w * wh / h) ww = wh * w / h; else if (ww < w * wh / h) wh = ww * h / w; if (w > dm.w*8/10 && h > dm.h*8/10) { ww = ww*8/10; wh = wh*8/10; } SDL_SetWindowSize(window,ww,wh); SDL_SetWindowPosition(window,SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED); if (w > dm.w*8/10 && h > dm.h*8/10) { SDL_MaximizeWindow(window); } window_size_set = 1; } // allocate enough room for the texture pointers and frame delays if (!image_frame) image_frame = calloc(flif_decoder_num_images(d), sizeof(FLIF_IMAGE*)); if (!frame_delay) frame_delay = calloc(flif_decoder_num_images(d), sizeof(int)); // produce one SDL_Texture per frame for (int f = 0; f < flif_decoder_num_images(d); f++) { if (quit) return 0; FLIF_IMAGE* image = flif_decoder_get_image(d, f); if (!image) { printf("Error: No decoded image found\n"); return 1; } frame_delay[f] = flif_image_get_frame_delay(image); // Copy the decoded pixels to a temporary surface if (!tmpsurf) tmpsurf = SDL_CreateRGBSurface(0,w,h,32,0x000000FF,0x0000FF00,0x00FF0000,0xFF000000); if (!tmpsurf) { printf("Error: Could not create surface\n"); return 1; } char* pp =(char*) tmpsurf->pixels; for (uint32_t r=0; r<h; r++) { flif_image_read_row_RGBA8(image, r, pp, w * sizeof(RGBA)); pp += tmpsurf->pitch; } // Draw checkerboard background for image/animation with alpha channel if (flif_image_get_nb_channels(image) > 3) { if (!bgsurf) bgsurf = SDL_CreateRGBSurface(0,w,h,32,0x000000FF,0x0000FF00,0x00FF0000,0xFF000000); if (!bgsurf) { printf("Error: Could not create surface\n"); return 1; } SDL_Rect sq; sq.w=20; sq.h=20; for (sq.y=0; sq.y<h; sq.y+=sq.h) for (sq.x=0; sq.x<w; sq.x+=sq.w) SDL_FillRect(bgsurf,&sq,((sq.y/sq.h + sq.x/sq.w)&1 ? 0xFF606060 : 0xFFA0A0A0)); // Alpha-blend decoded frame on top of checkerboard background SDL_BlitSurface(tmpsurf,NULL,bgsurf,NULL); SDL_FreeSurface(tmpsurf); tmpsurf = bgsurf; bgsurf = NULL; } if (!renderer) { printf("Error: Could not get renderer\n"); return 1; } if (image_frame[f]) SDL_DestroyTexture(image_frame[f]); // Convert the surface to a texture (for accelerated blitting) image_frame[f] = SDL_CreateTextureFromSurface(renderer, tmpsurf); if (!image_frame[f]) { printf("Could not create texture!\n"); quit=1; return 0; } SDL_SetTextureBlendMode(image_frame[f],SDL_BLENDMODE_NONE); } SDL_FreeSurface(tmpsurf); tmpsurf=NULL; loading = 0; draw_image(); // setting nb_frames to a value > 1 will make sure the main thread keeps calling draw_image() nb_frames = flif_decoder_num_images(d); if (quit) return 0; // stop decoding return quality + 1000; // call me back when you have at least 10.00% better quality }