| /*****************************************************************************/ |
| // Copyright 2006-2008 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_camera_profile.cpp#1 $ */ |
| /* $DateTime: 2012/05/30 13:28:51 $ */ |
| /* $Change: 832332 $ */ |
| /* $Author: tknoll $ */ |
| |
| #include "dng_camera_profile.h" |
| |
| #include "dng_1d_table.h" |
| #include "dng_assertions.h" |
| #include "dng_color_space.h" |
| #include "dng_host.h" |
| #include "dng_exceptions.h" |
| #include "dng_image_writer.h" |
| #include "dng_info.h" |
| #include "dng_parse_utils.h" |
| #include "dng_safe_arithmetic.h" |
| #include "dng_tag_codes.h" |
| #include "dng_tag_types.h" |
| #include "dng_temperature.h" |
| #include "dng_xy_coord.h" |
| |
| /*****************************************************************************/ |
| |
| const char * kProfileName_Embedded = "Embedded"; |
| |
| const char * kAdobeCalibrationSignature = "com.adobe"; |
| |
| /*****************************************************************************/ |
| |
| dng_camera_profile::dng_camera_profile () |
| |
| : fName () |
| , fCalibrationIlluminant1 (lsUnknown) |
| , fCalibrationIlluminant2 (lsUnknown) |
| , fColorMatrix1 () |
| , fColorMatrix2 () |
| , fForwardMatrix1 () |
| , fForwardMatrix2 () |
| , fReductionMatrix1 () |
| , fReductionMatrix2 () |
| , fFingerprint () |
| , fCopyright () |
| , fEmbedPolicy (pepAllowCopying) |
| , fHueSatDeltas1 () |
| , fHueSatDeltas2 () |
| , fHueSatMapEncoding (encoding_Linear) |
| , fLookTable () |
| , fLookTableEncoding (encoding_Linear) |
| , fBaselineExposureOffset (0, 100) |
| , fDefaultBlackRender (defaultBlackRender_Auto) |
| , fToneCurve () |
| , fProfileCalibrationSignature () |
| , fUniqueCameraModelRestriction () |
| , fWasReadFromDNG (false) |
| , fWasReadFromDisk (false) |
| , fWasBuiltinMatrix (false) |
| , fWasStubbed (false) |
| |
| { |
| |
| fToneCurve.SetInvalid (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_camera_profile::~dng_camera_profile () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| real64 dng_camera_profile::IlluminantToTemperature (uint32 light) |
| { |
| |
| switch (light) |
| { |
| |
| case lsStandardLightA: |
| case lsTungsten: |
| { |
| return 2850.0; |
| } |
| |
| case lsISOStudioTungsten: |
| { |
| return 3200.0; |
| } |
| |
| case lsD50: |
| { |
| return 5000.0; |
| } |
| |
| case lsD55: |
| case lsDaylight: |
| case lsFineWeather: |
| case lsFlash: |
| case lsStandardLightB: |
| { |
| return 5500.0; |
| } |
| |
| case lsD65: |
| case lsStandardLightC: |
| case lsCloudyWeather: |
| { |
| return 6500.0; |
| } |
| |
| case lsD75: |
| case lsShade: |
| { |
| return 7500.0; |
| } |
| |
| case lsDaylightFluorescent: |
| { |
| return (5700.0 + 7100.0) * 0.5; |
| } |
| |
| case lsDayWhiteFluorescent: |
| { |
| return (4600.0 + 5500.0) * 0.5; |
| } |
| |
| case lsCoolWhiteFluorescent: |
| case lsFluorescent: |
| { |
| return (3800.0 + 4500.0) * 0.5; |
| } |
| |
| case lsWhiteFluorescent: |
| { |
| return (3250.0 + 3800.0) * 0.5; |
| } |
| |
| case lsWarmWhiteFluorescent: |
| { |
| return (2600.0 + 3250.0) * 0.5; |
| } |
| |
| default: |
| { |
| return 0.0; |
| } |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::NormalizeColorMatrix (dng_matrix &m) |
| { |
| |
| if (m.NotEmpty ()) |
| { |
| |
| // Find scale factor to normalize the matrix. |
| |
| dng_vector coord = m * PCStoXYZ (); |
| |
| real64 maxCoord = coord.MaxEntry (); |
| |
| if (maxCoord > 0.0 && (maxCoord < 0.99 || maxCoord > 1.01)) |
| { |
| |
| m.Scale (1.0 / maxCoord); |
| |
| } |
| |
| // Round to four decimal places. |
| |
| m.Round (10000); |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::SetColorMatrix1 (const dng_matrix &m) |
| { |
| |
| fColorMatrix1 = m; |
| |
| NormalizeColorMatrix (fColorMatrix1); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::SetColorMatrix2 (const dng_matrix &m) |
| { |
| |
| fColorMatrix2 = m; |
| |
| NormalizeColorMatrix (fColorMatrix2); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| // Make sure the forward matrix maps to exactly the PCS. |
| |
| void dng_camera_profile::NormalizeForwardMatrix (dng_matrix &m) |
| { |
| |
| if (m.NotEmpty ()) |
| { |
| |
| dng_vector cameraOne; |
| |
| cameraOne.SetIdentity (m.Cols ()); |
| |
| dng_vector xyz = m * cameraOne; |
| |
| m = PCStoXYZ ().AsDiagonal () * |
| Invert (xyz.AsDiagonal ()) * |
| m; |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::SetForwardMatrix1 (const dng_matrix &m) |
| { |
| |
| fForwardMatrix1 = m; |
| |
| fForwardMatrix1.Round (10000); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::SetForwardMatrix2 (const dng_matrix &m) |
| { |
| |
| fForwardMatrix2 = m; |
| |
| fForwardMatrix2.Round (10000); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::SetReductionMatrix1 (const dng_matrix &m) |
| { |
| |
| fReductionMatrix1 = m; |
| |
| fReductionMatrix1.Round (10000); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| void dng_camera_profile::SetReductionMatrix2 (const dng_matrix &m) |
| { |
| |
| fReductionMatrix2 = m; |
| |
| fReductionMatrix2.Round (10000); |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile::HasColorMatrix1 () const |
| { |
| |
| return fColorMatrix1.Cols () == 3 && |
| fColorMatrix1.Rows () > 1; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile::HasColorMatrix2 () const |
| { |
| |
| return fColorMatrix2.Cols () == 3 && |
| fColorMatrix2.Rows () == fColorMatrix1.Rows (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::SetHueSatDeltas1 (const dng_hue_sat_map &deltas1) |
| { |
| |
| fHueSatDeltas1 = deltas1; |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::SetHueSatDeltas2 (const dng_hue_sat_map &deltas2) |
| { |
| |
| fHueSatDeltas2 = deltas2; |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::SetLookTable (const dng_hue_sat_map &table) |
| { |
| |
| fLookTable = table; |
| |
| ClearFingerprint (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| static void FingerprintMatrix (dng_md5_printer_stream &printer, |
| const dng_matrix &matrix) |
| { |
| |
| tag_matrix tag (0, matrix); |
| |
| // Tag's Put routine doesn't write the header, only the data |
| |
| tag.Put (printer); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| static void FingerprintHueSatMap (dng_md5_printer_stream &printer, |
| const dng_hue_sat_map &map) |
| { |
| |
| if (map.IsNull ()) |
| return; |
| |
| uint32 hues; |
| uint32 sats; |
| uint32 vals; |
| |
| map.GetDivisions (hues, sats, vals); |
| |
| printer.Put_uint32 (hues); |
| printer.Put_uint32 (sats); |
| printer.Put_uint32 (vals); |
| |
| for (uint32 val = 0; val < vals; val++) |
| for (uint32 hue = 0; hue < hues; hue++) |
| for (uint32 sat = 0; sat < sats; sat++) |
| { |
| |
| dng_hue_sat_map::HSBModify modify; |
| |
| map.GetDelta (hue, sat, val, modify); |
| |
| printer.Put_real32 (modify.fHueShift); |
| printer.Put_real32 (modify.fSatScale); |
| printer.Put_real32 (modify.fValScale); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::CalculateFingerprint () const |
| { |
| |
| DNG_ASSERT (!fWasStubbed, "CalculateFingerprint on stubbed profile"); |
| |
| dng_md5_printer_stream printer; |
| |
| // MD5 hash is always calculated on little endian data. |
| |
| printer.SetLittleEndian (); |
| |
| // The data that we fingerprint closely matches that saved |
| // by the profile_tag_set class in dng_image_writer.cpp, with |
| // the exception of the fingerprint itself. |
| |
| if (HasColorMatrix1 ()) |
| { |
| |
| uint32 colorChannels = ColorMatrix1 ().Rows (); |
| |
| printer.Put_uint16 ((uint16) fCalibrationIlluminant1); |
| |
| FingerprintMatrix (printer, fColorMatrix1); |
| |
| if (fForwardMatrix1.Rows () == fColorMatrix1.Cols () && |
| fForwardMatrix1.Cols () == fColorMatrix1.Rows ()) |
| { |
| |
| FingerprintMatrix (printer, fForwardMatrix1); |
| |
| } |
| |
| if (colorChannels > 3 && fReductionMatrix1.Rows () * |
| fReductionMatrix1.Cols () == colorChannels * 3) |
| { |
| |
| FingerprintMatrix (printer, fReductionMatrix1); |
| |
| } |
| |
| if (HasColorMatrix2 ()) |
| { |
| |
| printer.Put_uint16 ((uint16) fCalibrationIlluminant2); |
| |
| FingerprintMatrix (printer, fColorMatrix2); |
| |
| if (fForwardMatrix2.Rows () == fColorMatrix2.Cols () && |
| fForwardMatrix2.Cols () == fColorMatrix2.Rows ()) |
| { |
| |
| FingerprintMatrix (printer, fForwardMatrix2); |
| |
| } |
| |
| if (colorChannels > 3 && fReductionMatrix2.Rows () * |
| fReductionMatrix2.Cols () == colorChannels * 3) |
| { |
| |
| FingerprintMatrix (printer, fReductionMatrix2); |
| |
| } |
| |
| } |
| |
| printer.Put (fName.Get (), |
| fName.Length ()); |
| |
| printer.Put (fProfileCalibrationSignature.Get (), |
| fProfileCalibrationSignature.Length ()); |
| |
| printer.Put_uint32 (fEmbedPolicy); |
| |
| printer.Put (fCopyright.Get (), |
| fCopyright.Length ()); |
| |
| bool haveHueSat1 = HueSatDeltas1 ().IsValid (); |
| |
| bool haveHueSat2 = HueSatDeltas2 ().IsValid () && |
| HasColorMatrix2 (); |
| |
| if (haveHueSat1) |
| { |
| |
| FingerprintHueSatMap (printer, fHueSatDeltas1); |
| |
| } |
| |
| if (haveHueSat2) |
| { |
| |
| FingerprintHueSatMap (printer, fHueSatDeltas2); |
| |
| } |
| |
| if (haveHueSat1 || haveHueSat2) |
| { |
| |
| if (fHueSatMapEncoding != 0) |
| { |
| |
| printer.Put_uint32 (fHueSatMapEncoding); |
| |
| } |
| |
| } |
| |
| if (fLookTable.IsValid ()) |
| { |
| |
| FingerprintHueSatMap (printer, fLookTable); |
| |
| if (fLookTableEncoding != 0) |
| { |
| |
| printer.Put_uint32 (fLookTableEncoding); |
| |
| } |
| |
| } |
| |
| if (fBaselineExposureOffset.IsValid ()) |
| { |
| |
| if (fBaselineExposureOffset.As_real64 () != 0.0) |
| { |
| |
| printer.Put_real64 (fBaselineExposureOffset.As_real64 ()); |
| |
| } |
| |
| } |
| |
| if (fDefaultBlackRender != 0) |
| { |
| |
| printer.Put_int32 (fDefaultBlackRender); |
| |
| } |
| |
| if (fToneCurve.IsValid ()) |
| { |
| |
| for (uint32 i = 0; i < fToneCurve.fCoord.size (); i++) |
| { |
| |
| printer.Put_real32 ((real32) fToneCurve.fCoord [i].h); |
| printer.Put_real32 ((real32) fToneCurve.fCoord [i].v); |
| |
| } |
| |
| } |
| |
| } |
| |
| fFingerprint = printer.Result (); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| bool dng_camera_profile::ValidForwardMatrix (const dng_matrix &m) |
| { |
| |
| const real64 kThreshold = 0.01; |
| |
| if (m.NotEmpty ()) |
| { |
| |
| dng_vector cameraOne; |
| |
| cameraOne.SetIdentity (m.Cols ()); |
| |
| dng_vector xyz = m * cameraOne; |
| |
| dng_vector pcs = PCStoXYZ (); |
| |
| if (Abs_real64 (xyz [0] - pcs [0]) > kThreshold || |
| Abs_real64 (xyz [1] - pcs [1]) > kThreshold || |
| Abs_real64 (xyz [2] - pcs [2]) > kThreshold) |
| { |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| bool dng_camera_profile::IsValid (uint32 channels) const |
| { |
| |
| // For Monochrome images, we ignore the camera profile. |
| |
| if (channels == 1) |
| { |
| |
| return true; |
| |
| } |
| |
| // ColorMatrix1 is required for all color images. |
| |
| if (fColorMatrix1.Cols () != 3 || |
| fColorMatrix1.Rows () != channels) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ColorMatrix1 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // ColorMatrix2 is optional, but it must be valid if present. |
| |
| if (fColorMatrix2.Cols () != 0 || |
| fColorMatrix2.Rows () != 0) |
| { |
| |
| if (fColorMatrix2.Cols () != 3 || |
| fColorMatrix2.Rows () != channels) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ColorMatrix2 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // ForwardMatrix1 is optional, but it must be valid if present. |
| |
| if (fForwardMatrix1.Cols () != 0 || |
| fForwardMatrix1.Rows () != 0) |
| { |
| |
| if (fForwardMatrix1.Rows () != 3 || |
| fForwardMatrix1.Cols () != channels) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ForwardMatrix1 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Make sure ForwardMatrix1 does a valid mapping. |
| |
| if (!ValidForwardMatrix (fForwardMatrix1)) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ForwardMatrix1 does not map equal camera values to XYZ D50"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // ForwardMatrix2 is optional, but it must be valid if present. |
| |
| if (fForwardMatrix2.Cols () != 0 || |
| fForwardMatrix2.Rows () != 0) |
| { |
| |
| if (fForwardMatrix2.Rows () != 3 || |
| fForwardMatrix2.Cols () != channels) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ForwardMatrix2 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Make sure ForwardMatrix2 does a valid mapping. |
| |
| if (!ValidForwardMatrix (fForwardMatrix2)) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ForwardMatrix2 does not map equal camera values to XYZ D50"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // ReductionMatrix1 is optional, but it must be valid if present. |
| |
| if (fReductionMatrix1.Cols () != 0 || |
| fReductionMatrix1.Rows () != 0) |
| { |
| |
| if (fReductionMatrix1.Cols () != channels || |
| fReductionMatrix1.Rows () != 3) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ReductionMatrix1 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // ReductionMatrix2 is optional, but it must be valid if present. |
| |
| if (fReductionMatrix2.Cols () != 0 || |
| fReductionMatrix2.Rows () != 0) |
| { |
| |
| if (fReductionMatrix2.Cols () != channels || |
| fReductionMatrix2.Rows () != 3) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ReductionMatrix2 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // Make sure ColorMatrix1 is invertable. |
| |
| try |
| { |
| |
| if (fReductionMatrix1.NotEmpty ()) |
| { |
| |
| (void) Invert (fColorMatrix1, |
| fReductionMatrix1); |
| |
| } |
| |
| else |
| { |
| |
| (void) Invert (fColorMatrix1); |
| |
| } |
| |
| } |
| |
| catch (...) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ColorMatrix1 is not invertable"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Make sure ColorMatrix2 is invertable. |
| |
| if (fColorMatrix2.NotEmpty ()) |
| { |
| |
| try |
| { |
| |
| if (fReductionMatrix2.NotEmpty ()) |
| { |
| |
| (void) Invert (fColorMatrix2, |
| fReductionMatrix2); |
| |
| } |
| |
| else |
| { |
| |
| (void) Invert (fColorMatrix2); |
| |
| } |
| |
| } |
| |
| catch (...) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("ColorMatrix2 is not invertable"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile::EqualData (const dng_camera_profile &profile) const |
| { |
| |
| return fCalibrationIlluminant1 == profile.fCalibrationIlluminant1 && |
| fCalibrationIlluminant2 == profile.fCalibrationIlluminant2 && |
| fColorMatrix1 == profile.fColorMatrix1 && |
| fColorMatrix2 == profile.fColorMatrix2 && |
| fForwardMatrix1 == profile.fForwardMatrix1 && |
| fForwardMatrix2 == profile.fForwardMatrix2 && |
| fReductionMatrix1 == profile.fReductionMatrix1 && |
| fReductionMatrix2 == profile.fReductionMatrix2 && |
| fHueSatDeltas1 == profile.fHueSatDeltas1 && |
| fHueSatDeltas2 == profile.fHueSatDeltas2 && |
| fHueSatMapEncoding == profile.fHueSatMapEncoding && |
| fLookTable == profile.fLookTable && |
| fLookTableEncoding == profile.fLookTableEncoding && |
| fDefaultBlackRender == profile.fDefaultBlackRender && |
| fToneCurve == profile.fToneCurve && |
| fBaselineExposureOffset.As_real64 () == profile.fBaselineExposureOffset.As_real64 () && |
| fProfileCalibrationSignature == profile.fProfileCalibrationSignature; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::ReadHueSatMap (dng_stream &stream, |
| dng_hue_sat_map &hueSatMap, |
| uint32 hues, |
| uint32 sats, |
| uint32 vals, |
| bool skipSat0) |
| { |
| |
| hueSatMap.SetDivisions (hues, sats, vals); |
| |
| for (uint32 val = 0; val < vals; val++) |
| { |
| |
| for (uint32 hue = 0; hue < hues; hue++) |
| { |
| |
| for (uint32 sat = skipSat0 ? 1 : 0; sat < sats; sat++) |
| { |
| |
| dng_hue_sat_map::HSBModify modify; |
| |
| modify.fHueShift = stream.Get_real32 (); |
| modify.fSatScale = stream.Get_real32 (); |
| modify.fValScale = stream.Get_real32 (); |
| |
| hueSatMap.SetDelta (hue, sat, val, modify); |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::Parse (dng_stream &stream, |
| dng_camera_profile_info &profileInfo) |
| { |
| |
| SetUniqueCameraModelRestriction (profileInfo.fUniqueCameraModel.Get ()); |
| |
| if (profileInfo.fProfileName.NotEmpty ()) |
| { |
| |
| SetName (profileInfo.fProfileName.Get ()); |
| |
| } |
| |
| SetCopyright (profileInfo.fProfileCopyright.Get ()); |
| |
| SetEmbedPolicy (profileInfo.fEmbedPolicy); |
| |
| SetCalibrationIlluminant1 (profileInfo.fCalibrationIlluminant1); |
| |
| SetColorMatrix1 (profileInfo.fColorMatrix1); |
| |
| if (profileInfo.fForwardMatrix1.NotEmpty ()) |
| { |
| |
| SetForwardMatrix1 (profileInfo.fForwardMatrix1); |
| |
| } |
| |
| if (profileInfo.fReductionMatrix1.NotEmpty ()) |
| { |
| |
| SetReductionMatrix1 (profileInfo.fReductionMatrix1); |
| |
| } |
| |
| if (profileInfo.fColorMatrix2.NotEmpty ()) |
| { |
| |
| SetCalibrationIlluminant2 (profileInfo.fCalibrationIlluminant2); |
| |
| SetColorMatrix2 (profileInfo.fColorMatrix2); |
| |
| if (profileInfo.fForwardMatrix2.NotEmpty ()) |
| { |
| |
| SetForwardMatrix2 (profileInfo.fForwardMatrix2); |
| |
| } |
| |
| if (profileInfo.fReductionMatrix2.NotEmpty ()) |
| { |
| |
| SetReductionMatrix2 (profileInfo.fReductionMatrix2); |
| |
| } |
| |
| } |
| |
| SetProfileCalibrationSignature (profileInfo.fProfileCalibrationSignature.Get ()); |
| |
| if (profileInfo.fHueSatDeltas1Offset != 0 && |
| profileInfo.fHueSatDeltas1Count != 0) |
| { |
| |
| TempBigEndian setEndianness (stream, profileInfo.fBigEndian); |
| |
| stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset); |
| |
| bool skipSat0 = (profileInfo.fHueSatDeltas1Count == SafeUint32Mult( |
| profileInfo.fProfileHues, |
| SafeUint32Sub(profileInfo.fProfileSats, 1), |
| profileInfo.fProfileVals, 3)); |
| |
| ReadHueSatMap (stream, |
| fHueSatDeltas1, |
| profileInfo.fProfileHues, |
| profileInfo.fProfileSats, |
| profileInfo.fProfileVals, |
| skipSat0); |
| |
| } |
| |
| if (profileInfo.fHueSatDeltas2Offset != 0 && |
| profileInfo.fHueSatDeltas2Count != 0) |
| { |
| |
| TempBigEndian setEndianness (stream, profileInfo.fBigEndian); |
| |
| stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset); |
| |
| bool skipSat0 = (profileInfo.fHueSatDeltas2Count == SafeUint32Mult( |
| profileInfo.fProfileHues, |
| SafeUint32Sub(profileInfo.fProfileSats, 1), |
| profileInfo.fProfileVals, 3)); |
| |
| ReadHueSatMap (stream, |
| fHueSatDeltas2, |
| profileInfo.fProfileHues, |
| profileInfo.fProfileSats, |
| profileInfo.fProfileVals, |
| skipSat0); |
| |
| } |
| |
| if (profileInfo.fLookTableOffset != 0 && |
| profileInfo.fLookTableCount != 0) |
| { |
| |
| TempBigEndian setEndianness (stream, profileInfo.fBigEndian); |
| |
| stream.SetReadPosition (profileInfo.fLookTableOffset); |
| |
| bool skipSat0 = (profileInfo.fLookTableCount == SafeUint32Mult( |
| profileInfo.fLookTableHues, |
| SafeUint32Sub(profileInfo.fLookTableSats, 1), |
| profileInfo.fLookTableVals, 3)); |
| |
| ReadHueSatMap (stream, |
| fLookTable, |
| profileInfo.fLookTableHues, |
| profileInfo.fLookTableSats, |
| profileInfo.fLookTableVals, |
| skipSat0); |
| |
| } |
| |
| if ((profileInfo.fToneCurveCount & 1) == 0) |
| { |
| |
| TempBigEndian setEndianness (stream, profileInfo.fBigEndian); |
| |
| stream.SetReadPosition (profileInfo.fToneCurveOffset); |
| |
| uint32 points = profileInfo.fToneCurveCount / 2; |
| |
| fToneCurve.fCoord.resize (points); |
| |
| for (size_t i = 0; i < points; i++) |
| { |
| |
| dng_point_real64 point; |
| |
| point.h = stream.Get_real32 (); |
| point.v = stream.Get_real32 (); |
| |
| fToneCurve.fCoord [i] = point; |
| |
| } |
| |
| } |
| |
| SetHueSatMapEncoding (profileInfo.fHueSatMapEncoding); |
| |
| SetLookTableEncoding (profileInfo.fLookTableEncoding); |
| |
| SetBaselineExposureOffset (profileInfo.fBaselineExposureOffset.As_real64 ()); |
| |
| SetDefaultBlackRender (profileInfo.fDefaultBlackRender); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile::ParseExtended (dng_stream &stream) |
| { |
| |
| try |
| { |
| |
| dng_camera_profile_info profileInfo; |
| |
| if (!profileInfo.ParseExtended (stream)) |
| { |
| return false; |
| } |
| |
| Parse (stream, profileInfo); |
| |
| return true; |
| |
| } |
| |
| catch (...) |
| { |
| |
| // Eat parsing errors. |
| |
| } |
| |
| return false; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::SetFourColorBayer () |
| { |
| |
| uint32 j; |
| |
| if (!IsValid (3)) |
| { |
| ThrowProgramError (); |
| } |
| |
| if (fColorMatrix1.NotEmpty ()) |
| { |
| |
| dng_matrix m (4, 3); |
| |
| for (j = 0; j < 3; j++) |
| { |
| m [0] [j] = fColorMatrix1 [0] [j]; |
| m [1] [j] = fColorMatrix1 [1] [j]; |
| m [2] [j] = fColorMatrix1 [2] [j]; |
| m [3] [j] = fColorMatrix1 [1] [j]; |
| } |
| |
| fColorMatrix1 = m; |
| |
| } |
| |
| if (fColorMatrix2.NotEmpty ()) |
| { |
| |
| dng_matrix m (4, 3); |
| |
| for (j = 0; j < 3; j++) |
| { |
| m [0] [j] = fColorMatrix2 [0] [j]; |
| m [1] [j] = fColorMatrix2 [1] [j]; |
| m [2] [j] = fColorMatrix2 [2] [j]; |
| m [3] [j] = fColorMatrix2 [1] [j]; |
| } |
| |
| fColorMatrix2 = m; |
| |
| } |
| |
| fReductionMatrix1.Clear (); |
| fReductionMatrix2.Clear (); |
| |
| fForwardMatrix1.Clear (); |
| fForwardMatrix2.Clear (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_hue_sat_map * dng_camera_profile::HueSatMapForWhite (const dng_xy_coord &white) const |
| { |
| |
| if (fHueSatDeltas1.IsValid ()) |
| { |
| |
| // If we only have the first table, just use it for any color temperature. |
| |
| if (!fHueSatDeltas2.IsValid ()) |
| { |
| |
| return new dng_hue_sat_map (fHueSatDeltas1); |
| |
| } |
| |
| // Else we need to interpolate based on color temperature. |
| |
| real64 temperature1 = CalibrationTemperature1 (); |
| real64 temperature2 = CalibrationTemperature2 (); |
| |
| if (temperature1 <= 0.0 || |
| temperature2 <= 0.0 || |
| temperature1 == temperature2) |
| { |
| |
| return new dng_hue_sat_map (fHueSatDeltas1); |
| |
| } |
| |
| bool reverseOrder = temperature1 > temperature2; |
| |
| if (reverseOrder) |
| { |
| real64 temp = temperature1; |
| temperature1 = temperature2; |
| temperature2 = temp; |
| } |
| |
| // Convert to temperature/offset space. |
| |
| dng_temperature td (white); |
| |
| // Find fraction to weight the first calibration. |
| |
| real64 g; |
| |
| if (td.Temperature () <= temperature1) |
| g = 1.0; |
| |
| else if (td.Temperature () >= temperature2) |
| g = 0.0; |
| |
| else |
| { |
| |
| real64 invT = 1.0 / td.Temperature (); |
| |
| g = (invT - (1.0 / temperature2)) / |
| ((1.0 / temperature1) - (1.0 / temperature2)); |
| |
| } |
| |
| // Fix up if we swapped the order. |
| |
| if (reverseOrder) |
| { |
| g = 1.0 - g; |
| } |
| |
| // Do the interpolation. |
| |
| return dng_hue_sat_map::Interpolate (HueSatDeltas1 (), |
| HueSatDeltas2 (), |
| g); |
| |
| } |
| |
| return NULL; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_camera_profile::Stub () |
| { |
| |
| (void) Fingerprint (); |
| |
| dng_hue_sat_map nullTable; |
| |
| fHueSatDeltas1 = nullTable; |
| fHueSatDeltas2 = nullTable; |
| |
| fLookTable = nullTable; |
| |
| fToneCurve.SetInvalid (); |
| |
| fWasStubbed = true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void SplitCameraProfileName (const dng_string &name, |
| dng_string &baseName, |
| int32 &version) |
| { |
| |
| baseName = name; |
| |
| version = 0; |
| |
| uint32 len = baseName.Length (); |
| |
| if (len > 5 && baseName.EndsWith (" beta")) |
| { |
| |
| baseName.Truncate (len - 5); |
| |
| version += -10; |
| |
| } |
| |
| else if (len > 7) |
| { |
| |
| char lastChar = name.Get () [len - 1]; |
| |
| if (lastChar >= '0' && lastChar <= '9') |
| { |
| |
| dng_string temp = name; |
| |
| temp.Truncate (len - 1); |
| |
| if (temp.EndsWith (" beta ")) |
| { |
| |
| baseName.Truncate (len - 7); |
| |
| version += ((int32) (lastChar - '0')) - 10; |
| |
| } |
| |
| } |
| |
| } |
| |
| len = baseName.Length (); |
| |
| if (len > 3) |
| { |
| |
| char lastChar = name.Get () [len - 1]; |
| |
| if (lastChar >= '0' && lastChar <= '9') |
| { |
| |
| dng_string temp = name; |
| |
| temp.Truncate (len - 1); |
| |
| if (temp.EndsWith (" v")) |
| { |
| |
| baseName.Truncate (len - 3); |
| |
| version += ((int32) (lastChar - '0')) * 100; |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator, |
| uint32 encoding, |
| AutoPtr<dng_1d_table> &encodeTable, |
| AutoPtr<dng_1d_table> &decodeTable, |
| bool subSample) |
| { |
| |
| encodeTable.Reset (); |
| decodeTable.Reset (); |
| |
| switch (encoding) |
| { |
| |
| case encoding_Linear: |
| { |
| |
| break; |
| |
| } |
| |
| case encoding_sRGB: |
| { |
| |
| encodeTable.Reset (new dng_1d_table); |
| decodeTable.Reset (new dng_1d_table); |
| |
| const dng_1d_function & curve = dng_function_GammaEncode_sRGB::Get (); |
| |
| encodeTable->Initialize (allocator, |
| curve, |
| subSample); |
| |
| const dng_1d_inverse inverse (curve); |
| |
| decodeTable->Initialize (allocator, |
| inverse, |
| subSample); |
| |
| break; |
| |
| } |
| |
| default: |
| { |
| |
| DNG_REPORT ("Unsupported hue sat map / look table encoding."); |
| |
| break; |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |