You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
8.1 KiB
361 lines
8.1 KiB
|
|
/*
|
|
Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#define DEBUG_KP_COLOR 0
|
|
|
|
|
|
#include <kpcolor.h>
|
|
|
|
#include <tqdatastream.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
// public static
|
|
const int kpColor::Exact = 0;
|
|
|
|
// public static
|
|
const kpColor kpColor::invalid; // TODO: what's wrong with explicitly specifying () constructor?
|
|
const kpColor kpColor::transparent (0, 0, 0, true/*isTransparent*/);
|
|
|
|
|
|
kpColor::kpColor ()
|
|
: m_rgbaIsValid (false),
|
|
m_colorCacheIsValid (false)
|
|
{
|
|
}
|
|
|
|
kpColor::kpColor (int red, int green, int blue, bool isTransparent)
|
|
: m_colorCacheIsValid (false)
|
|
{
|
|
if (red < 0 || red > 255 ||
|
|
green < 0 || green > 255 ||
|
|
blue < 0 || blue > 255)
|
|
{
|
|
kdError () << "kpColor::<ctor>(r=" << red
|
|
<< ",g=" << green
|
|
<< ",b=" << blue
|
|
<< ",t=" << isTransparent
|
|
<< ") passed out of range values" << endl;
|
|
m_rgbaIsValid = false;
|
|
return;
|
|
}
|
|
|
|
m_rgba = tqRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/);
|
|
m_rgbaIsValid = true;
|
|
}
|
|
|
|
kpColor::kpColor (const TQRgb &rgba)
|
|
: m_colorCacheIsValid (false)
|
|
{
|
|
if (tqAlpha (rgba) > 0 && tqAlpha (rgba) < 255)
|
|
{
|
|
kdError () << "kpColor::<ctor>(TQRgb) passed translucent alpha "
|
|
<< tqAlpha (rgba)
|
|
<< " - trying to recover"
|
|
<< endl;
|
|
|
|
// Forget the alpha channel - make it opaque
|
|
m_rgba = tqRgb (tqRed (m_rgba), tqGreen (m_rgba), tqBlue (m_rgba));
|
|
m_rgbaIsValid = true;
|
|
}
|
|
else
|
|
{
|
|
m_rgba = rgba;
|
|
m_rgbaIsValid = true;
|
|
}
|
|
}
|
|
|
|
kpColor::kpColor (const kpColor &rhs)
|
|
: m_rgbaIsValid (rhs.m_rgbaIsValid),
|
|
m_rgba (rhs.m_rgba),
|
|
m_colorCacheIsValid (rhs.m_colorCacheIsValid),
|
|
m_colorCache (rhs.m_colorCache)
|
|
{
|
|
}
|
|
|
|
// friend
|
|
TQDataStream &operator<< (TQDataStream &stream, const kpColor &color)
|
|
{
|
|
stream << int (color.m_rgbaIsValid) << int (color.m_rgba);
|
|
|
|
return stream;
|
|
}
|
|
|
|
// friend
|
|
TQDataStream &operator>> (TQDataStream &stream, kpColor &color)
|
|
{
|
|
int a, b;
|
|
stream >> a >> b;
|
|
color.m_rgbaIsValid = a;
|
|
color.m_rgba = b;
|
|
|
|
color.m_colorCacheIsValid = false;
|
|
|
|
return stream;
|
|
}
|
|
|
|
kpColor &kpColor::operator= (const kpColor &rhs)
|
|
{
|
|
// (as soon as you add a ptr, you won't be complaining to me that this
|
|
// method was unnecessary :))
|
|
|
|
if (this == &rhs)
|
|
return *this;
|
|
|
|
m_rgbaIsValid = rhs.m_rgbaIsValid;
|
|
m_rgba = rhs.m_rgba;
|
|
m_colorCacheIsValid = rhs.m_colorCacheIsValid;
|
|
m_colorCache = rhs.m_colorCache;
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool kpColor::operator== (const kpColor &rhs) const
|
|
{
|
|
return isSimilarTo (rhs, kpColor::Exact);
|
|
}
|
|
|
|
bool kpColor::operator!= (const kpColor &rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
|
|
template <class dtype>
|
|
inline dtype square (dtype val)
|
|
{
|
|
return val * val;
|
|
}
|
|
|
|
// public static
|
|
int kpColor::processSimilarity (double colorSimilarity)
|
|
{
|
|
// sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3)
|
|
// dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3)
|
|
|
|
return int (square (colorSimilarity) * (square (255) * 3));
|
|
}
|
|
|
|
bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const
|
|
{
|
|
// Are we the same?
|
|
if (this == &rhs)
|
|
return true;
|
|
|
|
|
|
// Do we dither in terms of validity?
|
|
if (isValid () != rhs.isValid ())
|
|
return false;
|
|
|
|
// Are both of us invalid?
|
|
if (!isValid ())
|
|
return true;
|
|
|
|
// --- both are now valid ---
|
|
|
|
|
|
if (isTransparent () != rhs.isTransparent ())
|
|
return false;
|
|
|
|
// Are both of us transparent?
|
|
if (isTransparent ())
|
|
return true;
|
|
|
|
// --- both are now valid and opaque ---
|
|
|
|
|
|
if (m_rgba == rhs.m_rgba)
|
|
return true;
|
|
|
|
|
|
if (processedSimilarity == kpColor::Exact)
|
|
return false;
|
|
else
|
|
{
|
|
return (square (tqRed (m_rgba) - tqRed (rhs.m_rgba)) +
|
|
square (tqGreen (m_rgba) - tqGreen (rhs.m_rgba)) +
|
|
square (tqBlue (m_rgba) - tqBlue (rhs.m_rgba))
|
|
<= processedSimilarity);
|
|
}
|
|
}
|
|
|
|
kpColor::~kpColor ()
|
|
{
|
|
}
|
|
|
|
|
|
// public
|
|
bool kpColor::isValid () const
|
|
{
|
|
return m_rgbaIsValid;
|
|
}
|
|
|
|
|
|
// public
|
|
int kpColor::red () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::red() called with invalid kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
if (isTransparent ())
|
|
{
|
|
kdError () << "kpColor::red() called with transparent kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
return tqRed (m_rgba);
|
|
}
|
|
|
|
// public
|
|
int kpColor::green () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::green() called with invalid kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
if (isTransparent ())
|
|
{
|
|
kdError () << "kpColor::green() called with transparent kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
return tqGreen (m_rgba);
|
|
}
|
|
|
|
// public
|
|
int kpColor::blue () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::blue() called with invalid kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
if (isTransparent ())
|
|
{
|
|
kdError () << "kpColor::blue() called with transparent kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
return tqBlue (m_rgba);
|
|
}
|
|
|
|
// public
|
|
int kpColor::alpha () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::alpha() called with invalid kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
const int alpha = tqAlpha (m_rgba);
|
|
|
|
if (alpha > 0 && alpha < 255)
|
|
{
|
|
kdError () << "kpColor::alpha() called with translucent kpColor alpha=" << alpha << endl;
|
|
|
|
// no translucency
|
|
return alpha ? 255 : 0;
|
|
}
|
|
else
|
|
{
|
|
return alpha;
|
|
}
|
|
}
|
|
|
|
// public
|
|
bool kpColor::isTransparent () const
|
|
{
|
|
return (alpha () == 0);
|
|
}
|
|
|
|
// public
|
|
bool kpColor::isOpaque () const
|
|
{
|
|
return (alpha () == 255);
|
|
}
|
|
|
|
|
|
// public
|
|
TQRgb kpColor::toTQRgb () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::toTQRgb() called with invalid kpColor" << endl;
|
|
return 0;
|
|
}
|
|
|
|
return m_rgba;
|
|
}
|
|
|
|
// public
|
|
const TQColor &kpColor::toTQColor () const
|
|
{
|
|
if (!m_rgbaIsValid)
|
|
{
|
|
kdError () << "kpColor::toTQColor() called with invalid kpColor" << endl;
|
|
return TQt::black;
|
|
}
|
|
|
|
if (m_colorCacheIsValid)
|
|
return m_colorCache;
|
|
|
|
if (tqAlpha (m_rgba) < 255)
|
|
{
|
|
kdError () << "kpColor::toTQColor() called with not fully opaque kpColor alpha="
|
|
<< tqAlpha (m_rgba)
|
|
<< endl;
|
|
return TQt::black;
|
|
}
|
|
|
|
m_colorCache = TQColor (m_rgba);
|
|
if (!m_colorCache.isValid ())
|
|
{
|
|
kdError () << "kpColor::toTQColor () internal error - could not return valid TQColor"
|
|
<< endl;
|
|
return TQt::black;
|
|
}
|
|
|
|
m_colorCacheIsValid = true;
|
|
|
|
return m_colorCache;
|
|
}
|
|
|
|
// public
|
|
TQColor kpColor::maskColor () const
|
|
{
|
|
return isTransparent () ? TQt::color0 : TQt::color1;
|
|
}
|