Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

32
libpikacolor/Makefile.gi Normal file
View File

@ -0,0 +1,32 @@
# Introspectable sources for libpikacolor
libpikacolor_introspectable_headers = \
../libpikacolor/pikacolortypes.h \
../libpikacolor/pikaadaptivesupersample.h \
../libpikacolor/pikabilinear.h \
../libpikacolor/pikacairo.h \
../libpikacolor/pikacmyk.h \
../libpikacolor/pikacolormanaged.h \
../libpikacolor/pikacolorprofile.h \
../libpikacolor/pikacolorspace.h \
../libpikacolor/pikacolortransform.h \
../libpikacolor/pikahsl.h \
../libpikacolor/pikahsv.h \
../libpikacolor/pikapixbuf.h \
../libpikacolor/pikargb.h
libpikacolor_introspectable = \
../libpikacolor/pikaadaptivesupersample.c \
../libpikacolor/pikabilinear.c \
../libpikacolor/pikacairo.c \
../libpikacolor/pikacmyk.c \
../libpikacolor/pikacolormanaged.c \
../libpikacolor/pikacolorprofile.c \
../libpikacolor/pikacolorspace.c \
../libpikacolor/pikacolortransform.c \
../libpikacolor/pikahsl.c \
../libpikacolor/pikahsv.c \
../libpikacolor/pikapixbuf.c \
../libpikacolor/pikargb.c \
../libpikacolor/pikargb-parse.c \
$(libpikacolor_introspectable_headers)

76
libpikacolor/meson.build Normal file
View File

@ -0,0 +1,76 @@
libpikacolor_sources = files(
'pikaadaptivesupersample.c',
'pikabilinear.c',
'pikacairo.c',
'pikacmyk.c',
'pikacolormanaged.c',
'pikacolorprofile.c',
'pikacolorspace.c',
'pikacolortransform.c',
'pikahsl.c',
'pikahsv.c',
'pikapixbuf.c',
'pikargb-parse.c',
'pikargb.c',
)
libpikacolor_headers_introspectable = files(
'pikacolortypes.h',
'pikaadaptivesupersample.h',
'pikabilinear.h',
'pikacairo.h',
'pikacmyk.h',
'pikacolormanaged.h',
'pikacolorprofile.h',
'pikacolorspace.h',
'pikacolortransform.h',
'pikahsl.h',
'pikahsv.h',
'pikapixbuf.h',
'pikargb.h',
)
libpikacolor_headers = [
libpikacolor_headers_introspectable,
'pikacolor.h',
]
libpikacolor_introspectable = [
libpikacolor_sources,
libpikacolor_headers_introspectable,
]
libpikacolor = library('pikacolor-' + pika_api_version,
libpikacolor_sources,
include_directories: rootInclude,
dependencies: [
cairo, gdk_pixbuf, gegl, lcms, math,
],
c_args: [ '-DG_LOG_DOMAIN="LibPikaColor"', '-DPIKA_COLOR_COMPILATION', ],
link_with: [ libpikabase, ],
vs_module_defs: 'pikacolor.def',
install: true,
version: so_version,
)
install_headers(
libpikacolor_headers,
subdir: pika_api_name / 'libpikacolor',
)
# Test program, not installed
executable('test-color-parser',
'test-color-parser.c',
include_directories: rootInclude,
dependencies: [
cairo, gdk_pixbuf, gegl, lcms, math,
babl,
# glib,
],
c_args: '-DG_LOG_DOMAIN="LibPikaColor"',
link_with: [ libpikabase, libpikacolor, ],
install: false,
)

View File

@ -0,0 +1,414 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikacolortypes.h"
#include "pikaadaptivesupersample.h"
#include "pikargb.h"
/**
* SECTION: pikaadaptivesupersample
* @title: PikaAdaptiveSupersample
* @short_description: Functions to perform adaptive supersampling on
* an area.
*
* Functions to perform adaptive supersampling on an area.
**/
/*********************************************************************/
/* Sumpersampling code (Quartic) */
/* This code is *largely* based on the sources for POV-Ray 3.0. I am */
/* grateful to the POV-Team for such a great program and for making */
/* their sources available. All comments / bug reports / */
/* etc. regarding this code should be addressed to me, not to the */
/* POV-Ray team. Any bugs are my responsibility, not theirs. */
/*********************************************************************/
typedef struct _PikaSampleType PikaSampleType;
struct _PikaSampleType
{
guchar ready;
PikaRGB color;
};
static gulong
pika_render_sub_pixel (gint max_depth,
gint depth,
PikaSampleType **block,
gint x,
gint y,
gint x1,
gint y1,
gint x3,
gint y3,
gdouble threshold,
gint sub_pixel_size,
PikaRGB *color,
PikaRenderFunc render_func,
gpointer render_data)
{
gint x2, y2; /* Coords of center sample */
gdouble dx1, dy1; /* Delta to upper left sample */
gdouble dx3, dy3; /* Delta to lower right sample */
PikaRGB c[4]; /* Sample colors */
gulong num_samples = 0;
gint cnt;
g_return_val_if_fail (render_func != NULL, 0);
/* Get offsets for corners */
dx1 = (gdouble) (x1 - sub_pixel_size / 2) / sub_pixel_size;
dx3 = (gdouble) (x3 - sub_pixel_size / 2) / sub_pixel_size;
dy1 = (gdouble) (y1 - sub_pixel_size / 2) / sub_pixel_size;
dy3 = (gdouble) (y3 - sub_pixel_size / 2) / sub_pixel_size;
/* Render upper left sample */
if (! block[y1][x1].ready)
{
num_samples++;
render_func (x + dx1, y + dy1, &c[0], render_data);
block[y1][x1].ready = TRUE;
block[y1][x1].color = c[0];
}
else
{
c[0] = block[y1][x1].color;
}
/* Render upper right sample */
if (! block[y1][x3].ready)
{
num_samples++;
render_func (x + dx3, y + dy1, &c[1], render_data);
block[y1][x3].ready = TRUE;
block[y1][x3].color = c[1];
}
else
{
c[1] = block[y1][x3].color;
}
/* Render lower left sample */
if (! block[y3][x1].ready)
{
num_samples++;
render_func (x + dx1, y + dy3, &c[2], render_data);
block[y3][x1].ready = TRUE;
block[y3][x1].color = c[2];
}
else
{
c[2] = block[y3][x1].color;
}
/* Render lower right sample */
if (! block[y3][x3].ready)
{
num_samples++;
render_func (x + dx3, y + dy3, &c[3], render_data);
block[y3][x3].ready = TRUE;
block[y3][x3].color = c[3];
}
else
{
c[3] = block[y3][x3].color;
}
/* Check for supersampling */
if (depth <= max_depth)
{
/* Check whether we have to supersample */
if ((pika_rgba_distance (&c[0], &c[1]) >= threshold) ||
(pika_rgba_distance (&c[0], &c[2]) >= threshold) ||
(pika_rgba_distance (&c[0], &c[3]) >= threshold) ||
(pika_rgba_distance (&c[1], &c[2]) >= threshold) ||
(pika_rgba_distance (&c[1], &c[3]) >= threshold) ||
(pika_rgba_distance (&c[2], &c[3]) >= threshold))
{
/* Calc coordinates of center subsample */
x2 = (x1 + x3) / 2;
y2 = (y1 + y3) / 2;
/* Render sub-blocks */
num_samples += pika_render_sub_pixel (max_depth, depth + 1, block,
x, y, x1, y1, x2, y2,
threshold, sub_pixel_size,
&c[0],
render_func, render_data);
num_samples += pika_render_sub_pixel (max_depth, depth + 1, block,
x, y, x2, y1, x3, y2,
threshold, sub_pixel_size,
&c[1],
render_func, render_data);
num_samples += pika_render_sub_pixel (max_depth, depth + 1, block,
x, y, x1, y2, x2, y3,
threshold, sub_pixel_size,
&c[2],
render_func, render_data);
num_samples += pika_render_sub_pixel (max_depth, depth + 1, block,
x, y, x2, y2, x3, y3,
threshold, sub_pixel_size,
&c[3],
render_func, render_data);
}
}
if (c[0].a == 0.0 || c[1].a == 0.0 || c[2].a == 0.0 || c[3].a == 0.0)
{
PikaRGB tmpcol;
gdouble weight;
pika_rgb_set (&tmpcol, 0.0, 0.0, 0.0);
weight = 2.0;
for (cnt = 0; cnt < 4; cnt++)
{
if (c[cnt].a != 0.0)
{
tmpcol.r += c[cnt].r;
tmpcol.g += c[cnt].g;
tmpcol.b += c[cnt].b;
weight /= 2.0;
}
}
color->r = weight * tmpcol.r;
color->g = weight * tmpcol.g;
color->b = weight * tmpcol.b;
}
else
{
color->r = 0.25 * (c[0].r + c[1].r + c[2].r + c[3].r);
color->g = 0.25 * (c[0].g + c[1].g + c[2].g + c[3].g);
color->b = 0.25 * (c[0].b + c[1].b + c[2].b + c[3].b);
}
color->a = 0.25 * (c[0].a + c[1].a + c[2].a + c[3].a);
return num_samples;
}
/**
* pika_adaptive_supersample_area:
* @x1: left x coordinate of the area to process.
* @y1: top y coordinate of the area to process.
* @x2: right x coordinate of the area to process.
* @y2: bottom y coordinate of the area to process.
* @max_depth: maximum depth of supersampling.
* @threshold: lower threshold of pixel difference that stops
* supersampling.
* @render_func: (scope call): function calculate the color value at
* given coordinates.
* @render_data: user data passed to @render_func.
* @put_pixel_func: (scope call): function to a pixels to a color at
* given coordinates.
* @put_pixel_data: user data passed to @put_pixel_func.
* @progress_func: (scope call): function to report progress.
* @progress_data: user data passed to @progress_func.
*
* Returns: the number of pixels processed.
**/
gulong
pika_adaptive_supersample_area (gint x1,
gint y1,
gint x2,
gint y2,
gint max_depth,
gdouble threshold,
PikaRenderFunc render_func,
gpointer render_data,
PikaPutPixelFunc put_pixel_func,
gpointer put_pixel_data,
PikaProgressFunc progress_func,
gpointer progress_data)
{
gint x, y, width; /* Counters, width of region */
gint xt, xtt, yt; /* Temporary counters */
gint sub_pixel_size; /* Number of samples per pixel (1D) */
PikaRGB color; /* Rendered pixel's color */
PikaSampleType tmp_sample; /* For swapping samples */
PikaSampleType *top_row, *bot_row, *tmp_row; /* Sample rows */
PikaSampleType **block; /* Sample block matrix */
gulong num_samples;
g_return_val_if_fail (render_func != NULL, 0);
g_return_val_if_fail (put_pixel_func != NULL, 0);
/* Initialize color */
pika_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);
/* Calculate sub-pixel size */
sub_pixel_size = 1 << max_depth;
/* Create row arrays */
width = x2 - x1 + 1;
top_row = gegl_scratch_new (PikaSampleType, sub_pixel_size * width + 1);
bot_row = gegl_scratch_new (PikaSampleType, sub_pixel_size * width + 1);
for (x = 0; x < (sub_pixel_size * width + 1); x++)
{
top_row[x].ready = FALSE;
pika_rgba_set (&top_row[x].color, 0.0, 0.0, 0.0, 0.0);
bot_row[x].ready = FALSE;
pika_rgba_set (&bot_row[x].color, 0.0, 0.0, 0.0, 0.0);
}
/* Allocate block matrix */
block = gegl_scratch_new (PikaSampleType *, sub_pixel_size + 1); /* Rows */
for (y = 0; y < (sub_pixel_size + 1); y++)
{
block[y] = gegl_scratch_new (PikaSampleType, sub_pixel_size + 1); /* Columns */
for (x = 0; x < (sub_pixel_size + 1); x++)
{
block[y][x].ready = FALSE;
pika_rgba_set (&block[y][x].color, 0.0, 0.0, 0.0, 0.0);
}
}
/* Render region */
num_samples = 0;
for (y = y1; y <= y2; y++)
{
/* Clear the bottom row */
for (xt = 0; xt < (sub_pixel_size * width + 1); xt++)
bot_row[xt].ready = FALSE;
/* Clear first column */
for (yt = 0; yt < (sub_pixel_size + 1); yt++)
block[yt][0].ready = FALSE;
/* Render row */
for (x = x1; x <= x2; x++)
{
/* Initialize block by clearing all but first row/column */
for (yt = 1; yt < (sub_pixel_size + 1); yt++)
for (xt = 1; xt < (sub_pixel_size + 1); xt++)
block[yt][xt].ready = FALSE;
/* Copy samples from top row to block */
for (xtt = 0, xt = (x - x1) * sub_pixel_size;
xtt < (sub_pixel_size + 1);
xtt++, xt++)
block[0][xtt] = top_row[xt];
/* Render pixel on (x, y) */
num_samples += pika_render_sub_pixel (max_depth, 1, block, x, y, 0, 0,
sub_pixel_size, sub_pixel_size,
threshold, sub_pixel_size,
&color,
render_func, render_data);
if (put_pixel_func)
(* put_pixel_func) (x, y, &color, put_pixel_data);
/* Copy block information to rows */
top_row[(x - x1 + 1) * sub_pixel_size] = block[0][sub_pixel_size];
for (xtt = 0, xt = (x - x1) * sub_pixel_size;
xtt < (sub_pixel_size + 1);
xtt++, xt++)
bot_row[xt] = block[sub_pixel_size][xtt];
/* Swap first and last columns */
for (yt = 0; yt < (sub_pixel_size + 1); yt++)
{
tmp_sample = block[yt][0];
block[yt][0] = block[yt][sub_pixel_size];
block[yt][sub_pixel_size] = tmp_sample;
}
}
/* Swap rows */
tmp_row = top_row;
top_row = bot_row;
bot_row = tmp_row;
/* Call progress display function (if any) */
if (progress_func != NULL)
(* progress_func) (y1, y2, y, progress_data);
}
/* Free memory */
for (y = 0; y < (sub_pixel_size + 1); y++)
gegl_scratch_free (block[y]);
gegl_scratch_free (block);
gegl_scratch_free (top_row);
gegl_scratch_free (bot_row);
return num_samples;
}

View File

@ -0,0 +1,82 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_ADAPTIVE_SUPERSAMPLE_H__
#define __PIKA_ADAPTIVE_SUPERSAMPLE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/**
* PikaRenderFunc:
* @x:
* @y:
* @color: (out caller-allocates): The rendered pixel as RGB
* @data: (closure):
*/
typedef void (* PikaRenderFunc) (gdouble x,
gdouble y,
PikaRGB *color,
gpointer data);
/**
* PikaPutPixelFunc:
* @x:
* @y:
* @color:
* @data: (closure):
*/
typedef void (* PikaPutPixelFunc) (gint x,
gint y,
PikaRGB *color,
gpointer data);
/**
* PikaProgressFunc:
* @min:
* @max:
* @current:
* @data: (closure):
*/
typedef void (* PikaProgressFunc) (gint min,
gint max,
gint current,
gpointer data);
gulong pika_adaptive_supersample_area (gint x1,
gint y1,
gint x2,
gint y2,
gint max_depth,
gdouble threshold,
PikaRenderFunc render_func,
gpointer render_data,
PikaPutPixelFunc put_pixel_func,
gpointer put_pixel_data,
PikaProgressFunc progress_func,
gpointer progress_data);
G_END_DECLS
#endif /* __PIKA_ADAPTIVE_SUPERSAMPLE_H__ */

273
libpikacolor/pikabilinear.c Normal file
View File

@ -0,0 +1,273 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikacolortypes.h"
#include "pikabilinear.h"
/**
* SECTION: pikabilinear
* @title: PikaBilinear
* @short_description: Utility functions for bilinear interpolation.
*
* Utility functions for bilinear interpolation.
**/
/**
* pika_bilinear:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
gdouble
pika_bilinear (gdouble x,
gdouble y,
gdouble *values)
{
gdouble m0, m1;
g_return_val_if_fail (values != NULL, 0.0);
x = fmod (x, 1.0);
y = fmod (y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - x) * values[0] + x * values[1];
m1 = (1.0 - x) * values[2] + x * values[3];
return (1.0 - y) * m0 + y * m1;
}
/**
* pika_bilinear_8:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
guchar
pika_bilinear_8 (gdouble x,
gdouble y,
guchar *values)
{
gdouble m0, m1;
g_return_val_if_fail (values != NULL, 0);
x = fmod (x, 1.0);
y = fmod (y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - x) * values[0] + x * values[1];
m1 = (1.0 - x) * values[2] + x * values[3];
return (guchar) ((1.0 - y) * m0 + y * m1);
}
/**
* pika_bilinear_16:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
guint16
pika_bilinear_16 (gdouble x,
gdouble y,
guint16 *values)
{
gdouble m0, m1;
g_return_val_if_fail (values != NULL, 0);
x = fmod (x, 1.0);
y = fmod (y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - x) * values[0] + x * values[1];
m1 = (1.0 - x) * values[2] + x * values[3];
return (guint16) ((1.0 - y) * m0 + y * m1);
}
/**
* pika_bilinear_32:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
guint32
pika_bilinear_32 (gdouble x,
gdouble y,
guint32 *values)
{
gdouble m0, m1;
g_return_val_if_fail (values != NULL, 0);
x = fmod (x, 1.0);
y = fmod (y, 1.0);
if (x < 0.0)
x += 1.0;
if (y < 0.0)
y += 1.0;
m0 = (1.0 - x) * values[0] + x * values[1];
m1 = (1.0 - x) * values[2] + x * values[3];
return (guint32) ((1.0 - y) * m0 + y * m1);
}
/**
* pika_bilinear_rgb:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
PikaRGB
pika_bilinear_rgb (gdouble x,
gdouble y,
PikaRGB *values)
{
gdouble m0, m1;
gdouble ix, iy;
PikaRGB v = { 0, };
g_return_val_if_fail (values != NULL, v);
x = fmod(x, 1.0);
y = fmod(y, 1.0);
if (x < 0)
x += 1.0;
if (y < 0)
y += 1.0;
ix = 1.0 - x;
iy = 1.0 - y;
/* Red */
m0 = ix * values[0].r + x * values[1].r;
m1 = ix * values[2].r + x * values[3].r;
v.r = iy * m0 + y * m1;
/* Green */
m0 = ix * values[0].g + x * values[1].g;
m1 = ix * values[2].g + x * values[3].g;
v.g = iy * m0 + y * m1;
/* Blue */
m0 = ix * values[0].b + x * values[1].b;
m1 = ix * values[2].b + x * values[3].b;
v.b = iy * m0 + y * m1;
return v;
}
/**
* pika_bilinear_rgba:
* @x:
* @y:
* @values: (array fixed-size=4):
*/
PikaRGB
pika_bilinear_rgba (gdouble x,
gdouble y,
PikaRGB *values)
{
gdouble m0, m1;
gdouble ix, iy;
gdouble a0, a1, a2, a3, alpha;
PikaRGB v = { 0, };
g_return_val_if_fail (values != NULL, v);
x = fmod (x, 1.0);
y = fmod (y, 1.0);
if (x < 0)
x += 1.0;
if (y < 0)
y += 1.0;
ix = 1.0 - x;
iy = 1.0 - y;
a0 = values[0].a;
a1 = values[1].a;
a2 = values[2].a;
a3 = values[3].a;
/* Alpha */
m0 = ix * a0 + x * a1;
m1 = ix * a2 + x * a3;
alpha = v.a = iy * m0 + y * m1;
if (alpha > 0)
{
/* Red */
m0 = ix * a0 * values[0].r + x * a1 * values[1].r;
m1 = ix * a2 * values[2].r + x * a3 * values[3].r;
v.r = (iy * m0 + y * m1)/alpha;
/* Green */
m0 = ix * a0 * values[0].g + x * a1 * values[1].g;
m1 = ix * a2 * values[2].g + x * a3 * values[3].g;
v.g = (iy * m0 + y * m1)/alpha;
/* Blue */
m0 = ix * a0 * values[0].b + x * a1 * values[1].b;
m1 = ix * a2 * values[2].b + x * a3 * values[3].b;
v.b = (iy * m0 + y * m1)/alpha;
}
return v;
}

