File indexing completed on 2024-05-19 04:22:56

0001 
0002 /*
0003    Copyright (c) 2007 Mike Gashler <gashlerm@yahoo.com>
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 // TODO: Clarence's code review
0029 
0030 #include "kpEffectHSV.h"
0031 
0032 #include <cmath>
0033 
0034 #include <QImage>
0035 
0036 #include "kpLogCategories.h"
0037 
0038 #include "pixmapfx/kpPixmapFX.h"
0039 
0040 
0041 static void ColorToHSV(unsigned int c, float* pHue, float* pSaturation, float* pValue)
0042 {
0043     int r = qRed(c);
0044     int g = qGreen(c);
0045     int b = qBlue(c);
0046     int min{};
0047     if(b >= g && b >= r)
0048     {
0049         // Blue
0050         min = qMin(r, g);
0051         if(b != min)
0052         {
0053             *pHue = static_cast<float> (r - g) / ((b - min) * 6) + static_cast<float> (2) / 3;
0054             *pSaturation = 1.0f - static_cast<float> (min) / static_cast<float> (b);
0055         }
0056         else
0057         {
0058             *pHue = 0;
0059             *pSaturation = 0;
0060         }
0061         *pValue = static_cast<float> (b) / 255;
0062     }
0063     else if(g >= r)
0064     {
0065         // Green
0066         min = qMin(b, r);
0067         if(g != min)
0068         {
0069             *pHue = static_cast<float> (b - r) / ((g - min) * 6) + static_cast<float> (1) / 3;
0070             *pSaturation = 1.0f - static_cast<float> (min) / static_cast<float> (g);
0071         }
0072         else
0073         {
0074             *pHue = 0;
0075             *pSaturation = 0;
0076         }
0077         *pValue = static_cast<float> (g) / 255;
0078     }
0079     else
0080     {
0081         // Red
0082         min = qMin(g, b);
0083         if(r != min)
0084         {
0085             *pHue = static_cast<float> (g - b) / ((r - min) * 6);
0086             if(*pHue < 0) {
0087                 (*pHue) += 1.0f;
0088             }
0089             *pSaturation = 1.0f - static_cast<float> (min) / static_cast<float> (r);
0090         }
0091         else
0092         {
0093             *pHue = 0;
0094             *pSaturation = 0;
0095         }
0096         *pValue = static_cast<float> (r) / 255;
0097     }
0098 }
0099 
0100 static unsigned int HSVToColor(int alpha, float hue, float saturation, float value)
0101 {
0102     hue *= 5.999999f;
0103     int h = static_cast<int> (hue);
0104     float f = hue - h;
0105     float p = value * (1.0 - saturation);
0106     float q = value * (1.0 - ((h & 1) == 0 ? 1.0 - f : f) * saturation);
0107     switch(h)
0108     {
0109         case 0: return qRgba(static_cast<int> (value * 255.999999),
0110                              static_cast<int> (q * 255.999999),
0111                              static_cast<int> (p * 255.999999), alpha);
0112 
0113         case 1: return qRgba(static_cast<int> (q * 255.999999),
0114                              static_cast<int> (value * 255.999999),
0115                              static_cast<int> (p * 255.999999), alpha);
0116 
0117         case 2: return qRgba(static_cast<int> (p * 255.999999),
0118                              static_cast<int> (value * 255.999999),
0119                              static_cast<int> (q * 255.999999), alpha);
0120 
0121         case 3: return qRgba(static_cast<int> (p * 255.999999),
0122                              static_cast<int> (q * 255.999999),
0123                              static_cast<int> (value * 255.999999), alpha);
0124 
0125         case 4: return qRgba(static_cast<int> (q * 255.999999),
0126                              static_cast<int> (p * 255.999999),
0127                              static_cast<int> (value * 255.999999), alpha);
0128 
0129         case 5: return qRgba(static_cast<int> (value * 255.999999),
0130                              static_cast<int> (p * 255.999999),
0131                              static_cast<int> (q * 255.999999), alpha);
0132     }
0133     return qRgba(0, 0, 0, alpha);
0134 }
0135 
0136 static QRgb AdjustHSVInternal (QRgb pix, double hueDiv360, double saturation, double value)
0137 {
0138     float h, s, v;
0139     ::ColorToHSV(pix, &h, &s, &v);
0140     
0141     const int alpha = qAlpha(pix);
0142 
0143     h += static_cast<float> (hueDiv360);
0144     h -= std::floor(h);
0145 
0146     s = qMax(0.0f, qMin(static_cast<float>(1), s + static_cast<float> (saturation)));
0147 
0148     v = qMax(0.0f, qMin(static_cast<float>(1), v + static_cast<float> (value)));
0149 
0150     return ::HSVToColor(alpha, h, s, v);
0151 }
0152 
0153 static void AdjustHSV (QImage* pImage, double hue, double saturation, double value)
0154 {
0155     hue /= 360;
0156 
0157     if (pImage->depth () > 8)
0158     {
0159         for (int y = 0; y < pImage->height (); y++)
0160         {
0161             for (int x = 0; x < pImage->width (); x++)
0162             {
0163                 QRgb pix = pImage->pixel (x, y);
0164                 pix = ::AdjustHSVInternal (pix, hue, saturation, value);
0165                 pImage->setPixel (x, y, pix);
0166             }
0167         }
0168     }
0169     else
0170     {
0171         for (int i = 0; i < pImage->colorCount (); i++)
0172         {
0173             QRgb pix = pImage->color (i);
0174             pix = ::AdjustHSVInternal (pix, hue, saturation, value);
0175             pImage->setColor (i, pix);
0176         }
0177     }
0178 }
0179 
0180 // public static
0181 kpImage kpEffectHSV::applyEffect (const kpImage &image,
0182                                   double hue, double saturation, double value)
0183 {
0184     QImage qimage(image);
0185     ::AdjustHSV (&qimage, hue, saturation, value);
0186     return qimage;
0187 }
0188