/** * Try for modification time. png_get_tIME() should return PNG_INFO_tIME on * success or 0 otherwise. Then we handle time as an array of six strings like * (my) exif for the moment. */ var PNG::date() { if (!valid()) return lube::nil; png_timep timep = 0; png_uint_32 pngRet = png_get_tIME(mData, mInfo, &timep); if (!pngRet) return lube::nil; assert(timep); var time; time[0] = format(timep->year, 4); time[1] = format(timep->month, 2); time[2] = format(timep->day, 2); time[3] = format(timep->hour, 2); time[4] = format(timep->minute, 2); time[5] = format(timep->second, 2); return time; }
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header. // Bits (if set indicates existence of the chunk): // 0 - gAMA // 1 - sBIT // 2 - cHRM // 3 - PLTE // 4 - tRNS // 5 - bKGD // 6 - hIST // 7 - pHYs // 8 - oFFs // 9 - tIME // 10 - pCAL // 11 - sRGB // 12 - iCCP // 13 - sPLT // 14 - sCAL // 15 - IDAT // 16:30 - reserved be_t<u32> pngDecGetChunkInformation(PStream stream, bool IDAT = false) { // The end result of the chunk information (bigger-endian) be_t<u32> chunk_information = 0; // Needed pointers for getting the chunk information f64 gamma; f64 red_x; f64 red_y; f64 green_x; f64 green_y; f64 blue_x; f64 blue_y; f64 white_x; f64 white_y; f64 width; f64 height; s32 intent; s32 num_trans; s32 num_palette; s32 unit_type; s32 type; s32 nparams; s32 compression_type; s32 unit; u16* hist; u32 proflen; png_bytep profile; png_bytep trans_alpha; png_charp units; png_charp name; png_charp purpose; png_charpp params; png_int_32 X0; png_int_32 X1; png_int_32 offset_x; png_int_32 offset_y; png_uint_32 res_x; png_uint_32 res_y; png_colorp palette; png_color_8p sig_bit; png_color_16p background; png_color_16p trans_color; png_sPLT_tp entries; png_timep mod_time; // Get chunk information and set the appropriate bits if (png_get_gAMA(stream->png_ptr, stream->info_ptr, &gamma)) { chunk_information |= 1 << 0; // gAMA } if (png_get_sBIT(stream->png_ptr, stream->info_ptr, &sig_bit)) { chunk_information |= 1 << 1; // sBIT } if (png_get_cHRM(stream->png_ptr, stream->info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { chunk_information |= 1 << 2; // cHRM } if (png_get_PLTE(stream->png_ptr, stream->info_ptr, &palette, &num_palette)) { chunk_information |= 1 << 3; // PLTE } if (png_get_tRNS(stream->png_ptr, stream->info_ptr, &trans_alpha, &num_trans, &trans_color)) { chunk_information |= 1 << 4; // tRNS } if (png_get_bKGD(stream->png_ptr, stream->info_ptr, &background)) { chunk_information |= 1 << 5; // bKGD } if (png_get_hIST(stream->png_ptr, stream->info_ptr, &hist)) { chunk_information |= 1 << 6; // hIST } if (png_get_pHYs(stream->png_ptr, stream->info_ptr, &res_x, &res_y, &unit_type)) { chunk_information |= 1 << 7; // pHYs } if (png_get_oFFs(stream->png_ptr, stream->info_ptr, &offset_x, &offset_y, &unit_type)) { chunk_information |= 1 << 8; // oFFs } if (png_get_tIME(stream->png_ptr, stream->info_ptr, &mod_time)) { chunk_information |= 1 << 9; // tIME } if (png_get_pCAL(stream->png_ptr, stream->info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, ¶ms)) { chunk_information |= 1 << 10; // pCAL } if (png_get_sRGB(stream->png_ptr, stream->info_ptr, &intent)) { chunk_information |= 1 << 11; // sRGB } if (png_get_iCCP(stream->png_ptr, stream->info_ptr, &name, &compression_type, &profile, &proflen)) { chunk_information |= 1 << 12; // iCCP } if (png_get_sPLT(stream->png_ptr, stream->info_ptr, &entries)) { chunk_information |= 1 << 13; // sPLT } if (png_get_sCAL(stream->png_ptr, stream->info_ptr, &unit, &width, &height)) { chunk_information |= 1 << 14; // sCAL } if (IDAT) { chunk_information |= 1 << 15; // IDAT } return chunk_information; }
int main(int argc, char **argv) { static char *usage="Usage:\n\t%s png__file\n"; int i; FILE *fp_in = NULL; png_structp png_p; png_infop info_p; char header[8]; int bit_depth; int color_type; png_color_16p input_backgrd; double gammaval; int file_width, file_height; png_int_32 xoff, yoff; png_uint_32 xres, yres; int unit_type; int rgb_intent; double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; png_timep mod_time; png_textp text; int num_text; unsigned char *image; unsigned char **rows; if (argc != 2) { bu_log(usage, argv[0]); bu_exit(EXIT_FAILURE, "Incorrect number of arguments!!\n"); } else { if ((fp_in = fopen(argv[1], "rb")) == NULL) { perror(argv[1]); bu_log("png_onfo: cannot open \"%s\" for reading\n", argv[1]); bu_exit(EXIT_FAILURE, "Cannot open input file\n"); } } if (fread(header, 8, 1, fp_in) != 1) bu_exit(EXIT_FAILURE, "ERROR: Failed while reading file header!!!\n"); if (png_sig_cmp((png_bytep)header, 0, 8)) bu_exit(EXIT_FAILURE, "This is not a PNG file!!!\n"); png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_p) bu_exit(EXIT_FAILURE, "png_create_read_struct() failed!!\n"); info_p = png_create_info_struct(png_p); if (!info_p) bu_exit(EXIT_FAILURE, "png_create_info_struct() failed!!\n"); png_init_io(png_p, fp_in); png_set_sig_bytes(png_p, 8); png_read_info(png_p, info_p); color_type = png_get_color_type(png_p, info_p); bit_depth = png_get_bit_depth(png_p, info_p); switch (color_type) { case PNG_COLOR_TYPE_GRAY: bu_log("color type: b/w (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_GRAY_ALPHA: bu_log("color type: b/w with alpha channel (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_PALETTE: bu_log("color type: color palette (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB: bu_log("color type: RGB (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB_ALPHA: bu_log("color type: RGB with alpha channel (bit depth=%d)\n", bit_depth); break; default: bu_log("Unrecognized color type (bit depth=%d)\n", bit_depth); break; } file_width = png_get_image_width(png_p, info_p); file_height = png_get_image_height(png_p, info_p); bu_log("Image size: %d X %d\n", file_width, file_height); /* allocate memory for image */ image = (unsigned char *)bu_calloc(1, file_width*file_height*3, "image"); /* create rows array */ rows = (unsigned char **)bu_calloc(file_height, sizeof(unsigned char *), "rows"); for (i=0; i<file_height; i++) rows[file_height-1-i] = image+(i*file_width*3); png_read_image(png_p, rows); if (png_get_oFFs(png_p, info_p, &xoff, &yoff, &unit_type)) { if (unit_type == PNG_OFFSET_PIXEL) bu_log("X Offset: %d pixels\nY Offset: %d pixels\n", (int)xoff, (int)yoff); else if (unit_type == PNG_OFFSET_MICROMETER) bu_log("X Offset: %d um\nY Offset: %d um\n", (int)xoff, (int)yoff); } if (png_get_pHYs(png_p, info_p, &xres, &yres, &unit_type)) { if (unit_type == PNG_RESOLUTION_UNKNOWN) bu_log("Aspect ratio: %g (width/height)\n", (double)xres/(double)yres); else if (unit_type == PNG_RESOLUTION_METER) bu_log("pixel density:\n\t%d pixels/m horizontal\n\t%d pixels/m vertical\n", (int)xres, (int)yres); } if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) bu_log("not interlaced\n"); else bu_log("interlaced\n"); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) if (png_get_bKGD(png_p, info_p, &input_backgrd)) bu_log("background color: %d %d %d\n", input_backgrd->red, input_backgrd->green, input_backgrd->blue); if (png_get_sRGB(png_p, info_p, &rgb_intent)) { bu_log("rendering intent: "); switch (rgb_intent) { case PNG_sRGB_INTENT_SATURATION: bu_log("saturation\n"); break; case PNG_sRGB_INTENT_PERCEPTUAL: bu_log("perceptual\n"); break; case PNG_sRGB_INTENT_ABSOLUTE: bu_log("absolute\n"); break; case PNG_sRGB_INTENT_RELATIVE: bu_log("relative\n"); break; } } if (png_get_gAMA(png_p, info_p, &gammaval)) bu_log("gamma: %g\n", gammaval); #if defined(PNG_READ_cHRM_SUPPORTED) if (png_get_cHRM(png_p, info_p, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { bu_log("Chromaticity:\n"); bu_log("\twhite point\t(%g %g)\n\tred\t(%g %g)\n\tgreen\t(%g %g)\n\tblue\t(%g %g)\n", white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); } #endif if (png_get_text(png_p, info_p, &text, &num_text)) for (i=0; i<num_text; i++) bu_log("%s: %s\n", text[i].key, text[i].text); if (png_get_tIME(png_p, info_p, &mod_time)) bu_log("Last modified: %d/%d/%d %d:%d:%d\n", mod_time->month, mod_time->day, mod_time->year, mod_time->hour, mod_time->minute, mod_time->second); return 0; }
static BOOL ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { // XMP keyword const char *g_png_xmp_keyword = "XML:com.adobe.xmp"; FITAG *tag = NULL; png_textp text_ptr = NULL; png_timep mod_time = NULL; int num_text = 0; // iTXt/tEXt/zTXt chuncks if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) { for(int i = 0; i < num_text; i++) { // create a tag tag = FreeImage_CreateTag(); if(!tag) return FALSE; DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length); FreeImage_SetTagLength(tag, tag_length); FreeImage_SetTagCount(tag, tag_length); FreeImage_SetTagType(tag, FIDT_ASCII); FreeImage_SetTagValue(tag, text_ptr[i].text); if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) { // store the tag as XMP FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName); FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag); } else { // store the tag as a comment FreeImage_SetTagKey(tag, text_ptr[i].key); FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag); } // destroy the tag FreeImage_DeleteTag(tag); } } // timestamp chunk if(png_get_tIME(png_ptr, info_ptr, &mod_time)) { char timestamp[32]; // create a tag tag = FreeImage_CreateTag(); if(!tag) return FALSE; // convert as 'yyyy:MM:dd hh:mm:ss' sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); DWORD tag_length = (DWORD)strlen(timestamp) + 1; FreeImage_SetTagLength(tag, tag_length); FreeImage_SetTagCount(tag, tag_length); FreeImage_SetTagType(tag, FIDT_ASCII); FreeImage_SetTagID(tag, TAG_DATETIME); FreeImage_SetTagValue(tag, timestamp); // store the tag as Exif-TIFF FreeImage_SetTagKey(tag, "DateTime"); FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag); // destroy the tag FreeImage_DeleteTag(tag); } return TRUE; }
static void _png_load_bmp_attribute(png_structp png_ptr, png_infop info_ptr, CFX_DIBAttribute* pAttribute) { if (pAttribute) { #if defined(PNG_pHYs_SUPPORTED) pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr); pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr); png_uint_32 res_x, res_y; int unit_type; png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type); switch (unit_type) { case PNG_RESOLUTION_METER: pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER; break; default: pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_NONE; } #endif #if defined(PNG_iCCP_SUPPORTED) png_charp icc_name; png_bytep icc_profile; png_uint_32 icc_proflen; int compress_type; png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile, &icc_proflen); #endif int bTime = 0; #if defined(PNG_tIME_SUPPORTED) png_timep t = nullptr; png_get_tIME(png_ptr, info_ptr, &t); if (t) { FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime)); FXSYS_snprintf((FX_CHAR*)pAttribute->m_strTime, sizeof(pAttribute->m_strTime), "%4u:%2u:%2u %2u:%2u:%2u", t->year, t->month, t->day, t->hour, t->minute, t->second); pAttribute->m_strTime[sizeof(pAttribute->m_strTime) - 1] = 0; bTime = 1; } #endif #if defined(PNG_TEXT_SUPPORTED) int i; FX_STRSIZE len; const FX_CHAR* buf; int num_text; png_textp text = nullptr; png_get_text(png_ptr, info_ptr, &text, &num_text); for (i = 0; i < num_text; i++) { len = FXSYS_strlen(text[i].key); buf = "Time"; if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) { if (!bTime) { FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime)); FXSYS_memcpy( pAttribute->m_strTime, text[i].text, std::min(sizeof(pAttribute->m_strTime) - 1, text[i].text_length)); } } else { buf = "Author"; if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) { pAttribute->m_strAuthor = CFX_ByteString(reinterpret_cast<uint8_t*>(text[i].text), static_cast<FX_STRSIZE>(text[i].text_length)); } } } #endif } }
GivImage *giv_plugin_load_file(const char *filename, GError **error) { GivImage *img=NULL; FILE *fp = fopen(filename, "rb"); if (!fp) return NULL; // Check again that this is a png file const int number = 8; guchar header[9]; fread(header, 1, number, fp); gboolean is_png = !png_sig_cmp(header, 0, number); if (!is_png) { return NULL; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!png_ptr) return NULL; // Comments may be stored in the beginning or the end so create // a structure for both. png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); #if 0 printf("width height bit_depth color_type = %d %d %d %d\n", (int)width, (int)height, bit_depth, color_type); #endif if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); // Since giv doesn't support gray alpha, we upgrade to rgb if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_swap(png_ptr); // Reread info png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); GivImageType image_type; if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth <= 8) image_type = GIVIMAGE_U8; else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16) image_type = GIVIMAGE_U16; else if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 16) image_type = GIVIMAGE_RGB_U16; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 16) image_type = GIVIMAGE_RGBA_U16; else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 8) image_type = GIVIMAGE_RGBA_U8; else image_type = GIVIMAGE_RGB_U8; img = giv_image_new(image_type, width, height); if (!img) { *error = g_error_new(GIV_IMAGE_ERROR, -1, "Failed allocating memory for an image of size %dx%d pixels!", width, height); return NULL; } int png_transforms = PNG_TRANSFORM_PACKING; png_bytep *row_pointers = (png_bytep*)g_new0(gpointer, height); guchar *dst_buf = img->buf.buf; int dst_row_stride = img->row_stride; int row_idx; for (row_idx=0; row_idx<(int)height; row_idx++) row_pointers[row_idx] = dst_buf + dst_row_stride * row_idx; png_read_image(png_ptr, row_pointers); png_timep mod_time; if (png_get_tIME(png_ptr, info_ptr, &mod_time)) { gchar *mod_time_str = g_strdup_printf("%04d-%02d-%02d %02d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); giv_image_set_attribute(img, "mod_time", mod_time_str); g_free(mod_time_str); } png_textp png_text; int num_text; if (png_get_text(png_ptr, info_ptr, &png_text, &num_text)) { int i; for (i=0; i<num_text; i++) giv_image_set_attribute(img, png_text[i].key, png_text[i].text); } png_read_end(png_ptr, NULL); g_free(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return img; }
static void load_meta_data(png_structp png, png_infop png_info, gp_storage *storage) { double gamma; png_uint_32 res_x, res_y, w, h; int unit, depth, color_type, interlace_type, compr_method; const char *type; png_get_IHDR(png, png_info, &w, &h, &depth, &color_type, &interlace_type, &compr_method, NULL); gp_storage_add_string(storage, NULL, "Interlace Type", interlace_type_name(interlace_type)); gp_storage_add_int(storage, NULL, "Width", w); gp_storage_add_int(storage, NULL, "Height", h); gp_storage_add_int(storage, NULL, "Bit Depth", depth); if (color_type & PNG_COLOR_MASK_PALETTE) { type = "Palette"; } else { if (color_type & PNG_COLOR_MASK_COLOR) type = "RGB"; else type = "Grayscale"; } gp_storage_add_string(storage, NULL, "Color Type", type); //TODO: To string gp_storage_add_int(storage, NULL, "Compression Method", compr_method); /* TODO: BOOL ? */ gp_storage_add_string(storage, NULL, "Alpha Channel", color_type & PNG_COLOR_MASK_ALPHA ? "Yes" : "No"); if (png_get_gAMA(png, png_info, &gamma)) gp_storage_add_int(storage, NULL, "gamma", gamma * 100000); if (png_get_pHYs(png, png_info, &res_x, &res_y, &unit)) { gp_storage_add_int(storage, NULL, "X Resolution", res_x); gp_storage_add_int(storage, NULL, "Y Resolution", res_y); const char *str_unit; if (unit == PNG_RESOLUTION_METER) str_unit = "Meter"; else str_unit = "Unknown"; gp_storage_add_string(storage, NULL, "Resolution Unit", str_unit); } png_timep mod_time; if (png_get_tIME(png, png_info, &mod_time)) { char buf[128]; snprintf(buf, sizeof(buf), "%4i:%02i:%02i %02i:%02i:%02i", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); gp_storage_add_string(storage, NULL, "Date Time", buf); } png_textp text_ptr; int text_cnt; if (png_get_text(png, png_info, &text_ptr, &text_cnt)) { int i; char buf[128]; for (i = 0; i < text_cnt; i++) { if (text_ptr[i].compression != PNG_TEXT_COMPRESSION_NONE) continue; snprintf(buf, sizeof(buf), "Text %03i", i); gp_storage_add_string(storage, NULL, buf, text_ptr[i].text); } } }