static int test_rpng(const char *in_path) { #ifdef HAVE_IMLIB2 Imlib_Image img; const uint32_t *imlib_data = NULL; #endif const uint32_t test_data[] = { 0xff000000 | 0x50, 0xff000000 | 0x80, 0xff000000 | 0x40, 0xff000000 | 0x88, 0xff000000 | 0x50, 0xff000000 | 0x80, 0xff000000 | 0x40, 0xff000000 | 0x88, 0xff000000 | 0xc3, 0xff000000 | 0xd3, 0xff000000 | 0xc3, 0xff000000 | 0xd3, 0xff000000 | 0xc3, 0xff000000 | 0xd3, 0xff000000 | 0xc3, 0xff000000 | 0xd3, }; uint32_t *data = NULL; unsigned width = 0; unsigned height = 0; if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16)) return 1; if (!rpng_load_image_argb(in_path, &data, &width, &height)) return 2; fprintf(stderr, "Path: %s.\n", in_path); fprintf(stderr, "Got image: %u x %u.\n", width, height); #if 0 fprintf(stderr, "\nRPNG:\n"); for (unsigned h = 0; h < height; h++) { unsigned w; for (w = 0; w < width; w++) fprintf(stderr, "[%08x] ", data[h * width + w]); fprintf(stderr, "\n"); } #endif #ifdef HAVE_IMLIB2 /* Validate with imlib2 as well. */ img = imlib_load_image(in_path); if (!img) return 4; imlib_context_set_image(img); width = imlib_image_get_width(); height = imlib_image_get_width(); imlib_data = imlib_image_get_data_for_reading_only(); #if 0 fprintf(stderr, "\nImlib:\n"); for (unsigned h = 0; h < height; h++) { for (unsigned w = 0; w < width; w++) fprintf(stderr, "[%08x] ", imlib_data[h * width + w]); fprintf(stderr, "\n"); } #endif if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0) { fprintf(stderr, "Imlib and RPNG differs!\n"); return 5; } else fprintf(stderr, "Imlib and RPNG are equivalent!\n"); imlib_free_image(); #endif free(data); return 0; }
/* * Load & display image */ void qiv_load_image(qiv_image *q) { /* Don't initialize most variables here, initialize them after load_next_image: */ struct stat st; const char *image_name; Imlib_Image *im; struct timeval load_before, load_after; char is_stat_ok; /* Used to omit slow disk operations if image_file doesn't exist or isn't * a file. */ char is_maybe_image_file; char is_first_error = 1; load_next_image: is_stat_ok = 0; is_maybe_image_file = 1; image_name = image_names[image_idx]; gettimeofday(&load_before, 0); if (imlib_context_get_image()) imlib_free_image(); q->real_w = q->real_h = -2; q->has_thumbnail = FALSE; if (!do_omit_load_stat) { is_stat_ok = 0 == stat(image_name, &st); is_maybe_image_file = is_stat_ok && S_ISREG(st.st_mode); } current_mtime = is_stat_ok ? st.st_mtime : 0; im = NULL; if (thumbnail && fullscreen && (is_stat_ok || maxpect)) { char *th_image_name = is_maybe_image_file ? get_thumbnail_filename(image_name, &is_maybe_image_file) : NULL; if (th_image_name) { im = imlib_load_image(th_image_name); if (im && maxpect) { get_image_dimensions(image_name, th_image_name, &q->real_w, &q->real_h); } free(th_image_name); th_image_name = NULL; } } if (im) { /* We have a dumb thumbnail in im. */ if (maxpect) { current_mtime = 0; q->has_thumbnail = TRUE; /* Now im still has the thumbnail image. Keep it. */ } else { /* Use the real, non-thumbnail image instead. */ imlib_context_set_image(im); imlib_free_image(); im = is_maybe_image_file ? imlib_load_image((char*)image_name) : NULL; } } else { im = is_maybe_image_file ? imlib_load_image((char*)image_name) : NULL; } if (!im) { /* error */ q->error = 1; q->orig_w = 400; q->orig_h = 300; if (to_root || to_root_t || to_root_s) { fprintf(stderr, "qiv: cannot load background_image\n"); qiv_exit(1); } /* Shortcut to speed up lots of subsequent load failures. */ if (is_first_error) { check_size(q, TRUE); if (first) { setup_win(q); first = 0; } gdk_window_set_background(q->win, &error_bg); gdk_beep(); is_first_error = 0; } /* TODO(pts): Avoid the slow loop of copying pointers around in update_image_on_error. */ update_image_on_error(q); /* This is a shortcut to avoid stack overflow in the recursion of * qiv_load_image -> update_image -> qiv_load_image -> update_image -> ... * if there are errors loading many subsequent images. */ goto load_next_image; } if (thumbnail && !q->has_thumbnail && q->real_w < 0 && is_maybe_image_file) { FILE *f = fopen(image_name, "rb"); if (f) { get_real_dimensions_fast(f, &q->real_w, &q->real_h); fclose(f); } } /* Retrieve image properties */ imlib_context_set_image(im); q->error = 0; q->orig_w = imlib_image_get_width(); q->orig_h = imlib_image_get_height(); if (q->orig_w >= (1 << 23) / q->orig_h) { /* Workaround for Imlib2 1.4.6 on Ubuntu Trusty: PNG images with an * alpha channel and pixel count >= (1 << 23) are displayed as black. * imlib_image_query_pixel returns the correct value, but * imlib_render_pixmaps_for_whole_image_at_size renders only black * pixels if unzoomed. */ Imlib_Color c; /* Without this call, imlib_image_set_has_alpha(0) is too early, and * it has no effect. */ imlib_image_query_pixel(0, 0, &c); imlib_image_set_has_alpha(0); } #ifdef HAVE_EXIF if (autorotate) { transform( q, orient( image_name)); } #endif check_size(q, TRUE); if (first) { setup_win(q); first = 0; } /* desktop-background -> exit */ if (to_root || to_root_t || to_root_s) { set_desktop_image(q); if(slide) return; else qiv_exit(0); } gdk_window_set_background(q->win, &image_bg); if (do_grab || (fullscreen && !disable_grab) ) { gdk_keyboard_grab(q->win, FALSE, CurrentTime); gdk_pointer_grab(q->win, FALSE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, NULL, NULL, CurrentTime); } gettimeofday(&load_after, 0); /* load_elapsed used by update_image. */ load_elapsed = ((load_after.tv_sec + load_after.tv_usec / 1.0e6) - (load_before.tv_sec + load_before.tv_usec / 1.0e6)); update_image(q, FULL_REDRAW); // if (magnify && !fullscreen) { // [lc] // setup_magnify(q, &magnify_img); // update_magnify(q, &magnify_img, FULL_REDRAW, 0, 0); // } }
static int x11_load_image(w3mimg_op * self, W3MImage * img, char *fname, int w, int h) { struct x11_info *xi; #if defined(USE_IMLIB) ImlibImage *im; #elif defined(USE_IMLIB2) Imlib_Image im; #elif defined(USE_GDKPIXBUF) GdkPixbufAnimation *animation; GList *frames; int i, j, iw, ih, n, frame_num, delay, max_anim; double ratio_w, ratio_h; struct x11_image *ximg; Pixmap tmp_pixmap; #endif if (self == NULL) return 0; xi = (struct x11_info *)self->priv; if (xi == NULL) return 0; #if defined(USE_IMLIB) im = Imlib_load_image(xi->id, fname); if (!im) return 0; if (w <= 0) w = im->rgb_width; if (h <= 0) h = im->rgb_height; img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h, DefaultDepth(xi->display, 0)); if (!img->pixmap) return 0; XSetForeground(xi->display, xi->imageGC, xi->background_pixel); XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h); Imlib_paste_image(xi->id, im, (Pixmap) img->pixmap, 0, 0, w, h); Imlib_kill_image(xi->id, im); #elif defined(USE_IMLIB2) im = imlib_load_image(fname); if (!im) return 0; imlib_context_set_image(im); if (w <= 0) w = imlib_image_get_width(); if (h <= 0) h = imlib_image_get_height(); img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h, DefaultDepth(xi->display, 0)); if (!img->pixmap) return 0; XSetForeground(xi->display, xi->imageGC, xi->background_pixel); XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h); imlib_context_set_display(xi->display); imlib_context_set_visual(DefaultVisual(xi->display, 0)); imlib_context_set_colormap(DefaultColormap(xi->display, 0)); imlib_context_set_drawable((Drawable) img->pixmap); imlib_render_image_on_drawable_at_size(0, 0, w, h); imlib_free_image(); #elif defined(USE_GDKPIXBUF) max_anim = self->max_anim; animation = gdk_pixbuf_animation_new_from_file(fname); if (!animation) return 0; frames = gdk_pixbuf_animation_get_frames(animation); frame_num = n = gdk_pixbuf_animation_get_num_frames(animation); get_animation_size(animation, &iw, &ih, &delay); if (delay <= 0) max_anim = -1; if (max_anim < 0) { frame_num = (-max_anim > n) ? n : -max_anim; } else if (max_anim > 0) { frame_num = n = (max_anim > n) ? n : max_anim; } if (w < 1 || h < 1) { w = iw; h = ih; ratio_w = ratio_h = 1; } else { ratio_w = 1.0 * w / iw; ratio_h = 1.0 * h / ih; } tmp_pixmap = XCreatePixmap(xi->display, xi->parent, w, h, DefaultDepth(xi->display, 0)); XFillRectangle(xi->display, (Pixmap) tmp_pixmap, xi->imageGC, 0, 0, w, h); if (!tmp_pixmap) { gdk_pixbuf_animation_unref(animation); return 0; } ximg = x11_img_new(xi, w, h, frame_num); if (!ximg) { XFreePixmap(xi->display, tmp_pixmap); gdk_pixbuf_animation_unref(animation); return 0; } for (j = 0; j < n; j++) { GdkPixbufFrame *frame; GdkPixbuf *org_pixbuf, *pixbuf; int width, height, ofstx, ofsty; if (max_anim < 0) { i = (j - n + frame_num > 0) ? (j - n + frame_num) : 0; } else { i = j; } frame = (GdkPixbufFrame *) g_list_nth_data(frames, j); org_pixbuf = gdk_pixbuf_frame_get_pixbuf(frame); ofstx = gdk_pixbuf_frame_get_x_offset(frame); ofsty = gdk_pixbuf_frame_get_y_offset(frame); delay = gdk_pixbuf_frame_get_delay_time(frame); width = gdk_pixbuf_get_width(org_pixbuf); height = gdk_pixbuf_get_height(org_pixbuf); if (ofstx == 0 && ofsty == 0 && width == w && height == h) { pixbuf = resize_image(org_pixbuf, w, h); } else { pixbuf = resize_image(org_pixbuf, width * ratio_w, height * ratio_h); ofstx *= ratio_w; ofsty *= ratio_h; } width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); if (delay > ximg->delay) ximg->delay = delay; XCopyArea(xi->display, tmp_pixmap, ximg->pixmap[i], xi->imageGC, 0, 0, w, h, 0, 0); gdk_pixbuf_xlib_render_to_drawable_alpha(pixbuf, (Drawable) ximg->pixmap[i], 0, 0, ofstx, ofsty, width, height, GDK_PIXBUF_ALPHA_BILEVEL, 1, XLIB_RGB_DITHER_NORMAL, 0, 0); switch (gdk_pixbuf_frame_get_action(frame)) { case GDK_PIXBUF_FRAME_RETAIN: XCopyArea(xi->display, ximg->pixmap[i], tmp_pixmap, xi->imageGC, 0, 0, w, h, 0, 0); break; case GDK_PIXBUF_FRAME_DISPOSE: break; case GDK_PIXBUF_FRAME_REVERT: XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap, xi->imageGC, 0, 0, w, h, 0, 0); break; default: XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap, xi->imageGC, 0, 0, w, h, 0, 0); break; } if (org_pixbuf != pixbuf) gdk_pixbuf_finalize(pixbuf); } XFreePixmap(xi->display, tmp_pixmap); gdk_pixbuf_animation_unref(animation); img->pixmap = ximg; #endif img->width = w; img->height = h; return 1; }