/*****************************************************************************/ // Copyright 2007 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in // accordance with the terms of the Adobe license agreement accompanying it. /*****************************************************************************/ /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_hue_sat_map.cpp#1 $ */ /* $DateTime: 2012/05/30 13:28:51 $ */ /* $Change: 832332 $ */ /* $Author: tknoll $ */ /*****************************************************************************/ #include "dng_hue_sat_map.h" #include "dng_assertions.h" #include "dng_auto_ptr.h" #include "dng_bottlenecks.h" #include "dng_exceptions.h" #include "dng_host.h" /*****************************************************************************/ dng_hue_sat_map::dng_hue_sat_map () : fHueDivisions (0) , fSatDivisions (0) , fValDivisions (0) , fHueStep (0) , fValStep (0) , fDeltas () { } /*****************************************************************************/ dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src) : fHueDivisions (0) , fSatDivisions (0) , fValDivisions (0) , fHueStep (0) , fValStep (0) , fDeltas () { *this = src; } /*****************************************************************************/ dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs) { if (this != &rhs) { if (!rhs.IsValid ()) { SetInvalid (); } else { fHueDivisions = rhs.fHueDivisions; fSatDivisions = rhs.fSatDivisions; fValDivisions = rhs.fValDivisions; fHueStep = rhs.fHueStep; fValStep = rhs.fValStep; fDeltas = rhs.fDeltas; } } return *this; } /*****************************************************************************/ dng_hue_sat_map::~dng_hue_sat_map () { } /*****************************************************************************/ void dng_hue_sat_map::SetDivisions (uint32 hueDivisions, uint32 satDivisions, uint32 valDivisions) { DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division."); DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions."); if (valDivisions == 0) valDivisions = 1; if (hueDivisions == fHueDivisions && satDivisions == fSatDivisions && valDivisions == fValDivisions) { return; } fHueDivisions = hueDivisions; fSatDivisions = satDivisions; fValDivisions = valDivisions; fHueStep = satDivisions; fValStep = SafeUint32Mult(hueDivisions, fHueStep); uint32 size = SafeUint32Mult(DeltasCount (), (uint32) sizeof (HSBModify)); fDeltas.Allocate (size); DoZeroBytes (fDeltas.Buffer (), size); } /*****************************************************************************/ void dng_hue_sat_map::GetDelta (uint32 hueDiv, uint32 satDiv, uint32 valDiv, HSBModify &modify) const { if (hueDiv >= fHueDivisions || satDiv >= fSatDivisions || valDiv >= fValDivisions || fDeltas.Buffer () == NULL) { DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta"); ThrowProgramError (); } int32 offset = valDiv * fValStep + hueDiv * fHueStep + satDiv; const HSBModify *deltas = GetConstDeltas (); modify.fHueShift = deltas [offset].fHueShift; modify.fSatScale = deltas [offset].fSatScale; modify.fValScale = deltas [offset].fValScale; } /*****************************************************************************/ void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv, uint32 satDiv, uint32 valDiv, const HSBModify &modify) { if (hueDiv >= fHueDivisions || satDiv >= fSatDivisions || valDiv >= fValDivisions || fDeltas.Buffer () == NULL) { DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta"); ThrowProgramError (); } // Set this entry. int32 offset = valDiv * fValStep + hueDiv * fHueStep + satDiv; SafeGetDeltas () [offset] = modify; // The zero saturation entry is required to have a value scale // of 1.0f. if (satDiv == 0) { if (modify.fValScale != 1.0f) { #if qDNGValidate ReportWarning ("Value scale for zero saturation entries must be 1.0"); #endif SafeGetDeltas () [offset] . fValScale = 1.0f; } } // If we are settings the first saturation entry and we have not // set the zero saturation entry yet, fill in the zero saturation entry // by extrapolating first saturation entry. if (satDiv == 1) { HSBModify zeroSatModify; GetDelta (hueDiv, 0, valDiv, zeroSatModify); if (zeroSatModify.fValScale != 1.0f) { zeroSatModify.fHueShift = modify.fHueShift; zeroSatModify.fSatScale = modify.fSatScale; zeroSatModify.fValScale = 1.0f; SetDelta (hueDiv, 0, valDiv, zeroSatModify); } } } /*****************************************************************************/ bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const { if (fHueDivisions != rhs.fHueDivisions || fSatDivisions != rhs.fSatDivisions || fValDivisions != rhs.fValDivisions) return false; if (!IsValid ()) return true; return memcmp (GetConstDeltas (), rhs.GetConstDeltas (), DeltasCount () * sizeof (HSBModify)) == 0; } /*****************************************************************************/ dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1, const dng_hue_sat_map &map2, real64 weight1) { if (weight1 >= 1.0) { if (!map1.IsValid ()) { DNG_REPORT ("map1 is not valid"); ThrowProgramError (); } return new dng_hue_sat_map (map1); } if (weight1 <= 0.0) { if (!map2.IsValid ()) { DNG_REPORT ("map2 is not valid"); ThrowProgramError (); } return new dng_hue_sat_map (map2); } // Both maps must be valid if we are using both. if (!map1.IsValid () || !map2.IsValid ()) { DNG_REPORT ("map1 or map2 is not valid"); ThrowProgramError (); } // Must have the same dimensions. if (map1.fHueDivisions != map2.fHueDivisions || map1.fSatDivisions != map2.fSatDivisions || map1.fValDivisions != map2.fValDivisions) { DNG_REPORT ("map1 and map2 have different sizes"); ThrowProgramError (); } // Make table to hold interpolated results. AutoPtr result (new dng_hue_sat_map); result->SetDivisions (map1.fHueDivisions, map1.fSatDivisions, map1.fValDivisions); // Interpolate between the tables. real32 w1 = (real32) weight1; real32 w2 = 1.0f - w1; const HSBModify *data1 = map1.GetConstDeltas (); const HSBModify *data2 = map2.GetConstDeltas (); HSBModify *data3 = result->SafeGetDeltas (); uint32 count = map1.DeltasCount (); for (uint32 index = 0; index < count; index++) { data3->fHueShift = w1 * data1->fHueShift + w2 * data2->fHueShift; data3->fSatScale = w1 * data1->fSatScale + w2 * data2->fSatScale; data3->fValScale = w1 * data1->fValScale + w2 * data2->fValScale; data1++; data2++; data3++; } // Return interpolated tables. return result.Release (); } /*****************************************************************************/