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; }
GivImage *giv_image_new_from_file(const char *filename, GError **error) { GivImage *img = NULL; // TBD - run through a list of loaders. Right now just // use gdkpixbuf. gchar *extension = g_strrstr(filename, "."); if (extension) extension++; if ((img = giv_plugin_load_image(filename, error)) != NULL) { return img; } if (*error) { printf("Got error: %s\n", (*error)->message); return NULL; } else if (!extension) { } else if (g_regex_match_simple("png" "|jpe?g" "|p[bgp]m" "|bmp" "|svg" , extension, G_REGEX_CASELESS, 0)) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, error); if (*error) return img; gboolean is_mono = TRUE; // Check if the file is monochrome. int row_idx,col_idx; int width = gdk_pixbuf_get_width(pixbuf); int height = gdk_pixbuf_get_height(pixbuf); guint8 *buf = gdk_pixbuf_get_pixels(pixbuf); int row_stride = gdk_pixbuf_get_rowstride(pixbuf); for (row_idx=0; row_idx<height; row_idx++) { guint8 *p = buf + row_idx * row_stride; for (col_idx=0; col_idx<width; col_idx++) { if (p[0] != p[1] || p[0] != p[2]) { is_mono = FALSE; break; } p+= 3; } } if (is_mono) { GivImageType img_type = GIVIMAGE_U8; img = giv_image_new_full(img_type, width, width, height, width * height, 2, 1); 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; } guchar *src_buf = gdk_pixbuf_get_pixels(pixbuf); guchar *dst_buf = img->buf.buf; int row_idx, col_idx; int ncolors = 3; if (gdk_pixbuf_get_has_alpha(pixbuf)) ncolors = 4; for (row_idx=0; row_idx<height; row_idx++) { guchar *dst_row = dst_buf + row_idx*width; guchar *src_row = src_buf + row_idx*row_stride; for (col_idx=0; col_idx<width; col_idx++) dst_row[col_idx] = src_row[col_idx*ncolors]; } } else { GivImageType img_type = GIVIMAGE_RGB_U8; if (gdk_pixbuf_get_has_alpha(pixbuf)) img_type = GIVIMAGE_RGBA_U8; img = giv_image_new_full(img_type, width, row_stride, height, row_stride * height, 2, 1); 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; } memcpy(img->buf.buf, gdk_pixbuf_get_pixels(pixbuf), row_stride * height); } g_object_unref(pixbuf); } // Space separated value. A simple text format parser. Still // doesn't support comments. Fix this! else if (g_regex_match_simple("ssv", extension, G_REGEX_CASELESS, 0)) { gchar *ssv_string; gsize length; g_file_get_contents(filename, &ssv_string, &length, error); gchar **lines = g_regex_split_simple("\r?\n", ssv_string, 0, 0); int num_lines = g_strv_length(lines); // Count lines while skipping comments int height = 0; int line_idx; for (line_idx = 0; line_idx<num_lines; line_idx++) { if (lines[line_idx][0] == '#' || strlen(lines[line_idx]) == 0) continue; height++; } gint width = -1; float *fbuf; int row_idx = 0; for (line_idx=0; line_idx<num_lines; line_idx++) { int col_idx; if (lines[line_idx][0] == '#' || strlen(lines[line_idx]) == 0) continue; // comma or space split gchar *p = lines[line_idx]; // skip whitespace while(*p == ' ') p++; gchar **fields = g_regex_split_simple("(?:,|;|\\s)\\s*", p, 0,0); if (row_idx==0) { width = g_strv_length(fields); img = giv_image_new(GIVIMAGE_FLOAT, width, height); fbuf = img->buf.fbuf; } for (col_idx=0; col_idx<width; col_idx++) fbuf[row_idx*width + col_idx] = atof(fields[col_idx]); g_strfreev(fields); row_idx++; } g_strfreev(lines); g_free(ssv_string); } else if (g_regex_match_simple("npy", extension, G_REGEX_CASELESS, 0)) { gchar *npy_string; gsize length; g_file_get_contents(filename, &npy_string, &length, error); // Various checks that it is format we support gboolean header_ok = (g_strstr_len(npy_string, 6, "\223NUMPY") == npy_string ); gboolean ver_ok = (npy_string[6] == 1 && npy_string[7] == 0); gint header_len = *((guint16*)(npy_string+8)); // Use regex to parse the header. Should update this to allow // user attributes. GRegex *regex = g_regex_new ("^\\{\\s*" "'descr':\\s*\\'(.*?)\\'\\s*,\\s*" "'fortran_order':\\s*(\\w+)\\s*,\\s*" "'shape':\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\),?\\s*" "\\}", 0, 0, error); if (*error) { printf("Programming GivRegEx error: %s\n", (*error)->message); exit(-1); } GMatchInfo *match_info = NULL; gboolean is_match = g_regex_match_full(regex, npy_string+10, header_len, 0, (GRegexMatchFlags)0, &match_info, error); gboolean is_supported_type = TRUE; gboolean is_fortran_type = FALSE; gint width=-1, height = -1; GivImageType image_type; if (is_match) { gchar *match_string = g_match_info_fetch(match_info, 1); if (strcmp(match_string, "<f8")==0) image_type = GIVIMAGE_DOUBLE; else if (strcmp(match_string, "<f4")==0) image_type = GIVIMAGE_FLOAT; else if (strcmp(match_string, "<i4")==0) image_type = GIVIMAGE_I32; else if (strcmp(match_string, "<i2")==0) image_type = GIVIMAGE_I16; else if (strcmp(match_string, "<u2")==0) image_type = GIVIMAGE_U16; else if (strcmp(match_string, "|u1")==0) image_type = GIVIMAGE_U8; else is_supported_type = FALSE; g_free(match_string); match_string = g_match_info_fetch(match_info, 2); is_fortran_type = strcmp(match_string, "True") == 0; g_free(match_string); match_string = g_match_info_fetch(match_info, 3); height = atoi(match_string); g_free(match_string); match_string = g_match_info_fetch(match_info, 4); width = atoi(match_string); g_free(match_string); } g_regex_unref(regex); g_match_info_free(match_info); if (!is_match || !header_ok || !is_supported_type || is_fortran_type ) { *error = g_error_new(GIV_IMAGE_ERROR, -1, "Invalid npy file!"); g_free(npy_string); return NULL; } img = giv_image_new(image_type, width, height); // Copy the data // printf("image: type size width height= %d %d\n", image_type, giv_image_type_get_size(image_type), width, height); memcpy(img->buf.buf, npy_string + 10 + header_len, giv_image_type_get_size(image_type) * width * height / 8); g_free(npy_string); } else { *error = g_error_new(GIV_IMAGE_ERROR, -1, "Giv: Unknown filetype %s!", extension); } if (!img && !*error) *error = g_error_new(GIV_IMAGE_ERROR, -1, "Giv: Failed loading %s!", filename); return img; }