Example #1
0
File: png.c Project: GNOME/giv
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;
}
Example #2
0
File: givimage.c Project: dov/giv
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;
}