static gpointer negative_exec (GthAsyncTask *task, gpointer user_data) { NegativeData *negative_data = user_data; cairo_format_t format; int width; int height; int source_stride; int destination_stride; unsigned char *p_source_line; unsigned char *p_destination_line; unsigned char *p_source; unsigned char *p_destination; gboolean cancelled; double progress; gboolean terminated; int x, y; unsigned char red, green, blue, alpha; format = cairo_image_surface_get_format (negative_data->source); width = cairo_image_surface_get_width (negative_data->source); height = cairo_image_surface_get_height (negative_data->source); source_stride = cairo_image_surface_get_stride (negative_data->source); negative_data->destination = cairo_image_surface_create (format, width, height); destination_stride = cairo_image_surface_get_stride (negative_data->destination); p_source_line = _cairo_image_surface_flush_and_get_data (negative_data->source); p_destination_line = _cairo_image_surface_flush_and_get_data (negative_data->destination); for (y = 0; y < height; y++) { gth_async_task_get_data (task, NULL, &cancelled, NULL); if (cancelled) return NULL; progress = (double) y / height; gth_async_task_set_data (task, NULL, NULL, &progress); p_source = p_source_line; p_destination = p_destination_line; for (x = 0; x < width; x++) { CAIRO_GET_RGBA (p_source, red, green, blue, alpha); CAIRO_SET_RGBA (p_destination, 255 - red, 255 - green, 255 - blue, alpha); p_source += 4; p_destination += 4; } p_source_line += source_stride; p_destination_line += destination_stride; } cairo_surface_mark_dirty (negative_data->destination); terminated = TRUE; gth_async_task_set_data (task, &terminated, NULL, NULL); return NULL; }
cairo_surface_t * _cairo_image_surface_color_shift (cairo_surface_t *image, int shift) { cairo_surface_t *shifted; int i, j; int width, height, src_stride, dest_stride; guchar *src_pixels, *src_row, *src_pixel; guchar *dest_pixels, *dest_row, *dest_pixel; int val, temp; guchar r, g, b, a; shifted = _cairo_image_surface_create_compatible (image); width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); src_stride = cairo_image_surface_get_stride (image); src_pixels = _cairo_image_surface_flush_and_get_data (image); dest_stride = cairo_image_surface_get_stride (shifted); dest_pixels = _cairo_image_surface_flush_and_get_data (shifted); src_row = src_pixels; dest_row = dest_pixels; for (i = 0; i < height; i++) { src_pixel = src_row; dest_pixel = dest_row; for (j = 0; j < width; j++) { CAIRO_GET_RGBA (src_pixel, r, g, b, a); val = r + shift; r = CLAMP (val, 0, 255); val = g + shift; g = CLAMP (val, 0, 255); val = b + shift; b = CLAMP (val, 0, 255); CAIRO_SET_RGBA (dest_pixel, r, g, b, a); src_pixel += 4; dest_pixel += 4; } src_row += src_stride; dest_row += dest_stride; } cairo_surface_mark_dirty (shifted); return shifted; }
static gpointer adjust_contrast_exec (GthAsyncTask *task, gpointer user_data) { AdjustContrastData *adjust_data = user_data; cairo_format_t format; int width; int height; int source_stride; cairo_surface_t *destination; int destination_stride; unsigned char *p_source_line; unsigned char *p_destination_line; unsigned char *p_source; unsigned char *p_destination; gboolean cancelled; double progress; int x, y; unsigned char red, green, blue, alpha; GthImage *destination_image; /* initialize some extra data */ adjust_contrast_setup (adjust_data); /* convert the image */ format = cairo_image_surface_get_format (adjust_data->source); width = cairo_image_surface_get_width (adjust_data->source); height = cairo_image_surface_get_height (adjust_data->source); source_stride = cairo_image_surface_get_stride (adjust_data->source); destination = cairo_image_surface_create (format, width, height); destination_stride = cairo_image_surface_get_stride (destination); p_source_line = _cairo_image_surface_flush_and_get_data (adjust_data->source); p_destination_line = _cairo_image_surface_flush_and_get_data (destination); for (y = 0; y < height; y++) { gth_async_task_get_data (task, NULL, &cancelled, NULL); if (cancelled) return NULL; progress = (double) y / height; gth_async_task_set_data (task, NULL, NULL, &progress); p_source = p_source_line; p_destination = p_destination_line; for (x = 0; x < width; x++) { CAIRO_GET_RGBA (p_source, red, green, blue, alpha); red = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_RED, red); green = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_GREEN, green); blue = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_BLUE, blue); CAIRO_SET_RGBA (p_destination, red, green, blue, alpha); p_source += 4; p_destination += 4; } p_source_line += source_stride; p_destination_line += destination_stride; } cairo_surface_mark_dirty (destination); destination_image = gth_image_new_for_surface (destination); gth_image_task_set_destination (GTH_IMAGE_TASK (task), destination_image); _g_object_unref (destination_image); cairo_surface_destroy (destination); return NULL; }
static gpointer grayscale_exec (GthAsyncTask *task, gpointer user_data) { GrayscaleData *grayscale_data = user_data; cairo_surface_t *source; cairo_format_t format; int width; int height; int source_stride; cairo_surface_t *destination; int destination_stride; unsigned char *p_source_line; unsigned char *p_destination_line; unsigned char *p_source; unsigned char *p_destination; gboolean cancelled; double progress; int x, y; unsigned char red, green, blue, alpha; unsigned char min, max, value; source = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task)); format = cairo_image_surface_get_format (source); width = cairo_image_surface_get_width (source); height = cairo_image_surface_get_height (source); source_stride = cairo_image_surface_get_stride (source); destination = cairo_image_surface_create (format, width, height); destination_stride = cairo_image_surface_get_stride (destination); p_source_line = _cairo_image_surface_flush_and_get_data (source); p_destination_line = _cairo_image_surface_flush_and_get_data (destination); for (y = 0; y < height; y++) { gth_async_task_get_data (task, NULL, &cancelled, NULL); if (cancelled) return NULL; progress = (double) y / height; gth_async_task_set_data (task, NULL, NULL, &progress); p_source = p_source_line; p_destination = p_destination_line; for (x = 0; x < width; x++) { CAIRO_GET_RGBA (p_source, red, green, blue, alpha); switch (grayscale_data->method) { case METHOD_BRIGHTNESS: value = (0.2125 * red + 0.7154 * green + 0.072 * blue); break; case METHOD_SATURATION: max = MAX (MAX (red, green), blue); min = MIN (MIN (red, green), blue); value = (max + min) / 2; break; case METHOD_AVARAGE: value = (0.3333 * red + 0.3333 * green + 0.3333 * blue); break; default: g_assert_not_reached (); } CAIRO_SET_RGBA (p_destination, value, value, value, alpha); p_source += 4; p_destination += 4; } p_source_line += source_stride; p_destination_line += destination_stride; } cairo_surface_mark_dirty (destination); gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), destination); cairo_surface_destroy (destination); cairo_surface_destroy (source); return NULL; }
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; }