View File

@ -0,0 +1,56 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_BILINEAR_H__
#define __PIKA_BILINEAR_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/* bilinear interpolation functions taken from LibGCK */
gdouble pika_bilinear (gdouble x,
gdouble y,
gdouble *values);
guchar pika_bilinear_8 (gdouble x,
gdouble y,
guchar *values);
guint16 pika_bilinear_16 (gdouble x,
gdouble y,
guint16 *values);
guint32 pika_bilinear_32 (gdouble x,
gdouble y,
guint32 *values);
PikaRGB pika_bilinear_rgb (gdouble x,
gdouble y,
PikaRGB *values);
PikaRGB pika_bilinear_rgba (gdouble x,
gdouble y,
PikaRGB *values);
G_END_DECLS
#endif /* __PIKA_BILINEAR_H__ */

210
libpikacolor/pikacairo.c Normal file
View File

@ -0,0 +1,210 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacairo.c
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
* 2010-2012 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gio/gio.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "pikacolortypes.h"
#include "pikacairo.h"
/**
* SECTION: pikacairo
* @title: PikaCairo
* @short_description: Color utility functions for cairo
*
* Utility functions that make cairo easier to use with PIKA color
* data types.
**/
/**
* pika_cairo_set_source_rgb:
* @cr: Cairo context
* @color: PikaRGB color
*
* Sets the source pattern within @cr to the solid opaque color
* described by @color.
*
* This function calls cairo_set_source_rgb() for you.
*
* Since: 2.6
**/
void
pika_cairo_set_source_rgb (cairo_t *cr,
const PikaRGB *color)
{
cairo_set_source_rgb (cr, color->r, color->g, color->b);
}
/**
* pika_cairo_set_source_rgba:
* @cr: Cairo context
* @color: PikaRGB color
*
* Sets the source pattern within @cr to the solid translucent color
* described by @color.
*
* This function calls cairo_set_source_rgba() for you.
*
* Since: 2.6
**/
void
pika_cairo_set_source_rgba (cairo_t *cr,
const PikaRGB *color)
{
cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);
}
/**
* pika_cairo_checkerboard_create:
* @cr: Cairo context
* @size: check size
* @light: light check color or %NULL to use the default light gray
* @dark: dark check color or %NULL to use the default dark gray
*
* Create a repeating checkerboard pattern.
*
* Returns: a new Cairo pattern that can be used as a source on @cr.
*
* Since: 2.6
**/
cairo_pattern_t *
pika_cairo_checkerboard_create (cairo_t *cr,
gint size,
const PikaRGB *light,
const PikaRGB *dark)
{
cairo_t *context;
cairo_surface_t *surface;
cairo_pattern_t *pattern;
g_return_val_if_fail (cr != NULL, NULL);
g_return_val_if_fail (size > 0, NULL);
surface = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_COLOR,
2 * size, 2 * size);
context = cairo_create (surface);
if (light)
pika_cairo_set_source_rgb (context, light);
else
cairo_set_source_rgb (context,
PIKA_CHECK_LIGHT, PIKA_CHECK_LIGHT, PIKA_CHECK_LIGHT);
cairo_rectangle (context, 0, 0, size, size);
cairo_rectangle (context, size, size, size, size);
cairo_fill (context);
if (dark)
pika_cairo_set_source_rgb (context, dark);
else
cairo_set_source_rgb (context,
PIKA_CHECK_DARK, PIKA_CHECK_DARK, PIKA_CHECK_DARK);
cairo_rectangle (context, 0, size, size, size);
cairo_rectangle (context, size, 0, size, size);
cairo_fill (context);
cairo_destroy (context);
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
cairo_surface_destroy (surface);
return pattern;
}
/**
* pika_cairo_surface_get_format:
* @surface: a Cairo surface
*
* This function returns a #Babl format that corresponds to @surface's
* pixel format.
*
* Returns: the #Babl format of @surface.
*
* Since: 2.10
**/
const Babl *
pika_cairo_surface_get_format (cairo_surface_t *surface)
{
g_return_val_if_fail (surface != NULL, NULL);
g_return_val_if_fail (cairo_surface_get_type (surface) ==
CAIRO_SURFACE_TYPE_IMAGE, NULL);
switch (cairo_image_surface_get_format (surface))
{
case CAIRO_FORMAT_RGB24: return babl_format ("cairo-RGB24");
case CAIRO_FORMAT_ARGB32: return babl_format ("cairo-ARGB32");
case CAIRO_FORMAT_A8: return babl_format ("cairo-A8");
default:
break;
}
g_return_val_if_reached (NULL);
}
/**
* pika_cairo_surface_create_buffer:
* @surface: a Cairo surface
*
* This function returns a #GeglBuffer which wraps @surface's pixels.
* It must only be called on image surfaces, calling it on other surface
* types is an error.
*
* Returns: (transfer full): a #GeglBuffer
*
* Since: 2.10
**/
GeglBuffer *
pika_cairo_surface_create_buffer (cairo_surface_t *surface)
{
const Babl *format;
gint width;
gint height;
g_return_val_if_fail (surface != NULL, NULL);
g_return_val_if_fail (cairo_surface_get_type (surface) ==
CAIRO_SURFACE_TYPE_IMAGE, NULL);
format = pika_cairo_surface_get_format (surface);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
return
gegl_buffer_linear_new_from_data (cairo_image_surface_get_data (surface),
format,
GEGL_RECTANGLE (0, 0, width, height),
cairo_image_surface_get_stride (surface),
(GDestroyNotify) cairo_surface_destroy,
cairo_surface_reference (surface));
}

159
libpikacolor/pikacairo.h Normal file
View File

@ -0,0 +1,159 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacairo.h
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
* 2010-2012 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CAIRO_H__
#define __PIKA_CAIRO_H__
void pika_cairo_set_source_rgb (cairo_t *cr,
const PikaRGB *color);
void pika_cairo_set_source_rgba (cairo_t *cr,
const PikaRGB *color);
cairo_pattern_t * pika_cairo_checkerboard_create (cairo_t *cr,
gint size,
const PikaRGB *light,
const PikaRGB *dark);
const Babl * pika_cairo_surface_get_format (cairo_surface_t *surface);
GeglBuffer * pika_cairo_surface_create_buffer (cairo_surface_t *surface);
/* some useful macros for writing directly to a Cairo surface */
/**
* PIKA_CAIRO_RGB24_SET_PIXEL:
* @d: pointer to the destination buffer
* @r: red component
* @g: green component
* @b: blue component
*
* Sets a single pixel in an Cairo image surface in %CAIRO_FORMAT_RGB24.
*
* Since: 2.6
**/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define PIKA_CAIRO_RGB24_SET_PIXEL(d, r, g, b) \
G_STMT_START { d[0] = (b); d[1] = (g); d[2] = (r); } G_STMT_END
#else
#define PIKA_CAIRO_RGB24_SET_PIXEL(d, r, g, b) \
G_STMT_START { d[1] = (r); d[2] = (g); d[3] = (b); } G_STMT_END
#endif
/**
* PIKA_CAIRO_RGB24_GET_PIXEL:
* @s: pointer to the source buffer
* @r: red component
* @g: green component
* @b: blue component
*
* Gets a single pixel from a Cairo image surface in %CAIRO_FORMAT_RGB24.
*
* Since: 2.8
**/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define PIKA_CAIRO_RGB24_GET_PIXEL(s, r, g, b) \
G_STMT_START { (b) = s[0]; (g) = s[1]; (r) = s[2]; } G_STMT_END
#else
#define PIKA_CAIRO_RGB24_GET_PIXEL(s, r, g, b) \
G_STMT_START { (r) = s[1]; (g) = s[2]; (b) = s[3]; } G_STMT_END
#endif
/**
* PIKA_CAIRO_ARGB32_SET_PIXEL:
* @d: pointer to the destination buffer
* @r: red component, not pre-multiplied
* @g: green component, not pre-multiplied
* @b: blue component, not pre-multiplied
* @a: alpha component
*
* Sets a single pixel in an Cairo image surface in %CAIRO_FORMAT_ARGB32.
*
* Since: 2.6
**/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define PIKA_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
G_STMT_START { \
const guint tr = (a) * (r) + 0x80; \
const guint tg = (a) * (g) + 0x80; \
const guint tb = (a) * (b) + 0x80; \
(d)[0] = (((tb) >> 8) + (tb)) >> 8; \
(d)[1] = (((tg) >> 8) + (tg)) >> 8; \
(d)[2] = (((tr) >> 8) + (tr)) >> 8; \
(d)[3] = (a); \
} G_STMT_END
#else
#define PIKA_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
G_STMT_START { \
const guint tr = (a) * (r) + 0x80; \
const guint tg = (a) * (g) + 0x80; \
const guint tb = (a) * (b) + 0x80; \
(d)[0] = (a); \
(d)[1] = (((tr) >> 8) + (tr)) >> 8; \
(d)[2] = (((tg) >> 8) + (tg)) >> 8; \
(d)[3] = (((tb) >> 8) + (tb)) >> 8; \
} G_STMT_END
#endif
/**
* PIKA_CAIRO_ARGB32_GET_PIXEL:
* @s: pointer to the source buffer
* @r: red component, not pre-multiplied
* @g: green component, not pre-multiplied
* @b: blue component, not pre-multiplied
* @a: alpha component
*
* Gets a single pixel from a Cairo image surface in %CAIRO_FORMAT_ARGB32.
*
* Since: 2.8
**/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define PIKA_CAIRO_ARGB32_GET_PIXEL(s, r, g, b, a) \
G_STMT_START { \
const guint tb = (s)[0]; \
const guint tg = (s)[1]; \
const guint tr = (s)[2]; \
const guint ta = (s)[3]; \
(r) = (tr << 8) / (ta + 1); \
(g) = (tg << 8) / (ta + 1); \
(b) = (tb << 8) / (ta + 1); \
(a) = ta; \
} G_STMT_END
#else
#define PIKA_CAIRO_ARGB32_GET_PIXEL(s, r, g, b, a) \
G_STMT_START { \
const guint ta = (s)[0]; \
const guint tr = (s)[1]; \
const guint tg = (s)[2]; \
const guint tb = (s)[3]; \
(r) = (tr << 8) / (ta + 1); \
(g) = (tg << 8) / (ta + 1); \
(b) = (tb << 8) / (ta + 1); \
(a) = ta; \
} G_STMT_END
#endif
#endif /* __PIKA_CAIRO_H__ */

223
libpikacolor/pikacmyk.c Normal file
View File

@ -0,0 +1,223 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikacolortypes.h"
#include "pikacmyk.h"
/**
* SECTION: pikacmyk
* @title: PikaCMYK
* @short_description: Definitions and Functions relating to CMYK colors.
*
* Definitions and Functions relating to CMYK colors.
**/
/*
* PIKA_TYPE_CMYK
*/
static PikaCMYK * pika_cmyk_copy (const PikaCMYK *cmyk);
G_DEFINE_BOXED_TYPE (PikaCMYK, pika_cmyk, pika_cmyk_copy, g_free)
static PikaCMYK *
pika_cmyk_copy (const PikaCMYK *cmyk)
{
return g_memdup2 (cmyk, sizeof (PikaCMYK));
}
/* CMYK functions */
/**
* pika_cmyk_set:
* @cmyk: A #PikaCMYK structure which will hold the specified CMYK value.
* @cyan: The Cyan channel of the CMYK value
* @magenta: The Magenta channel
* @yellow: The Yellow channel
* @black: The blacK channel
*
* Very basic initialiser for the internal #PikaCMYK structure. Channel
* values are doubles in the range 0 to 1.
**/
void
pika_cmyk_set (PikaCMYK *cmyk,
gdouble cyan,
gdouble magenta,
gdouble yellow,
gdouble black)
{
g_return_if_fail (cmyk != NULL);
cmyk->c = cyan;
cmyk->m = magenta;
cmyk->y = yellow;
cmyk->k = black;
}
/**
* pika_cmyk_set_uchar:
* @cmyk: A #PikaCMYK structure which will hold the specified CMYK value.
* @cyan: The Cyan channel of the CMYK value
* @magenta: The Magenta channel
* @yellow: The Yellow channel
* @black: The blacK channel
*
* The same as pika_cmyk_set(), except that channel values are
* unsigned chars in the range 0 to 255.
**/
void
pika_cmyk_set_uchar (PikaCMYK *cmyk,
guchar cyan,
guchar magenta,
guchar yellow,
guchar black)
{
g_return_if_fail (cmyk != NULL);
cmyk->c = (gdouble) cyan / 255.0;
cmyk->m = (gdouble) magenta / 255.0;
cmyk->y = (gdouble) yellow / 255.0;
cmyk->k = (gdouble) black / 255.0;
}
/**
* pika_cmyk_get_uchar:
* @cmyk: A #PikaCMYK structure which will hold the specified CMYK value.
* @cyan: (out) (optional): The Cyan channel of the CMYK value
* @magenta: (out) (optional): The Magenta channel
* @yellow: (out) (optional): The Yellow channel
* @black: (out) (optional): The blacK channel
*
* Retrieve individual channel values from a #PikaCMYK structure. Channel
* values are pointers to unsigned chars in the range 0 to 255.
**/
void
pika_cmyk_get_uchar (const PikaCMYK *cmyk,
guchar *cyan,
guchar *magenta,
guchar *yellow,
guchar *black)
{
g_return_if_fail (cmyk != NULL);
if (cyan) *cyan = ROUND (CLAMP (cmyk->c, 0.0, 1.0) * 255.0);
if (magenta) *magenta = ROUND (CLAMP (cmyk->m, 0.0, 1.0) * 255.0);
if (yellow) *yellow = ROUND (CLAMP (cmyk->y, 0.0, 1.0) * 255.0);
if (black) *black = ROUND (CLAMP (cmyk->k, 0.0, 1.0) * 255.0);
}
/* CMYKA functions */
/**
* pika_cmyka_set:
* @cmyka: A #PikaCMYK structure which will hold the specified CMYKA value.
* @cyan: The Cyan channel of the CMYK value
* @magenta: The Magenta channel
* @yellow: The Yellow channel
* @black: The blacK channel
* @alpha: The Alpha channel
*
* Initialiser for the internal #PikaCMYK structure. Channel values are
* doubles in the range 0 to 1.
**/
void
pika_cmyka_set (PikaCMYK *cmyka,
gdouble cyan,
gdouble magenta,
gdouble yellow,
gdouble black,
gdouble alpha)
{
g_return_if_fail (cmyka != NULL);
cmyka->c = cyan;
cmyka->m = magenta;
cmyka->y = yellow;
cmyka->k = black;
cmyka->a = alpha;
}
/**
* pika_cmyka_set_uchar:
* @cmyka: A #PikaCMYK structure which will hold the specified CMYKA value.
* @cyan: The Cyan channel of the CMYK value
* @magenta: The Magenta channel
* @yellow: The Yellow channel
* @black: The blacK channel
* @alpha: The Alpha channel
*
* The same as pika_cmyka_set(), except that channel values are
* unsigned chars in the range 0 to 255.
**/
void
pika_cmyka_set_uchar (PikaCMYK *cmyka,
guchar cyan,
guchar magenta,
guchar yellow,
guchar black,
guchar alpha)
{
g_return_if_fail (cmyka != NULL);
cmyka->c = (gdouble) cyan / 255.0;
cmyka->m = (gdouble) magenta / 255.0;
cmyka->y = (gdouble) yellow / 255.0;
cmyka->k = (gdouble) black / 255.0;
cmyka->a = (gdouble) alpha / 255.0;
}
/**
* pika_cmyka_get_uchar:
* @cmyka: A #PikaCMYK structure which will hold the specified CMYKA value.
* @cyan: (out) (optional): The Cyan channel of the CMYK value
* @magenta: (out) (optional): The Magenta channel
* @yellow: (out) (optional): The Yellow channel
* @black: (out) (optional): The blacK channel
* @alpha: (out) (optional): The Alpha channel
*
* Retrieve individual channel values from a #PikaCMYK structure.
* Channel values are pointers to unsigned chars in the range 0 to 255.
**/
void
pika_cmyka_get_uchar (const PikaCMYK *cmyka,
guchar *cyan,
guchar *magenta,
guchar *yellow,
guchar *black,
guchar *alpha)
{
g_return_if_fail (cmyka != NULL);
if (cyan) *cyan = ROUND (CLAMP (cmyka->c, 0.0, 1.0) * 255.0);
if (magenta) *magenta = ROUND (CLAMP (cmyka->m, 0.0, 1.0) * 255.0);
if (yellow) *yellow = ROUND (CLAMP (cmyka->y, 0.0, 1.0) * 255.0);
if (black) *black = ROUND (CLAMP (cmyka->k, 0.0, 1.0) * 255.0);
if (alpha) *alpha = ROUND (CLAMP (cmyka->a, 0.0, 1.0) * 255.0);
}

