int int_png_load(const char *name, unsigned char **buffer, int* xp, int* yp, int* bpp, bool alpha) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type, number_passes, pass, int_bpp; png_byte * fbptr; FILE * fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr == NULL) { fclose(fh); return(FH_ERROR_FORMAT); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } #if (PNG_LIBPNG_VER < 10500) if (setjmp(png_ptr->jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); if (alpha) { *bpp = png_get_channels(png_ptr, info_ptr); if ((*bpp != 4) || !(color_type & PNG_COLOR_MASK_ALPHA)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return fh_png_load(name, buffer, xp, yp); } // 24bit PNGs with alpha-channel int_bpp = 4; // png_set_swap_alpha(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); }else // All other PNGs { if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } /* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least), but the data delivered is with alpha channel anyway, so always strip alpha for now */ #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36 if (color_type & PNG_COLOR_MASK_ALPHA) #endif png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); int_bpp = 3; } if (bit_depth == 16) png_set_strip_16(png_ptr); number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (width * int_bpp != rowbytes) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); printf(" width: %lu rowbytes: %lu\n", (unsigned long)width, (unsigned long)rowbytes); fclose(fh); return(FH_ERROR_FORMAT); } for (pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)(*buffer); for (i = 0; i < height; i++, fbptr += width * int_bpp) png_read_row(png_ptr, fbptr, NULL); } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
int show_image(char *devicename) { unsigned char * image = NULL; unsigned char * alpha = NULL; int x_size, y_size, screen_width, screen_height; int x_pan, y_pan, x_offs, y_offs, refresh = 1, ret = 1; int retransform = 1; int transform_stretch = opt_stretch, transform_enlarge = opt_enlarge, transform_cal = (opt_stretch == 2), transform_iaspect = opt_ignore_aspect, transform_rotation = 0; struct image i; memset(&i,0, sizeof(i)); if(fh_png_load(&image, &alpha, &x_size, &y_size) != FH_ERROR_OK) { fprintf(stderr, "Image data is corrupt?\n"); goto error_mem; } if(!opt_alpha) { free(alpha); alpha = NULL; } getCurrentRes(devicename, &screen_width, &screen_height); i.do_free = 0; if(retransform) { if(i.do_free) { free(i.rgb); free(i.alpha); } i.width = x_size; i.height = y_size; i.rgb = image; i.alpha = alpha; i.do_free = 0; if(transform_rotation) do_rotate(&i, transform_rotation); if(transform_stretch) do_fit_to_screen(&i, screen_width, screen_height, transform_iaspect, transform_cal); if(transform_enlarge) do_enlarge(&i, screen_width, screen_height, transform_iaspect); x_pan = y_pan = 0; refresh = 1; retransform = 0; } if(refresh) { if(i.width < screen_width) x_offs = (screen_width - i.width) / 2; else x_offs = 0; if(i.height < screen_height) y_offs = (screen_height - i.height) / 2; else y_offs = 0; fb_display(devicename, i.rgb, i.alpha, i.width, i.height, x_pan, y_pan, x_offs, y_offs); refresh = 0; } error_mem: free(image); free(alpha); if(i.do_free) { free(i.rgb); free(i.alpha); } return(ret); }