static GimpTempBuf * gimp_undo_get_new_preview (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpUndo *undo = GIMP_UNDO (viewable); if (undo->preview) { gint preview_width; gint preview_height; gimp_viewable_calc_preview_size (gimp_temp_buf_get_width (undo->preview), gimp_temp_buf_get_height (undo->preview), width, height, TRUE, 1.0, 1.0, &preview_width, &preview_height, NULL); if (preview_width < gimp_temp_buf_get_width (undo->preview) && preview_height < gimp_temp_buf_get_height (undo->preview)) { return gimp_temp_buf_scale (undo->preview, preview_width, preview_height); } return gimp_temp_buf_copy (undo->preview); } return NULL; }
void paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask, gint mask_x_offset, gint mask_y_offset, GimpTempBuf *paint_buf, gfloat paint_opacity) { gint width = gimp_temp_buf_get_width (paint_buf); gint height = gimp_temp_buf_get_height (paint_buf); const gint mask_stride = gimp_temp_buf_get_width (paint_mask); const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset; const Babl *mask_format = gimp_temp_buf_get_format (paint_mask); int iy, ix; gfloat *paint_pixel = (gfloat *)gimp_temp_buf_get_data (paint_buf); /* Validate that the paint buffer is withing the bounds of the paint mask */ g_return_if_fail (width <= gimp_temp_buf_get_width (paint_mask) - mask_x_offset); g_return_if_fail (height <= gimp_temp_buf_get_height (paint_mask) - mask_y_offset); if (mask_format == babl_format ("Y u8")) { const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; for (iy = 0; iy < height; iy++) { int mask_offset = iy * mask_stride; const guint8 *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < width; ix++) { paint_pixel[3] *= (((gfloat)*mask_pixel) / 255.0f) * paint_opacity; mask_pixel += 1; paint_pixel += 4; } } } else if (mask_format == babl_format ("Y float")) { const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; for (iy = 0; iy < height; iy++) { int mask_offset = iy * mask_stride; const gfloat *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < width; ix++) { paint_pixel[3] *= (*mask_pixel) * paint_opacity; mask_pixel += 1; paint_pixel += 4; } } } }
static GimpTempBuf * gimp_pattern_get_new_preview (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpPattern *pattern = GIMP_PATTERN (viewable); GimpTempBuf *temp_buf; GeglBuffer *src_buffer; GeglBuffer *dest_buffer; gint copy_width; gint copy_height; copy_width = MIN (width, gimp_temp_buf_get_width (pattern->mask)); copy_height = MIN (height, gimp_temp_buf_get_height (pattern->mask)); temp_buf = gimp_temp_buf_new (copy_width, copy_height, gimp_temp_buf_get_format (pattern->mask)); src_buffer = gimp_temp_buf_create_buffer (pattern->mask); dest_buffer = gimp_temp_buf_create_buffer (temp_buf); gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (0, 0, copy_width, copy_height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); g_object_unref (src_buffer); g_object_unref (dest_buffer); return temp_buf; }
GimpData * gimp_pattern_new (GimpContext *context, const gchar *name) { GimpPattern *pattern; guchar *data; gint row, col; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (name[0] != '\n', NULL); pattern = g_object_new (GIMP_TYPE_PATTERN, "name", name, NULL); pattern->mask = gimp_temp_buf_new (32, 32, babl_format ("R'G'B' u8")); data = gimp_temp_buf_get_data (pattern->mask); for (row = 0; row < gimp_temp_buf_get_height (pattern->mask); row++) for (col = 0; col < gimp_temp_buf_get_width (pattern->mask); col++) { memset (data, (col % 2) && (row % 2) ? 255 : 0, 3); data += 3; } return GIMP_DATA (pattern); }
static GimpValueArray * gimp_pattern_select_run_callback (GimpPdbDialog *dialog, GimpObject *object, gboolean closing, GError **error) { GimpPattern *pattern = GIMP_PATTERN (object); GimpArray *array; GimpValueArray *return_vals; array = gimp_array_new (gimp_temp_buf_get_data (pattern->mask), gimp_temp_buf_get_data_size (pattern->mask), TRUE); return_vals = gimp_pdb_execute_procedure_by_name (dialog->pdb, dialog->caller_context, NULL, error, dialog->callback_name, G_TYPE_STRING, gimp_object_get_name (object), GIMP_TYPE_INT32, gimp_temp_buf_get_width (pattern->mask), GIMP_TYPE_INT32, gimp_temp_buf_get_height (pattern->mask), GIMP_TYPE_INT32, babl_format_get_bytes_per_pixel (gimp_temp_buf_get_format (pattern->mask)), GIMP_TYPE_INT32, array->length, GIMP_TYPE_INT8_ARRAY, array, GIMP_TYPE_INT32, closing, G_TYPE_NONE); gimp_array_free (array); return return_vals; }
void gimp_view_renderer_render_temp_buf_simple (GimpViewRenderer *renderer, GtkWidget *widget, GimpTempBuf *temp_buf) { gint temp_buf_x = 0; gint temp_buf_y = 0; gint temp_buf_width; gint temp_buf_height; g_return_if_fail (GIMP_IS_VIEW_RENDERER (renderer)); g_return_if_fail (temp_buf != NULL); temp_buf_width = gimp_temp_buf_get_width (temp_buf); temp_buf_height = gimp_temp_buf_get_height (temp_buf); if (temp_buf_width < renderer->width) temp_buf_x = (renderer->width - temp_buf_width) / 2; if (temp_buf_height < renderer->height) temp_buf_y = (renderer->height - temp_buf_height) / 2; gimp_view_renderer_render_temp_buf (renderer, widget, temp_buf, temp_buf_x, temp_buf_y, -1, GIMP_VIEW_BG_CHECKS, GIMP_VIEW_BG_WHITE); }
static GimpValueArray * patterns_get_pattern_data_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; const gchar *name; gchar *actual_name = NULL; gint32 width = 0; gint32 height = 0; gint32 mask_bpp = 0; gint32 length = 0; guint8 *mask_data = NULL; name = g_value_get_string (gimp_value_array_index (args, 0)); if (success) { GimpPattern *pattern; if (name && strlen (name)) pattern = gimp_pdb_get_pattern (gimp, name, error); else pattern = gimp_context_get_pattern (context); if (pattern) { actual_name = g_strdup (gimp_object_get_name (pattern)); width = gimp_temp_buf_get_width (pattern->mask); height = gimp_temp_buf_get_height (pattern->mask); mask_bpp = babl_format_get_bytes_per_pixel (gimp_temp_buf_get_format (pattern->mask)); length = gimp_temp_buf_get_data_size (pattern->mask); mask_data = g_memdup (gimp_temp_buf_get_data (pattern->mask), length); } else success = FALSE; } return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) { g_value_take_string (gimp_value_array_index (return_vals, 1), actual_name); g_value_set_int (gimp_value_array_index (return_vals, 2), width); g_value_set_int (gimp_value_array_index (return_vals, 3), height); g_value_set_int (gimp_value_array_index (return_vals, 4), mask_bpp); g_value_set_int (gimp_value_array_index (return_vals, 5), length); gimp_value_take_int8array (gimp_value_array_index (return_vals, 6), mask_data, length); } return return_vals; }
void canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf, GeglBuffer *canvas_buffer, gint x_offset, gint y_offset) { /* Copy the canvas buffer in rect to the paint buffer's alpha channel */ GeglRectangle roi; GeglBufferIterator *iter; const guint paint_stride = gimp_temp_buf_get_width (paint_buf); gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf); roi.x = x_offset; roi.y = y_offset; roi.width = gimp_temp_buf_get_width (paint_buf); roi.height = gimp_temp_buf_get_height (paint_buf); iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gfloat *canvas_pixel = (gfloat *)iter->data[0]; int iy, ix; for (iy = 0; iy < iter->roi[0].height; iy++) { int paint_offset = (iy + iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x; float *paint_pixel = &paint_data[paint_offset * 4]; for (ix = 0; ix < iter->roi[0].width; ix++) { paint_pixel[3] *= *canvas_pixel; canvas_pixel += 1; paint_pixel += 4; } } } }
static gchar * gimp_pattern_get_description (GimpViewable *viewable, gchar **tooltip) { GimpPattern *pattern = GIMP_PATTERN (viewable); return g_strdup_printf ("%s (%d × %d)", gimp_object_get_name (pattern), gimp_temp_buf_get_width (pattern->mask), gimp_temp_buf_get_height (pattern->mask)); }
static gboolean gimp_pattern_get_size (GimpViewable *viewable, gint *width, gint *height) { GimpPattern *pattern = GIMP_PATTERN (viewable); *width = gimp_temp_buf_get_width (pattern->mask); *height = gimp_temp_buf_get_height (pattern->mask); return TRUE; }
static gboolean gimp_undo_get_popup_size (GimpViewable *viewable, gint width, gint height, gboolean dot_for_dot, gint *popup_width, gint *popup_height) { GimpUndo *undo = GIMP_UNDO (viewable); if (undo->preview && (gimp_temp_buf_get_width (undo->preview) > width || gimp_temp_buf_get_height (undo->preview) > height)) { *popup_width = gimp_temp_buf_get_width (undo->preview); *popup_height = gimp_temp_buf_get_height (undo->preview); return TRUE; } return FALSE; }
static void gimp_paint_options_gui_reset_size (GtkWidget *button, GimpPaintOptions *paint_options) { GimpBrush *brush = gimp_context_get_brush (GIMP_CONTEXT (paint_options)); if (brush) { g_object_set (paint_options, "brush-size", (gdouble) MAX (gimp_temp_buf_get_width (brush->mask), gimp_temp_buf_get_height (brush->mask)), NULL); } }
static GimpValueArray * patterns_get_pattern_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; gchar *name = NULL; gint32 width = 0; gint32 height = 0; GimpPattern *pattern = gimp_context_get_pattern (context); if (pattern) { name = g_strdup (gimp_object_get_name (pattern)); width = gimp_temp_buf_get_width (pattern->mask); height = gimp_temp_buf_get_height (pattern->mask); } else success = FALSE; return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) { g_value_take_string (gimp_value_array_index (return_vals, 1), name); g_value_set_int (gimp_value_array_index (return_vals, 2), width); g_value_set_int (gimp_value_array_index (return_vals, 3), height); } return return_vals; }
void combine_paint_mask_to_canvas_mask (const GimpTempBuf *paint_mask, gint mask_x_offset, gint mask_y_offset, GeglBuffer *canvas_buffer, gint x_offset, gint y_offset, gfloat opacity, gboolean stipple) { GeglRectangle roi; GeglBufferIterator *iter; const gint mask_stride = gimp_temp_buf_get_width (paint_mask); const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset; const Babl *mask_format = gimp_temp_buf_get_format (paint_mask); roi.x = x_offset; roi.y = y_offset; roi.width = gimp_temp_buf_get_width (paint_mask) - mask_x_offset; roi.height = gimp_temp_buf_get_height (paint_mask) - mask_y_offset; iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0, babl_format ("Y float"), GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); if (stipple) { if (mask_format == babl_format ("Y u8")) { const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = (gfloat *)iter->data[0]; int iy, ix; for (iy = 0; iy < iter->roi[0].height; iy++) { int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; const guint8 *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < iter->roi[0].width; ix++) { out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity; mask_pixel += 1; out_pixel += 1; } } } } else if (mask_format == babl_format ("Y float")) { const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = (gfloat *)iter->data[0]; int iy, ix; for (iy = 0; iy < iter->roi[0].height; iy++) { int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; const gfloat *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < iter->roi[0].width; ix++) { out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel) * opacity; mask_pixel += 1; out_pixel += 1; } } } } else { g_warning("Mask format not supported: %s", babl_get_name (mask_format)); } } else { if (mask_format == babl_format ("Y u8")) { const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = (gfloat *)iter->data[0]; int iy, ix; for (iy = 0; iy < iter->roi[0].height; iy++) { int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; const guint8 *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < iter->roi[0].width; ix++) { if (opacity > out_pixel[0]) out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity; mask_pixel += 1; out_pixel += 1; } } } } else if (mask_format == babl_format ("Y float")) { const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); mask_data += mask_start_offset; while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = (gfloat *)iter->data[0]; int iy, ix; for (iy = 0; iy < iter->roi[0].height; iy++) { int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; const gfloat *mask_pixel = &mask_data[mask_offset]; for (ix = 0; ix < iter->roi[0].width; ix++) { if (opacity > out_pixel[0]) out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel) * opacity; mask_pixel += 1; out_pixel += 1; } } } } else { g_warning("Mask format not supported: %s", babl_get_name (mask_format)); } } }
void do_layer_blend (GeglBuffer *src_buffer, GeglBuffer *dst_buffer, GimpTempBuf *paint_buf, GeglBuffer *mask_buffer, gfloat opacity, gint x_offset, gint y_offset, gint mask_x_offset, gint mask_y_offset, gboolean linear_mode, GimpLayerModeEffects paint_mode) { GeglRectangle roi; GeglRectangle mask_roi; GeglRectangle process_roi; const Babl *iterator_format; GeglBufferIterator *iter; const guint paint_stride = gimp_temp_buf_get_width (paint_buf); gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf); GimpLayerModeFunction apply_func = get_layer_mode_function (paint_mode, linear_mode); if (linear_mode) iterator_format = babl_format ("RGBA float"); else iterator_format = babl_format ("R'G'B'A float"); roi.x = x_offset; roi.y = y_offset; roi.width = gimp_temp_buf_get_width (paint_buf); roi.height = gimp_temp_buf_get_height (paint_buf); mask_roi.x = roi.x - mask_x_offset; mask_roi.y = roi.y - mask_y_offset; mask_roi.width = roi.width; mask_roi.height = roi.height; g_return_if_fail (gimp_temp_buf_get_format (paint_buf) == iterator_format); iter = gegl_buffer_iterator_new (dst_buffer, &roi, 0, iterator_format, GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, src_buffer, &roi, 0, iterator_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); if (mask_buffer) { gegl_buffer_iterator_add (iter, mask_buffer, &mask_roi, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); } while (gegl_buffer_iterator_next (iter)) { gfloat *out_pixel = (gfloat *)iter->data[0]; gfloat *in_pixel = (gfloat *)iter->data[1]; gfloat *mask_pixel = NULL; gfloat *paint_pixel = paint_data + ((iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x) * 4; int iy; if (mask_buffer) mask_pixel = (gfloat *)iter->data[2]; process_roi.x = iter->roi[0].x; process_roi.width = iter->roi[0].width; process_roi.height = 1; for (iy = 0; iy < iter->roi[0].height; iy++) { process_roi.y = iter->roi[0].y + iy; (*apply_func) (in_pixel, paint_pixel, mask_pixel, out_pixel, opacity, iter->roi[0].width, &process_roi, 0); in_pixel += iter->roi[0].width * 4; out_pixel += iter->roi[0].width * 4; if (mask_buffer) mask_pixel += iter->roi[0].width; paint_pixel += paint_stride * 4; } } }
static void gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer, GtkWidget *widget, GimpTempBuf *temp_buf, gint temp_buf_x, gint temp_buf_y, gint channel, GimpViewBG inside_bg, GimpViewBG outside_bg, cairo_surface_t *surface, gint surface_width, gint surface_height) { cairo_t *cr; gint x, y; gint width, height; const Babl *temp_buf_format; gint temp_buf_width; gint temp_buf_height; g_return_if_fail (temp_buf != NULL); g_return_if_fail (surface != NULL); temp_buf_format = gimp_temp_buf_get_format (temp_buf); temp_buf_width = gimp_temp_buf_get_width (temp_buf); temp_buf_height = gimp_temp_buf_get_height (temp_buf); /* Here are the different cases this functions handles correctly: * 1) Offset temp_buf which does not necessarily cover full image area * 2) Color conversion of temp_buf if it is gray and image is color * 3) Background check buffer for transparent temp_bufs * 4) Using the optional "channel" argument, one channel can be extracted * from a multi-channel temp_buf and composited as a grayscale * Prereqs: * 1) Grayscale temp_bufs have bytes == {1, 2} * 2) Color temp_bufs have bytes == {3, 4} * 3) If image is gray, then temp_buf should have bytes == {1, 2} */ cr = cairo_create (surface); if (outside_bg == GIMP_VIEW_BG_CHECKS || inside_bg == GIMP_VIEW_BG_CHECKS) { if (! renderer->pattern) renderer->pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, gimp_render_light_check_color (), gimp_render_dark_check_color ()); } switch (outside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_paint (cr); if (! gimp_rectangle_intersect (0, 0, surface_width, surface_height, temp_buf_x, temp_buf_y, temp_buf_width, temp_buf_height, &x, &y, &width, &height)) { cairo_destroy (cr); return; } if (inside_bg != outside_bg && babl_format_has_alpha (temp_buf_format) && channel == -1) { cairo_rectangle (cr, x, y, width, height); switch (inside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_fill (cr); } if (babl_format_has_alpha (temp_buf_format) && channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_t *alpha_surface; alpha_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (alpha_surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (alpha_surface); cairo_translate (cr, x, y); cairo_rectangle (cr, 0, 0, width, height); cairo_set_source_surface (cr, alpha_surface, 0, 0); cairo_fill (cr); cairo_surface_destroy (alpha_surface); } else if (channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_flush (surface); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (surface); } else { const Babl *fish; const guchar *src; guchar *dest; gint dest_stride; gint bytes; gint rowstride; gint i; cairo_surface_flush (surface); bytes = babl_format_get_bytes_per_pixel (temp_buf_format); rowstride = temp_buf_width * bytes; src = gimp_temp_buf_get_data (temp_buf) + ((y - temp_buf_y) * rowstride + (x - temp_buf_x) * bytes); dest = cairo_image_surface_get_data (surface); dest_stride = cairo_image_surface_get_stride (surface); dest += y * dest_stride + x * 4; fish = babl_fish (temp_buf_format, babl_format ("cairo-RGB24")); for (i = y; i < (y + height); i++) { const guchar *s = src; guchar *d = dest; gint j; for (j = x; j < (x + width); j++, d += 4, s += bytes) { if (bytes > 2) { guchar pixel[4] = { s[channel], s[channel], s[channel], 255 }; babl_process (fish, pixel, d, 1); } else { guchar pixel[2] = { s[channel], 255 }; babl_process (fish, pixel, d, 1); } } src += rowstride; dest += dest_stride; } cairo_surface_mark_dirty (surface); } cairo_destroy (cr); }