/* GIMP - The GNU Image Manipulation Program * Copyright (C) 2013 Daniel Sabo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "paint-types.h" #include "core/gimptempbuf.h" #include "gimppaintcore-loops.h" #include "operations/gimplayermodefunctions.h" 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); GimpTempBuf *modified_mask = gimp_temp_buf_copy (paint_mask); gint width; gint height; width = gimp_temp_buf_get_width (modified_mask); height = gimp_temp_buf_get_height (modified_mask); roi.x = x_offset; roi.y = y_offset; roi.width = width - mask_x_offset; roi.height = height - 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 (modified_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 (modified_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 (modified_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 (modified_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)); } } gimp_temp_buf_unref (modified_mask); } 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; } } } } 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; } } } } 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; } } } void mask_components_onto (GeglBuffer *src_buffer, GeglBuffer *aux_buffer, GeglBuffer *dst_buffer, GeglRectangle *roi, GimpComponentMask mask, gboolean linear_mode) { GeglBufferIterator *iter; const Babl *iterator_format; if (linear_mode) iterator_format = babl_format ("RGBA float"); else iterator_format = babl_format ("R'G'B'A float"); 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); gegl_buffer_iterator_add (iter, aux_buffer, roi, 0, iterator_format, GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gfloat *dest = (gfloat *)iter->data[0]; gfloat *src = (gfloat *)iter->data[1]; gfloat *aux = (gfloat *)iter->data[2]; glong samples = iter->length; while (samples--) { dest[RED] = (mask & GIMP_COMPONENT_MASK_RED) ? aux[RED] : src[RED]; dest[GREEN] = (mask & GIMP_COMPONENT_MASK_GREEN) ? aux[GREEN] : src[GREEN]; dest[BLUE] = (mask & GIMP_COMPONENT_MASK_BLUE) ? aux[BLUE] : src[BLUE]; dest[ALPHA] = (mask & GIMP_COMPONENT_MASK_ALPHA) ? aux[ALPHA] : src[ALPHA]; src += 4; aux += 4; dest += 4; } } }