File indexing completed on 2024-05-05 04:21:07

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 
0029 #define DEBUG_KP_COLOR 0
0030 
0031 
0032 #include "kpColor.h"
0033 
0034 #include <QDataStream>
0035 
0036 #include "kpLogCategories.h"
0037 
0038 //---------------------------------------------------------------------
0039 
0040 kpColor::kpColor()
0041   : m_rgbaIsValid(false),
0042     m_rgba(0),
0043     m_colorCacheIsValid(false)
0044 {
0045 }
0046 
0047 //---------------------------------------------------------------------
0048 
0049 kpColor::kpColor (int red, int green, int blue, bool isTransparent)
0050   : m_rgba(0), m_colorCacheIsValid(false)
0051 {
0052 #if DEBUG_KP_COLOR
0053     qCDebug(kpLogImagelib) << "kpColor::<ctor>(r=" << red << ",g=" << green << ",b=" << blue
0054               << ",isTrans=" << isTransparent << ")";
0055 #endif
0056     if (red < 0 || red > 255 ||
0057         green < 0 || green > 255 ||
0058         blue < 0 || blue > 255)
0059     {
0060         qCCritical(kpLogImagelib) << "kpColor::<ctor>(r=" << red
0061                    << ",g=" << green
0062                    << ",b=" << blue
0063                    << ",t=" << isTransparent
0064                    << ") passed out of range values";
0065         m_rgbaIsValid = false;
0066         return;
0067     }
0068 
0069     m_rgba = qRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/);
0070     m_rgbaIsValid = true;
0071 }
0072 
0073 //---------------------------------------------------------------------
0074 
0075 kpColor::kpColor (const QRgb &rgba)
0076     : m_colorCacheIsValid (false)
0077 {
0078 #if DEBUG_KP_COLOR
0079     qCDebug(kpLogImagelib) << "kpColor::<ctor>(rgba=" << (int *) rgba << ")";
0080 #endif
0081     m_rgba = rgba;
0082     m_rgbaIsValid = true;
0083 }
0084 
0085 //---------------------------------------------------------------------
0086 
0087 kpColor::kpColor (const kpColor &rhs)
0088     :  m_rgbaIsValid (rhs.m_rgbaIsValid),
0089        m_rgba (rhs.m_rgba),
0090        m_colorCacheIsValid (rhs.m_colorCacheIsValid),
0091        m_colorCache (rhs.m_colorCache)
0092 {
0093 #if DEBUG_KP_COLOR
0094     qCDebug(kpLogImagelib) << "kpColor::<copy_ctor>()";
0095 #endif
0096 }
0097 
0098 //---------------------------------------------------------------------
0099 
0100 // friend
0101 QDataStream &operator<< (QDataStream &stream, const kpColor &color)
0102 {
0103     stream << int (color.m_rgbaIsValid) << int (color.m_rgba);
0104 
0105     return stream;
0106 }
0107 
0108 //---------------------------------------------------------------------
0109 
0110 // friend
0111 QDataStream &operator>> (QDataStream &stream, kpColor &color)
0112 {
0113     int a, b;
0114     stream >> a >> b;
0115     color.m_rgbaIsValid = a;
0116     color.m_rgba = static_cast<unsigned int> (b);
0117 
0118     color.m_colorCacheIsValid = false;
0119 
0120     return stream;
0121 }
0122 
0123 //---------------------------------------------------------------------
0124 
0125 kpColor &kpColor::operator= (const kpColor &rhs)
0126 {
0127     // (as soon as you add a ptr, you won't be complaining to me that this
0128     //  method was unnecessary :))
0129 
0130     if (this == &rhs) {
0131         return *this;
0132     }
0133 
0134     m_rgbaIsValid = rhs.m_rgbaIsValid;
0135     m_rgba = rhs.m_rgba;
0136     m_colorCacheIsValid = rhs.m_colorCacheIsValid;
0137     m_colorCache = rhs.m_colorCache;
0138 
0139     return *this;
0140 }
0141 
0142 bool kpColor::operator== (const kpColor &rhs) const
0143 {
0144     return isSimilarTo (rhs, kpColor::Exact);
0145 }
0146 
0147 bool kpColor::operator!= (const kpColor &rhs) const
0148 {
0149     return !(*this == rhs);
0150 }
0151 
0152 //---------------------------------------------------------------------
0153 
0154 
0155 template <class dtype>
0156 inline dtype square (dtype val)
0157 {
0158     return val * val;
0159 }
0160 
0161 //---------------------------------------------------------------------
0162 
0163 // public static
0164 int kpColor::processSimilarity (double colorSimilarity)
0165 {
0166     // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity       * sqrt (255 ^ 2 * 3)
0167     //       dr ^ 2 + dg ^ 2 + db ^ 2  <= (colorSimilarity ^ 2) * (255 ^ 2 * 3)
0168 
0169     return int (square (colorSimilarity) * (square (255) * 3));
0170 }
0171 
0172 //---------------------------------------------------------------------
0173 
0174 bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const
0175 {
0176     // Are we the same?
0177     if (this == &rhs) {
0178         return true;
0179     }
0180 
0181 
0182     // Do we dither in terms of validity?
0183     if (isValid () != rhs.isValid ()) {
0184         return false;
0185     }
0186 
0187     // Are both of us invalid?
0188     if (!isValid ()) {
0189         return true;
0190     }
0191 
0192     // --- both are now valid ---
0193 
0194     if (m_rgba == rhs.m_rgba) {
0195         return true;
0196     }
0197 
0198     if (processedSimilarity == kpColor::Exact) {
0199         return false;
0200     }
0201 
0202 
0203     return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) +
0204             square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) +
0205             square (qBlue (m_rgba) - qBlue (rhs.m_rgba))
0206             <= processedSimilarity);
0207 
0208 }
0209 
0210 //---------------------------------------------------------------------
0211 
0212 // public
0213 bool kpColor::isValid () const
0214 {
0215     return m_rgbaIsValid;
0216 }
0217 
0218 //---------------------------------------------------------------------
0219 
0220 // public
0221 int kpColor::red () const
0222 {
0223     if (!m_rgbaIsValid)
0224     {
0225         qCCritical(kpLogImagelib) << "kpColor::red() called with invalid kpColor";
0226         return 0;
0227     }
0228 
0229     return qRed (m_rgba);
0230 }
0231 
0232 //---------------------------------------------------------------------
0233 
0234 // public
0235 int kpColor::green () const
0236 {
0237     if (!m_rgbaIsValid)
0238     {
0239         qCCritical(kpLogImagelib) << "kpColor::green() called with invalid kpColor";
0240         return 0;
0241     }
0242 
0243     return qGreen (m_rgba);
0244 }
0245 
0246 //---------------------------------------------------------------------
0247 
0248 // public
0249 int kpColor::blue () const
0250 {
0251     if (!m_rgbaIsValid)
0252     {
0253         qCCritical(kpLogImagelib) << "kpColor::blue() called with invalid kpColor";
0254         return 0;
0255     }
0256 
0257     return qBlue (m_rgba);
0258 }
0259 
0260 //---------------------------------------------------------------------
0261 
0262 // public
0263 int kpColor::alpha () const
0264 {
0265     if (!m_rgbaIsValid)
0266     {
0267         qCCritical(kpLogImagelib) << "kpColor::alpha() called with invalid kpColor";
0268         return 0;
0269     }
0270 
0271     return qAlpha (m_rgba);
0272 }
0273 
0274 //---------------------------------------------------------------------
0275 
0276 // public
0277 bool kpColor::isTransparent () const
0278 {
0279     return (alpha () == 0);
0280 }
0281 
0282 //---------------------------------------------------------------------
0283 
0284 // public
0285 QRgb kpColor::toQRgb () const
0286 {
0287     if (!m_rgbaIsValid)
0288     {
0289         qCCritical(kpLogImagelib) << "kpColor::toQRgb() called with invalid kpColor";
0290         return 0;
0291     }
0292 
0293     return m_rgba;
0294 }
0295 
0296 //---------------------------------------------------------------------
0297 
0298 // public
0299 QColor kpColor::toQColor () const
0300 {
0301     if (!m_rgbaIsValid)
0302     {
0303         qCCritical(kpLogImagelib) << "kpColor::toQColor() called with invalid kpColor";
0304         return Qt::black;
0305     }
0306 
0307     if (m_colorCacheIsValid) {
0308         return m_colorCache;
0309     }
0310 
0311     m_colorCache = QColor(qRed(m_rgba), qGreen(m_rgba), qBlue(m_rgba), qAlpha(m_rgba));
0312     m_colorCacheIsValid = true;
0313 
0314     return m_colorCache;
0315 }
0316 
0317 //---------------------------------------------------------------------