Code

Translations. French translation minor update.
[inkscape.git] / src / color.cpp
index 77fca3b4b338140b09cad3e8696f8fe16dc07acd..54af89ae5d5c92665b458a5cf5666d11179a7d5b 100644 (file)
@@ -1,11 +1,12 @@
 #define __SP_COLOR_C__
 
 /** \file
- * Colors and colorspaces.
+ * Colors.
  *
  * Author:
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   bulia byak <buliabyak@users.sf.net>
+ *   Jon A. Cruz <jon@joncruz.org>
  *
  * Copyright (C) 2001-2002 Lauris Kaplinski
  * Copyright (C) 2001 Ximian, Inc.
 
 #include <math.h>
 #include "color.h"
+#include "svg/svg-icc-color.h"
+#include "svg/svg-color.h"
 
-/// A color space is just a name.
-struct SPColorSpace {
-    gchar const *name;
-};
+#include "svg/css-ostringstream.h"
 
-static SPColorSpace const RGB = {"RGB"};
-static SPColorSpace const CMYK = {"CMYK"};
+using Inkscape::CSSOStringStream;
+using std::vector;
 
-/**
- * Returns one of three values depending on if color is valid and if it
- * has a valid color space. Likely redundant as soon as this is C++.
- */
-SPColorSpaceClass
-sp_color_get_colorspace_class(SPColor const *color)
-{
-    g_return_val_if_fail (color != NULL, SP_COLORSPACE_CLASS_INVALID);
+static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second );
 
-    if (color->colorspace == &RGB) return SP_COLORSPACE_CLASS_PROCESS;
-    if (color->colorspace == &CMYK) return SP_COLORSPACE_CLASS_PROCESS;
+#define PROFILE_EPSILON 0.00000001
 
-    return SP_COLORSPACE_CLASS_UNKNOWN;
+SPColor::SPColor() :
+    icc(0)
+{
+    v.c[0] = 0;
+    v.c[1] = 0;
+    v.c[2] = 0;
 }
 
-/**
- * Returns the SPColorSpaceType corresponding to color's color space.
- * \todo color->colorspace should simply be a named enum.
- */
-SPColorSpaceType
-sp_color_get_colorspace_type(SPColor const *color)
+SPColor::SPColor( SPColor const& other ) :
+    icc(0)
 {
-    g_return_val_if_fail (color != NULL, SP_COLORSPACE_TYPE_INVALID);
+    *this = other;
+}
 
-    if (color->colorspace == &RGB) return SP_COLORSPACE_TYPE_RGB;
-    if (color->colorspace == &CMYK) return SP_COLORSPACE_TYPE_CMYK;
+SPColor::SPColor( float r, float g, float b ) :
+    icc(0)
+{
+    set( r, g, b );
+}
 
-    return SP_COLORSPACE_TYPE_UNKNOWN;
+SPColor::SPColor( guint32 value ) :
+    icc(0)
+{
+    set( value );
 }
 
-/**
- * Shallow copy of color struct with NULL check.
- */
-void
-sp_color_copy(SPColor *dst, SPColor const *src)
+SPColor::~SPColor()
 {
-    g_return_if_fail (dst != NULL);
-    g_return_if_fail (src != NULL);
+    delete icc;
+    icc = 0;
+}
 
-    *dst = *src;
+
+SPColor& SPColor::operator= (SPColor const& other)
+{
+    SVGICCColor* tmp_icc = other.icc ? new SVGICCColor(*other.icc) : 0;
+
+    v.c[0] = other.v.c[0];
+    v.c[1] = other.v.c[1];
+    v.c[2] = other.v.c[2];
+    if ( icc ) {
+        delete icc;
+    }
+    icc = tmp_icc;
+
+    return *this;
 }
 
+
 /**
- * Returns TRUE if c0 or c1 is NULL, or if colors/opacities differ.
+ * Returns true if colors match.
  */
-gboolean
-sp_color_is_equal (SPColor const *c0, SPColor const *c1)
+bool SPColor::operator == (SPColor const& other) const
 {
-    g_return_val_if_fail (c0 != NULL, TRUE);
-    g_return_val_if_fail (c1 != NULL, TRUE);
+    bool match = (v.c[0] != other.v.c[0])
+        && (v.c[1] != other.v.c[1])
+        && (v.c[2] != other.v.c[2]);
 
-    if (c0->colorspace != c1->colorspace) return FALSE;
-    if (c0->v.c[0] != c1->v.c[0]) return FALSE;
-    if (c0->v.c[1] != c1->v.c[1]) return FALSE;
-    if (c0->v.c[2] != c1->v.c[2]) return FALSE;
-    if ((c0->colorspace == &CMYK) && (c0->v.c[3] != c1->v.c[3])) return FALSE;
+    match &= profileMatches( icc, other.icc );
 
-    return TRUE;
+    return match;
 }
 
 /**
- * Returns TRUE if no RGB value differs epsilon or more in both colors,
- * with CMYK aditionally comparing opacity, or if c0 or c1 is NULL.
- * \note Do we want the latter?
+ * Returns true if no RGB value differs epsilon or more in both colors,
+ * false otherwise.
  */