78
libpikacolor/pikacmyk.h Normal file
View File

@ -0,0 +1,78 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_CMYK_H__
#define __PIKA_CMYK_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/*
* PIKA_TYPE_CMYK
*/
#define PIKA_TYPE_CMYK (pika_cmyk_get_type ())
GType pika_cmyk_get_type (void) G_GNUC_CONST;
void pika_cmyk_set (PikaCMYK *cmyk,
gdouble cyan,
gdouble magenta,
gdouble yellow,
gdouble black);
void pika_cmyk_set_uchar (PikaCMYK *cmyk,
guchar cyan,
guchar magenta,
guchar yellow,
guchar black);
void pika_cmyk_get_uchar (const PikaCMYK *cmyk,
guchar *cyan,
guchar *magenta,
guchar *yellow,
guchar *black);
void pika_cmyka_set (PikaCMYK *cmyka,
gdouble cyan,
gdouble magenta,
gdouble yellow,
gdouble black,
gdouble alpha);
void pika_cmyka_set_uchar (PikaCMYK *cmyka,
guchar cyan,
guchar magenta,
guchar yellow,
guchar black,
guchar alpha);
void pika_cmyka_get_uchar (const PikaCMYK *cmyka,
guchar *cyan,
guchar *magenta,
guchar *yellow,
guchar *black,
guchar *alpha);
G_END_DECLS
#endif /* __PIKA_CMYK_H__ */

119
libpikacolor/pikacolor.def Normal file
View File

@ -0,0 +1,119 @@
EXPORTS
pika_adaptive_supersample_area
pika_bilinear
pika_bilinear_16
pika_bilinear_32
pika_bilinear_8
pika_bilinear_rgb
pika_bilinear_rgba
pika_cairo_checkerboard_create
pika_cairo_set_source_rgb
pika_cairo_set_source_rgba
pika_cairo_surface_create_buffer
pika_cairo_surface_get_format
pika_cmyk_get_type
pika_cmyk_get_uchar
pika_cmyk_set
pika_cmyk_set_uchar
pika_cmyk_to_rgb
pika_cmyka_get_uchar
pika_cmyka_set
pika_cmyka_set_uchar
pika_color_managed_get_color_profile
pika_color_managed_get_icc_profile
pika_color_managed_get_simulation_bpc
pika_color_managed_get_simulation_intent
pika_color_managed_get_simulation_profile
pika_color_managed_get_type
pika_color_managed_profile_changed
pika_color_managed_simulation_bpc_changed
pika_color_managed_simulation_intent_changed
pika_color_managed_simulation_profile_changed
pika_color_profile_get_copyright
pika_color_profile_get_description
pika_color_profile_get_format
pika_color_profile_get_icc_profile
pika_color_profile_get_label
pika_color_profile_get_lcms_format
pika_color_profile_get_lcms_profile
pika_color_profile_get_manufacturer
pika_color_profile_get_model
pika_color_profile_get_space
pika_color_profile_get_summary
pika_color_profile_get_type
pika_color_profile_is_cmyk
pika_color_profile_is_equal
pika_color_profile_is_gray
pika_color_profile_is_linear
pika_color_profile_is_rgb
pika_color_profile_new_d50_gray_lab_trc
pika_color_profile_new_d65_gray_linear
pika_color_profile_new_d65_gray_srgb_trc
pika_color_profile_new_from_file
pika_color_profile_new_from_icc_profile
pika_color_profile_new_from_lcms_profile
pika_color_profile_new_linear_from_color_profile
pika_color_profile_new_rgb_adobe
pika_color_profile_new_rgb_srgb
pika_color_profile_new_rgb_srgb_linear
pika_color_profile_new_srgb_trc_from_color_profile
pika_color_profile_save_to_file
pika_color_transform_can_gegl_copy
pika_color_transform_get_type
pika_color_transform_new
pika_color_transform_new_proofing
pika_color_transform_process_buffer
pika_color_transform_process_pixels
pika_hsl_get_type
pika_hsl_set
pika_hsl_set_alpha
pika_hsl_to_rgb
pika_hsv_clamp
pika_hsv_get_type
pika_hsv_set
pika_hsv_to_rgb
pika_hsva_set
pika_param_rgb_get_type
pika_param_spec_rgb
pika_param_spec_rgb_get_default
pika_param_spec_rgb_has_alpha
pika_pixbuf_create_buffer
pika_pixbuf_get_format
pika_pixbuf_get_icc_profile
pika_rgb_add
pika_rgb_clamp
pika_rgb_composite
pika_rgb_distance
pika_rgb_gamma
pika_rgb_get_pixel
pika_rgb_get_type
pika_rgb_get_uchar
pika_rgb_list_names
pika_rgb_luminance
pika_rgb_luminance_uchar
pika_rgb_max
pika_rgb_min
pika_rgb_multiply
pika_rgb_parse_css
pika_rgb_parse_hex
pika_rgb_parse_name
pika_rgb_set
pika_rgb_set_alpha
pika_rgb_set_pixel
pika_rgb_set_uchar
pika_rgb_subtract
pika_rgb_to_cmyk
pika_rgb_to_hsl
pika_rgb_to_hsv
pika_rgba_add
pika_rgba_distance
pika_rgba_get_pixel
pika_rgba_get_uchar
pika_rgba_multiply
pika_rgba_parse_css
pika_rgba_set
pika_rgba_set_pixel
pika_rgba_set_uchar
pika_rgba_subtract
pika_value_get_rgb
pika_value_set_rgb

41
libpikacolor/pikacolor.h Normal file
View File

@ -0,0 +1,41 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_H__
#define __PIKA_COLOR_H__
#define __PIKA_COLOR_H_INSIDE__
#include <libpikacolor/pikacolortypes.h>
#include <libpikacolor/pikaadaptivesupersample.h>
#include <libpikacolor/pikabilinear.h>
#include <libpikacolor/pikacairo.h>
#include <libpikacolor/pikacolormanaged.h>
#include <libpikacolor/pikacolorprofile.h>
#include <libpikacolor/pikacolorspace.h>
#include <libpikacolor/pikacolortransform.h>
#include <libpikacolor/pikacmyk.h>
#include <libpikacolor/pikahsl.h>
#include <libpikacolor/pikahsv.h>
#include <libpikacolor/pikapixbuf.h>
#include <libpikacolor/pikargb.h>
#undef __PIKA_COLOR_H_INSIDE__
#endif /* __PIKA_COLOR_H__ */

View File

