plug-ins: Improve color detection in file-pdf-export

Resolves #14583
If the user chooses to vectorize PDF layers with single colors,
get_layer_color () is run to use histograms to determine if they
are indeed a single color. gimp_drawable_histogram () is used to
get the RGB values as averages. This function returns values in the
0...255 range for 8-bit images and 0.0...1.0 range for all the
other precisions.

However, we did not properly normalize the values, resulting in
blown-out white layers when exporting 8-bit images. This patch
checks if the image is 8-bit and divides all values by 255.0f in
that case.

It also checks if the image is in linear precision or not, as
gegl_color_set_rgba () assumes the color values are linear. If not,
gegl_color_set_pixel () is used instead. Finally, the color mode
checks are made a bit more robust in preparation for future color
modes like CMYK.
This commit is contained in:
Alx Sa 2026-04-04 12:38:36 +00:00
parent b41deb138d
commit d88cd4cb7a

View file

@ -487,8 +487,8 @@ pdf_export (GimpProcedure *procedure,
GimpProcedureConfig *config, GimpProcedureConfig *config,
gpointer run_data) gpointer run_data)
{ {
GError *error = NULL; GError *error = NULL;
GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpPDBStatusType status = GIMP_PDB_SUCCESS;
gegl_init (NULL, NULL); gegl_init (NULL, NULL);
@ -1454,24 +1454,22 @@ get_cairo_surface (GimpDrawable *drawable,
return surface; return surface;
} }
/* A function to check if a drawable is single colored This allows to /* A function to check if a drawable is single colored. This allows to
* convert bitmaps to vector where possible * convert bitmaps to vector where possible
*/ */
static GeglColor * static GeglColor *
get_layer_color (GimpLayer *layer, get_layer_color (GimpLayer *layer,
gboolean *single) gboolean *single)
{ {
GeglColor *col = gegl_color_new (NULL); GeglColor *col = gegl_color_new (NULL);
gdouble red, green, blue, alpha; gdouble rgba[4] = { 0, 0, 0, 0 };
gdouble dev, devSum; gdouble dev, devSum;
gdouble median, pixels, count, percentile; gdouble median, pixels, count, percentile;
gint bpp;
devSum = 0; devSum = 0;
red = 0; dev = 0;
green = 0; bpp = gimp_drawable_get_bpp (GIMP_DRAWABLE (layer));
blue = 0;
alpha = 0;
dev = 0;
if (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer))) if (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)))
{ {
@ -1481,23 +1479,26 @@ get_layer_color (GimpLayer *layer,
return col; return col;
} }
if (gimp_drawable_get_bpp (GIMP_DRAWABLE (layer)) >= 3) if (gimp_drawable_is_rgb (GIMP_DRAWABLE (layer)))
{ {
/* Are we in RGB mode? */ /* Are we in RGB mode? */
gimp_drawable_histogram (GIMP_DRAWABLE (layer), gimp_drawable_histogram (GIMP_DRAWABLE (layer),
GIMP_HISTOGRAM_RED, 0.0, 1.0, GIMP_HISTOGRAM_RED, 0.0, 1.0,
&red, &dev, &median, &pixels, &count, &percentile); &rgba[0], &dev, &median, &pixels, &count,
&percentile);
devSum += dev; devSum += dev;
gimp_drawable_histogram (GIMP_DRAWABLE (layer), gimp_drawable_histogram (GIMP_DRAWABLE (layer),
GIMP_HISTOGRAM_GREEN, 0.0, 1.0, GIMP_HISTOGRAM_GREEN, 0.0, 1.0,
&green, &dev, &median, &pixels, &count, &percentile); &rgba[1], &dev, &median, &pixels, &count,
&percentile);
devSum += dev; devSum += dev;
gimp_drawable_histogram (GIMP_DRAWABLE (layer), gimp_drawable_histogram (GIMP_DRAWABLE (layer),
GIMP_HISTOGRAM_BLUE, 0.0, 1.0, GIMP_HISTOGRAM_BLUE, 0.0, 1.0,
&blue, &dev, &median, &pixels, &count, &percentile); &rgba[2], &dev, &median, &pixels, &count,
&percentile);
devSum += dev; devSum += dev;
} }
else else
@ -1506,23 +1507,50 @@ get_layer_color (GimpLayer *layer,
gimp_drawable_histogram (GIMP_DRAWABLE (layer), gimp_drawable_histogram (GIMP_DRAWABLE (layer),
GIMP_HISTOGRAM_VALUE, 0.0, 1.0, GIMP_HISTOGRAM_VALUE, 0.0, 1.0,
&red, &dev, &median, &pixels, &count, &percentile); &rgba[0], &dev, &median, &pixels, &count,
&percentile);
devSum += dev; devSum += dev;
green = red; rgba[1] = rgba[0];
blue = red; rgba[2] = rgba[0];
} }
if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))) if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
gimp_drawable_histogram (GIMP_DRAWABLE (layer), gimp_drawable_histogram (GIMP_DRAWABLE (layer),
GIMP_HISTOGRAM_ALPHA, 0.0, 1.0, GIMP_HISTOGRAM_ALPHA, 0.0, 1.0,
&alpha, &dev, &median, &pixels, &count, &percentile); &rgba[3], &dev, &median, &pixels, &count,
&percentile);
else else
alpha = 255; rgba[3] = 255.0f;
devSum += dev; devSum += dev;
*single = devSum == 0; *single = devSum == 0;
gegl_color_set_rgba (col, red, green, blue, alpha); /* If the image is 8-bit, we need to normalize the RGB values that are
* returned in the 0...255 range */
bpp -= gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)) ? 1 : 0;
if ((gimp_drawable_is_rgb (GIMP_DRAWABLE (layer)) && bpp == 3) ||
bpp == 1)
{
for (gint i = 0; i < 4; i++)
rgba[i] /= 255.0f;
}
switch (gimp_image_get_precision (gimp_item_get_image (GIMP_ITEM (layer))))
{
case GIMP_PRECISION_U8_LINEAR:
case GIMP_PRECISION_U16_LINEAR:
case GIMP_PRECISION_U32_LINEAR:
case GIMP_PRECISION_HALF_LINEAR:
case GIMP_PRECISION_FLOAT_LINEAR:
case GIMP_PRECISION_DOUBLE_LINEAR:
gegl_color_set_rgba (col, rgba[0], rgba[1], rgba[2], rgba[3]);
break;
default:
gegl_color_set_pixel (col, babl_format ("R'G'B'A double"), rgba);
break;
}
return col; return col;
} }