-gboolean
-sp_color_is_close (SPColor const *c0, SPColor const *c1, float epsilon)
+bool SPColor::isClose( SPColor const& other, float epsilon ) const
 {
-    g_return_val_if_fail (c0 != NULL, TRUE);
-    g_return_val_if_fail (c1 != NULL, TRUE);
+    bool match = false;
+
+    match = (fabs((v.c[0]) - (other.v.c[0])) < epsilon)
+        && (fabs((v.c[1]) - (other.v.c[1])) < epsilon)
+        && (fabs((v.c[2]) - (other.v.c[2])) < epsilon);
 
-    if (c0->colorspace != c1->colorspace) return FALSE;
-    if (fabs ((c0->v.c[0]) - (c1->v.c[0])) >= epsilon) return FALSE;
-    if (fabs ((c0->v.c[1]) - (c1->v.c[1])) >= epsilon) return FALSE;
-    if (fabs ((c0->v.c[2]) - (c1->v.c[2])) >= epsilon) return FALSE;
-    if ((c0->colorspace == &CMYK) && (fabs ((c0->v.c[3]) - (c1->v.c[3])) >= epsilon)) return FALSE;
+    match &= profileMatches( icc, other.icc );
 
-    return TRUE;
+    return match;
+}
+
+static bool profileMatches( SVGICCColor const* first, SVGICCColor const* second ) {
+    bool match = false;
+    if ( !first && !second ) {
+        match = true;
+    } else {
+        match = first && second
+            && (first->colorProfile == second->colorProfile)
+            && (first->colors.size() == second->colors.size());
+        if ( match ) {
+            for ( guint i = 0; i < first->colors.size(); i++ ) {
+                match &= (fabs(first->colors[i] - second->colors[i]) < PROFILE_EPSILON);
+            }
+        }
+    }
+    return match;
 }
 
 /**
  * Sets RGB values and colorspace in color.
- * \pre color != NULL && 0 <={r,g,b}<=1
+ * \pre 0 <={r,g,b}<=1
  */
-void
-sp_color_set_rgb_float(SPColor *color, float r, float g, float b)
+void SPColor::set( float r, float g, float b )
 {
-    g_return_if_fail(color != NULL);
     g_return_if_fail(r >= 0.0);
     g_return_if_fail(r <= 1.0);
     g_return_if_fail(g >= 0.0);
@@ -119,79 +138,35 @@ sp_color_set_rgb_float(SPColor *color, float r, float g, float b)
     g_return_if_fail(b >= 0.0);
     g_return_if_fail(b <= 1.0);
 
-    color->colorspace = &RGB;
-    color->v.c[0] = r;
-    color->v.c[1] = g;
-    color->v.c[2] = b;
-    color->v.c[3] = 0;
+    // TODO clear icc if set?
+    v.c[0] = r;
+    v.c[1] = g;
+    v.c[2] = b;
 }
 
 /**
  * Converts 32bit value to RGB floats and sets color.
- * \pre color != NULL
  */
-void
-sp_color_set_rgb_rgba32(SPColor *color, guint32 value)
+void SPColor::set( guint32 value )
 {
-    g_return_if_fail (color != NULL);
-
-    color->colorspace = &RGB;
-    color->v.c[0] = (value >> 24) / 255.0F;
-    color->v.c[1] = ((value >> 16) & 0xff) / 255.0F;
-    color->v.c[2] = ((value >> 8) & 0xff) / 255.0F;
-    color->v.c[3] = 0;
-}
-
-/**
- * Sets CMYK values and colorspace in color.
- * \pre color != NULL && 0 <={c,m,y,k}<=1
- */
-void
-sp_color_set_cmyk_float(SPColor *color, float c, float m, float y, float k)
-{
-    g_return_if_fail(color != NULL);
-    g_return_if_fail(c >= 0.0);
-    g_return_if_fail(c <= 1.0);
-    g_return_if_fail(m >= 0.0);
-    g_return_if_fail(m <= 1.0);
-    g_return_if_fail(y >= 0.0);
-    g_return_if_fail(y <= 1.0);
-    g_return_if_fail(k >= 0.0);
-    g_return_if_fail(k <= 1.0);
-
-    color->colorspace = &CMYK;
-    color->v.c[0] = c;
-    color->v.c[1] = m;
-    color->v.c[2] = y;
-    color->v.c[3] = k;
+    // TODO clear icc if set?
+    v.c[0] = (value >> 24) / 255.0F;
+    v.c[1] = ((value >> 16) & 0xff) / 255.0F;
+    v.c[2] = ((value >> 8) & 0xff) / 255.0F;
 }
 
 /**
  * Convert SPColor with integer alpha value to 32bit RGBA value.
- * \pre color != NULL && alpha < 256
+ * \pre alpha < 256
  */
