From 8a9ea2681171fa5bc2ff8eed05831c25deffb350 Mon Sep 17 00:00:00 2001 From: David Capello Date: Sat, 1 Nov 2014 23:14:48 -0300 Subject: [PATCH] Fix ReplaceInkProcessing to work correctly with transparent colors (fix #435) Now we can replace a solid color with transparent in RGBA and Grayscale images. --- src/app/color_utils.cpp | 51 +++++++++++++++++++++------------- src/app/tools/ink_processing.h | 22 ++++++++++++--- src/raster/blend.cpp | 18 ++++++++---- 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/app/color_utils.cpp b/src/app/color_utils.cpp index 67c8f0fa2..d7867e9ac 100644 --- a/src/app/color_utils.cpp +++ b/src/app/color_utils.cpp @@ -119,31 +119,44 @@ raster::color_t color_utils::color_for_layer(const app::Color& color, Layer* lay raster::color_t color_utils::color_for_target(const app::Color& color, const ColorTarget& colorTarget) { - if (color.getType() == app::Color::MaskType) - return colorTarget.maskColor(); - raster::color_t c = -1; + if (color.getType() == app::Color::MaskType) { + c = colorTarget.maskColor(); + } + else { + switch (colorTarget.pixelFormat()) { + case IMAGE_RGB: + c = raster::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255); + break; + case IMAGE_GRAYSCALE: + c = raster::graya(color.getGray(), 255); + break; + case IMAGE_INDEXED: + if (color.getType() == app::Color::IndexType) { + c = color.getIndex(); + } + else { + c = get_current_palette()->findBestfit( + color.getRed(), + color.getGreen(), + color.getBlue(), + colorTarget.isTransparent() ? + colorTarget.maskColor(): // Don't return the mask color + -1); // Return any color, we are in a background layer. + } + break; + } + } + switch (colorTarget.pixelFormat()) { case IMAGE_RGB: - c = raster::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255); + if (colorTarget.isBackground()) + c |= raster::rgba(0, 0, 0, 255); break; case IMAGE_GRAYSCALE: - c = raster::graya(color.getGray(), 255); - break; - case IMAGE_INDEXED: - if (color.getType() == app::Color::IndexType) { - c = color.getIndex(); - } - else { - c = get_current_palette()->findBestfit( - color.getRed(), - color.getGreen(), - color.getBlue(), - colorTarget.isTransparent() ? - colorTarget.maskColor(): // Don't return the mask color - -1); // Return any color, we are in a background layer. - } + if (colorTarget.isBackground()) + c |= raster::graya(0, 255); break; } diff --git a/src/app/tools/ink_processing.h b/src/app/tools/ink_processing.h index a18d4dce8..4909a9415 100644 --- a/src/app/tools/ink_processing.h +++ b/src/app/tools/ink_processing.h @@ -22,6 +22,7 @@ #include "app/tools/shading_options.h" #include "filters/neighboring_pixels.h" #include "raster/palette.h" +#include "raster/raster.h" #include "raster/rgbmap.h" #include "raster/sprite.h" @@ -475,14 +476,27 @@ private: template<> void ReplaceInkProcessing::processPixel(int x, int y) { - if (*m_srcAddress == m_color1) - *m_dstAddress = rgba_blend_normal(*m_srcAddress, m_color2, m_opacity); + color_t src = (*m_srcAddress); + + // Colors (m_srcAddress and m_color1) match if: + // * They are both completelly transparent (alpha == 0) + // * Or they are not transparent and the RGB values are the same + if ((rgba_geta(src) == 0 && rgba_geta(m_color1) == 0) || + (rgba_geta(src) > 0 && rgba_geta(m_color1) > 0 && + ((src & rgba_rgb_mask) == (m_color1 & rgba_rgb_mask)))) { + *m_dstAddress = rgba_blend_merge(src, m_color2, m_opacity); + } } template<> void ReplaceInkProcessing::processPixel(int x, int y) { - if (*m_srcAddress == m_color1) - *m_dstAddress = graya_blend_normal(*m_srcAddress, m_color2, m_opacity); + color_t src = (*m_srcAddress); + + if ((graya_geta(src) == 0 && graya_geta(m_color1) == 0) || + (graya_geta(src) > 0 && graya_geta(m_color1) > 0 && + ((src & graya_v_mask) == (m_color1 & graya_v_mask)))) { + *m_dstAddress = graya_blend_merge(src, m_color2, m_opacity); + } } template<> diff --git a/src/raster/blend.cpp b/src/raster/blend.cpp index 2399bab6d..8dc2a1ddb 100644 --- a/src/raster/blend.cpp +++ b/src/raster/blend.cpp @@ -109,6 +109,7 @@ int rgba_blend_merge(int back, int front, int opacity) int B_r, B_g, B_b, B_a; int F_r, F_g, F_b, F_a; int D_r, D_g, D_b, D_a; + int t; B_r = rgba_getr(back); B_g = rgba_getg(back); @@ -131,11 +132,13 @@ int rgba_blend_merge(int back, int front, int opacity) D_b = B_b; } else { - D_r = B_r + (F_r-B_r) * opacity / 255; - D_g = B_g + (F_g-B_g) * opacity / 255; - D_b = B_b + (F_b-B_b) * opacity / 255; + D_r = B_r + INT_MULT((F_r - B_r), opacity, t); + D_g = B_g + INT_MULT((F_g - B_g), opacity, t); + D_b = B_b + INT_MULT((F_b - B_b), opacity, t); } - D_a = B_a + (F_a-B_a) * opacity / 255; + D_a = B_a + INT_MULT((F_a - B_a), opacity, t); + if (D_a == 0) + D_r = D_g = D_b = 0; return rgba(D_r, D_g, D_b, D_a); } @@ -274,6 +277,7 @@ int graya_blend_merge(int back, int front, int opacity) int B_k, B_a; int F_k, F_a; int D_k, D_a; + int t; B_k = graya_getv(back); B_a = graya_geta(back); @@ -288,9 +292,11 @@ int graya_blend_merge(int back, int front, int opacity) D_k = B_k; } else { - D_k = B_k + (F_k-B_k) * opacity / 255; + D_k = B_k + INT_MULT((F_k-B_k), opacity, t); } - D_a = B_a + (F_a-B_a) * opacity / 255; + D_a = B_a + INT_MULT((F_a-B_a), opacity, t); + if (D_a == 0) + D_k = 0; return graya(D_k, D_a); }