@ -0,0 +1,300 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* PikaColorManaged interface
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#include <gegl.h>
#include "pikacolortypes.h"
#include "pikacolormanaged.h"
#include "pikacolorprofile.h"
/**
* SECTION: pikacolormanaged
* @title: PikaColorManaged
* @short_description: An interface dealing with color profiles.
*
* An interface dealing with color profiles.
**/
enum
{
PROFILE_CHANGED,
SIMULATION_PROFILE_CHANGED,
SIMULATION_INTENT_CHANGED,
SIMULATION_BPC_CHANGED,
LAST_SIGNAL
};
G_DEFINE_INTERFACE (PikaColorManaged, pika_color_managed, G_TYPE_OBJECT)
static guint pika_color_managed_signals[LAST_SIGNAL] = { 0 };
/* private functions */
static void
pika_color_managed_default_init (PikaColorManagedInterface *iface)
{
pika_color_managed_signals[PROFILE_CHANGED] =
g_signal_new ("profile-changed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorManagedInterface,
profile_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
pika_color_managed_signals[SIMULATION_PROFILE_CHANGED] =
g_signal_new ("simulation-profile-changed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorManagedInterface,
simulation_profile_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
pika_color_managed_signals[SIMULATION_INTENT_CHANGED] =
g_signal_new ("simulation-intent-changed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorManagedInterface,
simulation_intent_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
pika_color_managed_signals[SIMULATION_BPC_CHANGED] =
g_signal_new ("simulation-bpc-changed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorManagedInterface,
simulation_bpc_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
/* public functions */
/**
* pika_color_managed_get_icc_profile:
* @managed: an object the implements the #PikaColorManaged interface
* @len: (out): return location for the number of bytes in the profile data
*
* Returns: (array length=len): A blob of data that represents an ICC color
* profile.
*
* Since: 2.4
*/
const guint8 *
pika_color_managed_get_icc_profile (PikaColorManaged *managed,
gsize *len)
{
PikaColorManagedInterface *iface;
g_return_val_if_fail (PIKA_IS_COLOR_MANAGED (managed), NULL);
g_return_val_if_fail (len != NULL, NULL);
*len = 0;
iface = PIKA_COLOR_MANAGED_GET_IFACE (managed);
if (iface->get_icc_profile)
return iface->get_icc_profile (managed, len);
return NULL;
}
/**
* pika_color_managed_get_color_profile:
* @managed: an object the implements the #PikaColorManaged interface
*
* This function always returns a #PikaColorProfile and falls back to
* pika_color_profile_new_rgb_srgb() if the method is not implemented.
*
* Returns: (transfer full): The @managed's #PikaColorProfile.
*
* Since: 2.10
**/
PikaColorProfile *
pika_color_managed_get_color_profile (PikaColorManaged *managed)
{
PikaColorManagedInterface *iface;
g_return_val_if_fail (PIKA_IS_COLOR_MANAGED (managed), NULL);
iface = PIKA_COLOR_MANAGED_GET_IFACE (managed);
if (iface->get_color_profile)
return iface->get_color_profile (managed);
return NULL;
}
/**
* pika_color_managed_get_simulation_profile:
* @managed: an object the implements the #PikaColorManaged interface
*
* This function always returns a #PikaColorProfile
*
* Returns: (transfer full): The @managed's simulation #PikaColorProfile.
*
* Since: 3.0
**/
PikaColorProfile *
pika_color_managed_get_simulation_profile (PikaColorManaged *managed)
{
PikaColorManagedInterface *iface;
g_return_val_if_fail (PIKA_IS_COLOR_MANAGED (managed), NULL);
iface = PIKA_COLOR_MANAGED_GET_IFACE (managed);
if (iface->get_simulation_profile)
return iface->get_simulation_profile (managed);
return NULL;
}
/**
* pika_color_managed_get_simulation_intent:
* @managed: an object the implements the #PikaColorManaged interface
*
* This function always returns a #PikaColorRenderingIntent
*
* Returns: The @managed's simulation #PikaColorRenderingIntent.
*
* Since: 3.0
**/
PikaColorRenderingIntent
pika_color_managed_get_simulation_intent (PikaColorManaged *managed)
{
PikaColorManagedInterface *iface;
g_return_val_if_fail (PIKA_IS_COLOR_MANAGED (managed),
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC);
iface = PIKA_COLOR_MANAGED_GET_IFACE (managed);
if (iface->get_simulation_intent)
return iface->get_simulation_intent (managed);
return PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC;
}
/**
* pika_color_managed_get_simulation_bpc:
* @managed: an object the implements the #PikaColorManaged interface
*
* This function always returns a gboolean representing whether
* Black Point Compensation is enabled
*
* Returns: The @managed's simulation Black Point Compensation value.
*
* Since: 3.0
**/
gboolean
pika_color_managed_get_simulation_bpc (PikaColorManaged *managed)
{
PikaColorManagedInterface *iface;
g_return_val_if_fail (PIKA_IS_COLOR_MANAGED (managed), FALSE);
iface = PIKA_COLOR_MANAGED_GET_IFACE (managed);
if (iface->get_simulation_bpc)
return iface->get_simulation_bpc (managed);
return FALSE;
}
/**
* pika_color_managed_profile_changed:
* @managed: an object that implements the #PikaColorManaged interface
*
* Emits the "profile-changed" signal.
*
* Since: 2.4
**/
void
pika_color_managed_profile_changed (PikaColorManaged *managed)
{
g_return_if_fail (PIKA_IS_COLOR_MANAGED (managed));
g_signal_emit (managed, pika_color_managed_signals[PROFILE_CHANGED], 0);
}
/**
* pika_color_managed_simulation_profile_changed:
* @managed: an object that implements the #PikaColorManaged interface
*
* Emits the "simulation-profile-changed" signal.
*
* Since: 3.0
**/
void
pika_color_managed_simulation_profile_changed (PikaColorManaged *managed)
{
g_return_if_fail (PIKA_IS_COLOR_MANAGED (managed));
g_signal_emit (managed, pika_color_managed_signals[SIMULATION_PROFILE_CHANGED], 0);
}
/**
* pika_color_managed_simulation_intent_changed:
* @managed: an object that implements the #PikaColorManaged interface
*
* Emits the "simulation-intent-changed" signal.
*
* Since: 3.0
**/
void
pika_color_managed_simulation_intent_changed (PikaColorManaged *managed)
{
g_return_if_fail (PIKA_IS_COLOR_MANAGED (managed));
g_signal_emit (managed, pika_color_managed_signals[SIMULATION_INTENT_CHANGED], 0);
}
/**
* pika_color_managed_simulation_bpc_changed:
* @managed: an object that implements the #PikaColorManaged interface
*
* Emits the "simulation-bpc-changed" signal.
*
* Since: 3.0
**/
void
pika_color_managed_simulation_bpc_changed (PikaColorManaged *managed)
{
g_return_if_fail (PIKA_IS_COLOR_MANAGED (managed));
g_signal_emit (managed, pika_color_managed_signals[SIMULATION_BPC_CHANGED], 0);
}

View File

@ -0,0 +1,109 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* PikaColorManaged interface
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_MANAGED_H__
#define __PIKA_COLOR_MANAGED_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_COLOR_MANAGED (pika_color_managed_get_type ())
G_DECLARE_INTERFACE (PikaColorManaged, pika_color_managed, PIKA, COLOR_MANAGED, GObject)
/**
* PikaColorManagedInterface:
* @base_iface: The parent interface
* @get_icc_profile: Returns the ICC profile of the pixels managed by
* the object
* @profile_changed: This signal is emitted when the object's color profile
* has changed
* @get_color_profile: Returns the #PikaColorProfile of the pixels managed
* by the object
* @get_simulation_profile: Returns the simulation #PikaColorProfile of the
* pixels managed by the object
* @get_simulation_rendering_intent: Returns the simulation #PikaColorRenderingIntent
* of the pixels managed by the object
* @get_simulation_bpc: Returns whether black point compensation is enabled for the
* simulation of the pixels managed by the object
**/
struct _PikaColorManagedInterface
{
GTypeInterface base_iface;
/**
* PikaColorManagedInterface::get_icc_profile:
* @managed: an object the implements the #PikaColorManaged interface
* @len: (out): return location for the number of bytes in the profile data
*
* Returns: (array length=len): A blob of data that represents an ICC color
* profile.
*
* Since: 2.4
*/
const guint8 * (* get_icc_profile) (PikaColorManaged *managed,
gsize *len);
/* signals */
void (* profile_changed) (PikaColorManaged *managed);
void (* simulation_profile_changed) (PikaColorManaged *managed);
void (* simulation_intent_changed) (PikaColorManaged *managed);
void (* simulation_bpc_changed) (PikaColorManaged *managed);
/* virtual functions */
PikaColorProfile * (* get_color_profile) (PikaColorManaged *managed);
PikaColorProfile * (* get_simulation_profile) (PikaColorManaged *managed);
PikaColorRenderingIntent
(* get_simulation_intent) (PikaColorManaged *managed);
gboolean (* get_simulation_bpc) (PikaColorManaged *managed);
};
const guint8 * pika_color_managed_get_icc_profile (PikaColorManaged *managed,
gsize *len);
PikaColorProfile * pika_color_managed_get_color_profile (PikaColorManaged *managed);
PikaColorProfile * pika_color_managed_get_simulation_profile (PikaColorManaged *managed);
PikaColorRenderingIntent pika_color_managed_get_simulation_intent (PikaColorManaged *managed);
gboolean pika_color_managed_get_simulation_bpc (PikaColorManaged *managed);
void pika_color_managed_profile_changed (PikaColorManaged *managed);
void pika_color_managed_simulation_profile_changed (PikaColorManaged *managed);
void pika_color_managed_simulation_intent_changed (PikaColorManaged *managed);
void pika_color_managed_simulation_bpc_changed (PikaColorManaged *managed);
G_END_DECLS
#endif /* __PIKA_COLOR_MANAGED_IFACE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikacolorprofile.h
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
* Elle Stone <ellestone@ninedegreesbelow.com>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_PROFILE_H__
#define __PIKA_COLOR_PROFILE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_COLOR_PROFILE (pika_color_profile_get_type ())
#define PIKA_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PROFILE, PikaColorProfile))
#define PIKA_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PROFILE, PikaColorProfileClass))
#define PIKA_IS_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PROFILE))
#define PIKA_IS_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PROFILE))
#define PIKA_COLOR_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PROFILE, PikaColorProfileClass))
typedef struct _PikaColorProfilePrivate PikaColorProfilePrivate;
typedef struct _PikaColorProfileClass PikaColorProfileClass;
struct _PikaColorProfile
{
GObject parent_instance;
PikaColorProfilePrivate *priv;
};
struct _PikaColorProfileClass
{
GObjectClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_profile_get_type (void) G_GNUC_CONST;
PikaColorProfile * pika_color_profile_new_rgb_srgb (void);
PikaColorProfile * pika_color_profile_new_rgb_srgb_linear (void);
PikaColorProfile * pika_color_profile_new_rgb_adobe (void);
PikaColorProfile * pika_color_profile_new_d65_gray_srgb_trc (void);
PikaColorProfile * pika_color_profile_new_d65_gray_linear (void);
PikaColorProfile * pika_color_profile_new_d50_gray_lab_trc (void);
PikaColorProfile *
pika_color_profile_new_srgb_trc_from_color_profile (PikaColorProfile *profile);
PikaColorProfile *
pika_color_profile_new_linear_from_color_profile (PikaColorProfile *profile);
PikaColorProfile * pika_color_profile_new_from_file (GFile *file,
GError **error);
PikaColorProfile * pika_color_profile_new_from_icc_profile (const guint8 *data,
gsize length,
GError **error);
PikaColorProfile * pika_color_profile_new_from_lcms_profile (gpointer lcms_profile,
GError **error);
gboolean pika_color_profile_save_to_file (PikaColorProfile *profile,
GFile *file,
GError **error);
const guint8 * pika_color_profile_get_icc_profile (PikaColorProfile *profile,
gsize *length);
gpointer pika_color_profile_get_lcms_profile (PikaColorProfile *profile);
const gchar * pika_color_profile_get_description (PikaColorProfile *profile);
const gchar * pika_color_profile_get_manufacturer (PikaColorProfile *profile);
const gchar * pika_color_profile_get_model (PikaColorProfile *profile);
const gchar * pika_color_profile_get_copyright (PikaColorProfile *profile);
const gchar * pika_color_profile_get_label (PikaColorProfile *profile);
const gchar * pika_color_profile_get_summary (PikaColorProfile *profile);
gboolean pika_color_profile_is_equal (PikaColorProfile *profile1,
PikaColorProfile *profile2);
gboolean pika_color_profile_is_rgb (PikaColorProfile *profile);
gboolean pika_color_profile_is_gray (PikaColorProfile *profile);
gboolean pika_color_profile_is_cmyk (PikaColorProfile *profile);
gboolean pika_color_profile_is_linear (PikaColorProfile *profile);
const Babl * pika_color_profile_get_space (PikaColorProfile *profile,
PikaColorRenderingIntent intent,
GError **error);
const Babl * pika_color_profile_get_format (PikaColorProfile *profile,
const Babl *format,
PikaColorRenderingIntent intent,
GError **error);
const Babl * pika_color_profile_get_lcms_format (const Babl *format,
guint32 *lcms_format);
G_END_DECLS
#endif /* __PIKA_COLOR_PROFILE_H__ */

View File

@ -0,0 +1,401 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <babl/babl.h>
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikacolortypes.h"
#include "pikacolorspace.h"
#include "pikargb.h"
#include "pikahsv.h"
/**
* SECTION: pikacolorspace
* @title: PikaColorSpace
* @short_description: Utility functions which convert colors between
* different color models.
*
* When programming pixel data manipulation functions you will often
* use algorithms operating on a color model different from the one
* PIKA uses. This file provides utility functions to convert colors
* between different color spaces.
**/
#define PIKA_HSL_UNDEFINED -1.0
/* PikaRGB functions */
/**
* pika_rgb_to_hsv:
* @rgb: A color value in the RGB colorspace
* @hsv: (out caller-allocates): The value converted to the HSV colorspace
*
* Does a conversion from RGB to HSV (Hue, Saturation,
* Value) colorspace.
**/
void
pika_rgb_to_hsv (const PikaRGB *rgb,
PikaHSV *hsv)
{
gdouble max, min, delta;
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsv != NULL);
max = pika_rgb_max (rgb);
min = pika_rgb_min (rgb);
hsv->v = max;
delta = max - min;
if (delta > 0.0001)
{
hsv->s = delta / max;
if (rgb->r == max)
{
hsv->h = (rgb->g - rgb->b) / delta;
if (hsv->h < 0.0)
hsv->h += 6.0;
}
else if (rgb->g == max)
{
hsv->h = 2.0 + (rgb->b - rgb->r) / delta;
}
else
{
hsv->h = 4.0 + (rgb->r - rgb->g) / delta;
}
hsv->h /= 6.0;
}
else
{
hsv->s = 0.0;
hsv->h = 0.0;
}
hsv->a = rgb->a;
}
/**
* pika_hsv_to_rgb:
* @hsv: A color value in the HSV colorspace
* @rgb: (out caller-allocates): The returned RGB value.
*
* Converts a color value from HSV to RGB colorspace
**/
void
pika_hsv_to_rgb (const PikaHSV *hsv,
PikaRGB *rgb)
{
gint i;
gdouble f, w, q, t;
gdouble hue;
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsv != NULL);
if (hsv->s == 0.0)
{
rgb->r = hsv->v;
rgb->g = hsv->v;
rgb->b = hsv->v;
}
else
{
hue = hsv->h;
if (hue == 1.0)
hue = 0.0;
hue *= 6.0;
i = (gint) hue;
f = hue - i;
w = hsv->v * (1.0 - hsv->s);
q = hsv->v * (1.0 - (hsv->s * f));
t = hsv->v * (1.0 - (hsv->s * (1.0 - f)));
switch (i)
{
case 0:
rgb->r = hsv->v;
rgb->g = t;
rgb->b = w;
break;
case 1:
rgb->r = q;
rgb->g = hsv->v;
rgb->b = w;
break;
case 2:
rgb->r = w;
rgb->g = hsv->v;
rgb->b = t;
break;
case 3:
rgb->r = w;
rgb->g = q;
rgb->b = hsv->v;
break;
case 4:
rgb->r = t;
rgb->g = w;
rgb->b = hsv->v;
break;
case 5:
rgb->r = hsv->v;
rgb->g = w;
rgb->b = q;
break;
}
}
rgb->a = hsv->a;
}
/**
* pika_rgb_to_hsl:
* @rgb: A color value in the RGB colorspace
* @hsl: (out caller-allocates): The value converted to HSL
*
* Convert an RGB color value to a HSL (Hue, Saturation, Lightness)
* color value.
**/
void
pika_rgb_to_hsl (const PikaRGB *rgb,
PikaHSL *hsl)
{
gdouble max, min, delta;
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsl != NULL);
max = pika_rgb_max (rgb);
min = pika_rgb_min (rgb);
hsl->l = (max + min) / 2.0;
if (max == min)
{
hsl->s = 0.0;
hsl->h = PIKA_HSL_UNDEFINED;
}
else
{
if (hsl->l <= 0.5)
hsl->s = (max - min) / (max + min);
else
hsl->s = (max - min) / (2.0 - max - min);
delta = max - min;
if (delta == 0.0)
delta = 1.0;
if (rgb->r == max)
{
hsl->h = (rgb->g - rgb->b) / delta;
}
else if (rgb->g == max)
{
hsl->h = 2.0 + (rgb->b - rgb->r) / delta;
}
else
{
hsl->h = 4.0 + (rgb->r - rgb->g) / delta;
}
hsl->h /= 6.0;
if (hsl->h < 0.0)
hsl->h += 1.0;
}
hsl->a = rgb->a;
}
static inline gdouble
pika_hsl_value (gdouble n1,
gdouble n2,
gdouble hue)
{
gdouble val;
if (hue > 6.0)
hue -= 6.0;
else if (hue < 0.0)
hue += 6.0;
if (hue < 1.0)
val = n1 + (n2 - n1) * hue;
else if (hue < 3.0)
val = n2;
else if (hue < 4.0)
val = n1 + (n2 - n1) * (4.0 - hue);
else
val = n1;
return val;
}
/**
* pika_hsl_to_rgb:
* @hsl: A color value in the HSL colorspace
* @rgb: (out caller-allocates): The value converted to a value
* in the RGB colorspace
*
* Convert a HSL color value to an RGB color value.
**/
void
pika_hsl_to_rgb (const PikaHSL *hsl,
PikaRGB *rgb)
{
g_return_if_fail (hsl != NULL);
g_return_if_fail (rgb != NULL);
if (hsl->s == 0)
{
/* achromatic case */
rgb->r = hsl->l;
rgb->g = hsl->l;
rgb->b = hsl->l;
}
else
{
gdouble m1, m2;
if (hsl->l <= 0.5)
m2 = hsl->l * (1.0 + hsl->s);
else
m2 = hsl->l + hsl->s - hsl->l * hsl->s;
m1 = 2.0 * hsl->l - m2;
rgb->r = pika_hsl_value (m1, m2, hsl->h * 6.0 + 2.0);
rgb->g = pika_hsl_value (m1, m2, hsl->h * 6.0);
rgb->b = pika_hsl_value (m1, m2, hsl->h * 6.0 - 2.0);
}
rgb->a = hsl->a;
}
/**
* pika_rgb_to_cmyk:
* @rgb: A value in the RGB colorspace
* @pullout: A scaling value (0-1) indicating how much black should be
* pulled out
* @cmyk: (out caller-allocates): The input value naively converted
* to the CMYK colorspace
*
* Does a naive conversion from RGB to CMYK colorspace. A simple
* formula that doesn't take any color-profiles into account is used.
* The amount of black pullout how can be controlled via the @pullout
* parameter. A @pullout value of 0 makes this a conversion to CMY.
* A value of 1 causes the maximum amount of black to be pulled out.
**/
void
pika_rgb_to_cmyk (const PikaRGB *rgb,
gdouble pullout,
PikaCMYK *cmyk)
{
gdouble c, m, y, k;
g_return_if_fail (rgb != NULL);
g_return_if_fail (cmyk != NULL);
c = 1.0 - rgb->r;
m = 1.0 - rgb->g;
y = 1.0 - rgb->b;
k = 1.0;
if (c < k) k = c;
if (m < k) k = m;
if (y < k) k = y;
k *= pullout;
if (k < 1.0)
{
cmyk->c = (c - k) / (1.0 - k);
cmyk->m = (m - k) / (1.0 - k);
cmyk->y = (y - k) / (1.0 - k);
}
else
{
cmyk->c = 0.0;
cmyk->m = 0.0;
cmyk->y = 0.0;
}
cmyk->k = k;
cmyk->a = rgb->a;
}
/**
* pika_cmyk_to_rgb:
* @cmyk: A color value in the CMYK colorspace
* @rgb: (out caller-allocates): The value converted to the RGB colorspace
*
* Does a simple transformation from the CMYK colorspace to the RGB
* colorspace, without taking color profiles into account.
**/
void
pika_cmyk_to_rgb (const PikaCMYK *cmyk,
PikaRGB *rgb)
{
gdouble c, m, y, k;
g_return_if_fail (cmyk != NULL);
g_return_if_fail (rgb != NULL);
k = cmyk->k;
if (k < 1.0)
{
c = cmyk->c * (1.0 - k) + k;
m = cmyk->m * (1.0 - k) + k;
y = cmyk->y * (1.0 - k) + k;
}
else
{
c = 1.0;
m = 1.0;
y = 1.0;
}
rgb->r = 1.0 - c;
rgb->g = 1.0 - m;
rgb->b = 1.0 - y;
rgb->a = cmyk->a;
}

View File

@ -0,0 +1,53 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SPACE_H__
#define __PIKA_COLOR_SPACE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/* Color conversion routines */
/* PikaRGB function */
void pika_rgb_to_hsv (const PikaRGB *rgb,
PikaHSV *hsv);
void pika_rgb_to_hsl (const PikaRGB *rgb,
PikaHSL *hsl);
void pika_rgb_to_cmyk (const PikaRGB *rgb,
gdouble pullout,
PikaCMYK *cmyk);
void pika_hsv_to_rgb (const PikaHSV *hsv,
PikaRGB *rgb);
void pika_hsl_to_rgb (const PikaHSL *hsl,
PikaRGB *rgb);
void pika_cmyk_to_rgb (const PikaCMYK *cmyk,
PikaRGB *rgb);
G_END_DECLS
#endif /* __PIKA_COLOR_SPACE_H__ */

View File

@ -0,0 +1,642 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikacolortransform.c
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
* Elle Stone <ellestone@ninedegreesbelow.com>
* Øyvind Kolås <pippin@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <lcms2.h>
#include <gio/gio.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikacolortypes.h"
#include "pikacolorprofile.h"
#include "pikacolortransform.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolortransform
* @title: PikaColorTransform
* @short_description: Definitions and Functions relating to LCMS.
*
* Definitions and Functions relating to LCMS.
**/
/**
* PikaColorTransform:
*
* Simply a typedef to #gpointer, but actually is a cmsHTRANSFORM. It's
* used in public PIKA APIs in order to avoid having to include LCMS
* headers.
**/
enum
{
PROGRESS,
LAST_SIGNAL
};
struct _PikaColorTransformPrivate
{
PikaColorProfile *src_profile;
const Babl *src_format;
PikaColorProfile *dest_profile;
const Babl *dest_format;
cmsHTRANSFORM transform;
const Babl *fish;
};
static void pika_color_transform_finalize (GObject *object);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorTransform, pika_color_transform,
G_TYPE_OBJECT)
#define parent_class pika_color_transform_parent_class
static guint pika_color_transform_signals[LAST_SIGNAL] = { 0 };
static gchar *lcms_last_error = NULL;
static void
lcms_error_clear (void)
{
if (lcms_last_error)
{
g_free (lcms_last_error);
lcms_last_error = NULL;
}
}
static void
lcms_error_handler (cmsContext ContextID,
cmsUInt32Number ErrorCode,
const gchar *text)
{
lcms_error_clear ();
lcms_last_error = g_strdup_printf ("lcms2 error %d: %s", ErrorCode, text);
}
static void
pika_color_transform_class_init (PikaColorTransformClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_color_transform_finalize;
pika_color_transform_signals[PROGRESS] =
g_signal_new ("progress",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorTransformClass,
progress),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_DOUBLE);
cmsSetLogErrorHandler (lcms_error_handler);
}
static void
pika_color_transform_init (PikaColorTransform *transform)
{
transform->priv = pika_color_transform_get_instance_private (transform);
}
static void
pika_color_transform_finalize (GObject *object)
{
PikaColorTransform *transform = PIKA_COLOR_TRANSFORM (object);
g_clear_object (&transform->priv->src_profile);
g_clear_object (&transform->priv->dest_profile);
g_clear_pointer (&transform->priv->transform, cmsDeleteTransform);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* pika_color_transform_new:
* @src_profile: the source #PikaColorProfile
* @src_format: the source #Babl format
* @dest_profile: the destination #PikaColorProfile
* @dest_format: the destination #Babl format
* @rendering_intent: the rendering intent
* @flags: transform flags
*
* This function creates an color transform.
*
* The color transform is determined exclusively by @src_profile and
* @dest_profile. The color spaces of @src_format and @dest_format are
* ignored, the formats are only used to decide between what pixel
* encodings to transform.
*
* Note: this function used to return %NULL if
* pika_color_transform_can_gegl_copy() returned %TRUE for
* @src_profile and @dest_profile. This is no longer the case because
* special care has to be taken not to perform multiple implicit color
* transforms caused by babl formats with color spaces. Now, it always
* returns a non-%NULL transform and the code takes care of doing only
* exactly the requested color transform.
*
* Returns: (nullable): the #PikaColorTransform, or %NULL if there was an error.
*
* Since: 2.10
**/
PikaColorTransform *
pika_color_transform_new (PikaColorProfile *src_profile,
const Babl *src_format,
PikaColorProfile *dest_profile,
const Babl *dest_format,
PikaColorRenderingIntent rendering_intent,
PikaColorTransformFlags flags)
{
PikaColorTransform *transform;
PikaColorTransformPrivate *priv;
cmsHPROFILE src_lcms;
cmsHPROFILE dest_lcms;
cmsUInt32Number lcms_src_format;
cmsUInt32Number lcms_dest_format;
GError *error = NULL;
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (src_profile), NULL);
g_return_val_if_fail (src_format != NULL, NULL);
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (dest_profile), NULL);
g_return_val_if_fail (dest_format != NULL, NULL);
transform = g_object_new (PIKA_TYPE_COLOR_TRANSFORM, NULL);
priv = transform->priv;
/* only src_profile and dest_profile must determine the transform's
* color spaces, create formats with src_format's and dest_format's
* encoding, and the profiles' color spaces; see process_pixels()
* and process_buffer().
*/
priv->src_format = pika_color_profile_get_format (src_profile,
src_format,
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
&error);
if (! priv->src_format)
{
g_printerr ("%s: error making src format: %s\n",
G_STRFUNC, error->message);
g_clear_error (&error);
}
priv->dest_format = pika_color_profile_get_format (dest_profile,
dest_format,
rendering_intent,
&error);
if (! priv->dest_format)
{
g_printerr ("%s: error making dest format: %s\n",
G_STRFUNC, error->message);
g_clear_error (&error);
}
if (! g_getenv ("PIKA_COLOR_TRANSFORM_DISABLE_BABL") &&
priv->src_format && priv->dest_format)
{
priv->fish = babl_fish (priv->src_format,
priv->dest_format);
g_debug ("%s: using babl for '%s' -> '%s'",
G_STRFUNC,
pika_color_profile_get_label (src_profile),
pika_color_profile_get_label (dest_profile));
return transform;
}
/* see above: when using lcms, don't mess with formats with color
* spaces, pika_color_profile_get_lcms_format() might return the
* same format and it must be without space
*/
src_format = babl_format_with_space ((const gchar *) src_format, NULL);
dest_format = babl_format_with_space ((const gchar *) dest_format, NULL);
priv->src_format = pika_color_profile_get_lcms_format (src_format,
&lcms_src_format);
priv->dest_format = pika_color_profile_get_lcms_format (dest_format,
&lcms_dest_format);
src_lcms = pika_color_profile_get_lcms_profile (src_profile);
dest_lcms = pika_color_profile_get_lcms_profile (dest_profile);
lcms_error_clear ();
priv->transform = cmsCreateTransform (src_lcms, lcms_src_format,
dest_lcms, lcms_dest_format,
rendering_intent,
flags |
cmsFLAGS_COPY_ALPHA);
if (lcms_last_error)
{
if (priv->transform)
{
cmsDeleteTransform (priv->transform);
priv->transform = NULL;
}
g_printerr ("%s: %s\n", G_STRFUNC, lcms_last_error);
}
if (! priv->transform)
{
g_object_unref (transform);
transform = NULL;
}
return transform;
}
/**
* pika_color_transform_new_proofing:
* @src_profile: the source #PikaColorProfile
* @src_format: the source #Babl format
* @dest_profile: the destination #PikaColorProfile
* @dest_format: the destination #Babl format
* @proof_profile: the proof #PikaColorProfile
* @proof_intent: the proof intent
* @display_intent: the display intent
* @flags: transform flags
*
* This function creates a simulation / proofing color transform.
*
* See pika_color_transform_new() about the color spaces to transform
* between.
*
* Returns: (nullable): the #PikaColorTransform, or %NULL if there was an error.
*
* Since: 2.10
**/
PikaColorTransform *
pika_color_transform_new_proofing (PikaColorProfile *src_profile,
const Babl *src_format,
PikaColorProfile *dest_profile,
const Babl *dest_format,
PikaColorProfile *proof_profile,
PikaColorRenderingIntent proof_intent,
PikaColorRenderingIntent display_intent,
PikaColorTransformFlags flags)
{
PikaColorTransform *transform;
PikaColorTransformPrivate *priv;
cmsHPROFILE src_lcms;
cmsHPROFILE dest_lcms;
cmsHPROFILE proof_lcms;
cmsUInt32Number lcms_src_format;
cmsUInt32Number lcms_dest_format;
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (src_profile), NULL);
g_return_val_if_fail (src_format != NULL, NULL);
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (dest_profile), NULL);
g_return_val_if_fail (dest_format != NULL, NULL);
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (proof_profile), NULL);
transform = g_object_new (PIKA_TYPE_COLOR_TRANSFORM, NULL);
priv = transform->priv;
src_lcms = pika_color_profile_get_lcms_profile (src_profile);
dest_lcms = pika_color_profile_get_lcms_profile (dest_profile);
proof_lcms = pika_color_profile_get_lcms_profile (proof_profile);
/* see pika_color_transform_new(), we can't have color spaces
* on the formats
*/
src_format = babl_format_with_space ((const gchar *) src_format, NULL);
dest_format = babl_format_with_space ((const gchar *) dest_format, NULL);
priv->src_format = pika_color_profile_get_lcms_format (src_format,
&lcms_src_format);
priv->dest_format = pika_color_profile_get_lcms_format (dest_format,
&lcms_dest_format);
lcms_error_clear ();
priv->transform = cmsCreateProofingTransform (src_lcms, lcms_src_format,
dest_lcms, lcms_dest_format,
proof_lcms,
display_intent,
proof_intent,
flags |
cmsFLAGS_SOFTPROOFING |
cmsFLAGS_COPY_ALPHA);
if (lcms_last_error)
{
if (priv->transform)
{
cmsDeleteTransform (priv->transform);
priv->transform = NULL;
}
g_printerr ("%s: %s\n", G_STRFUNC, lcms_last_error);
}
if (! priv->transform)
{
g_object_unref (transform);
transform = NULL;
}
return transform;
}
/**
* pika_color_transform_process_pixels:
* @transform: a #PikaColorTransform
* @src_format: #Babl format of @src_pixels
* @src_pixels: pointer to the source pixels
* @dest_format: #Babl format of @dest_pixels
* @dest_pixels: pointer to the destination pixels
* @length: number of pixels to process
*
* This function transforms a contiguous line of pixels.
*
* See pika_color_transform_new(): only the pixel encoding of
* @src_format and @dest_format is honored, their color spaces are
* ignored. The transform always takes place between the color spaces
* determined by @transform's color profiles.
*
* Since: 2.10
**/
void
pika_color_transform_process_pixels (PikaColorTransform *transform,
const Babl *src_format,
gconstpointer src_pixels,
const Babl *dest_format,
gpointer dest_pixels,
gsize length)
{
PikaColorTransformPrivate *priv;
gpointer *src;
gpointer *dest;
g_return_if_fail (PIKA_IS_COLOR_TRANSFORM (transform));
g_return_if_fail (src_format != NULL);
g_return_if_fail (src_pixels != NULL);
g_return_if_fail (dest_format != NULL);
g_return_if_fail (dest_pixels != NULL);
priv = transform->priv;
/* we must not do any babl color transforms when reading from
* src_pixels or writing to dest_pixels, so construct formats with
* src_format's and dest_format's encoding, and the transform's
* input and output color spaces.
*/
src_format =
babl_format_with_space ((const gchar *) src_format,
babl_format_get_space (priv->src_format));
dest_format =
babl_format_with_space ((const gchar *) dest_format,
babl_format_get_space (priv->dest_format));
if (src_format != priv->src_format)
{
src = g_malloc (length * babl_format_get_bytes_per_pixel (priv->src_format));
babl_process (babl_fish (src_format,
priv->src_format),
src_pixels, src, length);
}
else
{
src = (gpointer) src_pixels;
}
if (dest_format != priv->dest_format)
{
dest = g_malloc (length * babl_format_get_bytes_per_pixel (priv->dest_format));
}
else
{
dest = dest_pixels;
}
if (priv->transform)
{
cmsDoTransform (priv->transform, src, dest, length);
}
else
{
babl_process (priv->fish, src, dest, length);
}
if (src_format != priv->src_format)
{
g_free (src);
}
if (dest_format != priv->dest_format)
{
babl_process (babl_fish (priv->dest_format,
dest_format),
dest, dest_pixels, length);
g_free (dest);
}
}
/**
* pika_color_transform_process_buffer:
* @transform: a #PikaColorTransform
* @src_buffer: source #GeglBuffer
* @src_rect: rectangle in @src_buffer
* @dest_buffer: destination #GeglBuffer
* @dest_rect: rectangle in @dest_buffer
*
* This function transforms buffer into another buffer.
*
* See pika_color_transform_new(): only the pixel encoding of
* @src_buffer's and @dest_buffer's formats honored, their color
* spaces are ignored. The transform always takes place between the
* color spaces determined by @transform's color profiles.
*
* Since: 2.10
**/
void
pika_color_transform_process_buffer (PikaColorTransform *transform,
GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect)
{
PikaColorTransformPrivate *priv;
const Babl *src_format;
const Babl *dest_format;
GeglBufferIterator *iter;
gint total_pixels;
gint done_pixels = 0;
g_return_if_fail (PIKA_IS_COLOR_TRANSFORM (transform));
g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
priv = transform->priv;
if (src_rect)
{
total_pixels = src_rect->width * src_rect->height;
}
else
{
total_pixels = (gegl_buffer_get_width (src_buffer) *
gegl_buffer_get_height (src_buffer));
}
/* we must not do any babl color transforms when reading from
* src_buffer or writing to dest_buffer, so construct formats with
* the transform's expected input and output encoding and
* src_buffer's and dest_buffers's color spaces.
*/
src_format = gegl_buffer_get_format (src_buffer);
dest_format = gegl_buffer_get_format (dest_buffer);
src_format =
babl_format_with_space ((const gchar *) priv->src_format,
babl_format_get_space (src_format));
dest_format =
babl_format_with_space ((const gchar *) priv->dest_format,
babl_format_get_space (dest_format));
if (src_buffer != dest_buffer)
{
iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
src_format,
GEGL_ACCESS_READ,
GEGL_ABYSS_NONE, 2);
gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
dest_format,
GEGL_ACCESS_WRITE,
GEGL_ABYSS_NONE);
while (gegl_buffer_iterator_next (iter))
{
if (priv->transform)
{
cmsDoTransform (priv->transform,
iter->items[0].data, iter->items[1].data, iter->length);
}
else
{
babl_process (priv->fish,
iter->items[0].data, iter->items[1].data, iter->length);
}
done_pixels += iter->items[0].roi.width * iter->items[0].roi.height;
g_signal_emit (transform, pika_color_transform_signals[PROGRESS], 0,
(gdouble) done_pixels /
(gdouble) total_pixels);
}
}
else
{
iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
src_format,
GEGL_ACCESS_READWRITE,
GEGL_ABYSS_NONE, 1);
while (gegl_buffer_iterator_next (iter))
{
if (priv->transform)
{
cmsDoTransform (priv->transform,
iter->items[0].data, iter->items[0].data, iter->length);
}
else
{
babl_process (priv->fish,
iter->items[0].data, iter->items[0].data, iter->length);
}
done_pixels += iter->items[0].roi.width * iter->items[0].roi.height;
g_signal_emit (transform, pika_color_transform_signals[PROGRESS], 0,
(gdouble) done_pixels /
(gdouble) total_pixels);
}
}
g_signal_emit (transform, pika_color_transform_signals[PROGRESS], 0,
1.0);
}
/**
* pika_color_transform_can_gegl_copy:
* @src_profile: source #PikaColorProfile
* @dest_profile: destination #PikaColorProfile
*
* This function checks if a PikaColorTransform is needed at all.
*
* Returns: %TRUE if pixels can be correctly converted between
* @src_profile and @dest_profile by simply using
* gegl_buffer_copy(), babl_process() or similar.
*
* Since: 2.10
**/
gboolean
pika_color_transform_can_gegl_copy (PikaColorProfile *src_profile,
PikaColorProfile *dest_profile)
{
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (src_profile), FALSE);
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE (dest_profile), FALSE);
if (pika_color_profile_is_equal (src_profile, dest_profile))
return TRUE;
if (pika_color_profile_get_space (src_profile,
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
NULL) &&
pika_color_profile_get_space (dest_profile,
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
NULL))
{
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,131 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikacolortransform.h
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
* Elle Stone <ellestone@ninedegreesbelow.com>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_TRANSFORM_H__
#define __PIKA_COLOR_TRANSFORM_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/**
* PikaColorTransformFlags:
* @PIKA_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE: optimize for accuracy rather
* than for speed
* @PIKA_COLOR_TRANSFORM_FLAGS_GAMUT_CHECK: mark out of gamut colors in the
* transform result
* @PIKA_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION: do black point
* compensation
*
* Flags for modifying #PikaColorTransform's behavior.
**/
typedef enum
{
PIKA_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE = 0x0100,
PIKA_COLOR_TRANSFORM_FLAGS_GAMUT_CHECK = 0x1000,
PIKA_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION = 0x2000,
} PikaColorTransformFlags;
#define PIKA_TYPE_COLOR_TRANSFORM (pika_color_transform_get_type ())
#define PIKA_COLOR_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_TRANSFORM, PikaColorTransform))
#define PIKA_COLOR_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_TRANSFORM, PikaColorTransformClass))
#define PIKA_IS_COLOR_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_TRANSFORM))
#define PIKA_IS_COLOR_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_TRANSFORM))
#define PIKA_COLOR_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_TRANSFORM, PikaColorTransformClass))
typedef struct _PikaColorTransformPrivate PikaColorTransformPrivate;
typedef struct _PikaColorTransformClass PikaColorTransformClass;
struct _PikaColorTransform
{
GObject parent_instance;
PikaColorTransformPrivate *priv;
};
struct _PikaColorTransformClass
{
GObjectClass parent_class;
/* signals */
void (* progress) (PikaColorTransform *transform,
gdouble fraction);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_transform_get_type (void) G_GNUC_CONST;
PikaColorTransform *
pika_color_transform_new (PikaColorProfile *src_profile,
const Babl *src_format,
PikaColorProfile *dest_profile,
const Babl *dest_format,
PikaColorRenderingIntent rendering_intent,
PikaColorTransformFlags flags);
PikaColorTransform *
pika_color_transform_new_proofing (PikaColorProfile *src_profile,
const Babl *src_format,
PikaColorProfile *dest_profile,
const Babl *dest_format,
PikaColorProfile *proof_profile,
PikaColorRenderingIntent proof_intent,
PikaColorRenderingIntent display_intent,
PikaColorTransformFlags flags);
void pika_color_transform_process_pixels (PikaColorTransform *transform,
const Babl *src_format,
gconstpointer src_pixels,
const Babl *dest_format,
gpointer dest_pixels,
gsize length);
void pika_color_transform_process_buffer (PikaColorTransform *transform,
GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect);
gboolean pika_color_transform_can_gegl_copy (PikaColorProfile *src_profile,
PikaColorProfile *dest_profile);
G_END_DECLS
#endif /* __PIKA_COLOR_TRANSFORM_H__ */

View File

@ -0,0 +1,112 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_TYPES_H__
#define __PIKA_COLOR_TYPES_H__
#include <libpikabase/pikabasetypes.h>
#include <libpikaconfig/pikaconfigtypes.h>
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
typedef struct _PikaColorManaged PikaColorManaged; /* dummy typedef */
typedef struct _PikaColorProfile PikaColorProfile;
typedef struct _PikaColorTransform PikaColorTransform;
/* usually we don't keep the structure definitions in the types file
* but PikaRGB appears in too many header files...
*/
typedef struct _PikaRGB PikaRGB;
typedef struct _PikaHSV PikaHSV;
typedef struct _PikaHSL PikaHSL;
typedef struct _PikaCMYK PikaCMYK;
/**
* PikaRGB:
* @r: the red component
* @g: the green component
* @b: the blue component
* @a: the alpha component
*
* Used to keep RGB and RGBA colors. All components are in a range of
* [0.0..1.0].
**/
struct _PikaRGB
{
gdouble r, g, b, a;
};
/**
* PikaHSV:
* @h: the hue component
* @s: the saturation component
* @v: the value component
* @a: the alpha component
*
* Used to keep HSV and HSVA colors. All components are in a range of
* [0.0..1.0].
**/
struct _PikaHSV
{
gdouble h, s, v, a;
};
/**
* PikaHSL:
* @h: the hue component
* @s: the saturation component
* @l: the lightness component
* @a: the alpha component
*
* Used to keep HSL and HSLA colors. All components are in a range of
* [0.0..1.0].
**/
struct _PikaHSL
{
gdouble h, s, l, a;
};
/**
* PikaCMYK:
* @c: the cyan component
* @m: the magenta component
* @y: the yellow component
* @k: the black component
* @a: the alpha component
*
* Used to keep CMYK and CMYKA colors. All components are in a range
* of [0.0..1.0]. An alpha value is somewhat useless in the CMYK
* colorspace, but we keep one around anyway so color conversions
* going to CMYK and back can preserve alpha.
**/
struct _PikaCMYK
{
gdouble c, m, y, k, a;
};
G_END_DECLS
#endif /* __PIKA_COLOR_TYPES_H__ */

82
libpikacolor/pikahsl.c Normal file
View File

@ -0,0 +1,82 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib-object.h>
#include "pikacolortypes.h"
#include "pikahsl.h"
/*
* PIKA_TYPE_HSL
*/
static PikaHSL * pika_hsl_copy (const PikaHSL *hsl);
G_DEFINE_BOXED_TYPE (PikaHSL, pika_hsl, pika_hsl_copy, g_free)
static PikaHSL *
pika_hsl_copy (const PikaHSL *hsl)
{
return g_memdup2 (hsl, sizeof (PikaHSL));
}
/* HSL functions */
/**
* pika_hsl_set:
* @hsl:
* @h:
* @s:
* @l:
*
* Since: 2.8
**/
void
pika_hsl_set (PikaHSL *hsl,
gdouble h,
gdouble s,
gdouble l)
{
g_return_if_fail (hsl != NULL);
hsl->h = h;
hsl->s = s;
hsl->l = l;
}
/**
* pika_hsl_set_alpha:
* @hsl:
* @a:
*
* Since: 2.10
**/
void
pika_hsl_set_alpha (PikaHSL *hsl,
gdouble a)
{
g_return_if_fail (hsl != NULL);
hsl->a = a;
}

49
libpikacolor/pikahsl.h Normal file
View File

@ -0,0 +1,49 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_HSL_H__
#define __PIKA_HSL_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/*
* PIKA_TYPE_HSL
*/
#define PIKA_TYPE_HSL (pika_hsl_get_type ())
GType pika_hsl_get_type (void) G_GNUC_CONST;
void pika_hsl_set (PikaHSL *hsl,
gdouble h,
gdouble s,
gdouble l);
void pika_hsl_set_alpha (PikaHSL *hsl,
gdouble a);
G_END_DECLS
#endif /* __PIKA_HSL_H__ */

96
libpikacolor/pikahsv.c Normal file
View File

@ -0,0 +1,96 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib-object.h>
#include "pikacolortypes.h"
#include "pikahsv.h"
/**
* SECTION: pikahsv
* @title: PikaHSV
* @short_description: Definitions and Functions relating to HSV colors.
*
* Definitions and Functions relating to HSV colors.
**/
/*
* PIKA_TYPE_HSV
*/
static PikaHSV * pika_hsv_copy (const PikaHSV *hsv);
G_DEFINE_BOXED_TYPE (PikaHSV, pika_hsv, pika_hsv_copy, g_free)
static PikaHSV *
pika_hsv_copy (const PikaHSV *hsv)
{
return g_memdup2 (hsv, sizeof (PikaHSV));
}
/* HSV functions */
void
pika_hsv_set (PikaHSV *hsv,
gdouble h,
gdouble s,
gdouble v)
{
g_return_if_fail (hsv != NULL);
hsv->h = h;
hsv->s = s;
hsv->v = v;
}
void
pika_hsv_clamp (PikaHSV *hsv)
{
g_return_if_fail (hsv != NULL);
hsv->h -= (gint) hsv->h;
if (hsv->h < 0)
hsv->h += 1.0;
hsv->s = CLAMP (hsv->s, 0.0, 1.0);
hsv->v = CLAMP (hsv->v, 0.0, 1.0);
hsv->a = CLAMP (hsv->a, 0.0, 1.0);
}
void
pika_hsva_set (PikaHSV *hsva,
gdouble h,
gdouble s,
gdouble v,
gdouble a)
{
g_return_if_fail (hsva != NULL);
hsva->h = h;
hsva->s = s;
hsva->v = v;
hsva->a = a;
}

54
libpikacolor/pikahsv.h Normal file
View File

@ -0,0 +1,54 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_HSV_H__
#define __PIKA_HSV_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/*
* PIKA_TYPE_HSV
*/
#define PIKA_TYPE_HSV (pika_hsv_get_type ())
GType pika_hsv_get_type (void) G_GNUC_CONST;
void pika_hsv_set (PikaHSV *hsv,
gdouble hue,
gdouble saturation,
gdouble value);
void pika_hsv_clamp (PikaHSV *hsv);
void pika_hsva_set (PikaHSV *hsva,
gdouble hue,
gdouble saturation,
gdouble value,
gdouble alpha);
G_END_DECLS
#endif /* __PIKA_HSV_H__ */

152
libpikacolor/pikapixbuf.c Normal file
View File

@ -0,0 +1,152 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikapixbuf.c
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "pikacolortypes.h"
#include "pikapixbuf.h"
/**
* SECTION: pikapixbuf
* @title: PikaPixbuf
* @short_description: Definitions and Functions relating to GdkPixbuf.
*
* Definitions and Functions relating to GdkPixbuf.
**/
/**
* pika_pixbuf_get_format:
* @pixbuf: a #GdkPixbuf
*
* Returns the Babl format that corresponds to the @pixbuf's pixel format.
*
* Returns: the @pixbuf's pixel format
*
* Since: 2.10
**/
const Babl *
pika_pixbuf_get_format (GdkPixbuf *pixbuf)
{
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
switch (gdk_pixbuf_get_n_channels (pixbuf))
{
case 3: return babl_format ("R'G'B' u8");
case 4: return babl_format ("R'G'B'A u8");
}
g_return_val_if_reached (NULL);
}
/**
* pika_pixbuf_create_buffer:
* @pixbuf: a #GdkPixbuf
*
* Returns a #GeglBuffer that's either backed by the @pixbuf's pixels,
* or a copy of them. This function tries to not copy the @pixbuf's
* pixels. If the pixbuf's rowstride is a multiple of its bpp, a
* simple reference to the @pixbuf's pixels is made and @pixbuf will
* be kept around for as long as the buffer exists; otherwise the
* pixels are copied.
*
* Returns: (transfer full): a new #GeglBuffer.
*
* Since: 2.10
**/
GeglBuffer *
pika_pixbuf_create_buffer (GdkPixbuf *pixbuf)
{
gint width;
gint height;
gint rowstride;
gint bpp;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
bpp = gdk_pixbuf_get_n_channels (pixbuf);
if ((rowstride % bpp) == 0)
{
return gegl_buffer_linear_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
pika_pixbuf_get_format (pixbuf),
GEGL_RECTANGLE (0, 0,
width, height),
rowstride,
(GDestroyNotify) g_object_unref,
g_object_ref (pixbuf));
}
else
{
GeglBuffer *buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
width, height),
pika_pixbuf_get_format (pixbuf));
gegl_buffer_set (buffer, NULL, 0, NULL,
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf));
return buffer;
}
}
/**
* pika_pixbuf_get_icc_profile:
* @pixbuf: a #GdkPixbuf
* @length: (out): return location for the ICC profile's length
*
* Returns the ICC profile attached to the @pixbuf, or %NULL if there
* is none.
*
* Returns: (array length=length) (nullable): The ICC profile data, or %NULL.
* The value should be freed with g_free().
*
* Since: 2.10
**/
guint8 *
pika_pixbuf_get_icc_profile (GdkPixbuf *pixbuf,
gsize *length)
{
const gchar *icc_base64;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
g_return_val_if_fail (length != NULL, NULL);
icc_base64 = gdk_pixbuf_get_option (pixbuf, "icc-profile");
if (icc_base64)
{
guint8 *icc_data;
icc_data = g_base64_decode (icc_base64, length);
return icc_data;
}
return NULL;
}