-guint32
-sp_color_get_rgba32_ualpha(SPColor const *color, guint32 alpha)
+guint32 SPColor::toRGBA32( gint alpha ) const
 {
-    guint32 rgba;
-
-    g_return_val_if_fail (color != NULL, 0x0);
     g_return_val_if_fail (alpha <= 0xff, 0x0);
 
-    if (color->colorspace == &RGB) {
-        rgba = SP_RGBA32_U_COMPOSE(SP_COLOR_F_TO_U(color->v.c[0]),
-                                   SP_COLOR_F_TO_U(color->v.c[1]),
-                                   SP_COLOR_F_TO_U(color->v.c[2]),
-                                   alpha);
-    } else {
-        float rgb[3];
-        sp_color_get_rgb_floatv (color, rgb);
-        rgba = SP_RGBA32_U_COMPOSE(SP_COLOR_F_TO_U(rgb[0]),
-                                   SP_COLOR_F_TO_U(rgb[1]),
-                                   SP_COLOR_F_TO_U(rgb[2]),
-                                   alpha);
-    }
-
+    guint32 rgba = SP_RGBA32_U_COMPOSE( SP_COLOR_F_TO_U(v.c[0]),
+                                        SP_COLOR_F_TO_U(v.c[1]),
+                                        SP_COLOR_F_TO_U(v.c[2]),
+                                        alpha );
     return rgba;
 }
 
@@ -199,16 +174,41 @@ sp_color_get_rgba32_ualpha(SPColor const *color, guint32 alpha)
  * Convert SPColor with float alpha value to 32bit RGBA value.
  * \pre color != NULL && 0 <= alpha <= 1
  */
-guint32
-sp_color_get_rgba32_falpha(SPColor const *color, float alpha)
+guint32 SPColor::toRGBA32( gdouble alpha ) const
 {
-    g_return_val_if_fail(color != NULL, 0x0);
     g_return_val_if_fail(alpha >= 0.0, 0x0);
     g_return_val_if_fail(alpha <= 1.0, 0x0);
 
-    return sp_color_get_rgba32_ualpha(color, SP_COLOR_F_TO_U(alpha));
+    return toRGBA32( static_cast<gint>(SP_COLOR_F_TO_U(alpha)) );
 }
 
+std::string SPColor::toString() const
+{
+    CSSOStringStream css;
+
+    std::string result;
+    char tmp[64] = {0};
+
+    sp_svg_write_color(tmp, sizeof(tmp), toRGBA32(0x0ff));
+    css << tmp;
+
+    if ( icc ) {
+        if ( !css.str().empty() ) {
+            css << " ";
+        }
+        css << "icc-color(" << icc->colorProfile;
+        for (vector<double>::const_iterator i(icc->colors.begin()),
+                 iEnd(icc->colors.end());
+             i != iEnd; ++i) {
+            css << ", " << *i;
+        }
+        css << ')';
+    }
+
+    return css.str();
+}
+
+
 /**
  * Fill rgb float array with values from SPColor.
  * \pre color != NULL && rgb != NULL && rgb[0-2] is meaningful
@@ -219,17 +219,9 @@ sp_color_get_rgb_floatv(SPColor const *color, float *rgb)
     g_return_if_fail (color != NULL);
     g_return_if_fail (rgb != NULL);
 
-    if (color->colorspace == &RGB) {
-        rgb[0] = color->v.c[0];
-        rgb[1] = color->v.c[1];
-        rgb[2] = color->v.c[2];
-    } else if (color->colorspace == &CMYK) {
-        sp_color_cmyk_to_rgb_floatv(rgb,
-                                    color->v.c[0],
-                                    color->v.c[1],
-                                    color->v.c[2],
-                                    color->v.c[3]);
-    }
+    rgb[0] = color->v.c[0];
+    rgb[1] = color->v.c[1];
+    rgb[2] = color->v.c[2];
 }
 
 /**
@@ -242,17 +234,10 @@ sp_color_get_cmyk_floatv(SPColor const *color, float *cmyk)
     g_return_if_fail (color != NULL);
     g_return_if_fail (cmyk != NULL);
 
-    if (color->colorspace == &CMYK) {
-        cmyk[0] = color->v.c[0];
-        cmyk[1] = color->v.c[1];
-        cmyk[2] = color->v.c[2];
-        cmyk[3] = color->v.c[3];
-    } else if (color->colorspace == &RGB) {
-        sp_color_rgb_to_cmyk_floatv(cmyk,
-                                    color->v.c[0],
-                                    color->v.c[1],
-                                    color->v.c[2]);
-    }
+    sp_color_rgb_to_cmyk_floatv( cmyk,
+                                 color->v.c[0],
+                                 color->v.c[1],
+                                 color->v.c[2] );
 }
 
 /* Plain mode helpers */
@@ -290,6 +275,8 @@ sp_color_rgb_to_hsv_floatv (float *hsv, float r, float g, float b)
 
         if (hsv[0] < 0) hsv[0] += 1.0;
     }
+    else
+        hsv[0] = 0.0;
 }
 
 /**
@@ -465,4 +452,4 @@ sp_color_cmyk_to_rgb_floatv (float *rgb, float c, float m, float y, float k)
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :