static void size_allocate_callback(GtkWidget *widget, GtkAllocation *allocation, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; if(g->image) cairo_surface_destroy(g->image); free(g->image_buffer); /* load the dt logo as a brackground */ char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.svg", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.svg"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir); g_free(logo); RsvgHandle *svg = rsvg_handle_new_from_file(filename, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = MIN(allocation->width, allocation->height) * 0.75; float factor = final_size / svg_size; float final_width = dimension.width * factor * darktable.gui->ppd, final_height = dimension.height * factor * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width); g->image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(g->image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(g->image_buffer); g->image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_destroy(cr); cairo_surface_flush(surface); g->image = surface; g->image_width = final_width / darktable.gui->ppd; g->image_height = final_height / darktable.gui->ppd; } g_object_unref(svg); } }
void gui_init(dt_lib_module_t *self) { char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; /* initialize ui widgets */ dt_lib_darktable_t *d = (dt_lib_darktable_t *)g_malloc0(sizeof(dt_lib_darktable_t)); self->data = (void *)d; /* create drawing area */ self->widget = gtk_event_box_new(); /* connect callbacks */ g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_lib_darktable_draw_callback), self); g_signal_connect(G_OBJECT(self->widget), "button-press-event", G_CALLBACK(_lib_darktable_button_press_callback), self); /* create a cairo surface of dt icon */ char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.%%s", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.%s"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir, "svg"); // first we try the SVG { GError *error = NULL; RsvgHandle *svg = rsvg_handle_new_from_file(filename, &error); if(!svg || error) { fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n%s\n", filename, error->message); g_error_free(error); error = NULL; goto png_fallback; } cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); int width = DT_PIXEL_APPLY_DPI(dimension.width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(dimension.height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; g_object_unref(svg); fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n", filename); goto png_fallback; } cr = cairo_create(surface); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); rsvg_handle_render_cairo(svg, cr); cairo_surface_flush(surface); d->image = surface; g_object_unref(svg); } goto done; png_fallback: // let's fall back to the PNG { cairo_surface_t *surface; cairo_t *cr; snprintf(filename, sizeof(filename), logo, datadir, "png"); surface = cairo_image_surface_create_from_png(filename); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } int png_width = cairo_image_surface_get_width(surface), png_height = cairo_image_surface_get_height(surface); // blow up the PNG. Ugly, but at least it has the correct size afterwards :-/ int width = DT_PIXEL_APPLY_DPI(png_width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(png_height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); d->image = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(d->image) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; cairo_surface_destroy(surface); fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } cr = cairo_create(d->image); cairo_rectangle(cr, 0, 0, width, height); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); cairo_set_source_surface(cr, surface, 0, 0); cairo_fill(cr); cairo_surface_flush(d->image); cairo_surface_destroy(surface); } done: g_free(logo); d->image_width = d->image ? dt_cairo_image_surface_get_width(d->image) : 0; d->image_height = d->image ? dt_cairo_image_surface_get_height(d->image) : 0; /* set size of drawing area */ gtk_widget_set_size_request(self->widget, d->image_width + (int)DT_PIXEL_APPLY_DPI(180), d->image_height + (int)DT_PIXEL_APPLY_DPI(8)); }
// maybe this should be (partly) in common/imageio.[c|h]? static void _lib_import_update_preview(GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf = NULL; gboolean have_preview = FALSE, no_preview_fallback = FALSE; preview = GTK_WIDGET(data); filename = gtk_file_chooser_get_preview_filename(file_chooser); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { no_preview_fallback = TRUE; } else { // don't create dng thumbnails to avoid crashes in libtiff when these are hdr: char *c = filename + strlen(filename); while(c > filename && *c != '.') c--; if(!strcasecmp(c, ".dng")) no_preview_fallback = TRUE; } // unfortunately we can not use following, because frequently it uses wrong orientation // pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL); have_preview = (pixbuf != NULL); if(!have_preview && !no_preview_fallback) { uint8_t *buffer = NULL; size_t size; char *mime_type = NULL; if(!dt_exif_get_thumbnail(filename, &buffer, &size, &mime_type)) { // Scale the image to the correct size GdkPixbuf *tmp; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!gdk_pixbuf_loader_write(loader, buffer, size, NULL)) goto cleanup; if (!(tmp = gdk_pixbuf_loader_get_pixbuf(loader))) goto cleanup; float ratio = 1.0 * gdk_pixbuf_get_height(tmp) / gdk_pixbuf_get_width(tmp); int width = 128, height = 128 * ratio; pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_BILINEAR); have_preview = TRUE; cleanup: gdk_pixbuf_loader_close(loader, NULL); free(mime_type); free(buffer); g_object_unref(loader); // This should clean up tmp as well } } if(have_preview && !no_preview_fallback) { // get image orientation dt_image_t img = { 0 }; (void)dt_exif_read(&img, filename); // Rotate the image to the correct orientation GdkPixbuf *tmp = pixbuf; if(img.orientation == ORIENTATION_ROTATE_CCW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_CW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_180_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); } if(pixbuf != tmp) { g_object_unref(pixbuf); pixbuf = tmp; } } if(no_preview_fallback || !have_preview) { guint8 *image_buffer = NULL; /* load the dt logo as a brackground */ char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.svg", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.svg"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir); g_free(logo); RsvgHandle *svg = rsvg_handle_new_from_file(filename, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = 128; float factor = final_size / svg_size; float final_width = dimension.width * factor * darktable.gui->ppd, final_height = dimension.height * factor * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width); image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(image_buffer); image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_surface_flush(surface); pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, final_width / darktable.gui->ppd, final_height / darktable.gui->ppd); } g_object_unref(svg); } have_preview = TRUE; } if(have_preview) gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf); if(pixbuf) g_object_unref(pixbuf); g_free(filename); gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); }