[gimp] app: make generated indexed palettes possibly contain pure black/white
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: make generated indexed palettes possibly contain pure black/white
- Date: Thu, 30 Apr 2020 19:22:00 +0000 (UTC)
commit 9bb3ff42d708d005886aa8cfc9a8492d12f77607
Author: Øyvind Kolås <pippin gimp org>
Date: Thu Apr 30 19:53:25 2020 +0200
app: make generated indexed palettes possibly contain pure black/white
The median-cut algorithm to derive a suitable palette for the image
computes each index to be used as the average of colors in a 3d box
in a color space, making the result value drift away from the extremes.
This makes it nigh impossible to achieve pure white or black, even
when the original image contained these colors, like in scans of
printed documents and technical drawings.
We counteract the drift by snapping the whitest color to white and the
blackest color to black if the resulting colors of median-cut are
already sufficiently close to white or black.
app/core/gimpimage-convert-indexed.c | 54 ++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
---
diff --git a/app/core/gimpimage-convert-indexed.c b/app/core/gimpimage-convert-indexed.c
index 47c6fa1259..3f1b72c9b7 100644
--- a/app/core/gimpimage-convert-indexed.c
+++ b/app/core/gimpimage-convert-indexed.c
@@ -2757,11 +2757,65 @@ median_cut_pass1_gray (QuantizeObj *quantobj)
select_colors_gray (quantobj, quantobj->histogram);
}
+static void
+snap_to_black_and_white (QuantizeObj *quantobj)
+{
+ /* find whitest and blackest colors in palette, if they are closer
+ * than 24 units of euclidian distance in sRGB snap them to pure
+ * black / white.
+ */
+#define POW2(a) ((a)*(a))
+ gint desired = quantobj->desired_number_of_colors;
+ gint whitest = 0;
+ gint blackest = 0;
+
+ glong white_dist = POW2(255) * 3;
+ glong black_dist = POW2(255) * 3;
+ gint i;
+
+ for (i = 0; i < desired; i ++)
+ {
+ int dist;
+
+ dist = POW2 (quantobj->cmap[i].red - 255) +
+ POW2 (quantobj->cmap[i].green - 255) +
+ POW2( quantobj->cmap[i].blue - 255);
+ if (dist < white_dist)
+ {
+ white_dist = dist;
+ whitest = i;
+ }
+
+ dist = POW2(quantobj->cmap[i].red - 0) +
+ POW2(quantobj->cmap[i].green - 0) +
+ POW2(quantobj->cmap[i].blue - 0);
+ if (dist < black_dist)
+ {
+ black_dist = dist;
+ blackest = i;
+ }
+ }
+
+ if (white_dist < POW2(24)) /* 24 units in sRGB ~= deltaE of 9.5 */
+ {
+ quantobj->cmap[whitest].red =
+ quantobj->cmap[whitest].green =
+ quantobj->cmap[whitest].blue = 255;
+ }
+ if (black_dist < POW2(24))
+ {
+ quantobj->cmap[blackest].red =
+ quantobj->cmap[blackest].green =
+ quantobj->cmap[blackest].blue = 0;
+ }
+#undef POW2
+}
static void
median_cut_pass1_rgb (QuantizeObj *quantobj)
{
select_colors_rgb (quantobj, quantobj->histogram);
+ snap_to_black_and_white (quantobj);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]