43
libpikacolor/pikapixbuf.h Normal file
View File

@ -0,0 +1,43 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikapixbuf.h
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_PIXBUF_H__
#define __PIKA_PIXBUF_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
const Babl * pika_pixbuf_get_format (GdkPixbuf *pixbuf);
GeglBuffer * pika_pixbuf_create_buffer (GdkPixbuf *pixbuf);
guint8 * pika_pixbuf_get_icc_profile (GdkPixbuf *pixbuf,
gsize *length);
G_END_DECLS
#endif /* __PIKA_PIXBUF_H__ */

View File

@ -0,0 +1,649 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikargb-parse.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* Some of the code in here was inspired and partly copied from pango
* and librsvg.
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <babl/babl.h>
#include <glib-object.h>
#include "pikacolortypes.h"
#include "pikacolorspace.h"
#include "pikargb.h"
static gchar * pika_rgb_parse_strip (const gchar *str,
gint len);
static gboolean pika_rgb_parse_name_internal (PikaRGB *rgb,
const gchar *name);
static gboolean pika_rgb_parse_hex_internal (PikaRGB *rgb,
const gchar *hex);
static gboolean pika_rgb_parse_css_internal (PikaRGB *rgb,
const gchar *css);
static gboolean pika_rgba_parse_css_internal (PikaRGB *rgb,
const gchar *css);
typedef struct
{
const gchar *name;
const guchar red;
const guchar green;
const guchar blue;
} ColorEntry;
static const ColorEntry named_colors[] =
{
{ "aliceblue", 240, 248, 255 },
{ "antiquewhite", 250, 235, 215 },
{ "aqua", 0, 255, 255 },
{ "aquamarine", 127, 255, 212 },
{ "azure", 240, 255, 255 },
{ "beige", 245, 245, 220 },
{ "bisque", 255, 228, 196 },
{ "black", 0, 0, 0 },
{ "blanchedalmond", 255, 235, 205 },
{ "blue", 0, 0, 255 },
{ "blueviolet", 138, 43, 226 },
{ "brown", 165, 42, 42 },
{ "burlywood", 222, 184, 135 },
{ "cadetblue", 95, 158, 160 },
{ "chartreuse", 127, 255, 0 },
{ "chocolate", 210, 105, 30 },
{ "coral", 255, 127, 80 },
{ "cornflowerblue", 100, 149, 237 },
{ "cornsilk", 255, 248, 220 },
{ "crimson", 220, 20, 60 },
{ "cyan", 0, 255, 255 },
{ "darkblue", 0, 0, 139 },
{ "darkcyan", 0, 139, 139 },
{ "darkgoldenrod", 184, 134, 11 },
{ "darkgray", 169, 169, 169 },
{ "darkgreen", 0, 100, 0 },
{ "darkgrey", 169, 169, 169 },
{ "darkkhaki", 189, 183, 107 },
{ "darkmagenta", 139, 0, 139 },
{ "darkolivegreen", 85, 107, 47 },
{ "darkorange", 255, 140, 0 },
{ "darkorchid", 153, 50, 204 },
{ "darkred", 139, 0, 0 },
{ "darksalmon", 233, 150, 122 },
{ "darkseagreen", 143, 188, 143 },
{ "darkslateblue", 72, 61, 139 },
{ "darkslategray", 47, 79, 79 },
{ "darkslategrey", 47, 79, 79 },
{ "darkturquoise", 0, 206, 209 },
{ "darkviolet", 148, 0, 211 },
{ "deeppink", 255, 20, 147 },
{ "deepskyblue", 0, 191, 255 },
{ "dimgray", 105, 105, 105 },
{ "dimgrey", 105, 105, 105 },
{ "dodgerblue", 30, 144, 255 },
{ "firebrick", 178, 34, 34 },
{ "floralwhite" , 255, 250, 240 },
{ "forestgreen", 34, 139, 34 },
{ "fuchsia", 255, 0, 255 },
{ "gainsboro", 220, 220, 220 },
{ "ghostwhite", 248, 248, 255 },
{ "gold", 255, 215, 0 },
{ "goldenrod", 218, 165, 32 },
{ "gray", 128, 128, 128 },
{ "green", 0, 128, 0 },
{ "greenyellow", 173, 255, 47 },
{ "grey", 128, 128, 128 },
{ "honeydew", 240, 255, 240 },
{ "hotpink", 255, 105, 180 },
{ "indianred", 205, 92, 92 },
{ "indigo", 75, 0, 130 },
{ "ivory", 255, 255, 240 },
{ "khaki", 240, 230, 140 },
{ "lavender", 230, 230, 250 },
{ "lavenderblush", 255, 240, 245 },
{ "lawngreen", 124, 252, 0 },
{ "lemonchiffon", 255, 250, 205 },
{ "lightblue", 173, 216, 230 },
{ "lightcoral", 240, 128, 128 },
{ "lightcyan", 224, 255, 255 },
{ "lightgoldenrodyellow", 250, 250, 210 },
{ "lightgray", 211, 211, 211 },
{ "lightgreen", 144, 238, 144 },
{ "lightgrey", 211, 211, 211 },
{ "lightpink", 255, 182, 193 },
{ "lightsalmon", 255, 160, 122 },
{ "lightseagreen", 32, 178, 170 },
{ "lightskyblue", 135, 206, 250 },
{ "lightslategray", 119, 136, 153 },
{ "lightslategrey", 119, 136, 153 },
{ "lightsteelblue", 176, 196, 222 },
{ "lightyellow", 255, 255, 224 },
{ "lime", 0, 255, 0 },
{ "limegreen", 50, 205, 50 },
{ "linen", 250, 240, 230 },
{ "magenta", 255, 0, 255 },
{ "maroon", 128, 0, 0 },
{ "mediumaquamarine", 102, 205, 170 },
{ "mediumblue", 0, 0, 205 },
{ "mediumorchid", 186, 85, 211 },
{ "mediumpurple", 147, 112, 219 },
{ "mediumseagreen", 60, 179, 113 },
{ "mediumslateblue", 123, 104, 238 },
{ "mediumspringgreen", 0, 250, 154 },
{ "mediumturquoise", 72, 209, 204 },
{ "mediumvioletred", 199, 21, 133 },
{ "midnightblue", 25, 25, 112 },
{ "mintcream", 245, 255, 250 },
{ "mistyrose", 255, 228, 225 },
{ "moccasin", 255, 228, 181 },
{ "navajowhite", 255, 222, 173 },
{ "navy", 0, 0, 128 },
{ "oldlace", 253, 245, 230 },
{ "olive", 128, 128, 0 },
{ "olivedrab", 107, 142, 35 },
{ "orange", 255, 165, 0 },
{ "orangered", 255, 69, 0 },
{ "orchid", 218, 112, 214 },
{ "palegoldenrod", 238, 232, 170 },
{ "palegreen", 152, 251, 152 },
{ "paleturquoise", 175, 238, 238 },
{ "palevioletred", 219, 112, 147 },
{ "papayawhip", 255, 239, 213 },
{ "peachpuff", 255, 218, 185 },
{ "peru", 205, 133, 63 },
{ "pink", 255, 192, 203 },
{ "plum", 221, 160, 221 },
{ "powderblue", 176, 224, 230 },
{ "purple", 128, 0, 128 },
{ "red", 255, 0, 0 },
{ "rosybrown", 188, 143, 143 },
{ "royalblue", 65, 105, 225 },
{ "saddlebrown", 139, 69, 19 },
{ "salmon", 250, 128, 114 },
{ "sandybrown", 244, 164, 96 },
{ "seagreen", 46, 139, 87 },
{ "seashell", 255, 245, 238 },
{ "sienna", 160, 82, 45 },
{ "silver", 192, 192, 192 },
{ "skyblue", 135, 206, 235 },
{ "slateblue", 106, 90, 205 },
{ "slategray", 112, 128, 144 },
{ "slategrey", 112, 128, 144 },
{ "snow", 255, 250, 250 },
{ "springgreen", 0, 255, 127 },
{ "steelblue", 70, 130, 180 },
{ "tan", 210, 180, 140 },
{ "teal", 0, 128, 128 },
{ "thistle", 216, 191, 216 },
{ "tomato", 255, 99, 71 },
{ "turquoise", 64, 224, 208 },
{ "violet", 238, 130, 238 },
{ "wheat", 245, 222, 179 },
{ "white", 255, 255, 255 },
{ "whitesmoke", 245, 245, 245 },
{ "yellow", 255, 255, 0 },
{ "yellowgreen", 154, 205, 50 }
};
/**
* pika_rgb_parse_name:
* @rgb: a #PikaRGB struct used to return the parsed color
* @name: (array length=len): a color name (in UTF-8 encoding)
* @len: the length of @name, in bytes. or -1 if @name is nul-terminated
*
* Attempts to parse a color name. This function accepts <ulink
* url="https://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG 1.0
* color keywords</ulink>.
*
* This function does not touch the alpha component of @rgb.
*
* Returns: %TRUE if @name was parsed successfully and @rgb has
* been set, %FALSE otherwise
*
* Since: 2.2
**/
gboolean
pika_rgb_parse_name (PikaRGB *rgb,
const gchar *name,
gint len)
{
gchar *tmp;
gboolean result;
g_return_val_if_fail (rgb != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
tmp = pika_rgb_parse_strip (name, len);
result = pika_rgb_parse_name_internal (rgb, tmp);
g_free (tmp);
return result;
}
/**
* pika_rgb_parse_hex:
* @rgb: a #PikaRGB struct used to return the parsed color
* @hex: (array length=len): a string describing a color in hexadecimal notation
* @len: the length of @hex, in bytes. or -1 if @hex is nul-terminated
*
* Attempts to parse a string describing an RGB color in hexadecimal
* notation (optionally prefixed with a '#').
*
* This function does not touch the alpha component of @rgb.
*
* Returns: %TRUE if @hex was parsed successfully and @rgb has
* been set, %FALSE otherwise
*
* Since: 2.2
**/
gboolean
pika_rgb_parse_hex (PikaRGB *rgb,
const gchar *hex,
gint len)
{
gchar *tmp;
gboolean result;
g_return_val_if_fail (rgb != NULL, FALSE);
g_return_val_if_fail (hex != NULL, FALSE);
tmp = pika_rgb_parse_strip (hex, len);
result = pika_rgb_parse_hex_internal (rgb, tmp);
g_free (tmp);
return result;
}
/**
* pika_rgb_parse_css:
* @rgb: a #PikaRGB struct used to return the parsed color
* @css: (array length=len): a string describing a color in CSS notation
* @len: the length of @css, in bytes. or -1 if @css is nul-terminated
*
* Attempts to parse a string describing an RGB color in CSS
* notation. This can be either a numerical representation
* (<code>rgb(255,0,0)</code> or <code>rgb(100%,0%,0%)</code>)
* or a hexadecimal notation as parsed by pika_rgb_parse_hex()
* (<code>##ff0000</code>) or a color name as parsed by
* pika_rgb_parse_name() (<code>red</code>).
*
* This function does not touch the alpha component of @rgb.
*
* Returns: %TRUE if @css was parsed successfully and @rgb has been
* set, %FALSE otherwise
*
* Since: 2.2
**/
gboolean
pika_rgb_parse_css (PikaRGB *rgb,
const gchar *css,
gint len)
{
gchar *tmp;
gboolean result;
g_return_val_if_fail (rgb != NULL, FALSE);
g_return_val_if_fail (css != NULL, FALSE);
tmp = pika_rgb_parse_strip (css, len);
result = pika_rgb_parse_css_internal (rgb, tmp);
g_free (tmp);
return result;
}
/**
* pika_rgba_parse_css:
* @rgba: a #PikaRGB struct used to return the parsed color
* @css: (array length=len): a string describing a color in CSS notation
* @len: the length of @css, in bytes. or -1 if @css is nul-terminated
*
* Similar to pika_rgb_parse_css() but handles RGB colors with alpha
* channel in the numerical CSS notation (<code>rgba(255,0,0,255)</code>
* or <code>rgba(100%,0%,0%,1000%)</code>).
*
* It doesn't handle the hexadecimal notation or color names because
* they leave the alpha channel unspecified.
*
* Returns: %TRUE if @css was parsed successfully and @rgb has been
* set, %FALSE otherwise
*
* Since: 2.2
**/
gboolean
pika_rgba_parse_css (PikaRGB *rgba,
const gchar *css,
gint len)
{
gchar *tmp;
gboolean result;
g_return_val_if_fail (rgba != NULL, FALSE);
g_return_val_if_fail (css != NULL, FALSE);
if (len < 0)
len = strlen (css);
tmp = pika_rgb_parse_strip (css, len);
if (strcmp (tmp, "transparent") == 0)
{
pika_rgba_set (rgba, 0.0, 0.0, 0.0, 0.0);
result = TRUE;
}
else
{
result = pika_rgba_parse_css_internal (rgba, tmp);
}
g_free (tmp);
return result;
}
/**
* pika_rgb_list_names:
* @names: (out) (array length=n_colors) (transfer container): return location for an array of color names
* @colors: (out) (array length=n_colors) (transfer container): return location for an array of PikaRGB structs
* @n_colors: (out): The number of named colors
*
* Returns the list of <ulink
* url="https://www.w3.org/TR/SVG/types.html">SVG 1.0 color
* keywords</ulink> that is used by pika_rgb_parse_name().
*
* The returned strings are const and must not be freed. Only the two
* arrays are allocated dynamically. You must call g_free() on the
* @names and @colors arrays when they are not any longer needed.
*
* Since: 2.2
**/
void
pika_rgb_list_names (const gchar ***names,
PikaRGB **colors,
gint *n_colors)
{
gint i;
g_return_if_fail (names != NULL);
g_return_if_fail (colors != NULL);
g_return_if_fail (n_colors != NULL);
*names = g_new (const gchar *, G_N_ELEMENTS (named_colors));
*colors = g_new (PikaRGB, G_N_ELEMENTS (named_colors));
*n_colors = G_N_ELEMENTS (named_colors);
for (i = 0; i < G_N_ELEMENTS (named_colors); i++)
{
(*names)[i] = named_colors[i].name;
pika_rgba_set_uchar ((*colors) + i,
named_colors[i].red,
named_colors[i].green,
named_colors[i].blue,
0xFF);
}
}
static gchar *
pika_rgb_parse_strip (const gchar *str,
gint len)
{
gchar *result;
while (len > 0 && g_ascii_isspace (*str))
{
str++;
len--;
}
if (len < 0)
{
while (g_ascii_isspace (*str))
str++;
len = strlen (str);
}
while (len > 0 && g_ascii_isspace (str[len - 1]))
len--;
result = g_malloc (len + 1);
memcpy (result, str, len);
result[len] = '\0';
return result;
}
static gint
pika_rgb_color_entry_compare (gconstpointer a,
gconstpointer b)
{
const gchar *name = a;
const ColorEntry *entry = b;
return g_ascii_strcasecmp (name, entry->name);
}
static gboolean
pika_rgb_parse_name_internal (PikaRGB *rgb,
const gchar *name)
{
ColorEntry *entry = bsearch (name, named_colors,
G_N_ELEMENTS (named_colors), sizeof (ColorEntry),
pika_rgb_color_entry_compare);
if (entry)
{
pika_rgb_set_uchar (rgb, entry->red, entry->green, entry->blue);
return TRUE;
}
return FALSE;
}
static gboolean
pika_rgb_parse_hex_component (const gchar *hex,
gint len,
gdouble *value)
{
gint i;
guint c = 0;
for (i = 0; i < len; i++, hex++)
{
if (!*hex || !g_ascii_isxdigit (*hex))
return FALSE;
c = (c << 4) | g_ascii_xdigit_value (*hex);
}
switch (len)
{
case 1: *value = (gdouble) c / 15.0; break;
case 2: *value = (gdouble) c / 255.0; break;
case 3: *value = (gdouble) c / 4095.0; break;
case 4: *value = (gdouble) c / 65535.0; break;
default:
g_return_val_if_reached (FALSE);
}
return TRUE;
}
static gboolean
pika_rgb_parse_hex_internal (PikaRGB *rgb,
const gchar *hex)
{
gint i;
gsize len;
gdouble val[3];
if (hex[0] == '#')
hex++;
len = strlen (hex);
if (len % 3 || len < 3 || len > 12)
return FALSE;
len /= 3;
for (i = 0; i < 3; i++, hex += len)
{
if (! pika_rgb_parse_hex_component (hex, len, val + i))
return FALSE;
}
pika_rgb_set (rgb, val[0], val[1], val[2]);
return TRUE;
}
static gboolean
pika_rgb_parse_css_numeric (PikaRGB *rgb,
const gchar *css)
{
gdouble values[4];
gboolean alpha;
gboolean hsl;
gint i;
if (css[0] == 'r' && css[1] == 'g' && css[2] == 'b')
hsl = FALSE;
else if (css[0] == 'h' && css[1] == 's' && css[2] == 'l')
hsl = TRUE;
else
return FALSE;
if (css[3] == 'a' && css[4] == '(')
alpha = TRUE;
else if (css[3] == '(')
alpha = FALSE;
else
return FALSE;
css += (alpha ? 5 : 4);
for (i = 0; i < (alpha ? 4 : 3); i++)
{
const gchar *end = css;
while (*end && *end != ',' && *end != '%' && *end != ')')
end++;
if (i == 3 || *end == '%')
{
values[i] = g_ascii_strtod (css, (gchar **) &end);
if (errno == ERANGE)
return FALSE;
if (*end == '%')
{
end++;
values[i] /= 100.0;
}
}
else
{
glong value = strtol (css, (gchar **) &end, 10);
if (errno == ERANGE)
return FALSE;
if (hsl)
values[i] = value / (i == 0 ? 360.0 : 100.0);
else
values[i] = value / 255.0;
}
while (*end == ',' || g_ascii_isspace (*end))
end++;
css = end;
}
if (*css != ')')
return FALSE;
if (alpha)
pika_rgba_set (rgb, values[0], values[1], values[2], values[3]);
else
pika_rgb_set (rgb, values[0], values[1], values[2]);
pika_rgb_clamp (rgb);
if (hsl)
{
PikaHSL tmp = (*((PikaHSL *) rgb));
pika_hsl_to_rgb (&tmp, rgb);
}
return TRUE;
}
static gboolean
pika_rgb_parse_css_internal (PikaRGB *rgb,
const gchar *css)
{
if (css[0] == '#')
{
return pika_rgb_parse_hex_internal (rgb, css);
}
else if (strncmp (css, "rgb(", 4) == 0 ||
strncmp (css, "hsl(", 4) == 0)
{
return pika_rgb_parse_css_numeric (rgb, css);
}
else
{
return pika_rgb_parse_name_internal (rgb, css);
}
}
static gboolean
pika_rgba_parse_css_internal (PikaRGB *rgba,
const gchar *css)
{
if (strncmp (css, "rgba(", 5) != 0 &&
strncmp (css, "hsla(", 5) != 0)
return FALSE;
return pika_rgb_parse_css_numeric (rgba, css);
}

814
libpikacolor/pikargb.c Normal file
View File

@ -0,0 +1,814 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <babl/babl.h>
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikacolortypes.h"
#include "pikargb.h"
/**
* SECTION: pikargb
* @title: PikaRGB
* @short_description: Definitions and Functions relating to RGB colors.
*
* Definitions and Functions relating to RGB colors.
**/
/*
* PIKA_TYPE_RGB
*/
static PikaRGB * pika_rgb_copy (const PikaRGB *rgb);
G_DEFINE_BOXED_TYPE (PikaRGB, pika_rgb, pika_rgb_copy, g_free)
void
pika_value_get_rgb (const GValue *value,
PikaRGB *rgb)
{
g_return_if_fail (PIKA_VALUE_HOLDS_RGB (value));
g_return_if_fail (rgb != NULL);
if (value->data[0].v_pointer)
*rgb = *((PikaRGB *) value->data[0].v_pointer);
else
pika_rgba_set (rgb, 0.0, 0.0, 0.0, 1.0);
}
void
pika_value_set_rgb (GValue *value,
const PikaRGB *rgb)
{
g_return_if_fail (PIKA_VALUE_HOLDS_RGB (value));
g_return_if_fail (rgb != NULL);
g_value_set_boxed (value, rgb);
}
static PikaRGB *
pika_rgb_copy (const PikaRGB *rgb)
{
return g_memdup2 (rgb, sizeof (PikaRGB));
}
/* RGB functions */
/**
* pika_rgb_set:
* @rgb: a #PikaRGB struct
* @red: the red component
* @green: the green component
* @blue: the blue component
*
* Sets the red, green and blue components of @rgb and leaves the
* alpha component unchanged. The color values should be between 0.0
* and 1.0 but there is no check to enforce this and the values are
* set exactly as they are passed in.
**/
void
pika_rgb_set (PikaRGB *rgb,
gdouble r,
gdouble g,
gdouble b)
{
g_return_if_fail (rgb != NULL);
rgb->r = r;
rgb->g = g;
rgb->b = b;
}
/**
* pika_rgb_set_alpha:
* @rgb: a #PikaRGB struct
* @alpha: the alpha component
*
* Sets the alpha component of @rgb and leaves the RGB components unchanged.
**/
void
pika_rgb_set_alpha (PikaRGB *rgb,
gdouble a)
{
g_return_if_fail (rgb != NULL);
rgb->a = a;
}
/**
* pika_rgb_set_pixel:
* @rgb: a #PikaRGB struct
* @format: a Babl format
* @pixel: pointer to the source pixel
*
* Sets the red, green and blue components of @rgb from the color
* stored in @pixel. The pixel format of @pixel is determined by
* @format.
*
* Since: 2.10
**/
void
pika_rgb_set_pixel (PikaRGB *rgb,
const Babl *format,
gconstpointer pixel)
{
g_return_if_fail (rgb != NULL);
g_return_if_fail (format != NULL);
g_return_if_fail (pixel != NULL);
babl_process (babl_fish (format,
babl_format ("R'G'B' double")),
pixel, rgb, 1);
}
/**
* pika_rgb_get_pixel:
* @rgb: a #PikaRGB struct
* @format: a Babl format
* @pixel: (out caller-allocates): pointer to the destination pixel
*
* Writes the red, green, blue and alpha components of @rgb to the
* color stored in @pixel. The pixel format of @pixel is determined by
* @format.
*
* Since: 2.10
**/
void
pika_rgb_get_pixel (const PikaRGB *rgb,
const Babl *format,
gpointer pixel)
{
g_return_if_fail (rgb != NULL);
g_return_if_fail (format != NULL);
g_return_if_fail (pixel != NULL);
babl_process (babl_fish (babl_format ("R'G'B' double"),
format),
rgb, pixel, 1);
}
/**
* pika_rgb_set_uchar:
* @rgb: a #PikaRGB struct
* @red: the red component
* @green: the green component
* @blue: the blue component
*
* Sets the red, green and blue components of @rgb from 8bit values
* (0 to 255) and leaves the alpha component unchanged.
**/
void
pika_rgb_set_uchar (PikaRGB *rgb,
guchar r,
guchar g,
guchar b)
{
g_return_if_fail (rgb != NULL);
rgb->r = (gdouble) r / 255.0;
rgb->g = (gdouble) g / 255.0;
rgb->b = (gdouble) b / 255.0;
}
/**
* pika_rgb_get_uchar:
* @rgb: a #PikaRGB struct
* @red: (out) (optional): Location for red component, or %NULL
* @green: (out) (optional): Location for green component, or %NULL
* @blue: (out) (optional): Location for blue component, or %NULL
*
* Writes the red, green, blue and alpha components of @rgb to the
* color components @red, @green and @blue.
*/
void
pika_rgb_get_uchar (const PikaRGB *rgb,
guchar *red,
guchar *green,
guchar *blue)
{
g_return_if_fail (rgb != NULL);
if (red) *red = ROUND (CLAMP (rgb->r, 0.0, 1.0) * 255.0);
if (green) *green = ROUND (CLAMP (rgb->g, 0.0, 1.0) * 255.0);
if (blue) *blue = ROUND (CLAMP (rgb->b, 0.0, 1.0) * 255.0);
}
void
pika_rgb_add (PikaRGB *rgb1,
const PikaRGB *rgb2)
{
g_return_if_fail (rgb1 != NULL);
g_return_if_fail (rgb2 != NULL);
rgb1->r += rgb2->r;
rgb1->g += rgb2->g;
rgb1->b += rgb2->b;
}
void
pika_rgb_subtract (PikaRGB *rgb1,
const PikaRGB *rgb2)
{
g_return_if_fail (rgb1 != NULL);
g_return_if_fail (rgb2 != NULL);
rgb1->r -= rgb2->r;
rgb1->g -= rgb2->g;
rgb1->b -= rgb2->b;
}
void
pika_rgb_multiply (PikaRGB *rgb,
gdouble factor)
{
g_return_if_fail (rgb != NULL);
rgb->r *= factor;
rgb->g *= factor;
rgb->b *= factor;
}
gdouble
pika_rgb_distance (const PikaRGB *rgb1,
const PikaRGB *rgb2)
{
g_return_val_if_fail (rgb1 != NULL, 0.0);
g_return_val_if_fail (rgb2 != NULL, 0.0);
return (fabs (rgb1->r - rgb2->r) +
fabs (rgb1->g - rgb2->g) +
fabs (rgb1->b - rgb2->b));
}
gdouble
pika_rgb_max (const PikaRGB *rgb)
{
g_return_val_if_fail (rgb != NULL, 0.0);
if (rgb->r > rgb->g)
return (rgb->r > rgb->b) ? rgb->r : rgb->b;
else
return (rgb->g > rgb->b) ? rgb->g : rgb->b;
}
gdouble
pika_rgb_min (const PikaRGB *rgb)
{
g_return_val_if_fail (rgb != NULL, 0.0);
if (rgb->r < rgb->g)
return (rgb->r < rgb->b) ? rgb->r : rgb->b;
else
return (rgb->g < rgb->b) ? rgb->g : rgb->b;
}
void
pika_rgb_clamp (PikaRGB *rgb)
{
g_return_if_fail (rgb != NULL);
rgb->r = CLAMP (rgb->r, 0.0, 1.0);
rgb->g = CLAMP (rgb->g, 0.0, 1.0);
rgb->b = CLAMP (rgb->b, 0.0, 1.0);
rgb->a = CLAMP (rgb->a, 0.0, 1.0);
}
void
pika_rgb_gamma (PikaRGB *rgb,
gdouble gamma)
{
gdouble ig;
g_return_if_fail (rgb != NULL);
if (gamma != 0.0)
ig = 1.0 / gamma;
else
ig = 0.0;
rgb->r = pow (rgb->r, ig);
rgb->g = pow (rgb->g, ig);
rgb->b = pow (rgb->b, ig);
}
/**
* pika_rgb_luminance:
* @rgb: a #PikaRGB struct
*
* Returns: the luminous intensity of the range from 0.0 to 1.0.
*
* Since: 2.4
**/
gdouble
pika_rgb_luminance (const PikaRGB *rgb)
{
gdouble luminance;
g_return_val_if_fail (rgb != NULL, 0.0);
luminance = PIKA_RGB_LUMINANCE (rgb->r, rgb->g, rgb->b);
return CLAMP (luminance, 0.0, 1.0);
}
/**
* pika_rgb_luminance_uchar:
* @rgb: a #PikaRGB struct
*
* Returns: the luminous intensity in the range from 0 to 255.
*
* Since: 2.4
**/
guchar
pika_rgb_luminance_uchar (const PikaRGB *rgb)
{
g_return_val_if_fail (rgb != NULL, 0);
return ROUND (pika_rgb_luminance (rgb) * 255.0);
}
void
pika_rgb_composite (PikaRGB *color1,
const PikaRGB *color2,
PikaRGBCompositeMode mode)
{
g_return_if_fail (color1 != NULL);
g_return_if_fail (color2 != NULL);
switch (mode)
{
case PIKA_RGB_COMPOSITE_NONE:
break;
case PIKA_RGB_COMPOSITE_NORMAL:
/* put color2 on top of color1 */
if (color2->a == 1.0)
{
*color1 = *color2;
}
else
{
gdouble factor = color1->a * (1.0 - color2->a);
color1->r = color1->r * factor + color2->r * color2->a;
color1->g = color1->g * factor + color2->g * color2->a;
color1->b = color1->b * factor + color2->b * color2->a;
color1->a = factor + color2->a;
}
break;
case PIKA_RGB_COMPOSITE_BEHIND:
/* put color2 below color1 */
if (color1->a < 1.0)
{
gdouble factor = color2->a * (1.0 - color1->a);
color1->r = color2->r * factor + color1->r * color1->a;
color1->g = color2->g * factor + color1->g * color1->a;
color1->b = color2->b * factor + color1->b * color1->a;
color1->a = factor + color1->a;
}
break;
}
}
/* RGBA functions */
/**
* pika_rgba_set_pixel:
* @rgba: a #PikaRGB struct
* @format: a Babl format
* @pixel: pointer to the source pixel
*
* Sets the red, green, blue and alpha components of @rgba from the
* color stored in @pixel. The pixel format of @pixel is determined
* by @format.
*
* Since: 2.10
**/
void
pika_rgba_set_pixel (PikaRGB *rgba,
const Babl *format,
gconstpointer pixel)
{
g_return_if_fail (rgba != NULL);
g_return_if_fail (format != NULL);
g_return_if_fail (pixel != NULL);
babl_process (babl_fish (format,
babl_format ("R'G'B'A double")),
pixel, rgba, 1);
}
/**
* pika_rgba_get_pixel:
* @rgba: a #PikaRGB struct
* @format: a Babl format
* @pixel: (out caller-allocates): pointer to the destination pixel
*
* Writes the red, green, blue and alpha components of @rgba to the
* color stored in @pixel. The pixel format of @pixel is determined by
* @format.
*
* Since: 2.10
**/
void
pika_rgba_get_pixel (const PikaRGB *rgba,
const Babl *format,
gpointer pixel)
{
g_return_if_fail (rgba != NULL);
g_return_if_fail (format != NULL);
g_return_if_fail (pixel != NULL);
babl_process (babl_fish (babl_format ("R'G'B'A double"),
format),
rgba, pixel, 1);
}
/**
* pika_rgba_set:
* @rgba: a #PikaRGB struct
* @red: the red component
* @green: the green component
* @blue: the blue component
* @alpha: the alpha component
*
* Sets the red, green, blue and alpha components of @rgb. The values
* should be between 0.0 and 1.0 but there is no check to enforce this
* and the values are set exactly as they are passed in.
**/
void
pika_rgba_set (PikaRGB *rgba,
gdouble r,
gdouble g,
gdouble b,
gdouble a)
{
g_return_if_fail (rgba != NULL);
rgba->r = r;
rgba->g = g;
rgba->b = b;
rgba->a = a;
}
/**
* pika_rgba_set_uchar:
* @rgba: a #PikaRGB struct
* @red: the red component
* @green: the green component
* @blue: the blue component
* @alpha: the alpha component
*
* Sets the red, green, blue and alpha components of @rgba from 8bit
* values (0 to 255).
**/
void
pika_rgba_set_uchar (PikaRGB *rgba,
guchar r,
guchar g,
guchar b,
guchar a)
{
g_return_if_fail (rgba != NULL);
rgba->r = (gdouble) r / 255.0;
rgba->g = (gdouble) g / 255.0;
rgba->b = (gdouble) b / 255.0;
rgba->a = (gdouble) a / 255.0;
}
/**
* pika_rgba_get_uchar:
* @rgba: a #PikaRGB struct
* @red: (out) (optional): Location for the red component
* @green: (out) (optional): Location for the green component
* @blue: (out) (optional): Location for the blue component
* @alpha: (out) (optional): Location for the alpha component
*
* Gets the 8bit red, green, blue and alpha components of @rgba.
**/
void
pika_rgba_get_uchar (const PikaRGB *rgba,
guchar *r,
guchar *g,
guchar *b,
guchar *a)
{
g_return_if_fail (rgba != NULL);
if (r) *r = ROUND (CLAMP (rgba->r, 0.0, 1.0) * 255.0);
if (g) *g = ROUND (CLAMP (rgba->g, 0.0, 1.0) * 255.0);
if (b) *b = ROUND (CLAMP (rgba->b, 0.0, 1.0) * 255.0);
if (a) *a = ROUND (CLAMP (rgba->a, 0.0, 1.0) * 255.0);
}
void
pika_rgba_add (PikaRGB *rgba1,
const PikaRGB *rgba2)
{
g_return_if_fail (rgba1 != NULL);
g_return_if_fail (rgba2 != NULL);
rgba1->r += rgba2->r;
rgba1->g += rgba2->g;
rgba1->b += rgba2->b;
rgba1->a += rgba2->a;
}
void
pika_rgba_subtract (PikaRGB *rgba1,
const PikaRGB *rgba2)
{
g_return_if_fail (rgba1 != NULL);
g_return_if_fail (rgba2 != NULL);
rgba1->r -= rgba2->r;
rgba1->g -= rgba2->g;
rgba1->b -= rgba2->b;
rgba1->a -= rgba2->a;
}
void
pika_rgba_multiply (PikaRGB *rgba,
gdouble factor)
{
g_return_if_fail (rgba != NULL);
rgba->r *= factor;
rgba->g *= factor;
rgba->b *= factor;
rgba->a *= factor;
}
gdouble
pika_rgba_distance (const PikaRGB *rgba1,
const PikaRGB *rgba2)
{
g_return_val_if_fail (rgba1 != NULL, 0.0);
g_return_val_if_fail (rgba2 != NULL, 0.0);
return (fabs (rgba1->r - rgba2->r) +
fabs (rgba1->g - rgba2->g) +
fabs (rgba1->b - rgba2->b) +
fabs (rgba1->a - rgba2->a));
}
/*
* PIKA_TYPE_PARAM_RGB
*/
#define PIKA_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), PIKA_TYPE_PARAM_RGB, PikaParamSpecRGB))
struct _PikaParamSpecRGB
{
GParamSpecBoxed parent_instance;
gboolean has_alpha;
gboolean validate; /* change this to enable [0.0...1.0] */
PikaRGB default_value;
};
static void pika_param_rgb_class_init (GParamSpecClass *class);
static void pika_param_rgb_init (GParamSpec *pspec);
static void pika_param_rgb_set_default (GParamSpec *pspec,
GValue *value);
static gboolean pika_param_rgb_validate (GParamSpec *pspec,
GValue *value);
static gint pika_param_rgb_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2);
/**
* pika_param_rgb_get_type:
*
* Reveals the object type
*
* Returns: the #GType for a PikaParamRGB object
*
* Since: 2.4
**/
GType
pika_param_rgb_get_type (void)
{
static GType spec_type = 0;
if (! spec_type)
{
const GTypeInfo type_info =
{
sizeof (GParamSpecClass),
NULL, NULL,
(GClassInitFunc) pika_param_rgb_class_init,
NULL, NULL,
sizeof (PikaParamSpecRGB),
0,
(GInstanceInitFunc) pika_param_rgb_init
};
spec_type = g_type_register_static (G_TYPE_PARAM_BOXED,
"PikaParamRGB",
&type_info, 0);
}
return spec_type;
}
static void
pika_param_rgb_class_init (GParamSpecClass *class)
{
class->value_type = PIKA_TYPE_RGB;
class->value_set_default = pika_param_rgb_set_default;
class->value_validate = pika_param_rgb_validate;
class->values_cmp = pika_param_rgb_values_cmp;
}
static void
pika_param_rgb_init (GParamSpec *pspec)
{
PikaParamSpecRGB *cspec = PIKA_PARAM_SPEC_RGB (pspec);
pika_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
}
static void
pika_param_rgb_set_default (GParamSpec *pspec,
GValue *value)
{
PikaParamSpecRGB *cspec = PIKA_PARAM_SPEC_RGB (pspec);
g_value_set_static_boxed (value, &cspec->default_value);
}
static gboolean
pika_param_rgb_validate (GParamSpec *pspec,
GValue *value)
{
PikaParamSpecRGB *rgb_spec = PIKA_PARAM_SPEC_RGB (pspec);
PikaRGB *rgb = value->data[0].v_pointer;
if (rgb_spec->validate && rgb)
{
PikaRGB oval = *rgb;
pika_rgb_clamp (rgb);
return (oval.r != rgb->r ||
oval.g != rgb->g ||
oval.b != rgb->b ||
(rgb_spec->has_alpha && oval.a != rgb->a));
}
return FALSE;
}
static gint
pika_param_rgb_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
{
PikaRGB *rgb1 = value1->data[0].v_pointer;
PikaRGB *rgb2 = value2->data[0].v_pointer;
/* try to return at least *something*, it's useless anyway... */
if (! rgb1)
{
return rgb2 != NULL ? -1 : 0;
}
else if (! rgb2)
{
return rgb1 != NULL;
}
else
{
guint32 int1 = 0;
guint32 int2 = 0;
if (PIKA_PARAM_SPEC_RGB (pspec)->has_alpha)
{
pika_rgba_get_uchar (rgb1,
((guchar *) &int1) + 0,
((guchar *) &int1) + 1,
((guchar *) &int1) + 2,
((guchar *) &int1) + 3);
pika_rgba_get_uchar (rgb2,
((guchar *) &int2) + 0,
((guchar *) &int2) + 1,
((guchar *) &int2) + 2,
((guchar *) &int2) + 3);
}
else
{
pika_rgb_get_uchar (rgb1,
((guchar *) &int1) + 0,
((guchar *) &int1) + 1,
((guchar *) &int1) + 2);
pika_rgb_get_uchar (rgb2,
((guchar *) &int2) + 0,
((guchar *) &int2) + 1,
((guchar *) &int2) + 2);
}
return int1 - int2;
}
}
/**
* pika_param_spec_rgb:
* @name: Canonical name of the param
* @nick: Nickname of the param
* @blurb: Brief description of param.
* @has_alpha: %TRUE if the alpha channel has relevance.
* @default_value: Value to use if none is assigned.
* @flags: a combination of #GParamFlags
*
* Creates a param spec to hold an #PikaRGB value.
* See g_param_spec_internal() for more information.
*
* Returns: (transfer full): a newly allocated #GParamSpec instance
*
* Since: 2.4
**/
GParamSpec *
pika_param_spec_rgb (const gchar *name,
const gchar *nick,
const gchar *blurb,
gboolean has_alpha,
const PikaRGB *default_value,
GParamFlags flags)
{
PikaParamSpecRGB *cspec;
cspec = g_param_spec_internal (PIKA_TYPE_PARAM_RGB,
name, nick, blurb, flags);
cspec->has_alpha = has_alpha;
if (default_value)
cspec->default_value = *default_value;
else
pika_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
return G_PARAM_SPEC (cspec);
}
/**
* pika_param_spec_rgb_get_default:
* @pspec: a #PikaParamSpecRGB.
* @default_value: return location for @pspec's default value
*
* Returns the @pspec's default color value.
*
* Since: 2.10.14
**/
void
pika_param_spec_rgb_get_default (GParamSpec *pspec,
PikaRGB *default_value)
{
g_return_if_fail (PIKA_IS_PARAM_SPEC_RGB (pspec));
g_return_if_fail (default_value != NULL);
*default_value = PIKA_PARAM_SPEC_RGB (pspec)->default_value;
}
/**
* pika_param_spec_rgb_has_alpha:
* @pspec: a #GParamSpec to hold an #PikaRGB value.
*
* Returns: %TRUE if the alpha channel is relevant.
*
* Since: 2.4
**/
gboolean
pika_param_spec_rgb_has_alpha (GParamSpec *pspec)
{
g_return_val_if_fail (PIKA_IS_PARAM_SPEC_RGB (pspec), FALSE);
return PIKA_PARAM_SPEC_RGB (pspec)->has_alpha;
}

