cairo_surface_t * _cairo_image_surface_scale (cairo_surface_t *image, int scaled_width, int scaled_height, scale_filter_t filter, GthAsyncTask *task) { int src_width; int src_height; cairo_surface_t *scaled; cairo_surface_metadata_t *metadata; resize_filter_t *resize_filter; ScaleReal x_factor; ScaleReal y_factor; cairo_surface_t *tmp; src_width = cairo_image_surface_get_width (image); src_height = cairo_image_surface_get_height (image); if ((src_width == scaled_width) && (src_height == scaled_height)) return _cairo_image_surface_copy (image); scaled = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, scaled_width, scaled_height); _cairo_image_surface_copy_metadata (image, scaled); metadata = _cairo_image_surface_get_metadata (scaled); if (metadata->original_width <= 0) { metadata->original_width = src_width; metadata->original_height = src_height; } if (scaled == NULL) return NULL; if (g_once_init_enter (&coefficients_initialization)) { initialize_coefficients (1.0, 0.0); g_once_init_leave (&coefficients_initialization, 1); } resize_filter = resize_filter_create (task); resize_filter_set_type (resize_filter, filter); resize_filter->total_lines = scaled_width + scaled_height; resize_filter->processed_lines = 0; x_factor = (ScaleReal) scaled_width / src_width; y_factor = (ScaleReal) scaled_height / src_height; tmp = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, src_height, scaled_width); horizontal_scale_transpose (image, tmp, x_factor, resize_filter); horizontal_scale_transpose (tmp, scaled, y_factor, resize_filter); resize_filter_destroy (resize_filter); cairo_surface_destroy (tmp); return scaled; }
cairo_surface_t * _cairo_image_surface_copy (cairo_surface_t *source) { cairo_surface_t *result; unsigned char *p_source; unsigned char *p_destination; if (source == NULL) return NULL; result = _cairo_image_surface_create (cairo_image_surface_get_format (source), cairo_image_surface_get_width (source), cairo_image_surface_get_height (source)); if (result == NULL) return NULL; p_source = _cairo_image_surface_flush_and_get_data (source); p_destination = _cairo_image_surface_flush_and_get_data (result); memcpy (p_destination, p_source, cairo_image_surface_get_stride (source) * cairo_image_surface_get_height (source)); cairo_surface_mark_dirty (result); return result; }
cairo_surface_t * _cairo_create_dnd_icon (cairo_surface_t *image, int icon_size, ItemStyle style, gboolean multi_dnd) { cairo_rectangle_int_t thumbnail_rect; cairo_surface_t *thumbnail; cairo_rectangle_int_t icon_rect; int icon_padding; cairo_rectangle_int_t frame_rect; cairo_surface_t *icon; cairo_t *cr; thumbnail_rect.width = cairo_image_surface_get_width (image); thumbnail_rect.height = cairo_image_surface_get_height (image); if (scale_keeping_ratio (&thumbnail_rect.width, &thumbnail_rect.height, icon_size, icon_size, FALSE)) thumbnail = _cairo_image_surface_scale_fast (image, thumbnail_rect.width, thumbnail_rect.height); else thumbnail = cairo_surface_reference (image); switch (style) { case ITEM_STYLE_ICON: icon_padding = 8; icon_rect.width = icon_size + icon_padding; icon_rect.height = icon_size + icon_padding; thumbnail_rect.x = round ((double) (icon_rect.width - thumbnail_rect.width) / 2.0); thumbnail_rect.y = round ((double) (icon_rect.height - thumbnail_rect.height) / 2.0); frame_rect.x = 0; frame_rect.y = 0; frame_rect.width = icon_rect.width; frame_rect.height = icon_rect.height; break; case ITEM_STYLE_IMAGE: icon_padding = 8; /* padding for the frame border */ icon_rect.width = thumbnail_rect.width + icon_padding; icon_rect.height = thumbnail_rect.height + icon_padding; thumbnail_rect.x = 3; thumbnail_rect.y = 3; frame_rect.x = 0; frame_rect.y = 0; frame_rect.width = thumbnail_rect.width + icon_padding - 2; frame_rect.height = thumbnail_rect.height + icon_padding - 2; break; case ITEM_STYLE_VIDEO: icon_padding = 4; /* padding for the drop shadow effect */ icon_rect.width = thumbnail_rect.width + icon_padding; icon_rect.height = icon_size + icon_padding; thumbnail_rect.x = 0; thumbnail_rect.y = round ((double) (icon_size - thumbnail_rect.height) / 2.0); frame_rect.x = thumbnail_rect.x; frame_rect.y = 0; frame_rect.width = thumbnail_rect.width; frame_rect.height = icon_size; break; } if (multi_dnd) { icon_rect.width += DRAG_ICON_THUMBNAIL_OFFSET; icon_rect.height += DRAG_ICON_THUMBNAIL_OFFSET; } icon = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, icon_rect.width, icon_rect.height); cr = cairo_create (icon); switch (style) { case ITEM_STYLE_ICON: cairo_save (cr); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.2); _cairo_draw_rounded_box (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height, 4); cairo_fill (cr); cairo_restore (cr); break; case ITEM_STYLE_IMAGE: if (multi_dnd) _cairo_draw_thumbnail_frame (cr, frame_rect.x + DRAG_ICON_THUMBNAIL_OFFSET, frame_rect.y + DRAG_ICON_THUMBNAIL_OFFSET, frame_rect.width, frame_rect.height); _cairo_draw_thumbnail_frame (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height); break; case ITEM_STYLE_VIDEO: _cairo_draw_film_background (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height); break; } cairo_save (cr); cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); cairo_set_source_surface (cr, thumbnail, thumbnail_rect.x, thumbnail_rect.y); cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST); cairo_rectangle (cr, thumbnail_rect.x, thumbnail_rect.y, thumbnail_rect.width, thumbnail_rect.height); cairo_fill (cr); cairo_restore (cr); if (style == ITEM_STYLE_VIDEO) _cairo_draw_film_foreground (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height, icon_size); cairo_surface_set_device_offset (icon, -icon_rect.width / 2, -icon_rect.height / 2); cairo_surface_destroy (thumbnail); cairo_destroy (cr); return icon; }
GthImage * _cairo_image_surface_create_from_tiff (GInputStream *istream, GthFileData *file_data, int requested_size, int *original_width_p, int *original_height_p, gboolean *loaded_original_p, gpointer user_data, GCancellable *cancellable, GError **error) { GthImage *image; Handle handle; TIFF *tif; gboolean first_directory; int best_directory; int max_width, max_height, min_diff; uint32 image_width; uint32 image_height; uint32 spp; uint16 extrasamples; uint16 *sampleinfo; uint16 orientation; char emsg[1024]; cairo_surface_t *surface; cairo_surface_metadata_t*metadata; uint32 *raster; image = gth_image_new (); handle.cancellable = cancellable; handle.size = 0; if ((file_data != NULL) && (file_data->info != NULL)) { handle.istream = g_buffered_input_stream_new (istream); handle.size = g_file_info_get_size (file_data->info); } else { void *data; gsize size; /* read the whole stream to get the file size */ if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error)) return image; handle.istream = g_memory_input_stream_new_from_data (data, size, g_free); handle.size = size; } TIFFSetErrorHandler (tiff_error_handler); TIFFSetWarningHandler (tiff_error_handler); tif = TIFFClientOpen ("gth-tiff-reader", "r", &handle, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); if (tif == NULL) { g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } /* find the best image to load */ first_directory = TRUE; best_directory = -1; max_width = -1; max_height = -1; min_diff = 0; do { int width; int height; if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) != 1) continue; if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) != 1) continue; if (! TIFFRGBAImageOK (tif, emsg)) continue; if (width > max_width) { max_width = width; max_height = height; if (requested_size <= 0) best_directory = TIFFCurrentDirectory (tif); } if (requested_size > 0) { int diff = abs (requested_size - width); if (first_directory) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } else if (diff < min_diff) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } } first_directory = FALSE; } while (TIFFReadDirectory (tif)); if (best_directory == -1) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid TIFF format"); return image; } /* read the image */ TIFFSetDirectory (tif, best_directory); TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width); TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height); TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1) orientation = ORIENTATION_TOPLEFT; if (original_width_p) *original_width_p = max_width; if (original_height_p) *original_height_p = max_height; if (loaded_original_p) *loaded_original_p = (max_width == image_width); surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height); if (surface == NULL) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } metadata = _cairo_image_surface_get_metadata (surface); _cairo_metadata_set_has_alpha (metadata, (extrasamples == 1) || (spp == 4)); _cairo_metadata_set_original_size (metadata, max_width, max_height); raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32)); if (raster == NULL) { cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) { guchar *surface_row; int line_step; int x, y, temp; guchar r, g, b, a; uint32 *src_pixel; surface_row = _cairo_image_surface_flush_and_get_data (surface); line_step = cairo_image_surface_get_stride (surface); src_pixel = raster; for (y = 0; y < image_height; y++) { guchar *dest_pixel = surface_row; if (g_cancellable_is_cancelled (cancellable)) goto stop_loading; for (x = 0; x < image_width; x++) { r = TIFFGetR (*src_pixel); g = TIFFGetG (*src_pixel); b = TIFFGetB (*src_pixel); a = TIFFGetA (*src_pixel); CAIRO_SET_RGBA (dest_pixel, r, g, b, a); dest_pixel += 4; src_pixel += 1; } surface_row += line_step; } } stop_loading: cairo_surface_mark_dirty (surface); if (! g_cancellable_is_cancelled (cancellable)) gth_image_set_cairo_surface (image, surface); _TIFFfree (raster); cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); return image; }