static void read_png(struct display *dp, struct buffer *bp, const char *operation, int transforms) { png_structp pp; png_infop ip; /* This cleans out any previous read and sets operation and transforms to * empty. */ display_clean_read(dp); if (operation != NULL) /* else this is a verify and do not overwrite info */ { dp->operation = operation; dp->transforms = transforms; } dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp, display_error, display_warning); if (pp == NULL) display_log(dp, LIBPNG_ERROR, "failed to create read struct"); /* The png_read_png API requires us to make the info struct, but it does the * call to png_read_info. */ dp->read_ip = ip = png_create_info_struct(pp); if (ip == NULL) display_log(dp, LIBPNG_ERROR, "failed to create info struct"); # ifdef PNG_SET_USER_LIMITS_SUPPORTED /* Remove the user limits, if any */ png_set_user_limits(pp, 0x7fffffff, 0x7fffffff); # endif /* Set the IO handling */ buffer_start_read(bp); png_set_read_fn(pp, bp, read_function); png_read_png(pp, ip, transforms, NULL/*params*/); #if 0 /* crazy debugging */ { png_bytep pr = png_get_rows(pp, ip)[0]; size_t rb = png_get_rowbytes(pp, ip); size_t cb; char c = ' '; fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb); for (cb=0; cb<rb; ++cb) fputc(c, stderr), fprintf(stderr, "%.2x", pr[cb]), c='.'; fputc('\n', stderr); } #endif }
int savePNG(const char * fileName,uint32_t width,uint32_t height,void * ptr,uint8_t*pal,unsigned pn){ //saves a 24bit png with rgb byte order png_byte * dat=(png_byte*)ptr;//convert to uint8_t FILE * fp=fopen(fileName,"wb"); if (!fp) return 1; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)0,0,0); if (!png_ptr){ fclose(fp); return 1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr){ png_destroy_write_struct(&png_ptr,(png_infopp)NULL); return 1; } if (setjmp(png_jmpbuf(png_ptr))){ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return 1; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height,8,pal?PNG_COLOR_TYPE_PALETTE:PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);//must be called before other png_set_*() functions png_color_struct*palTmp=0; if(pal){ palTmp=(png_color_struct*)malloc(pn*sizeof(png_color_struct)); for(unsigned i=0;i<pn;++i){ palTmp[i].red=pal[i*3]; palTmp[i].green=pal[i*3+1]; palTmp[i].blue=pal[i*3+2]; } png_set_PLTE(png_ptr,info_ptr,palTmp,pn); } png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); uint32_t y; png_set_user_limits(png_ptr, width, height); png_write_info(png_ptr, info_ptr); for (y=0;y<height;++y) png_write_row(png_ptr, &dat[(y*width*(pal?1:3))]); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp);//done with file free(palTmp); return 0;//will return 0 on success non-zero in error }
/* ================= image_png_load ================= */ GNUC_NONNULL static erbool image_png_load (const char *name, image_t *im) { fs_file_t f; int size, r, width, height, inc; png_byte *image = NULL, *p = NULL; png_structp pngst; png_infop info = NULL; png_byte depth, color_type; if (NULL == (f = fs_open(name, FS_RDONLY, &size, false))) return false; if (NULL == (pngst = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &epng_error, &epng_warn))) { sys_printf("failed to create png read struct\n"); fs_close(f); return false; } if (NULL == (info = png_create_info_struct(pngst))) { sys_printf("failed to create png info struct\n"); goto error; } if (setjmp(png_jmpbuf(pngst))) goto error; png_set_user_limits(pngst, IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT); png_set_read_fn(pngst, f, &epng_read); png_read_info(pngst, info); width = png_get_image_width(pngst, info); height = png_get_image_height(pngst, info); depth = png_get_bit_depth(pngst, info); if (16 == depth) { /* 16 -> 8 */ png_set_strip_16(pngst); depth = 8; } color_type = png_get_color_type(pngst, info); /* 1/2/4 gray -> 8 gray */ if (PNG_COLOR_TYPE_GRAY == color_type && depth < 8) png_set_expand_gray_1_2_4_to_8(pngst); /* gray/palette -> rgb */ if (PNG_COLOR_TYPE_GRAY == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) png_set_gray_to_rgb(pngst); else if (PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(pngst); /* transparency -> alpha */ if (png_get_valid(pngst, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngst); } else { /* to rgba */ if (PNG_COLOR_TYPE_RGB_ALPHA != color_type && PNG_COLOR_TYPE_GRAY_ALPHA != color_type) png_set_add_alpha(pngst, 0xff, PNG_FILLER_AFTER); } /* deinterlace */ png_set_interlace_handling(pngst); /* read */ inc = width * 4; p = image = mem_alloc(image_mempool, height * inc); for (r = 0; r < height ;r++, p += inc) png_read_row(pngst, p, NULL); png_read_end(pngst, NULL); png_destroy_read_struct(&pngst, &info, NULL); fs_close(f); im->width = width; im->height = height; im->data = image; return true; error: if (NULL != f) fs_close(f); png_destroy_read_struct(&pngst, NULL != info ? &info : NULL, NULL); if (NULL != image) mem_free(image); return false; }
static void read_png_file(const char* file_name, png_image_data_t *png_image_data, int max_width, int max_height) { png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; char header[8]; // 8 is the maximum size that can be checked int y; char* dest; /* open file and test for it being a png */ FILE *fp = fopen(file_name, "rb"); if (!fp) abort_("[read_png_file] File %s could not be opened for reading", file_name); fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) abort_("[read_png_file] File %s is not recognized as a PNG file", file_name); /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) abort_("[read_png_file] png_create_read_struct failed"); if (max_width > 0 && max_height > 0) png_set_user_limits(png_ptr, max_width, max_height); info_ptr = png_create_info_struct(png_ptr); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_init_io(png_ptr, fp); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_set_sig_bytes(png_ptr, sizeof(header)); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_ALPHA, png_voidp_NULL); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); row_pointers = png_get_rows(png_ptr, info_ptr); png_image_data->height = png_get_image_height(png_ptr, info_ptr); png_image_data->width = png_get_image_width(png_ptr, info_ptr); png_image_data->image4c = (void*)qemu_malloc(png_image_data->width * png_image_data->height * 4); dest = (char*)png_image_data->image4c; /* transform this from 3 channels to a (fake for now) 4 channels */ for (y=0; y < png_image_data->height; y++) { char* src = row_pointers[y]; int x; for (x = 0; x < png_image_data->width; x++) { *dest = *src; dest++, src++; *dest = *src; dest++, src++; *dest = *src; dest++, src++; *dest = 0; dest++; /* alpha channel ignored */ } } png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); }
int filter_png(struct media_info const *info, int out_fd, int in_fd) { FILE *fp = fdopen(out_fd, "wb"); struct png_struct_def *png_ptr = NULL; struct png_info_def *png_info = NULL; volatile int rc = EX_SOFTWARE; png_bytep row_pointers[info->height]; void * volatile raw_data = NULL; void * volatile rgb_data = NULL; size_t rgb_stride = info->width * ((info->bpp + 7) / 8) * 3; if (!fp) { perror("fdopen()"); return EX_OSERR; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto out; if (setjmp(png_jmpbuf(png_ptr))) goto out; /* allocate memory for raw (YCbCr) image data */ raw_data = png_malloc(png_ptr, info->stride * info->height); if (!raw_data) goto out; rgb_data = png_malloc(png_ptr, rgb_stride * info->height); if (!rgb_data) goto out; for (size_t y = 0; y < info->height; ++y) row_pointers[y] = rgb_data + y * rgb_stride; png_info = png_create_info_struct(png_ptr); if (!png_info) goto out; png_init_io(png_ptr, fp); png_set_user_limits(png_ptr, info->width, info->height); png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); /* atm, only 8bpp support is implemented */ assert(info->bpp == 8); for (;;) { bool eof = false; if (read_all(in_fd, raw_data, info->stride * info->height, &eof)) ; /* noop */ else if (!eof) goto out; else break; convert_yuv422_rgb888(rgb_data, raw_data, info->bpp, info->width, info->height); png_set_rows(png_ptr, png_info, row_pointers); png_set_IHDR(png_ptr, png_info, info->width, info->height, info->bpp, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_png(png_ptr, png_info, PNG_TRANSFORM_IDENTITY, NULL); fflush(fp); break; } rc = 0; out: png_free(png_ptr, rgb_data); png_free(png_ptr, raw_data); png_destroy_write_struct(&png_ptr, &png_info); fclose(fp); return rc; }
HBITMAP PngByteToBmpHandle(VBuf *vbuf) { png_struct *png = NULL; png_info *info = NULL; HBITMAP hBmp = NULL; BITMAPINFO *bmi = NULL; png_byte **row = NULL; BYTE *data = NULL; HWND hWnd = ::GetDesktopWindow(); HDC hDc = NULL; int line_size, aligned_line_size, header_size; VBuf bmpVbuf; if (vbuf->Size() < PNG_SIG_SIZE || !png_check_sig(vbuf->Buf(), PNG_SIG_SIZE)) return NULL; if (!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL; if (!(info = png_create_info_struct(png))) goto END; if (setjmp(png_jmpbuf(png))) goto END; png_set_user_limits(png, 15000, 10000); // 15,000 * 10,000 pix png_set_read_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_rfunc); png_read_png(png, info, PNG_TRANSFORM_BGR, NULL); if (info->bit_depth > 8) goto END; // not support line_size = info->width * info->channels * ALIGN_SIZE(info->bit_depth, 8) / 8; aligned_line_size = ALIGN_SIZE(line_size, 4); header_size = sizeof(BITMAPV5HEADER) + sizeof(RGBQUAD) * info->num_palette; if (!bmpVbuf.AllocBuf(header_size + aligned_line_size * info->height)) goto END; bmi = (BITMAPINFO *)bmpVbuf.Buf(); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biSizeImage = aligned_line_size * info->height; bmi->bmiHeader.biWidth = info->width; bmi->bmiHeader.biHeight = -(int)info->height; bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biCompression = BI_RGB; if (info->color_type == PNG_COLOR_TYPE_PALETTE) { bmi->bmiHeader.biBitCount = info->bit_depth; bmi->bmiHeader.biClrUsed = info->num_palette; for (int i=0; i < info->num_palette; i++) { bmi->bmiColors[i].rgbRed = info->palette[i].red; bmi->bmiColors[i].rgbGreen = info->palette[i].green; bmi->bmiColors[i].rgbBlue = info->palette[i].blue; } } else { bmi->bmiHeader.biBitCount = info->bit_depth * info->channels; if (info->channels == 4) { bmi->bmiHeader.biSize = sizeof(BITMAPV5HEADER); BITMAPV5HEADER *bm5 = (BITMAPV5HEADER*)bmi; bm5->bV5Compression = BI_BITFIELDS; bm5->bV5RedMask = 0x00FF0000; bm5->bV5GreenMask = 0x0000FF00; bm5->bV5BlueMask = 0x000000FF; bm5->bV5AlphaMask = 0xFF000000; } } if (!(row = png_get_rows(png, info))) goto END; data = bmpVbuf.Buf() + header_size; u_int i; for (i=0; i < info->height; i++) { memcpy(data + aligned_line_size * i, row[i], line_size); } if (!(hDc = ::GetDC(hWnd))) goto END; hBmp = ::CreateDIBitmap(hDc, (BITMAPINFOHEADER *)bmi, CBM_INIT, data, bmi, DIB_RGB_COLORS); if (hDc) ::ReleaseDC(hWnd, hDc); END: png_destroy_read_struct(&png, &info, 0); return hBmp; }
static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_t *grpatch) { png_structp png_ptr; png_infop png_info_ptr; png_uint_32 width, height; int bit_depth, color_type; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; #endif #endif png_FILE_p png_FILE; char *pngfilename = va("md2/%s", filename); FIL_ForceExtension(pngfilename, ".png"); png_FILE = fopen(pngfilename, "rb"); if (!png_FILE) { //CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename); return 0; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); fclose(png_FILE); return 0; } png_info_ptr = png_create_info_struct(png_ptr); if (!png_info_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(png_FILE); return 0; } #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); fclose(png_FILE); Z_Free(grpatch->mipmap.grInfo.data); return 0; } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); #endif png_init_io(png_ptr, png_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_set_user_limits(png_ptr, 2048, 2048); #endif png_read_info(png_ptr, png_info_ptr); png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); else if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA) { #if PNG_LIBPNG_VER < 10207 png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); #else png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); #endif } png_read_update_info(png_ptr, png_info_ptr); { png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr); png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRCACHE, &grpatch->mipmap.grInfo.data); png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep)); for (i = 0; i < height; i++) row_pointers[i] = PNG_image + i*pitch; png_read_image(png_ptr, row_pointers); png_free(png_ptr, (png_voidp)row_pointers); } png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); fclose(png_FILE); *w = (int)width; *h = (int)height; return GR_RGBA; }