208
libpikacolor/pikargb.h Normal file
View File

@ -0,0 +1,208 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_COLOR_H_INSIDE__) && !defined (PIKA_COLOR_COMPILATION)
#error "Only <libpikacolor/pikacolor.h> can be included directly."
#endif
#ifndef __PIKA_RGB_H__
#define __PIKA_RGB_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/*
* PIKA_TYPE_RGB
*/
#define PIKA_TYPE_RGB (pika_rgb_get_type ())
#define PIKA_VALUE_HOLDS_RGB(value) (G_TYPE_CHECK_VALUE_TYPE ((value), PIKA_TYPE_RGB))
GType pika_rgb_get_type (void) G_GNUC_CONST;
void pika_value_get_rgb (const GValue *value,
PikaRGB *rgb);
void pika_value_set_rgb (GValue *value,
const PikaRGB *rgb);
/*
* PIKA_TYPE_PARAM_RGB
*/
#define PIKA_TYPE_PARAM_RGB (pika_param_rgb_get_type ())
#define PIKA_IS_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), PIKA_TYPE_PARAM_RGB))
typedef struct _PikaParamSpecRGB PikaParamSpecRGB;
GType pika_param_rgb_get_type (void) G_GNUC_CONST;
GParamSpec * pika_param_spec_rgb (const gchar *name,
const gchar *nick,
const gchar *blurb,
gboolean has_alpha,
const PikaRGB *default_value,
GParamFlags flags);
void pika_param_spec_rgb_get_default (GParamSpec *pspec,
PikaRGB *default_value);
gboolean pika_param_spec_rgb_has_alpha (GParamSpec *pspec);
/* RGB and RGBA color types and operations taken from LibGCK */
/**
* PikaRGBCompositeMode:
* @PIKA_RGB_COMPOSITE_NONE: don't do compositing
* @PIKA_RGB_COMPOSITE_NORMAL: composite on top
* @PIKA_RGB_COMPOSITE_BEHIND: composite behind
**/
typedef enum
{
PIKA_RGB_COMPOSITE_NONE = 0,
PIKA_RGB_COMPOSITE_NORMAL,
PIKA_RGB_COMPOSITE_BEHIND
} PikaRGBCompositeMode;
void pika_rgb_set (PikaRGB *rgb,
gdouble red,
gdouble green,
gdouble blue);
void pika_rgb_set_alpha (PikaRGB *rgb,
gdouble alpha);
void pika_rgb_set_pixel (PikaRGB *rgb,
const Babl *format,
gconstpointer pixel);
void pika_rgb_get_pixel (const PikaRGB *rgb,
const Babl *format,
gpointer pixel);
void pika_rgb_set_uchar (PikaRGB *rgb,
guchar red,
guchar green,
guchar blue);
void pika_rgb_get_uchar (const PikaRGB *rgb,
guchar *red,
guchar *green,
guchar *blue);
gboolean pika_rgb_parse_name (PikaRGB *rgb,
const gchar *name,
gint len);
gboolean pika_rgb_parse_hex (PikaRGB *rgb,
const gchar *hex,
gint len);
gboolean pika_rgb_parse_css (PikaRGB *rgb,
const gchar *css,
gint len);
void pika_rgb_add (PikaRGB *rgb1,
const PikaRGB *rgb2);
void pika_rgb_subtract (PikaRGB *rgb1,
const PikaRGB *rgb2);
void pika_rgb_multiply (PikaRGB *rgb1,
gdouble factor);
gdouble pika_rgb_distance (const PikaRGB *rgb1,
const PikaRGB *rgb2);
gdouble pika_rgb_max (const PikaRGB *rgb);
gdouble pika_rgb_min (const PikaRGB *rgb);
void pika_rgb_clamp (PikaRGB *rgb);
void pika_rgb_gamma (PikaRGB *rgb,
gdouble gamma);
gdouble pika_rgb_luminance (const PikaRGB *rgb);
guchar pika_rgb_luminance_uchar (const PikaRGB *rgb);
void pika_rgb_composite (PikaRGB *color1,
const PikaRGB *color2,
PikaRGBCompositeMode mode);
/* access to the list of color names */
void pika_rgb_list_names (const gchar ***names,
PikaRGB **colors,
gint *n_colors);
void pika_rgba_set (PikaRGB *rgba,
gdouble red,
gdouble green,
gdouble blue,
gdouble alpha);
void pika_rgba_set_pixel (PikaRGB *rgba,
const Babl *format,
gconstpointer pixel);
void pika_rgba_get_pixel (const PikaRGB *rgba,
const Babl *format,
gpointer pixel);
void pika_rgba_set_uchar (PikaRGB *rgba,
guchar red,
guchar green,
guchar blue,
guchar alpha);
void pika_rgba_get_uchar (const PikaRGB *rgba,
guchar *red,
guchar *green,
guchar *blue,
guchar *alpha);
gboolean pika_rgba_parse_css (PikaRGB *rgba,
const gchar *css,
gint len);
void pika_rgba_add (PikaRGB *rgba1,
const PikaRGB *rgba2);
void pika_rgba_subtract (PikaRGB *rgba1,
const PikaRGB *rgba2);
void pika_rgba_multiply (PikaRGB *rgba,
gdouble factor);
gdouble pika_rgba_distance (const PikaRGB *rgba1,
const PikaRGB *rgba2);
/* Map D50-adapted sRGB to luminance */
/*
* The weights to compute true CIE luminance from linear red, green
* and blue as defined by the sRGB color space specs in an ICC profile
* color managed application. The weights below have been chromatically
* adapted from D65 (as specified by the sRGB color space specs)
* to D50 (as specified by D50 illuminant values in the ICC V4 specs).
*/
#define PIKA_RGB_LUMINANCE_RED (0.22248840)
#define PIKA_RGB_LUMINANCE_GREEN (0.71690369)
#define PIKA_RGB_LUMINANCE_BLUE (0.06060791)
#define PIKA_RGB_LUMINANCE(r,g,b) ((r) * PIKA_RGB_LUMINANCE_RED + \
(g) * PIKA_RGB_LUMINANCE_GREEN + \
(b) * PIKA_RGB_LUMINANCE_BLUE)
G_END_DECLS
#endif /* __PIKA_RGB_H__ */

