/////////////////////////////////////////////////////////////////////////////// // Pixel.cpp // // These functions implement th pixel class. Each pixel object contains // the color data for one pixel. The color data may be stored in one of // several different color models. You may access the color data using // any color model you choose -- the color data will be converted to this // model. // // Note that in all cases, color values range from 0.0 to 1.0 // inclusive. Any values less than 0.0 are rounded up to 0.0, and any values // greater than 1.0 are rounded down to 1.0. Note that this has special // meaning for the YIQ color model because it has some negative values. // The valid range of values are mapped to [0.0 ... 1.0]. /////////////////////////////////////////////////////////////////////////////// #include "Pixel.h" // No global data. /////////////////////////////////////////////////////////////////////////////// // Pixel::Pixel () Default Constructor // // This constructor initializes the pixel's color to black. /////////////////////////////////////////////////////////////////////////////// Pixel::Pixel () : model (RGB), red (0.0), blue (0.0), green (0.0) { // No code needed. } /////////////////////////////////////////////////////////////////////////////// // Pixel::~Pixel () Default Denstructor // // Since no memory was allocated for this object, nothing needs to be // done here. /////////////////////////////////////////////////////////////////////////////// Pixel::~Pixel () { // No code needed. } /////////////////////////////////////////////////////////////////////////////// // double Pixel::getRed () // double Pixel::getGreen () // double Pixel::getBlue () // // These functions get at the color values of this pixel. They first // convert the pixel to store its color using the RGB format, and then // they get at the individual values. /////////////////////////////////////////////////////////////////////////////// double Pixel::getRed () { if (model != RGB) convertTo (RGB); return red; } double Pixel::getGreen () { if (model != RGB) convertTo (RGB); return green; } double Pixel::getBlue () { if (model != RGB) convertTo (RGB); return blue; } /////////////////////////////////////////////////////////////////////////////// // double Pixel::getHue () // double Pixel::getSaturation () // double Pixel::getIntensity () // // These functions get at the color values of this pixel. They first // convert the pixel to store its color using the HSV format, and then // they get at the individual values. /////////////////////////////////////////////////////////////////////////////// double Pixel::getHue () { if (model != HSV) convertTo (HSV); return hue; } double Pixel::getSaturation () { if (model != HSV) convertTo (HSV); return saturation; } double Pixel::getIntensity () { if (model != HSV) convertTo (HSV); return intensity; } /////////////////////////////////////////////////////////////////////////////// // double Pixel::getBrightness () // double Pixel::getChroma () // double Pixel::getPurity () // // These functions get at the color values of this pixel. They first // convert the pixel to store its color using the YIQ format, and then // they get at the individual values. /////////////////////////////////////////////////////////////////////////////// double Pixel::getBrightness () { if (model != YIQ) convertTo (YIQ); return brightness; } double Pixel::getChroma () { if (model != YIQ) convertTo (YIQ); return chroma; } double Pixel::getPurity () { if (model != YIQ) convertTo (YIQ); return purity; } /////////////////////////////////////////////////////////////////////////////// // double Pixel::getCyan () // double Pixel::getMagenta () // double Pixel::getYellow () // // These functions get at the color values of this pixel. They first // convert the pixel to store its color using the CMY format, and then // they get at the individual values. /////////////////////////////////////////////////////////////////////////////// double Pixel::getCyan () { if (model != CMY) convertTo (CMY); return cyan; } double Pixel::getMagenta () { if (model != CMY) convertTo (CMY); return magenta; } double Pixel::getYellow () { if (model != CMY) convertTo (CMY); return yellow; } /////////////////////////////////////////////////////////////////////////////// // void Pixel::setRGBColor (double red, double green, double blue) // void Pixel::setHSVColor (double hue, double saturation, double intensity) // void Pixel::setYIQColor (double brightness, double chroma, double purity) // void Pixel::setCMYColor (double cyan, double magenta, double yellow) // // These functions set the color (and color model) of this pixel. The // parameters are rounded (clipped) after the values are set. /////////////////////////////////////////////////////////////////////////////// void Pixel::setRGBColor (double _red, double _green, double _blue) { model = RGB; red = _red; green = _green; blue = _blue; clipValues (); } void Pixel::setHSVColor (double _hue, double _saturation, double _intensity) { model = HSV; hue = _hue; saturation = _saturation; intensity = _intensity; clipValues (); } void Pixel::setYIQColor (double _brightness, double _chroma, double _purity) { model = YIQ; brightness = _brightness; chroma = _chroma; purity = _purity; clipValues (); } void Pixel::setCMYColor (double _cyan, double _magenta, double _yellow) { model = CMY; cyan = _cyan; magenta = _magenta; yellow = _yellow; clipValues (); } /////////////////////////////////////////////////////////////////////////////// // void Pixel::adjustRed (double newValue) // . . . // . . . // . . . // void Pixel::adjustYellow (double newValue) // // These functions tweak the color of the pixel. You may adjust // a single value using these functions. Note that the current color // model is changed if needed. The values are clipped to [0.0 ... 1.0]. /////////////////////////////////////////////////////////////////////////////// void Pixel::adjustRed (double newValue) { convertTo (RGB); red = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustGreen (double newValue) { convertTo (RGB); green = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustBlue (double newValue) { convertTo (RGB); blue = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustHue (double newValue) { convertTo (HSV); hue = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustSaturation (double newValue) { convertTo (HSV); saturation = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustIntensity (double newValue) { convertTo (HSV); intensity = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustBrightness (double newValue) { convertTo (YIQ); brightness = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustChroma (double newValue) { convertTo (YIQ); chroma = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustPurity (double newValue) { convertTo (YIQ); purity = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustCyan (double newValue) { convertTo (CMY); cyan = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustMagenta (double newValue) { convertTo (CMY); magenta = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } void Pixel::adjustYellow (double newValue) { convertTo (CMY); yellow = (newValue < 0.0) ? 0.0 : ((newValue > 1.0) ? 1.0 : newValue); } /////////////////////////////////////////////////////////////////////////////// // void Pixel::clipValues () // // This function makes sure that all the values for this pixel are // in the range [0.0 ... 1.0]. /////////////////////////////////////////////////////////////////////////////// void Pixel::clipValues () { if (value1 < 0.0) value1 = 0.0; else if (value1 > 1.0) value1 = 1.0; if (value2 < 0.0) value2 = 0.0; else if (value2 > 1.0) value2 = 1.0; if (value3 < 0.0) value3 = 0.0; else if (value3 > 1.0) value3 = 1.0; } /////////////////////////////////////////////////////////////////////////////// // void Pixel::convertTo (ColorModel newModel) // // This function changes the way this pixel stores its color. There // are four color models that this pixel can use: RGB, HSV, YIQ, and CMY. // This function changes this pixel from the current color model to the // specified color model. /////////////////////////////////////////////////////////////////////////////// void Pixel::convertTo (ColorModel newModel) { double tempRed, tempGreen, tempBlue; // If the color model is already correct, bail. if (model == newModel) return; // First, convert the current color to RGB and store it locally. switch (model) { case RGB: tempRed = red; tempGreen = green; tempBlue = blue; break; case HSV: if (saturation == 0) tempRed = tempGreen = tempBlue = intensity; else { int i; double a, b, c, f; hue *= 6.0; if (hue >= 6.0) hue -= 6.0; i = (int) hue; f = hue - i; a = intensity * (1.0 - saturation); b = intensity * (1.0 - (saturation * f)); c = intensity * (1.0 - (saturation * (1.0 - f))); switch (i) { case 0: tempRed = intensity; tempGreen = c; tempBlue = a; break; case 1: tempRed = b; tempGreen = intensity; tempBlue = a; break; case 2: tempRed = a; tempGreen = intensity; tempBlue = c; break; case 3: tempRed = a; tempGreen = b; tempBlue = intensity; break; case 4: tempRed = c; tempGreen = a; tempBlue = intensity; break; case 5: tempRed = intensity; tempGreen = a; tempBlue = b; break; } } break; case YIQ: brightness *= 1.03; chroma = chroma * 1.192 - 0.596; purity = purity * 1.046 - 0.523; tempRed = (brightness + 0.9556880604 * chroma + 0.6198580945 * purity); tempGreen = (brightness - 0.2715817969 * chroma - 0.6468738161 * purity); tempBlue = (brightness - 1.108177327 * chroma + 1.705064560 * purity); break; case CMY: tempRed = 1.0 - cyan; tempGreen = 1.0 - magenta; tempBlue = 1.0 - yellow; break; } // Next, switch color models and convert the temporary RGB to the correct // model. model = newModel; switch (model) { case RGB: red = tempRed; green = tempGreen; blue = tempBlue; break; case HSV: double cmin, cmax, delta, rc, gc, bc; cmax = (tempRed > tempGreen) ? tempRed : tempGreen; cmax = (cmax > tempBlue) ? cmax : tempBlue; cmin = (tempRed < tempGreen) ? tempRed : tempGreen; cmin = (cmin < tempBlue) ? cmin : tempBlue; delta = cmax - cmin; intensity = cmax; saturation = (cmax != 0.0) ? delta / cmax : 0.0; if (saturation == 0.0) hue = 0.0; // No hue. else { if (tempRed == cmax) { hue = (((tempBlue > tempGreen) ? 6.0 : 0.0) + (tempGreen - tempBlue) / delta) / 6.0; } else if (tempGreen == cmax) hue = (2.0 + (tempBlue - tempRed) / delta) / 6.0; else hue = (4.0 + (tempRed - tempGreen) / delta) / 6.0; } break; case YIQ: brightness = (0.299 * tempRed + 0.587 * tempGreen + 0.114 * tempBlue) / 1.03; chroma = ((0.596 * tempRed - 0.275 * tempGreen - 0.321 * tempBlue) + 0.596) / 1.192; purity = ((0.212 * tempRed - 0.523 * tempGreen + 0.311 * tempBlue) + 0.523) / 1.046; break; case CMY: cyan = 1.0 - tempRed; magenta = 1.0 - tempGreen; yellow = 1.0 - tempBlue; break; } // Done, clip the values just in case there was a rounding error. clipValues (); }