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; } } } }
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); }
GimpTempBuf * gimp_image_get_new_preview (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpImage *image = GIMP_IMAGE (viewable); const Babl *format; gboolean linear; GimpTempBuf *buf; gdouble scale_x; gdouble scale_y; scale_x = (gdouble) width / (gdouble) gimp_image_get_width (image); scale_y = (gdouble) height / (gdouble) gimp_image_get_height (image); format = gimp_projectable_get_format (GIMP_PROJECTABLE (image)); linear = gimp_babl_format_get_linear (format); format = gimp_babl_format (gimp_babl_format_get_base_type (format), gimp_babl_precision (GIMP_COMPONENT_TYPE_U8, linear), babl_format_has_alpha (format)); buf = gimp_temp_buf_new (width, height, format); gegl_buffer_get (gimp_pickable_get_buffer (GIMP_PICKABLE (image)), GEGL_RECTANGLE (0, 0, width, height), MIN (scale_x, scale_y), gimp_temp_buf_get_format (buf), gimp_temp_buf_get_data (buf), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); return buf; }
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; }
static GimpTempBuf * gimp_buffer_get_new_preview (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpBuffer *buffer = GIMP_BUFFER (viewable); const Babl *format = gimp_buffer_get_format (buffer); GimpTempBuf *preview; if (babl_format_is_palette (format)) format = gimp_babl_format (GIMP_RGB, GIMP_PRECISION_U8_GAMMA, babl_format_has_alpha (format)); else format = gimp_babl_format (gimp_babl_format_get_base_type (format), gimp_babl_precision (GIMP_COMPONENT_TYPE_U8, gimp_babl_format_get_linear (format)), babl_format_has_alpha (format)); preview = gimp_temp_buf_new (width, height, format); gegl_buffer_get (buffer->buffer, GEGL_RECTANGLE (0, 0, width, height), MIN ((gdouble) width / (gdouble) gimp_buffer_get_width (buffer), (gdouble) height / (gdouble) gimp_buffer_get_height (buffer)), format, gimp_temp_buf_get_data (preview), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); return preview; }
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; }
GimpTempBuf * gimp_drawable_get_sub_preview (GimpDrawable *drawable, gint src_x, gint src_y, gint src_width, gint src_height, gint dest_width, gint dest_height) { GimpItem *item; GimpImage *image; GeglBuffer *buffer; GimpTempBuf *preview; gdouble scale; gint scaled_x; gint scaled_y; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (src_x >= 0, NULL); g_return_val_if_fail (src_y >= 0, NULL); g_return_val_if_fail (src_width > 0, NULL); g_return_val_if_fail (src_height > 0, NULL); g_return_val_if_fail (dest_width > 0, NULL); g_return_val_if_fail (dest_height > 0, NULL); item = GIMP_ITEM (drawable); g_return_val_if_fail ((src_x + src_width) <= gimp_item_get_width (item), NULL); g_return_val_if_fail ((src_y + src_height) <= gimp_item_get_height (item), NULL); image = gimp_item_get_image (item); if (! image->gimp->config->layer_previews) return NULL; buffer = gimp_drawable_get_buffer (drawable); preview = gimp_temp_buf_new (dest_width, dest_height, gimp_drawable_get_preview_format (drawable)); scale = MIN ((gdouble) dest_width / (gdouble) src_width, (gdouble) dest_height / (gdouble) src_height); scaled_x = RINT ((gdouble) src_x * scale); scaled_y = RINT ((gdouble) src_y * scale); gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, dest_width, dest_height), scale, gimp_temp_buf_get_format (preview), gimp_temp_buf_get_data (preview), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); return preview; }
static void gimp_pattern_clipboard_buffer_changed (Gimp *gimp, GimpPattern *pattern) { if (pattern->mask) { gimp_temp_buf_unref (pattern->mask); pattern->mask = NULL; } if (gimp->global_buffer) { GimpBuffer *buffer = gimp->global_buffer; gint width; gint height; width = MIN (gimp_buffer_get_width (buffer), 2048); height = MIN (gimp_buffer_get_height (buffer), 2048); pattern->mask = gimp_temp_buf_new (width, height, gimp_buffer_get_format (buffer)); gegl_buffer_get (gimp_buffer_get_buffer (buffer), GEGL_RECTANGLE (0, 0, width, height), 1.0, NULL, gimp_temp_buf_get_data (pattern->mask), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); } else { pattern->mask = gimp_temp_buf_new (16, 16, babl_format ("R'G'B' u8")); memset (gimp_temp_buf_get_data (pattern->mask), 255, 16 * 16 * 3); } gimp_data_dirty (GIMP_DATA (pattern)); }
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_checksum (GimpTagged *tagged) { GimpPattern *pattern = GIMP_PATTERN (tagged); gchar *checksum_string = NULL; if (pattern->mask) { GChecksum *checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, gimp_temp_buf_get_data (pattern->mask), gimp_temp_buf_get_data_size (pattern->mask)); checksum_string = g_strdup (g_checksum_get_string (checksum)); g_checksum_free (checksum); } return checksum_string; }
static void gimp_brush_clipboard_buffer_changed (Gimp *gimp, GimpBrush *brush) { gint width; gint height; if (brush->mask) { gimp_temp_buf_unref (brush->mask); brush->mask = NULL; } if (brush->pixmap) { gimp_temp_buf_unref (brush->pixmap); brush->pixmap = NULL; } if (gimp->global_buffer) { GeglBuffer *buffer = gimp_buffer_get_buffer (gimp->global_buffer); const Babl *format = gegl_buffer_get_format (buffer); GeglBuffer *dest_buffer; width = MIN (gimp_buffer_get_width (gimp->global_buffer), 512); height = MIN (gimp_buffer_get_height (gimp->global_buffer), 512); brush->mask = gimp_temp_buf_new (width, height, babl_format ("Y u8")); brush->pixmap = gimp_temp_buf_new (width, height, babl_format ("R'G'B' u8")); /* copy the alpha channel into the brush's mask */ if (babl_format_has_alpha (format)) { dest_buffer = gimp_temp_buf_create_buffer (brush->mask); gegl_buffer_set_format (dest_buffer, babl_format ("A u8")); gegl_buffer_copy (buffer, NULL, dest_buffer, NULL); g_object_unref (dest_buffer); } else { memset (gimp_temp_buf_get_data (brush->mask), 255, width * height); } /* copy the color channels into the brush's pixmap */ dest_buffer = gimp_temp_buf_create_buffer (brush->pixmap); gegl_buffer_copy (buffer, NULL, dest_buffer, NULL); g_object_unref (dest_buffer); } else { width = 17; height = 17; brush->mask = gimp_temp_buf_new (width, height, babl_format ("Y u8")); gimp_temp_buf_data_clear (brush->mask); } brush->x_axis.x = width / 2; brush->x_axis.y = 0; brush->y_axis.x = 0; brush->y_axis.y = height / 2; gimp_data_dirty (GIMP_DATA (brush)); }
GdkPixbuf * gimp_image_get_new_pixbuf (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpImage *image = GIMP_IMAGE (viewable); GdkPixbuf *pixbuf; gdouble scale_x; gdouble scale_y; GimpColorTransform *transform; scale_x = (gdouble) width / (gdouble) gimp_image_get_width (image); scale_y = (gdouble) height / (gdouble) gimp_image_get_height (image); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); transform = gimp_image_get_color_transform_to_srgb_u8 (image); if (transform) { GimpTempBuf *temp_buf; GeglBuffer *src_buf; GeglBuffer *dest_buf; temp_buf = gimp_temp_buf_new (width, height, gimp_pickable_get_format (GIMP_PICKABLE (image))); gegl_buffer_get (gimp_pickable_get_buffer (GIMP_PICKABLE (image)), GEGL_RECTANGLE (0, 0, width, height), MIN (scale_x, scale_y), gimp_temp_buf_get_format (temp_buf), gimp_temp_buf_get_data (temp_buf), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); src_buf = gimp_temp_buf_create_buffer (temp_buf); dest_buf = gimp_pixbuf_create_buffer (pixbuf); gimp_temp_buf_unref (temp_buf); gimp_color_transform_process_buffer (transform, src_buf, GEGL_RECTANGLE (0, 0, width, height), dest_buf, GEGL_RECTANGLE (0, 0, 0, 0)); g_object_unref (src_buf); g_object_unref (dest_buf); } else { gegl_buffer_get (gimp_pickable_get_buffer (GIMP_PICKABLE (image)), GEGL_RECTANGLE (0, 0, width, height), MIN (scale_x, scale_y), gimp_pixbuf_get_format (pixbuf), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), GEGL_ABYSS_CLAMP); } return pixbuf; }
GdkPixbuf * gimp_drawable_get_sub_pixbuf (GimpDrawable *drawable, gint src_x, gint src_y, gint src_width, gint src_height, gint dest_width, gint dest_height) { GimpItem *item; GimpImage *image; GeglBuffer *buffer; GdkPixbuf *pixbuf; gdouble scale; gint scaled_x; gint scaled_y; GimpColorTransform *transform; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (src_x >= 0, NULL); g_return_val_if_fail (src_y >= 0, NULL); g_return_val_if_fail (src_width > 0, NULL); g_return_val_if_fail (src_height > 0, NULL); g_return_val_if_fail (dest_width > 0, NULL); g_return_val_if_fail (dest_height > 0, NULL); item = GIMP_ITEM (drawable); g_return_val_if_fail ((src_x + src_width) <= gimp_item_get_width (item), NULL); g_return_val_if_fail ((src_y + src_height) <= gimp_item_get_height (item), NULL); image = gimp_item_get_image (item); if (! image->gimp->config->layer_previews) return NULL; buffer = gimp_drawable_get_buffer (drawable); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, dest_width, dest_height); scale = MIN ((gdouble) dest_width / (gdouble) src_width, (gdouble) dest_height / (gdouble) src_height); scaled_x = RINT ((gdouble) src_x * scale); scaled_y = RINT ((gdouble) src_y * scale); transform = gimp_image_get_color_transform_to_srgb_u8 (image); if (transform) { GimpTempBuf *temp_buf; GeglBuffer *src_buf; GeglBuffer *dest_buf; temp_buf = gimp_temp_buf_new (dest_width, dest_height, gimp_drawable_get_format (drawable)); gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, dest_width, dest_height), scale, gimp_temp_buf_get_format (temp_buf), gimp_temp_buf_get_data (temp_buf), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); src_buf = gimp_temp_buf_create_buffer (temp_buf); dest_buf = gimp_pixbuf_create_buffer (pixbuf); gimp_temp_buf_unref (temp_buf); gimp_color_transform_process_buffer (transform, src_buf, GEGL_RECTANGLE (0, 0, dest_width, dest_height), dest_buf, GEGL_RECTANGLE (0, 0, 0, 0)); g_object_unref (src_buf); g_object_unref (dest_buf); } else { gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, dest_width, dest_height), scale, gimp_pixbuf_get_format (pixbuf), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), GEGL_ABYSS_CLAMP); } return pixbuf; }
static GimpTempBuf * gimp_brush_generated_calc (GimpBrushGenerated *brush, GimpBrushGeneratedShape shape, gfloat radius, gint spikes, gfloat hardness, gfloat aspect_ratio, gfloat angle, GimpVector2 *xaxis, GimpVector2 *yaxis) { guchar *centerp; guchar *lookup; guchar a; gint x, y; gdouble c, s, cs, ss; GimpVector2 x_axis; GimpVector2 y_axis; GimpTempBuf *mask; gint width; gint height; gint half_width; gint half_height; gimp_brush_generated_get_size (brush, shape, radius, spikes, hardness, aspect_ratio, angle, &width, &height, &s, &c, &x_axis, &y_axis); mask = gimp_temp_buf_new (width, height, babl_format ("Y u8")); half_width = width / 2; half_height = height / 2; centerp = gimp_temp_buf_get_data (mask) + half_height * width + half_width; lookup = gimp_brush_generated_calc_lut (radius, hardness); cs = cos (- 2 * G_PI / spikes); ss = sin (- 2 * G_PI / spikes); /* for an even number of spikes compute one half and mirror it */ for (y = ((spikes % 2) ? -half_height : 0); y <= half_height; y++) { for (x = -half_width; x <= half_width; x++) { gdouble d = 0; gdouble tx = c * x - s * y; gdouble ty = fabs (s * x + c * y); if (spikes > 2) { gdouble angle = atan2 (ty, tx); while (angle > G_PI / spikes) { gdouble sx = tx; gdouble sy = ty; tx = cs * sx - ss * sy; ty = ss * sx + cs * sy; angle -= 2 * G_PI / spikes; } } ty *= aspect_ratio; switch (shape) { case GIMP_BRUSH_GENERATED_CIRCLE: d = sqrt (SQR (tx) + SQR (ty)); break; case GIMP_BRUSH_GENERATED_SQUARE: d = MAX (fabs (tx), fabs (ty)); break; case GIMP_BRUSH_GENERATED_DIAMOND: d = fabs (tx) + fabs (ty); break; } if (d < radius + 1) a = lookup[(gint) RINT (d * OVERSAMPLING)]; else a = 0; centerp[y * width + x] = a; if (spikes % 2 == 0) centerp[-1 * y * width - x] = a; } } g_free (lookup); if (xaxis) *xaxis = x_axis; if (yaxis) *yaxis = y_axis; return mask; }
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); }
static GdkPixbuf * gimp_buffer_get_new_pixbuf (GimpViewable *viewable, GimpContext *context, gint width, gint height) { GimpBuffer *buffer = GIMP_BUFFER (viewable); GdkPixbuf *pixbuf; gdouble scale; pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); scale = MIN ((gdouble) width / (gdouble) gimp_buffer_get_width (buffer), (gdouble) height / (gdouble) gimp_buffer_get_height (buffer)); if (buffer->color_profile) { GimpColorProfile *srgb_profile; GimpTempBuf *temp_buf; GeglBuffer *src_buf; GeglBuffer *dest_buf; srgb_profile = gimp_color_profile_new_rgb_srgb (); temp_buf = gimp_temp_buf_new (width, height, gimp_buffer_get_format (buffer)); gegl_buffer_get (buffer->buffer, GEGL_RECTANGLE (0, 0, width, height), scale, gimp_temp_buf_get_format (temp_buf), gimp_temp_buf_get_data (temp_buf), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); src_buf = gimp_temp_buf_create_buffer (temp_buf); dest_buf = gimp_pixbuf_create_buffer (pixbuf); gimp_temp_buf_unref (temp_buf); gimp_gegl_convert_color_profile (src_buf, GEGL_RECTANGLE (0, 0, width, height), buffer->color_profile, dest_buf, GEGL_RECTANGLE (0, 0, 0, 0), srgb_profile, GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL, TRUE, NULL); g_object_unref (src_buf); g_object_unref (dest_buf); g_object_unref (srgb_profile); } else { gegl_buffer_get (buffer->buffer, GEGL_RECTANGLE (0, 0, width, height), scale, gimp_pixbuf_get_format (pixbuf), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), GEGL_ABYSS_CLAMP); } return pixbuf; }
GList * gimp_pattern_load (GimpContext *context, GFile *file, GInputStream *input, GError **error) { GimpPattern *pattern = NULL; const Babl *format = NULL; PatternHeader header; gsize size; gsize bytes_read; gint bn_size; gchar *name = NULL; g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* read the size */ if (! g_input_stream_read_all (input, &header, sizeof (header), &bytes_read, NULL, error) || bytes_read != sizeof (header)) { g_prefix_error (error, _("File appears truncated: ")); goto error; } /* rearrange the bytes in each unsigned int */ header.header_size = g_ntohl (header.header_size); header.version = g_ntohl (header.version); header.width = g_ntohl (header.width); header.height = g_ntohl (header.height); header.bytes = g_ntohl (header.bytes); header.magic_number = g_ntohl (header.magic_number); /* Check for correct file format */ if (header.magic_number != GPATTERN_MAGIC || header.version != 1 || header.header_size <= sizeof (header)) { g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, _("Unknown pattern format version %d."), header.version); goto error; } /* Check for supported bit depths */ if (header.bytes < 1 || header.bytes > 4) { g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, _("Unsupported pattern depth %d.\n" "GIMP Patterns must be GRAY or RGB."), header.bytes); goto error; } /* Read in the pattern name */ if ((bn_size = (header.header_size - sizeof (header)))) { gchar *utf8; name = g_new (gchar, bn_size); if (! g_input_stream_read_all (input, name, bn_size, &bytes_read, NULL, error) || bytes_read != bn_size) { g_prefix_error (error, _("File appears truncated.")); g_free (name); goto error; } utf8 = gimp_any_to_utf8 (name, -1, _("Invalid UTF-8 string in pattern file '%s'."), gimp_file_get_utf8_name (file)); g_free (name); name = utf8; } if (! name) name = g_strdup (_("Unnamed")); pattern = g_object_new (GIMP_TYPE_PATTERN, "name", name, "mime-type", "image/x-gimp-pat", NULL); g_free (name); switch (header.bytes) { case 1: format = babl_format ("Y' u8"); break; case 2: format = babl_format ("Y'A u8"); break; case 3: format = babl_format ("R'G'B' u8"); break; case 4: format = babl_format ("R'G'B'A u8"); break; } pattern->mask = gimp_temp_buf_new (header.width, header.height, format); size = header.width * header.height * header.bytes; if (! g_input_stream_read_all (input, gimp_temp_buf_get_data (pattern->mask), size, &bytes_read, NULL, error) || bytes_read != size) { g_prefix_error (error, _("File appears truncated.")); goto error; } return g_list_prepend (NULL, pattern); error: if (pattern) g_object_unref (pattern); g_prefix_error (error, _("Fatal parse error in pattern file: ")); return NULL; }