View File

@ -0,0 +1,119 @@
/* unit tests for the color parsing routines in pikargb-parse.c
*/
#include "config.h"
#include <stdlib.h>
#include <babl/babl.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib-object.h>
#include <cairo.h>
#include "pikacolor.h"
#define DBL(c) ((gdouble)(c) / 255.0)
typedef struct
{
const gchar *str;
gboolean alpha;
gboolean fail;
const gdouble r;
const gdouble g;
const gdouble b;
const gdouble a;
} ColorSample;
static const ColorSample samples[] =
{
/* sample alpha fail red green blue alpha */
{ "#000000", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "#FFff00", FALSE, FALSE, 1.0, 1.0, 0.0, 0.0 },
{ "#6495ed", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
{ "#fff", FALSE, FALSE, 1.0, 1.0, 1.0, 0.0 },
{ "#64649595eded", FALSE, FALSE, 1.0, 1.0, 0.0, 0.0 },
{ "rgb(0,0,0)", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "rgb(100,149,237)", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
{ "rgba(100%,0,100%,0.5)", TRUE, FALSE, 255.0, 0.0, 255.0, 0.5 },
{ "rgba(100%,0,100%,0.5)", FALSE, TRUE, 255.0, 0.0, 255.0, 0.5 },
{ "rgb(100%,149,20%)", FALSE, FALSE, 1.0, DBL(149), 0.2, 0.0 },
{ "rgb(100%,149,20%)", TRUE, TRUE, 1.0, DBL(149), 0.2, 0.0 },
{ "rgb(foobar)", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "rgb(100,149,237", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "rED", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "cornflowerblue", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
{ " red", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "red ", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "red", TRUE, TRUE, 1.0, 0.0, 0.0, 0.0 },
{ "red blue", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "transparent", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "transparent", TRUE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "23foobar", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 }
};
static gint
check_failure (const ColorSample *sample,
gboolean success,
PikaRGB *rgb)
{
if (success && sample->fail)
{
g_print ("Parser succeeded for sample \"%s\" but should have failed!\n"
" parsed color: (%g, %g, %g, %g)\n",
sample->str, rgb->r, rgb->g, rgb->b, rgb->a);
return 1;
}
if (!success && !sample->fail)
{
g_print ("Parser failed for sample \"%s\" but should have succeeded!\n"
" parsed color: (%g, %g, %g, %g)\n",
sample->str, rgb->r, rgb->g, rgb->b, rgb->a);
return 1;
}
return 0;
}
int
main (void)
{
gint failures = 0;
gint i;
g_print ("\nTesting the PIKA color parser ...\n");
for (i = 0; i < G_N_ELEMENTS (samples); i++)
{
PikaRGB rgb = { 0.0, 0.0, 0.0, 0.0 };
gboolean success;
if (samples[i].alpha)
success = pika_rgba_parse_css (&rgb, samples[i].str, -1);
else
success = pika_rgb_parse_css (&rgb, samples[i].str, -1);
failures += check_failure (samples + i, success, &rgb);
}
if (failures)
{
g_print ("%d out of %d samples failed!\n\n",
failures, (int)G_N_ELEMENTS (samples));
return EXIT_FAILURE;
}
else
{
g_print ("All %d samples passed.\n\n", (int)G_N_ELEMENTS (samples));
return EXIT_SUCCESS;
}
}