aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2022-02-08 10:16:43 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2022-02-08 10:16:43 +0200
commit6b107d96ccd620fbe1c7d31fbe72166c24bbfe09 (patch)
tree10b3f42fc2c6f36ee15fdbcc7f0bc39e3e3478bf
parentb10afe316e91d0600cd1f668f86767883cce4bb9 (diff)
downloadTango-6b107d96ccd620fbe1c7d31fbe72166c24bbfe09.tar.gz
Tango-6b107d96ccd620fbe1c7d31fbe72166c24bbfe09.zip
Added CE v5 + fixes for v4.
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp107
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h6
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.cpp30
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.h8
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.cpp719
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.h67
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.cpp5791
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.h228
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverterCLipRGB.cpp3219
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.cpp68
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.h6
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.cpp217
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.h32
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.c105
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.h76
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.c145
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.h82
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.c131
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.h78
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.c119
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.c105
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.h74
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.c43
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.h46
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.c261
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.h100
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.c158
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.h81
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.c183
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.h89
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.c118
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.h76
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.c248
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.h98
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.c118
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.h77
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.c248
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.h97
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.c131
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.h79
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.c144
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.h82
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.c131
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.h78
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.c119
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.c53
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.h51
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.c105
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.c170
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.h86
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.c118
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.c183
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.h87
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.c106
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.c105
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.h74
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.c183
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.h89
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.c118
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.h75
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ReadMe.txt48
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj270
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj.filters318
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.cpp114
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.h63
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.cpp188
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.h48
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.cpp90
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.h33
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.cpp1254
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.h140
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.cpp769
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.h94
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.cpp577
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.h55
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.cpp155
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.h24
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.cpp340
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.h38
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.cpp45
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.h39
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.cpp127
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.h24
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.cpp129
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.h13
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.cpp457
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.h66
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.cpp333
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.h60
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.cpp85
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.h18
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.cpp142
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.h49
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.c3642
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.h1106
-rw-r--r--Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/targetver.h8
-rw-r--r--Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj9
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj7
-rw-r--r--Software/Visual_Studio/Tango.sln31
104 files changed, 27159 insertions, 45 deletions
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp
index 55c1b9cc6..8be5bfafe 100644
--- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp
@@ -62,6 +62,8 @@
#define maxPerRegion 100.0
#define GamutMinReg0 200
#define GamutMinReg1 300
+#define GamutMinReg0_E 140
+#define GamutMinReg1_E 180
//#define LowVolumeThreshold 0.5
//#define LowVolHalf LowVolumeThreshold/2
#define GradientEndThr 0.95
@@ -78,7 +80,7 @@ Tango::ColorLib::ColorConverter::ColorConverter() :
m_nProcessRanges(0), m_NormGamutRegionMaxLim(NULL), m_GamutRegionMaxLim(NULL),
m_GamutRegionMinLim(NULL),
m_UseLightInks(false), m_InkNames(NULL), m_LightInksThr (0.0),
- m_LowVolumeThreshold(0.0), m_LowVolHalf(0.0)//, m_NormFactor(0.0), m_InvnormFactor(0.0)
+ m_LowVolumeThreshold(0.0), m_LowVolHalf(0.0), m_NormFactor(NULL), m_InvNormFactor(NULL)
{
m_whitepointLab.Set(-1, -1, -1);
m_whitepointXYZ_Strip.Set(-1, -1, -1);
@@ -257,8 +259,7 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv
ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_Strip); //to Relative
m_colortable->m_B2ATransform->evalLab2InkP(Lab1P, InkOut, GamutRegion[iHive]); //InkOut is in the [0-100] interval
- double tmpNormFactor = m_colortable->GetNormFactor();
-
+
VectorXd NLInkOut(m_nInks);
m_currentMaxNLPerCM = m_maxNlPerCM;
for (int iP = 0; iP < m_nProcessRanges; ++iP)
@@ -277,7 +278,7 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv
else
{
for (int iInk = 0; iInk < m_nInks; ++iInk)
- InkOut[iInk] *= tmpNormFactor; //full range Thread units
+ InkOut[iInk] *= m_NormFactor[iInk]; //full range Thread units
LimitNLInks2Volume(DoubleToVector(InkOut, m_nInks), GamutRegion[iHive], Vol);
}
InGamut = IsInGamut(Lab1P, sur, CS, LabOnGamut);
@@ -644,7 +645,7 @@ void Tango::ColorLib::ColorConverter::SetCalibMode()
{
double *maxVal = new double[m_nInks];
m_maxCalX = new double[m_nInks];
- for (int i= 0; i<m_nInks; ++i)
+ for (int i = 0; i < m_nInks; ++i)
maxVal[i] = m_CalibCurves[i].GetMaxXValue();
int CalType = 0;
int sumCalType = 0;
@@ -659,7 +660,11 @@ void Tango::ColorLib::ColorConverter::SetCalibMode()
}
if (sumCalType == 0)
+ {
m_CalibMode = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ m_maxCalX[i] = m_maxNlPerCM(i);
+ }
else if (sumCalType == m_nInks)
m_CalibMode = 1;
else
@@ -835,7 +840,7 @@ void Tango::ColorLib::ColorConverter::ConvertLabColorToLinearInks(InputCoordinat
else
{
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetNormFactor();
+ InkOutP[i] *= m_NormFactor[i];
}
InkOut = DoubleToVector(InkOutP, m_nInks);
@@ -942,7 +947,7 @@ void Tango::ColorLib::ColorConverter::ConvertRGBColorToLinearInks(InputCoordinat
else
{
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetNormFactor();
+ InkOutP[i] *=m_NormFactor[i];
}
InkOut = DoubleToVector(InkOutP, m_nInks);
@@ -1026,33 +1031,31 @@ void Tango::ColorLib::ColorConverter::ColorTable2Threadunits(VectorXd InkIn, Vec
void Tango::ColorLib::ColorConverter::ApplyCTLinearCurves(double *InkIn, double* InkOut)
{
- double tmpNormFactor = m_colortable->GetNormFactor();
if (m_CalibMode == 1)
{
for (int i = 0; i < m_nInks; ++i)
{
m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkIn[i] * 655.35, InkOut[i]);
InkOut[i] /= 655.35;
- InkOut[i] *= tmpNormFactor;
+ InkOut[i] *= m_NormFactor[i];
}
}
else
{
for (int i = 0; i < m_nInks; ++i)
- InkOut[i] *= tmpNormFactor;
+ InkOut[i] *= m_NormFactor[i];
}
}
void Tango::ColorLib::ColorConverter::ApplyCTInvLinearCurves(double *InkIn, double* InkOut)
{
- double tmpNormFactor = m_colortable->GetInverseNormFactor();
if (m_CalibMode == 1)
{
for (int i = 0; i < m_nInks; ++i)
{
- m_colortable->m_LinCurves->m_InvInterpCurves[i].Eval(InkIn[i] * 655.35*tmpNormFactor, InkOut[i]);
+ m_colortable->m_LinCurves->m_InvInterpCurves[i].Eval(InkIn[i] * 655.35*m_InvNormFactor[i], InkOut[i]);
InkOut[i] /= 655.35;
- InkOut[i] /= tmpNormFactor;
+ InkOut[i] /= m_InvNormFactor[i];
}
}
}
@@ -1380,7 +1383,7 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
VectorXd NLInkP((int)(m_nInks));
VectorXd InkOut((int)(m_nInks));
VectorXd Volume((int)(m_TotalNumberofInks));
-
+ VectorXd FinalVolumeNoLI(m_nInks);
//Convert to Nonlinear Inks
double SumVol_Ink = 0.0;
//Get Gamut Region
@@ -1426,6 +1429,8 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
GamutRegion = GetGamutRegion(VolumeNoLI, m_GamutRegionMaxLim);
GetClosestInk(VolumeNoLI, GamutRegion, VolumeNoLI); //VolumeNoLI is in [%]
VolumeToNLInkP(VolumeNoLI, NLInkP); //NLInkP is in %
+ for (int i = 0; i < m_nInks; ++i)
+ FinalVolumeNoLI(i) = VolumeNoLI(i);
VectorToDouble(NLInkP, InkOutP);
// NLcmtoPercentage(VolumeNoLI, VolumeNoLI);
@@ -1437,7 +1442,7 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
{
//Convert to [0-100] before applying the Linear Curves
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetInverseNormFactor();
+ InkOutP[i] *= m_InvNormFactor[i];
ApplyCTLinearCurves(InkOutP, LinInkP); //Full Range in Color Table Units %
ColorTable2Threadunits(DoubleToVector(LinInkP, m_nInks), InkOut); //Full Range in Thread units %
ConvertToNLInks(InkOut,InkOut); //ful range in Thread units %
@@ -1461,6 +1466,9 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
GamutRegion = GetGamutRegion(VolumeNoLI, m_CurrentProcessRangesMax);
GetClosestInk(VolumeNoLI, GamutRegion, VolumeNoLI); //VolumeNoLI is in [%]
VolumeToNLInkP(VolumeNoLI, NLInkP); //NLInkP is in %
+ //save the above volume as the final one, then calculate RGB coordinates
+ for (int i = 0; i < m_nInks; ++i)
+ FinalVolumeNoLI(i) = VolumeNoLI(i);
VectorToDouble(NLInkP, InkOutP);
Ink4Vol = NLInkP;
//NLInkP are the final Volume values, the transformations are applied to get the right RGB
@@ -1506,7 +1514,7 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
double *LabOutP = new double[3];
//InkOutP has to be normalized to match the transform units
for (int i = 0; i < m_nInks; ++i)
- Ink4RGB[i] *= m_colortable->GetInverseNormFactor(); //[0-100] range, same as Color Table
+ Ink4RGB[i] *= m_InvNormFactor[i]; //[0-100] range, same as Color Table
m_colortable->m_A2BTransform->evalInkP2Lab(Ink4RGB, LabOutP, GamutRegion);
//LabOutP is in Relative Colorimetric
@@ -1529,6 +1537,10 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates
{
RGBOut(i) = RGBOutP[i];
}
+
+
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = FinalVolumeNoLI(i);
if (InkOutP != NULL)
{
delete[]InkOutP;
@@ -1684,6 +1696,11 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i
else
m_nProcessRanges = conversionInput->n_processranges;
+ m_NormFactor = new double[m_nInks];
+ m_InvNormFactor = new double[m_nInks];
+ m_NormFactor = GetNormFactor();
+ m_InvNormFactor = GetInvNormFactor();
+
if (m_NormGamutRegionMaxLim == NULL)
m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
double *tmpVal = m_colortable->GetNormGamutRegionMaxLim();
@@ -1697,8 +1714,16 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i
m_GamutRegionMaxLim[i] = tmpVal[i];
if (m_GamutRegionMinLim == NULL)
m_GamutRegionMinLim = new double[m_nProcessRanges];
- m_GamutRegionMinLim[0] = GamutMinReg0;
- m_GamutRegionMinLim[1] = GamutMinReg1;
+ if(m_GamutRegionMaxLim[1] == 400) //this is replaced in CE V5
+ {
+ m_GamutRegionMinLim[0] = GamutMinReg0;
+ m_GamutRegionMinLim[1] = GamutMinReg1;
+ }
+ else
+ {
+ m_GamutRegionMinLim[0] = GamutMinReg0_E;
+ m_GamutRegionMinLim[1] = GamutMinReg1_E;
+ }
//read calibration tables and store them in m_CalibCurves
InputLiquid **inputliquids = conversionInput->inputcoordinates->inputliquids;
@@ -2737,6 +2762,12 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size
readCalibrationTables(inputliquid, n_inputliquids);
+ m_NormFactor = new double[m_nInks];
+ m_InvNormFactor = new double[m_nInks];
+ m_NormFactor = GetNormFactor();
+ m_InvNormFactor = GetInvNormFactor();
+
+
//Initialize CIECAM02 transformation
Illum IL = D65;
SURROUND sur = average;
@@ -3300,9 +3331,14 @@ void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates*
C_RGB_XYZ_Lab DataLab;
VectorXd InkOut(m_nInks);
- double normFactor = 1;
+ double *normFactor = new double[m_nInks];
if (!same_regions)
normFactor = m_colortable->GetNormFactor();
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ normFactor[i] = 1.0;
+ }
ColorConvert CConvertD65(D65, D65); //Destination, source
if (colorspace == COLOR_SPACE__RGB)
{
@@ -3346,7 +3382,7 @@ void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates*
else
{
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetNormFactor(); //Full Range
+ InkOutP[i] *= normFactor[i]; //Full Range
ColorTable2Threadunits(DoubleToVector(InkOutP, m_nInks) , InkOut); //Full Range
//LimitNLInks2VolumeThr(InkOut, GamutRegion, Volume);
}
@@ -3380,7 +3416,6 @@ void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates*
//convert to Inks
int GamutRegion;
double *InkOutP = new double[m_nInks];
- double tmpNormFactor = m_colortable->GetNormFactor();
if (same_regions)
{
m_colortable->m_B2ARTransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
@@ -3402,7 +3437,7 @@ void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates*
else
{
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetNormFactor(); //Full Range Color Table units
+ InkOutP[i] *= normFactor[i]; //Full Range Color Table units
ColorTable2Threadunits(DoubleToVector(InkOutP, m_nInks), InkOut); //full range Thread Units
}
}
@@ -3424,7 +3459,11 @@ void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates*
throw std::exception("Unsupported Color Space");
return;
}
-
+ if (normFactor != NULL)
+ {
+ delete[] normFactor;
+ normFactor = NULL;
+ }
m_currentMaxNLPerCM = m_maxNlPerCM;
for (int i = 0; i < m_nProcessRanges; ++i)
{
@@ -3471,6 +3510,10 @@ void Tango::ColorLib::ColorConverter::PrepareGradient(GradientConversionInput* c
uint8_t *data = conversionInput->forwarddata.data;
m_nProcessRanges = conversionInput->n_processranges;
m_colortable->InitColorTables(has_forwarddata, data, m_nProcessRanges);
+ m_NormFactor = new double[m_nInks];
+ m_InvNormFactor = new double[m_nInks];
+ m_NormFactor = GetNormFactor();
+ m_InvNormFactor = GetInvNormFactor();
SetNumberofInks(m_colortable->GetnA2BnSepIn());
if (m_NormGamutRegionMaxLim == NULL)
m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
@@ -4512,9 +4555,8 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToLabRel(VectorXd &Volume, Ve
//Convert to Lab
double *LabOutP = new double[3];
-
for (int i = 0; i < m_nInks; ++i)
- InkOutP[i] *= m_colortable->GetInverseNormFactor();
+ InkOutP[i] *= m_InvNormFactor[i];
m_colortable->m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion);
//LabOutP is in Relative Colorimetric
@@ -4815,14 +4857,21 @@ size_t Tango::ColorLib::ColorConverter::GetRecommendedProcessParameters(uint8_t
bool InGamut = false;
m_WP.Set(0.9505, 1.00, 1.0888); //D65
-
if (m_colortable == NULL)
m_colortable = new ColorTable();
readColorTransformations(Input);
+
if (Input->n_processranges <= 0)
throw std::exception("number of process ranges is zero");
else
m_nProcessRanges = Input->n_processranges;
+
+
+ m_NormFactor = new double[m_nInks];
+ m_InvNormFactor = new double[m_nInks];
+ m_NormFactor = GetNormFactor();
+ m_InvNormFactor = GetInvNormFactor();
+
if (m_NormGamutRegionMaxLim == NULL)
m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
double *tmpVal = m_colortable->GetNormGamutRegionMaxLim();
@@ -5183,6 +5232,12 @@ size_t Tango::ColorLib::ColorConverter::CheckOutOfGamut(uint8_t * input_buffer,
throw std::exception("number of process ranges is zero");
else
m_nProcessRanges = Input->n_processranges;
+
+ m_NormFactor = new double[m_nInks];
+ m_InvNormFactor = new double[m_nInks];
+ m_NormFactor = GetNormFactor();
+ m_InvNormFactor = GetInvNormFactor();
+
if (m_NormGamutRegionMaxLim == NULL)
m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
double *tmpVal = m_colortable->GetNormGamutRegionMaxLim();
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h
index d22a074dc..88a781d56 100644
--- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h
@@ -115,8 +115,10 @@ namespace Tango
double m_LightInksThr;
double m_LowVolumeThreshold;
double m_LowVolHalf;
- double m_NormFactor;
- double m_InvnormFactor;
+ double *m_NormFactor;
+ double *m_InvNormFactor;
+ double *GetNormFactor() { return(m_colortable->GetNormFactor()); };
+ double *GetInvNormFactor() { return(m_colortable->GetInverseNormFactor()); };
int m_TotalNumberofInks;
double *m_CalibGain;
double *m_CalibOffset;
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.cpp
index ef2813688..d629a5c11 100644
--- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.cpp
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.cpp
@@ -11,7 +11,7 @@ m_GBD(NULL), m_GBDR(NULL),
m_LinCurves(NULL), m_LinCurvesR(NULL),
m_nB2AnSepIn(0), m_nB2AnSepOut(0),
m_nA2BnSepIn(0), m_nA2BnSepOut(0),
-m_TableVersion(0), m_NormFactor(0.0), m_InvNormFactor(1.0),
+m_TableVersion(0), m_NormFactor(NULL), m_InvNormFactor(NULL),
m_nGamutRegions(0), m_nProcessRanges(0),
m_GamutRegionMaxLim(NULL), m_NormGamutRegionMaxLim(NULL), m_CTLiquidFactors(NULL), m_whitepointXYZ_CT(0.0)
{
@@ -69,6 +69,16 @@ ColorTable::~ColorTable()
delete[] m_NormGamutRegionMaxLim;
m_NormGamutRegionMaxLim = NULL;
}
+ if (m_NormFactor != NULL)
+ {
+ delete[] m_NormFactor;
+ m_NormFactor = NULL;
+ }
+ if (m_InvNormFactor != NULL)
+ {
+ delete[] m_InvNormFactor;
+ m_InvNormFactor = NULL;
+ }
/*if (m_CTLiquidFactors != NULL)
{
delete[] m_CTLiquidFactors;
@@ -645,15 +655,23 @@ void ColorTable::read_text_description_type(int offset, int data_size, std::stri
void ColorTable::SetNormFactor()
{
- m_NormFactor = m_GamutRegionMaxLim[m_nProcessRanges - 1] / m_GamutRegionMaxLim[0];
+ if (m_NormFactor == NULL)
+ m_NormFactor = new double[m_nA2BnSepIn];
+ for (int i = 0; i < m_nA2BnSepIn; ++i)
+ m_NormFactor[i] = m_GamutRegionMaxLim[m_nProcessRanges - 1] / m_CTLiquidFactors[i];
}
void ColorTable::SetInverseNormFactor()
{
- if (m_NormFactor <= 0)
- throw std::exception("NormFactor is zero or Negative");
- else
- m_InvNormFactor = 1.0 / m_NormFactor;
+ if (m_InvNormFactor == NULL)
+ m_InvNormFactor = new double[m_nA2BnSepIn];
+ for (int i = 0; i < m_nA2BnSepIn; ++i)
+ {
+ if (m_NormFactor[i] <= 0)
+ throw std::exception("NormFactor is zero or Negative");
+ else
+ m_InvNormFactor[i] = 1.0 / m_NormFactor[i];
+ }
}
void ColorTable::NormGamutRegionMaxLim()
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.h
index e1c9e1998..047211319 100644
--- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.h
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorTable.h
@@ -32,8 +32,8 @@ public:
int GetnA2BnSepIn() { return(m_nA2BnSepIn); };
int GetnA2BnSepOut() { return(m_nA2BnSepOut); };
int GetnGamutRegions() { return(m_nGamutRegions); };
- double GetNormFactor() { return(m_NormFactor); };
- double GetInverseNormFactor() { return(m_InvNormFactor); };
+ double *GetNormFactor() { return(m_NormFactor); };
+ double *GetInverseNormFactor() { return(m_InvNormFactor); };
double *GetNormGamutRegionMaxLim() { return(m_NormGamutRegionMaxLim); };
double *GetGamutRegionMaxLim() { return(m_GamutRegionMaxLim); };
double *GetCTLiquidFactors() { return(m_CTLiquidFactors); };
@@ -58,8 +58,8 @@ private:
int m_nGamutRegions;
int m_nProcessRanges;
int m_TableVersion;
- double m_NormFactor;
- double m_InvNormFactor;
+ double *m_NormFactor;
+ double *m_InvNormFactor;
double *m_GamutRegionMaxLim;
double*m_NormGamutRegionMaxLim;
double *m_CTLiquidFactors;
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.cpp
new file mode 100644
index 000000000..9234a9ed7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.cpp
@@ -0,0 +1,719 @@
+#include "ColorCalibrator.h"
+#include "CalibrationInput.pb-c.h"
+#include "CalibrationOutput.pb-c.h"
+#include "CalibrationMeasurement.pb-c.h"
+#include "LinearizationInput.pb-c.h"
+#include "LinearizationOutput.pb-c.h"
+#include "LinearizationMeasurement.pb-c.h"
+#include "Interp.h"
+
+#include <math.h>
+#include <algorithm>
+#include <exception>
+#include <vector>
+using namespace std;
+
+#ifdef MEMORY_TEST
+ #define _CRTDBG_MAP_ALLOC
+ #include <stdlib.h>
+ #include <crtdbg.h>
+ #include <cstdlib>
+#endif
+
+//#ifdef _DEBUG
+//#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+//// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+//// allocations to be of _CLIENT_BLOCK type
+//#else
+//#define DBG_NEW new
+//#endif
+
+#define MDRThr 1.0
+#define epsTol 0.05
+#define PI 4*atan(1.0)
+#define dEThr 1.0
+
+
+Tango::ColorLib::ColorCalibrator::ColorCalibrator(): m_nsize(0), m_nlcm(NULL), m_LabData(NULL), m_inkChannel(0), m_targetVal(NULL), m_CalIndex(0), m_inkpercentage(NULL)
+{
+#ifdef MEMORY_TEST
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
+#endif // MEMORY_TEST
+}
+
+
+Tango::ColorLib::ColorCalibrator::~ColorCalibrator()
+{
+ ClearData();
+#ifdef MEMORY_TEST
+ _CrtDumpMemoryLeaks();
+#endif // MEMORY_TEST
+}
+
+void Tango::ColorLib::ColorCalibrator::ClearData()
+{
+ if (m_LabData != NULL)
+ {
+ for (int i = 0; i < m_nsize; ++i)
+ delete[] m_LabData[i];
+ delete[] m_LabData;
+ m_LabData = NULL;
+ }
+ if (m_nlcm != NULL)
+ {
+ delete[] m_nlcm;
+ m_nlcm = NULL;
+ }
+ if (m_targetVal != NULL)
+ {
+ delete[] m_targetVal;
+ m_targetVal = NULL;
+ }
+ if (m_inkpercentage != NULL)
+ {
+ delete[] m_inkpercentage;
+ m_inkpercentage = NULL;
+ }
+}
+
+size_t Tango::ColorLib::ColorCalibrator::GetLiquidFactor(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ //Get Input
+ CalibrationInput* calibrationInput = calibration_input__unpack(NULL, input_buffer_size, input_buffer);
+
+ //Investigate Input
+ InitData((const CalibrationMeasurement**)calibrationInput->measurements, calibrationInput->n_measurements, calibrationInput->liquidtype, calibrationInput->targetl, calibrationInput->targeta, calibrationInput->targetb);
+
+ //Init Output
+ CalibrationOutput *calibrationOutput = (CalibrationOutput*)malloc(sizeof(CalibrationOutput));
+ calibration_output__init(calibrationOutput);
+
+
+ //{{{ TEST
+ //double targetL = calibrationInput->has_targetl; //Get Target LAB...
+
+ //for (size_t i = 0; i < calibrationInput->n_measurements; i++) //Iterate measurements...
+ //{
+ // CalibrationMeasurement* m = calibrationInput->measurements[i];
+
+ // m->nanoliterpercentimeter; //NL PER CM..
+ // m->l; //L
+ // m->a; //A
+ // m->b; //B
+ //}
+ //calibrationOutput->liquidfactor = 5.0;
+ //}}}
+
+ //Set Output
+ calibrationOutput->has_liquidfactor = true;
+ std::string error_message;
+ MaximalDispensingRate(calibrationOutput->liquidfactor, error_message);
+ const char* c_error = error_message.c_str();
+ if (strlen(c_error) > 0)
+ {
+ calibrationOutput->errormessage = strdup(c_error);
+ }
+
+ //Pack Output
+ output_buffer = (uint8_t*)malloc(calibration_output__get_packed_size(calibrationOutput));
+ int size = calibration_output__pack(calibrationOutput, output_buffer);
+
+ //Free Resources
+ calibration_input__free_unpacked(calibrationInput, NULL);
+ calibration_output__free_unpacked(calibrationOutput, NULL);
+
+ return size;
+}
+
+size_t Tango::ColorLib::ColorCalibrator::GetLinearizationMeasurements(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ //Get Input
+ LinearizationInput* linearizationInput = linearization_input__unpack(NULL, input_buffer_size, input_buffer);
+ try
+ {
+ //Investigate Input
+ LinearizationInitData((const LinearizationMeasurement**)linearizationInput->measurements, linearizationInput->n_measurements, linearizationInput->liquidtype, linearizationInput->targetl, linearizationInput->targeta, linearizationInput->targetb);
+
+ //Init Output
+ LinearizationOutput *linearizationOutput = (LinearizationOutput*)malloc(sizeof(LinearizationOutput));
+ linearization_output__init(linearizationOutput);
+
+ std::string error_message;
+ linearizationOutput->n_inkpercentage = m_nsize;
+ linearizationOutput->inkpercentage = new double[m_nsize];
+ Linearizaton(m_inkpercentage, linearizationOutput->inkpercentage, error_message);
+ const char* c_error = error_message.c_str();
+ if (strlen(c_error) > 0)
+ {
+ //linearizationOutput->has_haserror = true;
+ //linearizationOutput->haserror = true;
+ linearizationOutput->errormessage = strdup(c_error);
+ }
+ //Pack Output
+ output_buffer = (uint8_t*)malloc(linearization_output__get_packed_size(linearizationOutput));
+ int size = linearization_output__pack(linearizationOutput, output_buffer);
+
+ //Free Resources
+ linearization_input__free_unpacked(linearizationInput, NULL);
+ linearization_output__free_unpacked(linearizationOutput, NULL);
+
+ return size;
+ }
+ catch (const std::exception& e)
+ {
+ //Notify Error...
+ LinearizationOutput *linearizationOutput = (LinearizationOutput*)malloc(sizeof(LinearizationOutput));
+ linearization_output__init(linearizationOutput);
+
+ linearizationOutput->has_haserror = true;
+ linearizationOutput->haserror = true;
+
+ const char* what = e.what();
+ linearizationOutput->errormessage = strdup(what);
+
+ output_buffer = (uint8_t*)malloc(linearization_output__get_packed_size(linearizationOutput));
+ int size = linearization_output__pack(linearizationOutput, output_buffer);
+ //Free Resources
+ linearization_input__free_unpacked(linearizationInput, NULL);
+ linearization_output__free_unpacked(linearizationOutput, NULL);
+
+ return (size);
+ }
+}
+
+void Tango::ColorLib::ColorCalibrator::InitData(const CalibrationMeasurement** m, const size_t &nsize, const int &inkChannel, const double& targetl, const double& targeta, const double& targetb)
+{
+ ClearData();
+
+ m_nsize = nsize;
+ m_LabData = new double*[m_nsize];
+ m_nlcm = new double[m_nsize];
+
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ m_LabData[i] = new double[3];
+ m_LabData[i][0] = m[i]->l;
+ m_LabData[i][1] = m[i]->a;
+ m_LabData[i][2] = m[i]->b;
+ m_nlcm[i] = m[i]->nanoliterpercentimeter;
+
+ }
+ m_inkChannel = inkChannel;
+ m_targetVal = new double[3];
+ m_targetVal[0] = targetl;
+ m_targetVal[1] = targeta;
+ m_targetVal[2] = targetb;
+
+ m_CalIndex = 0;
+ if (m_inkChannel == 2)
+ m_CalIndex = 2;
+}
+void Tango::ColorLib::ColorCalibrator::MaximalDispensingRate(double &MDispRate, std::string &outputmessage)
+{
+ MDispRate = -1000;
+ double *yVal = new double[m_nsize];
+
+ double maxVal = -1000;
+ double minVal = 1000;
+ int maxInd = -1;
+ int minInd = -1;
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ yVal[i] = m_LabData[i][m_CalIndex];
+ if (maxVal < yVal[i])
+ {
+ maxVal = yVal[i];
+ maxInd = i;
+ }
+ if (minVal > yVal[i])
+ {
+ minVal = yVal[i];
+ minInd = i;
+ }
+ }
+ if (maxVal - minVal < MDRThr)
+ {
+ delete[] yVal;
+ yVal = NULL;
+ outputmessage = "Maximal and Minimal Values are too close";
+ return;
+ }
+
+ //increasing or decreasing
+ int KC = 0;
+ if (yVal[0] < yVal[m_nsize - 1])
+ KC = 1; // increasing
+ else if (yVal[0] > yVal[m_nsize - 1])
+ KC = -1; // decreasing
+ int indLab = 0;
+ if (m_inkChannel == 2) //Yellow
+ indLab = 2;
+ double dE = 0.0;
+ if ((m_targetVal[indLab] < minVal) | (m_targetVal[indLab] > maxVal))
+ {
+ //Advice
+ if (KC == 1)
+ {
+ if (m_targetVal[indLab] < minVal)
+ {
+ //Increasing Function, dispensing rate above values
+ dEcmc(m_targetVal, m_LabData[minInd], dE);
+ if (dE < dEThr)
+ MDispRate = m_nlcm[minInd];
+ else
+ {
+ if (yVal != NULL)
+ {
+ delete[] yVal;
+ yVal = NULL;
+ }
+ outputmessage = "Target Value does not fall in data interval,decrease dispensing rate";
+ return;
+ }
+ }
+ else if (m_targetVal[indLab] > maxVal)
+ {
+ //Increasing Function, dispensing rate below values
+ dEcmc(m_targetVal, m_LabData[maxInd], dE);
+ if (dE < dEThr)
+ MDispRate = m_nlcm[maxInd];
+ else
+ {
+ if (yVal != NULL)
+ {
+ delete[] yVal;
+ yVal = NULL;
+ }
+ outputmessage ="Target Value does not fall in data interval,increase dispensing rate";
+ return;
+ }
+ }
+ }
+ else //decreasing //KC = -1
+ {
+ if (m_targetVal[indLab] < minVal)
+ {
+ //decreasing Function, dispensing rate above values
+ dEcmc(m_targetVal, m_LabData[minInd], dE);
+ if (dE < dEThr)
+ MDispRate = m_nlcm[minInd];
+ else
+ {
+ if (yVal != NULL)
+ {
+ delete[] yVal;
+ yVal = NULL;
+ }
+ outputmessage = "Target Value does not fall in data interval,increase dispensing rate";
+ return;
+ }
+ }
+ else if (m_targetVal[indLab] > maxVal)
+ {
+ //Increasing Function, dispensing rate below values
+ dEcmc(m_targetVal, m_LabData[maxInd], dE);
+ if (dE < dEThr)
+ MDispRate = m_nlcm[maxInd];
+ else
+ {
+
+ if (yVal != NULL)
+ {
+ delete[] yVal;
+ yVal = NULL;
+ outputmessage = "Target Value does not fall in data interval,decrease dispensing rate";
+ return;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_nsize; ++i)
+ yVal[i] *= KC;
+ double targetVal = KC * m_targetVal[indLab];
+ for (int i = 0; i < m_nsize - 1; ++i)
+ {
+ if ((yVal[i] <= targetVal) & (targetVal < yVal[i + 1]))
+ MDispRate = ((targetVal - yVal[i])*m_nlcm[i + 1] + (yVal[i + 1] - targetVal)*m_nlcm[i]) / (yVal[i + 1] - yVal[i]);
+ }
+ }
+
+}
+
+void Tango::ColorLib::ColorCalibrator::dEcmc(double *refX, double *samX, double &dECMC)
+{
+ //dEcmc(refX, samX) calculates color difference CMC(2:1) in
+ //CIE - L*a*b* colorspace between references(refX) and
+ // samples(samX)
+
+// reference parameter calculations
+ // hue calculation
+ double h1 = atan2(refX[2], refX[1])*(180 / PI);
+ if (h1 < 0)
+ h1 = h1 + 360;
+ double h2 = atan2(samX[2], samX[1])*(180 / PI);
+ if (h2 < 0)
+ h2 = h2 + 360;
+ double refX_H = h1;
+ //chroma calculation
+ double refX_C = sqrt(refX[1] * refX[1] + refX[2] * refX[2]);
+ //reference SL parameter
+ double refX_SL;
+ if (refX[1] <= 16)
+ refX_SL = 0.511;
+ else
+ refX_SL = refX[1] * 0.040975 / (1 + 0.01765*refX[1]);
+ //reference SC parameter
+ double refX_SC = (0.638 + 0.0638*refX_C / (1 + 0.0131*refX_C));
+ //reference CQ parameter
+ double refX_CQ = pow(refX_C, 4);
+ //reference F parameter
+ double refX_F = sqrt(refX_CQ / (refX_CQ + 1900));
+ // reference T parameter
+ double refX_T = 0;
+ if ((refX_H > 164) & (refX_H < 345))
+ refX_T = 0.56 + abs(0.2*cos(PI*(refX_H + 168) / 180));
+ else if ((refX_H >= 345) | (refX_H <= 164))
+ refX_T = 0.36 + abs(0.4*cos(PI*(refX_H + 35) / 180));
+ // reference SH parameter
+ double refX_SH = refX_SC * (refX_T*refX_F + 1 - refX_F);
+
+ //sample parameter calculations
+ //hue calculation
+ double samX_H = h2;
+ //chroma calculation
+ double samX_C = sqrt(samX[1] * samX[1] + samX[2] * samX[2]);
+
+ double dL = refX[0] - samX[0];
+ double dC = samX_C - refX_C;
+ double da = refX[1] - samX[1];
+ double db = refX[2] - samX[2];
+ double dH = sqrt(max(da*da + db * db - dC * dC, 0.0));
+
+ dECMC = sqrt(pow(dL / (2 * refX_SL), 2) + pow(dC / refX_SC, 2) + pow(dH / refX_SH, 2));
+}
+
+void Tango::ColorLib::ColorCalibrator::LinearizationInitData(const LinearizationMeasurement** m, const size_t &nsize, const int &inkChannel, const double& targetl, const double& targeta, const double& targetb)
+{
+ ClearData();
+ m_nsize = nsize;
+ m_LabData = new double*[m_nsize];
+ m_inkpercentage = new double[m_nsize];
+
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ m_LabData[i] = new double[3];
+ m_LabData[i][0] = m[i]->l;
+ m_LabData[i][1] = m[i]->a;
+ m_LabData[i][2] = m[i]->b;
+ m_inkpercentage[i] = m[i]->inkpercentage;
+
+ }
+ m_inkChannel = inkChannel;
+ m_targetVal = new double[3];
+ m_targetVal[0] = targetl;
+ m_targetVal[1] = targeta;
+ m_targetVal[2] = targetb;
+
+ m_CalIndex = 0;
+ if (m_inkChannel == 2)
+ m_CalIndex = 2;
+}
+void Tango::ColorLib::ColorCalibrator::Linearizaton(double *InkVals, double *&LinearInkVal, std::string &error)
+{
+ double maxVal = -1000;
+ double minVal = 1000;
+ double * yVal = new double[m_nsize];
+
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ yVal[i] = m_LabData[i][m_CalIndex];
+ }
+ bool res = SortValues(InkVals, yVal);
+
+ if (CheckDuplicates(InkVals, error))
+ return;
+ int foundValInd = -1;
+ if (CheckLimits(InkVals, foundValInd, error))
+ return;
+
+ //Values are sorted and unique
+ //SmoothCurveData(InkVals, yVal, 7);
+ if (CheckMonotonicity(yVal, error))
+ return;
+ //Values are monotonic, therefore can be inverted
+
+ int Kconst = 1;
+ if (yVal[0] > yVal[m_nsize - 1])
+ Kconst = -1;
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ yVal[i] *= Kconst;
+ }
+
+ if (false == Linearize(yVal, LinearInkVal, 0, m_nsize, error))
+ {
+ return;
+ }
+}
+
+bool Tango::ColorLib::ColorCalibrator::SortValues(double *InkVals, double *yVal)
+{
+ //prepare data
+ std::vector<VectorPair> IndVal;
+
+ //fill up first vector pair
+
+ double *tmpLab = new double[m_nsize];
+ double *tmpInk = new double[m_nsize];
+ int *tmpSort = new int[m_nsize];
+ int *SortIndex = new int[m_nsize];
+ //init index
+ IndVal.resize(m_nsize);
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ IndVal[i].m_ID = i;
+ SortIndex[i] = i;
+ IndVal[i].m_val = m_inkpercentage[i];
+ yVal[i] = m_LabData[i][m_CalIndex];
+ }
+
+ std::stable_sort(IndVal.begin(), IndVal.end(), ByDouble());
+ //arrange all sorted values
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ tmpLab[i] = yVal[IndVal[i].m_ID];
+ tmpInk[i] = InkVals[IndVal[i].m_ID];
+ tmpSort[i] = SortIndex[IndVal[i].m_ID];
+ }
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ yVal[i] = tmpLab[i];
+ m_inkpercentage[i] = tmpInk[i];
+ InkVals[i] = tmpInk[i];
+ SortIndex[i] = tmpSort[i];
+ }
+ if (tmpSort != NULL)
+ {
+ delete[] tmpSort;
+ tmpSort = NULL;
+ }
+ if (tmpLab != NULL)
+ {
+ delete[] tmpLab;
+ tmpLab = NULL;
+ }
+ if (tmpInk != NULL)
+ {
+ delete[] tmpInk;
+ tmpInk = NULL;
+ }
+ IndVal.resize(0);
+ return(true);
+}
+bool Tango::ColorLib::ColorCalibrator::CheckDuplicates(double *InkVals, std::string &error)
+{
+ double diff;
+ for (int i = 0; i < m_nsize - 1; ++i)
+ {
+ diff = InkVals[i + 1] - InkVals[i];
+ if (diff == 0.0)
+ {
+ error = "Ink Percentages have to be unique";
+ return true;
+ //throw std::exception("Ink Percentages have to be unique");
+ }
+ }
+ return false;
+}
+
+bool Tango::ColorLib::ColorCalibrator::CheckLimits(double *InkVals, int &foundValInd, std::string &error)
+{
+ double maxVal = -1000.0;
+ double minVal = 1000.0;
+ double constVal = 100.0;
+ bool foundVal = false;
+
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ if (InkVals[i] == constVal)
+ {
+ foundValInd = i;
+ foundVal = true;
+ }
+ maxVal = fmax(maxVal, InkVals[i]);
+ minVal = fmin(minVal, InkVals[i]);
+ }
+ if (maxVal < 100.0)
+ {
+ error ="Maximal value has to be at least 100%";
+ return true;
+ }
+ if (foundVal == false)
+ {
+ error = "Inks List has to contain 100%";
+ return true;
+ }
+ //if (foundValInd >= 0)
+ // if (maxVal > InkVals[foundValInd])
+ // NumIntervals = 2;
+ if (minVal != 0.0)
+ {
+ error = "Minimal value has to be 0";
+ return true;
+ }
+ return false;
+}
+
+void Tango::ColorLib::ColorCalibrator::SmoothCurveData(double *XVal, double *YVal, int FilterWidth)
+{
+ int NumIter = max(FilterWidth, 3) - 2;
+ //Smooth the data with repeated applications of a[1 1 1] filter
+ int npts = 101;
+ int n_interval = npts - 1;
+ double *xinterp = new double[npts];
+ double *yinterp = new double[npts];
+ Interp AddPts;
+ double *sxVal = new double[m_nsize];
+ double *syVal = new double[m_nsize];
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ sxVal[i] = XVal[i];
+ syVal[i] = YVal[i];
+ }
+ AddPts.SetNPoints(m_nsize);
+ AddPts.SetXCoords(sxVal);
+ AddPts.SetYCoords(syVal);
+ double dInterval = (sxVal[m_nsize - 1] - sxVal[0]) / n_interval;
+ double ytmp = 0;
+ for (int iadd = 0; iadd < npts; ++iadd)
+ {
+ xinterp[iadd] = double(iadd)*dInterval;
+ AddPts.Eval(xinterp[iadd], ytmp);
+ yinterp[iadd] = ytmp;
+ }
+
+ double *tmpyVal = new double[npts];
+ for (int i = 0; i < NumIter; ++i)
+ {
+ for (int j = 0; j < npts; ++j)
+ tmpyVal[j] = yinterp[j];
+ for (int j = 1; j < npts - 1; ++j)
+ yinterp[j] = (tmpyVal[j - 1] + tmpyVal[j] + tmpyVal[j + 1]) / 3;
+ }
+ Interp SmoothPts;
+ SmoothPts.SetNPoints(npts);
+ SmoothPts.SetXCoords(xinterp);
+ SmoothPts.SetYCoords(yinterp);
+ for (int i = 0; i < m_nsize; ++i)
+ {
+ SmoothPts.Eval(XVal[i], ytmp);
+ YVal[i] = ytmp;
+ }
+ if(tmpyVal!=NULL)
+ {
+ delete[] tmpyVal;
+ tmpyVal = NULL;
+ }
+ /*if (xinterp != NULL)
+ {
+ delete[] xinterp;
+ xinterp = NULL;
+ }
+ if (yinterp != NULL)
+ {
+ delete[] yinterp;
+ yinterp = NULL;
+ }*/
+}
+
+bool Tango::ColorLib::ColorCalibrator::CheckMonotonicity(double *yVal, std::string &error)
+{
+ //Check Monotonicity of Smooth Lab Channel
+
+ double diff;
+ diff = yVal[m_nsize - 1] - yVal[0];
+ int CF = 1;
+ if (diff < 0)
+ CF = -1;
+
+ for (int i = 0; i < m_nsize - 1; ++i)
+ {
+ diff = CF * (yVal[i + 1] - yVal[i]);
+ if (diff <= 0.0)
+ {
+ error = "Non monotonic behavior, please remeasure";
+ return true;
+ }
+ }
+ return false;
+}
+bool Tango::ColorLib::ColorCalibrator::Linearize(double *yVal, double*LinearInkVal, int FirstInkInd, int LasInkInd, std::string &error)
+{
+ double Gain = (yVal[LasInkInd - FirstInkInd-1] - yVal[0]) / (m_inkpercentage[LasInkInd - 1] - m_inkpercentage[FirstInkInd]);
+ double Offset = yVal[0] - Gain * m_inkpercentage[FirstInkInd];
+ int nPoints = LasInkInd - FirstInkInd ;
+ double *LabLinear = new double[nPoints];
+ double *partialInkPercentage = new double[nPoints];
+ for (int i = 0; i < nPoints; i++)
+ {
+ LabLinear[i] = Gain * m_inkpercentage[FirstInkInd + i] + Offset;
+ partialInkPercentage[i] = m_inkpercentage[FirstInkInd + i];
+ }
+ double outVal = 0.0;
+ for (int i = 0; i < nPoints; i++)
+ {
+ if (false == Interp1D(LabLinear, partialInkPercentage, yVal[i], nPoints, outVal, error))
+ {
+ delete[] LabLinear;
+ LabLinear = NULL;
+ delete[] partialInkPercentage;
+ partialInkPercentage = NULL;
+ return false;
+ }
+ LinearInkVal[i] = outVal;
+ }
+ delete[] LabLinear;
+ LabLinear = NULL;
+ delete[] partialInkPercentage;
+ partialInkPercentage = NULL;
+ return true;
+}
+bool Tango::ColorLib::ColorCalibrator::Interp1D(double* xx, double *yy, double InValue, int np, double &OutValue, std::string &error)
+{
+ int m, ind;
+ int errType = 0;
+
+ ind = -1;
+
+ //Check Bounds
+ if ((InValue < xx[0] - epsTol) || (InValue > xx[np - 1] + epsTol))
+ {
+ error = "Interp1D: In Value out of Bounds";
+ return false;
+ }
+
+ if ((InValue > xx[0] - epsTol) && (InValue < xx[0]))
+ InValue = xx[0];
+
+ if ((InValue > xx[np - 1]) && (InValue < xx[np - 1] + epsTol))
+ InValue = xx[np - 1];
+
+ for (m = 0; m < np - 1; ++m)
+ {
+ if (xx[m] <= InValue && xx[m + 1] >= InValue)
+ {
+ ind = m;
+ break;
+ }
+ }
+ if (ind == -1)
+ {
+ error = "Could not find interpolation interval";
+ return false;
+ }
+ OutValue = ((InValue - xx[m])*yy[m + 1] + (xx[m + 1] - InValue)*yy[m]) / (xx[m + 1] - xx[m]);
+ return true;
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.h
new file mode 100644
index 000000000..3e9a00e51
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorCalibrator.h
@@ -0,0 +1,67 @@
+#include <cstdlib>
+#include <cstdint>
+#include <string>
+#include "CalibrationInput.pb-c.h"
+#include "CalibrationOutput.pb-c.h"
+#include "CalibrationMeasurement.pb-c.h"
+#include "LinearizationMeasurement.pb-c.h"
+
+#pragma once
+
+namespace Tango
+{
+ namespace ColorLib
+ {
+ class ColorCalibrator
+ {
+ public:
+ ColorCalibrator();
+ ~ColorCalibrator();
+ size_t Tango::ColorLib::ColorCalibrator::GetLiquidFactor(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ size_t Tango::ColorLib::ColorCalibrator::GetLinearizationMeasurements(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ protected:
+ void InitData(const CalibrationMeasurement** m,
+ const size_t &nsize, const int &inkChannel, const double& targetl, const double& targeta, const double& targetb);
+ void MaximalDispensingRate(double &MDispRate, std::string &outputmessage);
+ void dEcmc(double *refX, double *samX, double &dECMC);
+
+ void LinearizationInitData(const LinearizationMeasurement** m,
+ const size_t &nsize, const int &inkChannel, const double& targetl, const double& targeta, const double& targetb);
+ void Linearizaton(double *InkVals, double*& LinearInkVal, std::string &error);
+ bool SortValues(double *InkVals, double *yVal);
+ bool CheckLimits(double *InkVals, int &foundValInd, std::string &error);
+ void SmoothCurveData(double *XVal, double *YVal, int FilterWidth);
+ bool CheckMonotonicity(double *yVal, std::string &error);
+ bool CheckDuplicates(double *InkVals, std::string &error);
+ bool Linearize(double *yVal, double*LinearInkVal, int FirstInkInd, int LasInkInd, std::string &error);
+ bool Interp1D(double* xx, double *yy, double InValue, int np, double &OutValue, std::string &error);
+
+ protected:
+ struct VectorPair
+ {
+ int m_ID;
+ double m_val;
+ };
+ struct ByDouble : public std::binary_function<VectorPair, VectorPair, bool>
+ {
+ bool operator()(const VectorPair& lhs, const VectorPair& rhs) const
+ {
+ return lhs.m_val < rhs.m_val;
+ }
+ };
+ private:
+ void ClearData();
+
+ private:
+ int m_nsize;
+ double *m_nlcm;
+ double **m_LabData;
+ int m_inkChannel;
+ double *m_targetVal;
+ int m_CalIndex;
+
+ double *m_inkpercentage;
+ };
+ }
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.cpp
new file mode 100644
index 000000000..5d929b48a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.cpp
@@ -0,0 +1,5791 @@
+#include "ColorConverter.h"
+#include "ColorConvert.h"
+#include "CalibrationPoint.pb-c.h"
+#include "CalibrationData.pb-c.h"
+#include "ColorSpace.pb-c.h"
+#include "ConversionInput.pb-c.h"
+#include "ConversionOutput.pb-c.h"
+#include "InputCoordinates.pb-c.h"
+#include "OutputCoordinates.pb-c.h"
+#include "OutputLiquid.pb-c.h"
+#include "InputLiquid.pb-c.h"
+#include "LiquidType.pb-c.h"
+#include "ObjectiveFunction.h"
+#include "LevMar.h"
+#include <iostream>
+#include <stdio.h>
+#include "Dense"
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorConvert.h"
+#include "ColorTransf.h"
+#include "NumConversions.h"
+#include "Interp.h"
+#include <cmath>
+#include <algorithm>
+#include <sstream>
+#include<vector>
+#include <map>
+
+#include "GradientConversionInput.pb-c.h"
+#include "GradientConversionOutput.pb-c.h"
+#include "GradientInputStop.pb-c.h"
+#include "GradientOutputStop.pb-c.h"
+#include "LiquidVolume.pb-c.h"
+#include "RecommendedProcessTableInput.pb-c.h"
+#include "RecommendedProcessTableOutput.pb-c.h"
+#include "OutOfGamutInput.pb-c.h"
+#include "OutOfGamutOutput.pb-c.h"
+
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif
+
+#define dL 2.0
+#define dC 2.0
+#define dH6 EIGEN_PI / 3.0
+#define dH12 EIGEN_PI / 6.0
+#define LUMINANCE_PCS 159.16
+#define L_A LUMINANCE_PCS / 5.0
+#define Y_b 20.0
+#define eps 1e-06
+#define NegValue -1000
+#define WPTol 1.0
+#define dETol 2.0
+# define ROUNDINGDigits 2.0
+#define maxPerRegion 100.0
+#define GamutMinReg0 200
+#define GamutMinReg1 300
+//#define LowVolumeThreshold 0.5
+//#define LowVolHalf LowVolumeThreshold/2
+#define GradientEndThr 0.95
+#define DilutionFactor 10
+//#define LightInksThr 5
+
+
+Tango::ColorLib::ColorConverter::ColorConverter() :
+ m_CalibCurves(NULL), m_Conv02(NULL),
+ m_maxNlPerCM(NULL), m_CTmaxNlPerCM(NULL), m_currentMaxNLPerCM(NULL), m_maxCalX(NULL),
+ m_nInks(0), m_nVolumes(0), m_CalibMode(0), m_CalibGain(NULL), m_CalibOffset(NULL),
+ m_GradStops(NULL), m_nGradStops(0), m_colortable(NULL), m_ProcessRangesMaxP(NULL),
+ m_ProcessRangesMinP(NULL), m_CurrentProcessRangesMax(NULL), m_CurrentProcessRangesMin(NULL),
+ m_nProcessRanges(0), //m_NormGamutRegionMaxLim(NULL),
+ m_GamutRegionMaxLim(NULL),
+ m_GamutRegionMinLim(NULL), m_forwardmodel(NULL),
+ m_UseLightInks(false), m_InkNames(NULL), m_LightInksThr (0.0),
+ m_LowVolumeThreshold(0.0), m_LowVolHalf(0.0)
+ //, m_NormFactor(0.0), m_InvnormFactor(0.0)
+{
+ m_whitepointLab.Set(-1, -1, -1);
+ m_whitepointXYZ_Strip.Set(-1, -1, -1);
+ m_WP.Set(-1, -1, -1);
+}
+
+Tango::ColorLib::ColorConverter::~ColorConverter()
+{
+ if (m_Conv02 != NULL)
+ {
+ delete m_Conv02;
+ m_Conv02 = NULL;
+ }
+ if (m_CalibCurves != NULL)
+ {
+ delete[] m_CalibCurves;
+ m_CalibCurves = NULL;
+ }
+ if (m_GradStops != NULL)
+ {
+ delete[] m_GradStops;
+ m_GradStops = NULL;
+ }
+ if (m_colortable != NULL)
+ {
+ delete m_colortable;
+ m_colortable = NULL;
+ }
+/* if (m_NormGamutRegionMaxLim != NULL)
+ {
+ delete[] m_NormGamutRegionMaxLim;
+ m_NormGamutRegionMaxLim = NULL;
+ } */
+ if (m_GamutRegionMaxLim != NULL)
+ {
+ delete[] m_GamutRegionMaxLim;
+ m_GamutRegionMaxLim = NULL;
+ }
+ if (m_GamutRegionMinLim != NULL)
+ {
+ delete[] m_GamutRegionMinLim;
+ m_GamutRegionMinLim = NULL;
+ }
+ if (m_ProcessRangesMaxP != NULL)
+ {
+ delete[] m_ProcessRangesMaxP;
+ m_ProcessRangesMaxP = NULL;
+ }
+ if (m_ProcessRangesMinP != NULL)
+ {
+ delete[] m_ProcessRangesMinP;
+ m_ProcessRangesMaxP = NULL;
+ }
+ if (m_InkNames != NULL)
+ {
+ delete[] m_InkNames;
+ m_InkNames = NULL;
+ }
+ if (m_CalibGain != NULL)
+ {
+ delete[] m_CalibGain;
+ m_CalibGain = NULL;
+ }
+ if (m_CalibOffset != NULL)
+ {
+ delete[] m_CalibOffset;
+ m_CalibOffset = NULL;
+ }
+ if (m_maxCalX != NULL)
+ {
+ delete[] m_maxCalX;
+ m_maxCalX = NULL;
+ }
+ if (m_CurrentProcessRangesMax != NULL)
+ {
+ delete[] m_CurrentProcessRangesMax;
+ m_CurrentProcessRangesMax = NULL;
+ }
+ if (m_CurrentProcessRangesMin != NULL)
+ {
+ delete[] m_CurrentProcessRangesMin;
+ m_CurrentProcessRangesMin = NULL;
+ }
+ //_CrtDumpMemoryLeaks();
+}
+
+void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conversionInput, VectorXd Lab,
+ VectorXd RGB, VectorXd Volume, int InGamutRegion, MatrixXd &ORGBHive, MatrixXd &OLabHive,
+ MatrixXd &OVolumeHive, int nHive, int *&OGamutRegion, int *indDataMax)
+{
+ size_t retVal = 0;
+ ColorConvert ColConv(D65, D65);
+ SURROUND sur = m_Conv02->getSurround();
+ CAM02CS CS = m_Conv02->getCAM02CS();
+ VectorXd LabV(3);
+
+ LabV = Lab;
+
+ //LCH coordinates
+ double hue = 0.0;
+ double chroma = sqrt(Lab(1)*Lab(1) + Lab(2)*Lab(2));
+
+ if ((abs(Lab(1)) < eps) & (abs(Lab(2)) < eps))
+ hue = 0.0;
+ else
+ hue = atan2(Lab(2), Lab(1));
+
+ double d1 = dC;
+ double de = 0;
+ MatrixXd Lab1(nHive, 3);
+ for (int i = 0; i < 6; ++i)
+ {
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + dC * cos(i*dH6);
+ LabV(2) = Lab(2) + dC * sin(i*dH6);
+ //Iterate to get the correct dECMC
+ d1 = dC;
+ de = 0.0;
+ while (abs(de - dC) > 0.01)
+ {
+ ColConv.dEcmc(LabV, Lab, de);
+ d1 = dC * d1 / de;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + d1 * cos(i*dH6);
+ LabV(2) = Lab(2) + d1 * sin(i*dH6);
+ }
+ //fix
+ Lab1(i, 0) = LabV(0);
+ Lab1(i, 1) = Lab(1) + d1 * cos(i*dH6);
+ Lab1(i, 2) = Lab(2) + d1 * sin(i*dH6);
+ }
+
+ int j1 = 0, j2 = 0;
+ double dC2 = dC * 2.0;
+ for (int i = 0; i < 12; ++i)
+ {
+ j1 = i + 6;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + dC2 * cos(i*dH12);
+ LabV(2) = Lab(2) + dC2 * sin(i*dH12);
+ de = 0.0;
+ while (abs(de - dC2) > 0.01)
+ {
+ ColConv.SymmetricaldECMC(LabV, Lab, de);
+ d1 = dC2 * d1 / de;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + d1 * cos(i*dH12);
+ LabV(2) = Lab(2) + d1 * sin(i*dH12);
+ }
+ //fix
+ Lab1(j1, 0) = LabV(0);
+ Lab1(j1, 1) = Lab(1) + d1 * cos(i*dH12);
+ Lab1(j1, 2) = Lab(2) + d1 * sin(i*dH12);
+ }
+
+ MatrixXd RGBTmpVec(nHive + 1, 3);
+ MatrixXd VolumeHive(nHive + 1, m_TotalNumberofInks);
+ MatrixXd LabHive(nHive + 1, 3);
+ VectorXd xyz(3);
+ C_RGB_XYZ_Lab xyzVal, LabVal;
+ double *tmpRGB = new double[3];
+// double *InkOut = new double[m_nInks];
+ int *GamutRegion = new int[nHive + 1];
+ double *Lab1P = new double[3];
+ VectorXd Vol(m_nInks);
+ int j = 0;
+ double * LabInFinal1 = new double[3];
+ double * LabOnGamut = new double[3];
+ double *InkOutP = new double[m_nInks];
+ bool InGamut = true;
+ double *tmpNormFactor = m_colortable->GetNormFactor();
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] = m_ProcessRangesMaxP[iP];
+ m_CurrentProcessRangesMin[iP] = m_ProcessRangesMinP[iP];
+ }
+ VectorXd NLInkOut(m_nInks);
+ VectorXd InkOutV(m_nInks);
+ VectorXd RGBOutV(3);
+ VectorXd LabOutV(3);
+ for (int iHive = 0; iHive < nHive; ++iHive)
+ {
+ //Get Lab's inGamut
+ for (j = 0; j < 3; ++j)
+ Lab1P[j] = Lab1(iHive, j);
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ DirectInversionCalc(Lab1P, InkOutV, RGBOutV, Vol, LabOutV,
+ GamutRegion[iHive], InGamut, sur, CS);
+ PercentagetoNLcm(Vol, Vol);
+ GetClosestInk(Vol, GamutRegion[iHive], Vol); //Input Volume is in [nl/cm] Output Volume is in [%]
+ ConfineVolumes(Vol);
+ VectorToDouble(LabOutV, LabInFinal1);
+ VectorToDouble(RGBOutV, tmpRGB);
+ }
+ else
+ {
+ ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_Strip); //to Relative
+ m_colortable->m_B2ATransform->evalLab2InkP(Lab1P, InkOutP, GamutRegion[iHive]); //InkOut is in the [0-100] interval
+ if (m_CalibMode == 1)
+ {
+ ApplyCTLinearCurves(InkOutP, InkOutP); // full range color table units
+ InkOutV = DoubleToVector(InkOutP, m_nInks);
+ ColorTable2Threadunits(InkOutV, InkOutV); // full range Thread units
+ ConvertToNLInks(InkOutV, NLInkOut);
+ LimitNLInks2Volume(NLInkOut, GamutRegion[iHive], Vol);
+ }
+ else
+ {
+ for (int iInk = 0; iInk < m_nInks; ++iInk)
+ InkOutP[iInk] *= tmpNormFactor[iInk]; //full range Thread units
+ LimitNLInks2Volume(DoubleToVector(InkOutP, m_nInks), GamutRegion[iHive], Vol);
+ }
+ InGamut = IsInGamut(Lab1P, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+ m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_Strip, m_WP); //convert back to Absolute
+ LimitLab(LabInFinal1); //Absolute
+ m_Conv02->SetReferenceWhite(D65);
+ //Convert to RGB, relative col is converted
+ m_Conv02->LabtoRGB(LabOnGamut, tmpRGB);
+ }
+
+ VectorXd VolumeLI(m_TotalNumberofInks);
+ if (m_UseLightInks)
+ {
+ SplitVolume(Vol, VolumeLI, GamutRegion[iHive]);
+ }
+ else
+ {
+ for (int iVol = 0; iVol < m_nInks; ++iVol)
+ VolumeLI(iVol) = Vol(iVol);
+ }
+
+ for (int j = 0; j < 3; ++j)
+ LabHive(iHive, j) = LabInFinal1[j];
+
+ for (int j = 0; j < 3; ++j)
+ RGBTmpVec(iHive, j) = std::min(std::max(tmpRGB[j], 0.0), 255.0);
+
+ for (int j = 0; j < m_TotalNumberofInks; ++j)
+ VolumeHive(iHive, j) = VolumeLI(j);
+ }
+
+ VectorXd VolumeLI_s(m_TotalNumberofInks);
+ if (m_UseLightInks)
+ {
+ SplitVolume(Volume, VolumeLI_s, InGamutRegion);
+ }
+ else
+ {
+ for (int iVol = 0; iVol < m_nInks; ++iVol)
+ VolumeLI_s(iVol) = Volume(iVol);
+ }
+ for (j = 0; j < m_TotalNumberofInks; ++j)
+ VolumeHive(nHive, j) = VolumeLI_s(j);
+ for (j = 0; j < 3; ++j)
+ {
+ RGBTmpVec(nHive, j) = RGB(j);
+ LabHive(nHive, j) = Lab(j);
+ }
+ GamutRegion[nHive] = InGamutRegion;
+
+ //Organize hive into 5x5 matrix
+ //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),....,
+ //22-(4,2), 23-(4,3), 24-(4,4) not implemented yet
+ //Some of the matrix elements are empty
+ VectorXd xpos(nHive + 1);
+ xpos << 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 1, 2, 3, 3, 4, 3, 3, 2, /*, 5, 5, 5, 5, 5,*/ 2;
+ VectorXd ypos(nHive + 1);
+ ypos << 3, 2, 1, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4,/* 0, 1, 3, 4, 2,*/ 2;
+ ArrangeHiveData(LabHive, RGBTmpVec, VolumeHive, GamutRegion, xpos, ypos, nHive,
+ OLabHive, ORGBHive, OVolumeHive, OGamutRegion);
+ FindTriplet(Lab, Lab1, nHive, indDataMax);
+ indDataMax[0] = (int)(xpos(indDataMax[0]) * 5 + ypos(indDataMax[0]));
+ indDataMax[1] = (int)(xpos(indDataMax[1]) * 5 + ypos(indDataMax[1]));
+
+ if (LabOnGamut != NULL)
+ {
+ delete[]LabOnGamut;
+ LabOnGamut = NULL;
+ }
+/* if (InkOut != NULL)
+ {
+ delete[]InkOut;
+ InkOut = NULL;
+ }*/
+ if (GamutRegion != NULL)
+ {
+ delete[] GamutRegion;
+ GamutRegion = NULL;
+ }
+ if (Lab1P != NULL)
+ {
+ delete[] Lab1P;
+ Lab1P = NULL;
+ }
+ if (tmpRGB != NULL)
+ {
+ delete[] tmpRGB;
+ tmpRGB = NULL;
+ }
+
+ if (LabInFinal1 != NULL)
+ {
+ delete[]LabInFinal1;
+ LabInFinal1 = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::FindTriplet(VectorXd Lab, MatrixXd Lab1, int nHive, int*indDataMax)
+{
+
+ int vecSize = nHive * (nHive - 1) / 2;
+ double *dECMC = new double[vecSize];
+ int i, j;
+ for (i = 0; i < vecSize; ++i)
+ dECMC[i] = -1;
+ int **indexpairs = new int*[vecSize];
+ for (i = 0; i < vecSize; ++i)
+ {
+ indexpairs[i] = new int[2];
+ for (int j = 0; j < 2; ++j)
+ indexpairs[i][j] = 0;
+ }
+
+ int ind = -1;
+ ColorConvert ColConv(D65, D65);
+ VectorXd Labi(3);
+ VectorXd Labj(3);
+
+ for (i = 0; i < nHive; ++i)
+ {
+ Labi << Lab1(i, 0), Lab1(i, 1), Lab1(i, 2);
+ for (j = i + 1; j < nHive; ++j)
+ {
+ Labj << Lab1(j, 0), Lab1(j, 1), Lab1(j, 2);
+ ind++;
+ ColConv.SymmetricaldECMC(Labi, Labj, dECMC[ind]);
+ indexpairs[ind][0] = i;
+ indexpairs[ind][1] = j;
+ }
+ }
+ double maxdE = dECMC[0];
+ int maxInd = 0;
+ for (int i = 1; i < vecSize; ++i)
+ {
+ if ((maxdE < dECMC[i]) && (dECMC[i] < 5))
+ {
+ maxdE = dECMC[i];
+ maxInd = i;
+ }
+ }
+ indDataMax[0] = indexpairs[maxInd][0];
+ indDataMax[1] = indexpairs[maxInd][1];
+ if (dECMC != NULL)
+ {
+ delete[]dECMC;
+ dECMC = NULL;
+ }
+
+ if (indexpairs != NULL)
+ {
+ for (int i = 0; i < vecSize; ++i)
+ delete[] indexpairs[i];
+ delete[] indexpairs;
+ indexpairs = NULL;
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::ArrangeHiveData(MatrixXd LabHive, MatrixXd RGBTmpVec, MatrixXd VolumeHive, int *GamutRegion,
+ VectorXd xpos, VectorXd ypos, int nHive, MatrixXd &OLabHive, MatrixXd &RGBHive, MatrixXd &OVolumeHive, int *&OGamutRegion)
+{
+ //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),...., 22-(4,2), 23-(4,3), 24-(4,4)
+ //Some of the matrix elements are empty
+ //Ordering is by hexagon position in a 5x5 grid.
+
+ int i, j;
+ for (i = 0; i < nHive + 1; ++i)
+ {
+ int index = (int)(xpos(i) * 5 + ypos(i));
+ for (j = 0; j < 3; ++j)
+ OLabHive(index, j) = LabHive(i, j);
+
+ for (j = 0; j < 3; ++j)
+ RGBHive(index, j) = RGBTmpVec(i, j);
+
+ for (j = 0; j < m_TotalNumberofInks; ++j)
+ OVolumeHive(index, j) = VolumeHive(i, j);
+
+ OGamutRegion[index] = GamutRegion[i];
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::fillVolume(OutputCoordinates *&outputCoords, VectorXd Volume)
+{
+ int i = 0;
+ OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * m_TotalNumberofInks);
+ for (i = 0; i < m_TotalNumberofInks; ++i)
+ {
+ outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid));
+ output_liquid__init(outputLiquids[i]);
+ switch (m_InkNames[i])
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ case LIQUID_TYPE__LightCyan:
+ case LIQUID_TYPE__LightMagenta:
+ case LIQUID_TYPE__LightYellow:
+ {
+ outputLiquids[i]->has_volume = true;
+ outputLiquids[i]->has_liquidtype = true;
+ outputLiquids[i]->liquidtype = (LiquidType)(m_InkNames[i]);
+ outputLiquids[i]->volume = Volume(i);
+ break;
+ }
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ outputCoords->outputliquids = outputLiquids;
+ outputCoords->n_outputliquids = m_TotalNumberofInks;
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::fillRGB(OutputCoordinates *outputCoords, VectorXd RGBOut)
+{
+ outputCoords->has_red = true;
+ outputCoords->red = (int32_t)std::round(RGBOut(0));
+ outputCoords->has_green = true;
+ outputCoords->green = (int32_t)std::round(RGBOut(1));
+ outputCoords->has_blue = true;
+ outputCoords->blue = (int32_t)std::round(RGBOut(2));
+}
+
+void Tango::ColorLib::ColorConverter::fillLab(OutputCoordinates *outputCoords, VectorXd LabOut)
+{
+ outputCoords->has_l = true;
+ outputCoords->l = LabOut(0);
+ outputCoords->has_a = true;
+ outputCoords->a = LabOut(1);
+ outputCoords->has_b = true;
+ outputCoords->b = LabOut(2);
+}
+
+void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* conversionInput)
+{
+ SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb);
+ bool has_forwarddata = conversionInput->has_forwarddata;
+ uint8_t *data = conversionInput->forwarddata.data;
+ int nprocessranges = conversionInput->n_processranges;
+ if (nprocessranges <= 0)
+ throw std::exception("number of process ranges is zero or less");
+
+ m_colortable->InitColorTables(has_forwarddata, data, nprocessranges);
+ SetNumberofInks(m_colortable->GetnA2BnSepOut());
+}
+
+void Tango::ColorLib::ColorConverter::readColorTransformations(OutOfGamutInput* Input)
+{
+ SetStripWhitepoint(Input->threadl, Input->threada, Input->threadb);
+ bool has_forwarddata = Input->has_forwarddata;
+ uint8_t *data = Input->forwarddata.data;
+ int nprocessranges = Input->n_processranges;
+ if (nprocessranges <= 0)
+ throw std::exception("number of process ranges is zero or less");
+
+ m_colortable->InitColorTables(has_forwarddata, data, nprocessranges);
+ SetNumberofInks(m_colortable->GetnA2BnSepOut());
+}
+
+void Tango::ColorLib::ColorConverter::readColorTransformations(RecommendedProcessTableInput* conversionInput)
+{
+ SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb);
+ bool has_forwarddata = conversionInput->has_forwarddata;
+ uint8_t *data = conversionInput->forwarddata.data;
+ int nprocessranges = conversionInput->n_processranges;
+ if (nprocessranges <= 0)
+ throw std::exception("number of process ranges is zero or less");
+
+ m_colortable->InitColorTables(has_forwarddata, data, nprocessranges);
+ SetNumberofInks(m_colortable->GetnA2BnSepOut());
+}
+
+void Tango::ColorLib::ColorConverter::SetStripWhitepoint(double threadl, double threada, double threadb)
+{
+ //Read thread white. Thread White is given in CIELab Space
+ if ((threadl <= 0 || threadl > 100) || (threada < -127 || threada>128) || (threadb < -127 || threadb>128))
+ throw std::exception("White Point Lab exceeds limits");
+ else
+ m_whitepointLab.Set(threadl, threada, threadb);
+ //White point in XYZ Color Space
+ ColorConvert CConvert(D65, D65);
+ C_RGB_XYZ_Lab tmpW;
+ tmpW = CConvert.LabToXYZ(m_whitepointLab);
+ m_whitepointXYZ_Strip.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z());
+}
+
+
+
+void Tango::ColorLib::ColorConverter::readCalibrationTables(InputLiquid **inputliquid, int n_inputliquid)
+{
+ SetNumberofInks((int)(n_inputliquid));
+
+ // Verify Data
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (inputliquid[i]->maxnanoliterpercentimeter <= 0)
+ {
+ throw std::exception("Liquid Factor is zero or negative!");
+ return;
+ }
+
+ }
+ // Verify x and y are monotonic for each ink channel
+ bool IsValid = false;
+ CalibrationData *calibdata;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ calibdata = inputliquid[i]->calibrationdata;
+ IsValid = CheckMonotonicity(calibdata);
+ if (IsValid = false)
+ {
+ throw std::exception("Calibration Data is not monotonic");
+ return;
+ }
+ }
+
+ if (m_CalibCurves == NULL)
+ m_CalibCurves = new CalibData[m_nInks];
+
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InputLiquid* InkType = inputliquid[i];
+ m_CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype));
+ m_CalibCurves[i].SetMaxNlPerCM(inputliquid[i]->maxnanoliterpercentimeter);
+
+ switch (InkType->calibrationdata->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ {
+ // calibration data.
+ CalibrationData* calibrationData = InkType->calibrationdata;
+ SetCalibData(calibrationData, i, &m_CalibCurves[i]);
+ m_CalibCurves[i].InitInterpolations();
+ break;
+ }
+ default:
+ {
+ throw std::exception("could not fill all calibration tables");
+ return;
+ }
+ }
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::SetCalibMode()
+{
+ double *maxVal = new double[m_nInks];
+ m_maxCalX = new double[m_nInks];
+ for (int i= 0; i<m_nInks; ++i)
+ maxVal[i] = m_CalibCurves[i].GetMaxXValue();
+ int CalType = 0;
+ int sumCalType = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ m_maxCalX[i] = maxVal[i];
+ if (maxVal[i] == 100)
+ CalType = 0;
+ else
+ CalType = 1;
+ sumCalType += CalType;
+ }
+
+ if (sumCalType == 0)
+ {
+ m_CalibMode = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ m_maxCalX[i] = m_maxNlPerCM(i);
+ }
+ else if (sumCalType == m_nInks)
+ m_CalibMode = 1;
+ else
+ {
+ if (maxVal != NULL)
+ {
+ delete[] maxVal;
+ maxVal = NULL;
+ }
+ throw std::exception("Mixed Calibration Type calibration tables");
+ }
+ if (maxVal != NULL)
+ {
+ delete[] maxVal;
+ maxVal = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::SetCalibFactorization()
+{
+ //relates to [nl/cm]
+ m_CalibGain = new double[m_nInks];
+ m_CalibOffset = new double[m_nInks];
+ double denom;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ denom = (m_GamutRegionMaxLim[m_nProcessRanges - 1] - m_CTmaxNlPerCM(i));
+ if(m_CalibMode ==1)
+ {
+ m_CalibGain[i] = ( (m_maxNlPerCM(i)/100.0) * m_maxCalX[i] - m_maxNlPerCM(i)) /denom ;
+
+ m_CalibOffset[i] = (m_GamutRegionMaxLim[m_nProcessRanges - 1] * m_maxNlPerCM(i) -
+ (m_maxCalX[i] * (m_maxNlPerCM(i) / 100.0) * m_CTmaxNlPerCM(i))) / denom;
+ }
+ else
+ {
+ //This is a compromise to keep the inks volumes within limits.
+ m_CalibGain[i] = (m_ProcessRangesMaxP[m_nProcessRanges - 1] - m_maxNlPerCM(i)) / denom;
+
+ m_CalibOffset[i] = (m_GamutRegionMaxLim[m_nProcessRanges - 1] * m_maxNlPerCM(i) -
+ (m_ProcessRangesMaxP[m_nProcessRanges - 1] * m_CTmaxNlPerCM(i))) / denom;
+ }
+ }
+}
+
+void Tango::ColorLib::ColorConverter::SetCalibData(CalibrationData *calibrationData, int i, CalibData *tmpCurve)
+{
+ if (calibrationData->n_calibrationpoints < 2)
+ {
+ char msg[100];
+ strcpy_s(msg, 100, "Not enough Calibration points in table ");
+ throw std::exception(msg);
+ return;
+ }
+ //check data validity
+
+ tmpCurve->SetCalibCurveSize((int)(calibrationData->n_calibrationpoints));
+ //Iterate over calibration points..
+ double *pointsx = new double[calibrationData->n_calibrationpoints];
+ double *pointsy = new double[calibrationData->n_calibrationpoints];
+
+ for (size_t j = 0; j < calibrationData->n_calibrationpoints; ++j)
+ {
+ //Calibration Point
+ pointsx[j] = calibrationData->calibrationpoints[j]->x;
+ pointsy[j] = calibrationData->calibrationpoints[j]->y;
+ }
+ tmpCurve->SetXCoords(pointsx);
+ tmpCurve->SetYCoords(pointsy);
+ if (pointsx != NULL)
+ {
+ delete[] pointsx;
+ pointsx = NULL;
+ }
+
+ if (pointsy != NULL)
+ {
+ delete[] pointsy;
+ pointsy = NULL;
+ }
+ return;
+}
+
+bool Tango::ColorLib::ColorConverter::CheckMonotonicity(CalibrationData *calibdata)
+{
+ //Check Monotonicity of Smooth Lab Channel
+ bool retvalue = true;
+ if (calibdata->n_calibrationpoints < 2)
+ {
+ throw std::exception("Not enough Calibration points in table ");
+ retvalue = false;
+ return(retvalue);
+ }
+ double diffx, diffy;
+ double *xval = new double[calibdata->n_calibrationpoints];
+ double *yval = new double[calibdata->n_calibrationpoints];
+ for (int i = 0; i < (int)calibdata->n_calibrationpoints; ++i)
+ {
+ xval[i] = calibdata->calibrationpoints[i]->x;
+ yval[i] = calibdata->calibrationpoints[i]->y;
+ }
+
+ diffy = yval[calibdata->n_calibrationpoints - 1] - yval[0];
+ diffx = xval[calibdata->n_calibrationpoints - 1] - xval[0];
+ int CFx = 1;
+ if (diffx < 0)
+ CFx = -1;
+ int CFy = 1;
+ if (diffy < 0)
+ CFy = -1;
+
+ for (int i = 0; i < (int)calibdata->n_calibrationpoints - 1; ++i)
+ {
+ diffx = CFx * (xval[i + 1] - xval[i]);
+ if (diffx <= 0.0)
+ {
+ throw std::exception("non-monotonic x-axis ");
+ retvalue = false;
+ return(retvalue);
+ }
+ diffy = CFx * (yval[i + 1] - yval[i]);
+ if (diffy <= 0.0)
+ {
+ throw std::exception("non-monotonic y-axis ");
+ retvalue = false;
+ return(retvalue);
+ }
+ }
+ return retvalue;
+}
+
+void Tango::ColorLib::ColorConverter::ConvertLabColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ // Basic assumption: Lab data has the same whitepoint as the STRIP thread.
+ //The workflow is a follows:
+ //1. Convert Lab to Relative colorimetric. check if there is a match between STRIP and Color Tables
+ //2. Convert Lab to Inks (B2A tables), Inks to Volume
+ //3. Map the Lab value onto the gamut surface, if it is out of gamut
+ //4. Convert Lab to Absolute colorimetric taking into account the Strip and CT whitepoints
+ //5. Use the Relative Colorimetric Lab to obtain RGB
+ double *LabIn = new double[3];
+ double *LabOnGamut = new double[3];
+
+ LabIn[0] = inputcoordinates->l; //Absolute Colorimetric
+ LabIn[1] = inputcoordinates->a;
+ LabIn[2] = inputcoordinates->b;
+ //the assumption is that the color space has illumination that matches the whitepoint of the Strip
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+
+ double *LabInFinal2 = new double[3];
+
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //LabInFinal2 is in Relative Colorimetric Space
+ LimitLab(LabInFinal2);
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+
+ //convert to Inks
+ double *InkOutP = new double[m_nInks];
+ m_colortable->m_B2ATransform->evalLab2InkP(LabInFinal2, InkOutP, GamutRegion); //InkOutP is in units of 16 bits
+ //Convert Inks to Lab to get the Gamut Mapped Lab
+
+//Convert InkOutP to linear in the m_GamutRegionMaxLim[0] range
+ //Color Tables are encoded in 16 bits which are equivalent to [0-100]
+ //The same is true for linear curves
+ //Therefore the factorization by normfactor has to be done after the calculation of the linear curves
+ //Linear Curves in the color table are defined in the full range (Sylko [0-200]%)
+ //We apply the linear curves to the full range
+ // InkOutP is in the full range of the color table
+ if(m_CalibMode ==1)
+ ApplyCTLinearCurves(InkOutP, InkOutP);
+ else
+ {
+ double *tmpval = m_colortable->GetNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i];
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+
+double *LabOutFinal = new double[3];
+ //double *LabOutFinal = DBG_NEW double[3];
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal[i] = LabOnGamut[i];
+ //LabOutFinal is in Relative Colorimetric
+ //Reverse the conversion process to bring back Lab to STRIP white point
+ CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_WP);
+
+ LabOut = DoubleToVector(LabOutFinal, 3);
+ CConvertD65.SetReferenceWhite(D65);
+ //Convert to RGB
+ double *RGBOutP = new double[3];
+
+ //Use Relative colorimetric to get RGB
+ CConvertD65.LabtoRGB(LabOnGamut, RGBOutP);
+ RGBOut = DoubleToVector(RGBOutP, 3);
+ if (LabOnGamut != NULL)
+ {
+ delete[] LabOnGamut;
+ LabOnGamut = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (LabInFinal2 != NULL)
+ {
+ delete[]LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ if (LabOutFinal != NULL)
+ {
+ delete[]LabOutFinal;
+ LabOutFinal = NULL;
+ }
+
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::ConvertRGBColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ // Basic assumption: if data is given in RGB space, RGB is assumed to be in Strip Color Coordinates,
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread, but will be shown in Relative Colorimetric to the user
+ //The workflow is a follows:
+ //1. Convert RGB to Lab (Whitepoint is D65, same as tables)
+ //1-a. Convert Lab to Relative Colorimetric
+ //2. Convert Lab to Inks (B2A tables), Inks to Volume
+ //3. Convert Inks to Lab (A2B tables) to get the in/on Gamut Lab
+ //4. Convert Lab to Absolute colorimetric taking into account the Strip and Color Table whitepoints
+ //5. Use the Relative Colorimetric Lab to obtain RGB
+
+ RGBOut(0) = inputcoordinates->red;
+ RGBOut(1) = inputcoordinates->green;
+ RGBOut(2) = inputcoordinates->blue;
+ //convert to Lab
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+
+ double *LabIn = new double[3];
+ double *LabInFinal1 = new double[3];
+ double RGBOutP[3];
+
+ VectorToDouble(RGBOut, RGBOutP);
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Absolute Colorimetric, D65
+ //Convert LabIn to Relative Colorimetric - Feb 2021
+ double *LabInFinal2 = new double[3];
+ LimitLab(LabIn);
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip);
+ //Is In Gamut?
+// double *LabInFinal = new double[3];
+ double *LabOnGamut = new double[3];
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+
+ //convert to inks
+
+ double *InkOutP = new double[m_nInks];
+ //double *InkOutP = DBG_NEW double[m_nB2AnSepOut];
+ //LabInFinal is in Relative Colorimetric, just like the Color Tables
+ m_colortable->m_B2ATransform->evalLab2InkP(LabInFinal2, InkOutP, GamutRegion); //InkOutP is inthe [0-100] interval
+
+ //Convert to Lab to get the actual in Gamut Lab
+ //Convert InkOut to Linear via initial calibration Tables
+ //Initial calibration tables are the ones that were included in the color table
+ // if m_CalibMode = 0, do not convert via calibration tables
+ if(m_CalibMode ==1)
+ ApplyCTLinearCurves(InkOutP, InkOutP);
+ else
+ {
+ double *tmpval = m_colortable->GetNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i];
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+
+ //Convert to CT thread, LabOnGamut is in Relative Colorimetric Space
+ CConvertD65.ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_Strip, m_WP);
+ LabOut = DoubleToVector( LabInFinal1, 3);
+ CConvertD65.SetReferenceWhite(D65);
+ double *RGBOutP1 = new double[3];
+ CConvertD65.LabtoRGB(LabOnGamut, RGBOutP1);
+ RGBOut = DoubleToVector(RGBOutP1, 3);
+
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (LabInFinal2 != NULL)
+ {
+ delete[] LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ if (LabInFinal1 != NULL)
+ {
+ delete[] LabInFinal1;
+ LabInFinal1 = NULL;
+ }
+ if (RGBOutP1 != NULL)
+ {
+ delete[] RGBOutP1;
+ RGBOutP1 = NULL;
+ }
+/* if (LabInFinal != NULL)
+ {
+ delete[] LabInFinal;
+ LabInFinal = NULL;
+ }*/
+}
+
+void Tango::ColorLib::ColorConverter::Thread2ColorTableunits(VectorXd InkIn, VectorXd &InkOut)
+{
+ double Iconst = 0.0;
+ double lconstCT = 0.0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (InkIn(i) > 100.0)
+ {
+ Iconst = m_maxNlPerCM(i) / 100.0;
+ lconstCT = m_CTmaxNlPerCM(i) / 100;
+ InkOut(i) = ((InkIn(i)*Iconst) - m_CalibOffset[i]) / m_CalibGain[i];
+ //back to %
+ InkOut(i) /= lconstCT;
+ }
+ else
+ InkOut(i) = InkIn(i);
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ColorTable2Threadunits(VectorXd InkIn, VectorXd &InkOut)
+{
+ double Iconst = 0.0;
+ double lconstCT = 0.0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (InkIn(i) > 100.0)
+ {
+ Iconst = m_CTmaxNlPerCM(i) / 100.0;
+ lconstCT = m_maxNlPerCM(i) / 100;
+ InkOut(i) = m_CalibGain[i] * (InkIn(i)*Iconst) + m_CalibOffset[i];
+ //back to %
+ InkOut(i) /= lconstCT;
+ }
+ else
+ InkOut(i) = InkIn(i);
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ApplyCTLinearCurves(double *InkIn, double* InkOut)
+{
+ double *tmpNormFactor = m_colortable->GetNormFactor();
+ if (m_CalibMode == 1)
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkIn[i] * 655.35, InkOut[i]);
+ InkOut[i] /= 655.35;
+ InkOut[i] *= tmpNormFactor[i];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ InkOut[i] *= tmpNormFactor[i];
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ApplyCTInvLinearCurves(double *InkIn, double* InkOut)
+{
+ double *tmpNormFactor = m_colortable->GetInverseNormFactor();
+ if (m_CalibMode == 1)
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ m_colortable->m_LinCurves->m_InvInterpCurves[i].Eval(InkIn[i] * 655.35*tmpNormFactor[i], InkOut[i]);
+ InkOut[i] /= 655.35;
+ InkOut[i] /= tmpNormFactor[i];
+ }
+ }
+}
+//void Tango::ColorLib::ColorConverter::ConvertCMYKColorToLinearInks(InputCoordinates* inputcoordinates,
+// VectorXd &InkOut, VectorXd &RGBOut,
+// VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+//{
+// //no conversion
+// //missing from structure light inks or special colors
+// // just convert Lab for rgb display
+//
+// double *outData = new double[m_nInks];
+// //double *outData = DBG_NEW double[m_nA2BnSepIn];
+// size_t CountSep = 0;
+// outData[0] = (double)(inputcoordinates->cyan);
+// outData[1] = (double)(inputcoordinates->magenta);
+// outData[2] = (double)(inputcoordinates->yellow);
+// outData[3] = (double)(inputcoordinates->key);
+// CountSep = 4;
+//
+// if (CountSep != m_nInks)
+// {
+// //mismatch between table and sent data
+// throw std::exception("Mismatch between table and sent data");
+// return;
+// }
+// //Convert to RGB
+// double *InkOutP = new double[m_nInks];
+//
+// for (int i = 0; i < m_nInks; ++i)
+// InkOutP[i] = outData[i];
+// double *LabOutP = new double[3];
+//
+// m_colortable->m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion);
+// InkOut = DoubleToVector(InkOutP, m_nInks);
+// //LabOutP is in relative colorimetric
+// ColorConvert CConvertD65(D65, D65);
+// double *LabOutFinal1 = new double[3];
+// for (int i = 0; i < 3; ++i)
+// LabOutFinal1[i] = LabOutP[i];
+// double *LabOutFinal2 = new double[3];
+// for (int i = 0; i < 3; ++i)
+// LabOutFinal2[i] = LabOutP[i];
+// InGamut = true;
+// //Check if white points match
+// CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_Strip, m_WP); //To Absolute
+// LabOut = DoubleToVector(LabOutFinal1, 3);
+// CConvertD65.SetReferenceWhite(D65);
+// //Get RGB
+// double *RGBOutP = new double[3];
+// CConvertD65.LabtoRGB(LabOutP, RGBOutP);
+// RGBOut = DoubleToVector(RGBOutP, 3);
+//
+// if (outData != NULL)
+// {
+// delete[] outData;
+// outData = NULL;
+// }
+// if (LabOutP != NULL)
+// {
+// delete[] LabOutP;
+// LabOutP = NULL;
+// }
+// if (InkOutP != NULL)
+// {
+// delete[] InkOutP;
+// InkOutP = NULL;
+// }
+// if (RGBOutP != NULL)
+// {
+// delete[] RGBOutP;
+// RGBOutP = NULL;
+// }
+// if (LabOutFinal1 != NULL)
+// {
+// delete[] LabOutFinal1;
+// LabOutFinal1 = NULL;
+// }
+// if (LabOutFinal2 != NULL)
+// {
+// delete[] LabOutFinal2;
+// LabOutFinal2 = NULL;
+// }
+//}
+void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut)
+{
+ size_t nInks = 0;
+
+ C_RGB_XYZ_Lab DataLab;
+ SURROUND sur = m_Conv02->getSurround();
+ CAM02CS CS = m_Conv02->getCAM02CS();
+ switch (colorspace)
+ {
+ case (COLOR_SPACE__RGB):
+ {
+ ConvertRGBColorToLinearInks(inputcoordinates,
+ InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+ break;
+ }
+ case (COLOR_SPACE__LAB):
+ {
+ ConvertLabColorToLinearInks(inputcoordinates,
+ InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+ break;
+ }
+
+ //case(COLOR_SPACE__CMYK):
+ //{
+ // ConvertCMYKColorToLinearInks(inputcoordinates,
+ // InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+
+ // break;
+ //}
+ //case(COLOR_SPACE__Catalog):
+ //{
+ // int32_t inData;
+ // if (inputcoordinates->has_pantoncode)
+ // inData = inputcoordinates->pantoncode;
+ // else
+ // {
+ // //mismatch between color space and data
+ // throw std::exception("Mismatch between color space and data");
+ // return;
+ // }
+ // break;
+ //}
+
+ default:
+ {
+ throw std::exception(" Unsupported Color Space");
+ break;
+ }
+ }
+ //all data is now in linear ink format
+ return;
+}
+
+
+void Tango::ColorLib::ColorConverter::ConvertToNLInks(VectorXd InkIn, VectorXd &InkOut)
+{
+ //Assumes Calibration curves are defined for the whole range in %
+ for (int i = 0; i < m_nInks; ++i)
+ m_CalibCurves[i].m_InvLinearInterp->Eval(InkIn(i), InkOut(i));
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::ConvertToLinearInks(VectorXd InkIn, VectorXd &InkOut)
+{
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ m_CalibCurves[i].m_LinearInterp->Eval(InkIn(i), InkOut(i));
+ }
+
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::VolumeToNLInkP(VectorXd Volume, VectorXd &NLInkP)
+{
+ //Volume is in %. In order to be compatible with NL to volume it has to be tranlated to nl/cm
+ VectorXd InkP(m_TotalNumberofInks);
+ int MaxInd = -1;
+ double InkMax = -1.;
+ double InkSum = 0.;
+ //Convert volume to Volume without Light Inks
+ VectorXd VolumeNoLI((int)(m_nInks));
+ if (m_UseLightInks)
+ {
+ //Convert Light Ink Volumes to Ink Volumes
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = Volume(i);
+
+ for (int i = 4; i < m_nVolumes; ++i)
+ {
+ if ((Volume(i) > 0) & (Volume(i - 4) == 0))
+ {
+ VolumeNoLI(i - 4) = Volume(i) / DilutionFactor;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = Volume(i);
+ }
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InkP(i) = VolumeNoLI(i)* m_currentMaxNLPerCM(i) / 100; //Volume is in %, InkP is in [nl/cm]
+ if (InkMax < InkP(i))
+ {
+ InkMax = InkP(i);
+ MaxInd = i;
+ }
+ InkSum += InkP(i);
+ }
+ NLInkP(MaxInd) = 100 * InkSum / m_currentMaxNLPerCM(MaxInd); //Back to %
+ //Limit inks to max Ink Percentage // Added October 14, 2021
+ NLInkP(MaxInd) = std::min(m_maxCalX[MaxInd], NLInkP(MaxInd));
+ if (InkSum == 0.0)
+ {
+ for (int i = 0; i < m_nVolumes; ++i)
+ NLInkP(i) = 0.0;
+ return;
+ }
+
+ //Prepare Matrix to get the remainder values
+ MatrixXd MatNLI(m_nVolumes - 1, m_nVolumes - 1);
+ VectorXd RHSide(m_nVolumes - 1);
+ MatrixXd DiagMat(m_nVolumes - 1, m_nVolumes - 1);
+ DiagMat.setZero();
+ int ind = -1;
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ if (i != MaxInd)
+ {
+ ind += 1;
+ RHSide(ind) = InkP(i);
+ DiagMat(ind, ind) = -InkSum;
+ }
+ }
+ for (int i = 0; i < m_nVolumes - 1; ++i)
+ {
+ for (int j = 0; j < m_nVolumes - 1; ++j)
+ {
+ MatNLI(i, j) = RHSide(i) + DiagMat(i, j);
+ }
+ RHSide(i) *= (-InkSum);
+ }
+ //Solve System of Linear Equations
+ MatrixXd MatNLIInv(m_nVolumes - 1, m_nVolumes - 1);
+ MatNLIInv = MatNLI.inverse();
+ VectorXd Result = MatNLIInv * RHSide;
+
+ //rearrange solution
+ ind = -1;
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ if (i != MaxInd)
+ {
+ ind += 1;
+ NLInkP(i) = 100 * Result(ind) / m_currentMaxNLPerCM(i); //Back to %
+ //Limit inks to max Ink Percentage // Added October 14, 2021
+ NLInkP(i) = std::min(m_maxCalX[i], NLInkP(i));
+ }
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::NLInkPToVolume(VectorXd NLInk, VectorXd &Volume)
+{
+ //Max Ink Component
+ double MaxInk = -1.;
+ VectorXd InkNorm(m_nInks);
+ double InkSum = 0;
+ int i = 0;
+ for (i = 0; i < m_nInks; ++i)
+ {
+ MaxInk = std::max(MaxInk, NLInk(i));
+ InkSum += NLInk(i);
+ }
+
+ if (MaxInk == 0)
+ for (i = 0; i < m_nInks; ++i)
+ Volume(i) = 0.0;
+ else
+ {
+ for (i = 0; i < m_nInks; ++i)
+ {
+ InkNorm(i) = MaxInk * NLInk(i) / InkSum;
+ Volume(i) = InkNorm(i); // InkNorm(i) * m_maxNlPerCM(i) / 100; // Volume is in %
+ }
+ // Round to k decimal digits, verify that sum in within allowed values.
+ double sumNorm = 0.0;
+ double RsumNorm = 0.0;
+ VectorXd RVolNorm(m_nInks);
+ double ROUNDINGTol = pow(10, ROUNDINGDigits);
+
+ for (i = 0; i < m_nInks; ++i)
+ {
+ sumNorm += Volume(i);
+ RVolNorm(i) = round(Volume(i)*ROUNDINGTol) / ROUNDINGTol;
+ RsumNorm += RVolNorm(i);
+ }
+ if (RsumNorm > m_CurrentProcessRangesMax[m_nProcessRanges - 1] || abs(sumNorm - RsumNorm) >= 1 / ROUNDINGTol)
+ {
+ VectorXd dd(m_nInks);
+ double maxdd = -1;
+ int maxInd = -1;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ dd(i) = Volume(i) - RVolNorm(i);
+ if (abs(dd(i)) > maxdd)
+ {
+ maxdd = abs(dd(i));
+ maxInd = i;
+ }
+ }
+ int signdd = 0;
+ if (dd(maxInd) > 0)
+ signdd = 1;
+ else if (dd(maxInd) < 0)
+ signdd = -1;
+ else
+ signdd = 0;
+ RVolNorm(maxInd) = RVolNorm(maxInd) + signdd / ROUNDINGTol;
+ }
+ for (int i = 0; i < m_nInks; ++i)
+ Volume(i) = RVolNorm(i);
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::SetMaxNLperCM(double maxNlPerCM, int i)
+{
+ m_maxNlPerCM(i) = maxNlPerCM;
+}
+
+void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates *inputcoordinates, int n_processRanges,
+ int colorspace, VectorXd &VolumeNoLI, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion)
+{
+ //July 29 2020
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+ VectorXd NLInkP((int)(m_nInks));
+ VectorXd InkOut((int)(m_nInks));
+ VectorXd Volume((int)(m_TotalNumberofInks));
+ VectorXd FinalVolumeNoLI(m_nInks);
+ //Convert to Nonlinear Inks
+ double SumVol_Ink = 0.0;
+ //Get Gamut Region
+ for (int i = 0; i < m_TotalNumberofInks; ++i)
+ Volume(i) = inputcoordinates->inputliquids[i]->volume;
+
+
+ if (m_UseLightInks)
+ {
+ //Convert Light Ink Volumes to Ink Volumes
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = Volume(i);
+
+ for (int i = 4; i < m_TotalNumberofInks; ++i)
+ {
+ if ((Volume(i) > 0) & (Volume(i - 4) == 0))
+ {
+ VolumeNoLI(i - 4) = inputcoordinates->inputliquids[i]->volume / DilutionFactor;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = Volume(i);
+ }
+ //Catalog and Volumes have different conversion factors
+ //Verify Volume is within the allowed limits
+ double *InkOutP = new double[m_nInks];
+ double *LinInkP = new double[m_nInks];
+ double *Ink4RGB = new double[m_nInks];
+ VectorXd Ink4Vol(m_nInks);
+
+ if (colorspace == COLOR_SPACE__Catalog)
+ {
+ for (int i = 0; i < m_nInks; ++i) // % to nl/cm
+ VolumeNoLI(i) *= (m_CTmaxNlPerCM(i) / 100);
+ m_currentMaxNLPerCM = m_CTmaxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] = m_GamutRegionMaxLim[iP];
+ m_CurrentProcessRangesMin[iP] = m_GamutRegionMinLim[iP];
+ }
+ GamutRegion = GetGamutRegion(VolumeNoLI, m_GamutRegionMaxLim); //Volume is in Color Table UYnits
+ GetClosestInk(VolumeNoLI, GamutRegion, VolumeNoLI); //Input VolumeNoLI is in [nl/cm] Output VolumeNoLI is in [%]
+ VolumeToNLInkP(VolumeNoLI, NLInkP); //NLInkP is in %
+ for (int i = 0; i < m_nInks; ++i)
+ FinalVolumeNoLI(i) = VolumeNoLI(i);
+ VectorToDouble(NLInkP, InkOutP);
+ // NLcmtoPercentage(VolumeNoLI, VolumeNoLI);
+
+ //Non Linear Inks are in Color Table space, convert to reflect the thread characteristics
+ // Inks are in their natural coordinates
+ // Inks need to be converted to thread units, RGB is calculated from initial inks
+
+ if(m_CalibMode ==1)
+ {
+ //Convert to [0-100] before applying the Linear Curves
+ double *tmpval = m_colortable->GetInverseNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i]; //scaled to real unitS, still in %
+ ApplyCTLinearCurves(InkOutP, LinInkP); //Full Range in Color Table Units %
+ ColorTable2Threadunits(DoubleToVector(LinInkP, m_nInks), InkOut); //Full Range in Thread units %
+ ConvertToNLInks(InkOut,InkOut); //ful range in Thread units %
+ }
+ else
+ ColorTable2Threadunits(DoubleToVector(InkOutP, m_nInks), InkOut); // Full Range in %
+
+ Ink4Vol = InkOut;
+ }
+ else if (colorspace == COLOR_SPACE__Volume)
+ {
+ //Volume is in Thread Space, need to convert to Color Table space to get RGB
+ for (int i = 0; i < m_nInks; ++i) // % to nl/cm in Thread Space
+ VolumeNoLI(i) *= (m_maxNlPerCM(i) / 100);
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_CurrentProcessRangesMax[i] = m_ProcessRangesMaxP[i];
+ m_CurrentProcessRangesMin[i] = m_ProcessRangesMinP[i];
+ }
+ GamutRegion = GetGamutRegion(VolumeNoLI, m_CurrentProcessRangesMax);
+ GetClosestInk(VolumeNoLI, GamutRegion, VolumeNoLI); //VolumenoLi Input is in [nl/cm], VolumeNoLI Output is in [%] in thread space
+ VolumeToNLInkP(VolumeNoLI, NLInkP); //NLInkP is in % Full Range
+ //save the above volume as the final one, then calculate RGB coordinates
+ for (int i = 0; i < m_nInks; ++i)
+ FinalVolumeNoLI(i) = VolumeNoLI(i);
+ VectorToDouble(NLInkP, InkOutP);
+ Ink4Vol = NLInkP;
+ //NLInkP are the final Volume values, the transformations are applied to get the right RGB
+ if (m_CalibMode == 1)
+ {
+ VectorXd InkLinV(m_nInks);
+ ConvertToLinearInks(NLInkP, InkLinV); //Use Calib tables //full range Thread Units %
+ Thread2ColorTableunits(InkLinV, InkLinV); //full range Color Table Units %
+ //Linear Inks are in their natural coordinates %
+ VectorToDouble(InkLinV, InkOutP);
+ //for (int i = 0; i < m_nInks; ++i)
+ // InkOutP[i] *= m_colortable->GetInverseNormFactor(); //[0-100]
+ ApplyCTInvLinearCurves(InkOutP, InkOutP); //full range % in Color Table Space // //Inks are now nonlinear
+ }
+ else
+ {
+ Thread2ColorTableunits(NLInkP, InkOut); //full range color table units
+ VectorToDouble(InkOut, InkOutP); //full range color table units
+ }
+ }
+
+ for (int i = 0; i < m_nInks; ++i)
+ Ink4RGB[i] = InkOutP[i];
+ //July 29 2020
+ //Inks are limited in their nonlinear form
+ //Ink4Vol is in Thread units
+
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int j = 0; j < m_nProcessRanges; ++j)
+ {
+ m_CurrentProcessRangesMax[j] = m_ProcessRangesMaxP[j];
+ m_CurrentProcessRangesMin[j] = m_ProcessRangesMinP[j];
+ }
+ LimitInks(Ink4Vol, InkOutP); //in [nl/cm] nonlinear inks // Color table Space
+ NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), VolumeNoLI); //VolumeNoLI in [nl/cm]
+ GamutRegion = GetGamutRegion(VolumeNoLI, m_ProcessRangesMaxP);
+ NLcmtoPercentage(VolumeNoLI, VolumeNoLI); //VolumeNoLI in %
+
+ //Convert to RGB
+ //GamutRegion = 0;
+ //Convert to Lab
+ double *LabOutP = new double[3];
+ //InkOutP has to be normalized to match the transform units
+
+ double *tmpval = m_colortable->GetInverseNormFactor();
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ Ink4RGB[i] *= tmpval[i]; //[0-100] range, same as Color Table
+
+ ApplyCTLinearCurves(Ink4RGB, Ink4RGB); //Use Color Table Curves //full range % Linear
+ tmpval = m_colortable->GetInverseNormFactor();
+ for (int i = 0; i < m_nInks; ++i) // Forward Model in [0-1] interval
+ {
+ Ink4RGB[i] *= tmpval[i]; //[0-100] range, same as Color Table
+ Ink4RGB[i] /= 100.0;
+ }
+ m_forwardmodel->CalcFM(Ink4RGB, LabOutP);
+ }
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ Ink4RGB[i] *= tmpval[i]; //[0-100] range, same as Color Table
+ m_colortable->m_A2BTransform->evalInkP2Lab(Ink4RGB, LabOutP, GamutRegion);
+
+ }
+
+ //LabOutP is in Relative Colorimetric
+ ColorConvert CConvertD65(D65, D65);
+// double *LabOutFinal1 = new double[3];
+ double *LabOutFinal = new double[3];
+
+ CConvertD65.ChangeWP(LabOutP, LabOutFinal, m_whitepointXYZ_Strip, m_WP); //To Absolute
+/* for (int i = 0; i < 3; ++i)
+ m_LabOutFinal[i] = LabOutFinal1[i]; */
+
+ LabOut = DoubleToVector(LabOutFinal, 3);
+
+ CConvertD65.SetReferenceWhite(D65);
+ double *RGBOutP = new double[3];
+
+ CConvertD65.LabtoRGB(LabOutP, RGBOutP);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ RGBOut(i) = RGBOutP[i];
+ }
+
+
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeNoLI(i) = FinalVolumeNoLI(i);
+ if (InkOutP != NULL)
+ {
+ delete[]InkOutP;
+ InkOutP = NULL;
+ }
+ if (LinInkP != NULL)
+ {
+ delete[]LinInkP;
+ LinInkP = NULL;
+ }
+ if (LabOutP != NULL)
+ {
+ delete[] LabOutP;
+ LabOutP = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+/* if (LabOutFinal1 != NULL)
+ {
+ delete[] LabOutFinal1;
+ LabOutFinal1 = NULL;
+ }*/
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+ if (Ink4RGB != NULL)
+ {
+ delete[] Ink4RGB;
+ Ink4RGB = NULL;
+ }
+ return;
+
+}
+
+void Tango::ColorLib::ColorConverter::VectorToDouble(VectorXd VecIn, double * doubOut)
+{
+ int nSize = VecIn.size();
+ for (int i = 0; i < nSize; ++i)
+ doubOut[i] = VecIn(i);
+}
+
+
+VectorXd Tango::ColorLib::ColorConverter::DoubleToVector(double *doub, int nSize)
+{
+ VectorXd Vec(nSize);
+ for (int i = 0; i < nSize; ++i)
+ Vec(i) = doub[i];
+ return(Vec);
+}
+
+void Tango::ColorLib::ColorConverter::LimitLab(double* LabIn)
+{
+ LabIn[0] = std::min(std::max(LabIn[0], 0.0), 100.0);
+ LabIn[1] = std::min(std::max(LabIn[1], -128.0), 127.0);
+ LabIn[2] = std::min(std::max(LabIn[2], -128.0), 127.0);
+ return;
+}
+
+size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+
+ ConversionInput* conversionInput = NULL;
+ InputLiquid** original_input_liquids = NULL;
+ int original_input_liquids_count = 0;
+
+ try
+ {
+ //Get Input
+ int numofInks = 0;
+ int numLightInks = 0;
+ conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+ size_t retValue = InitConvertLiquids(conversionInput, original_input_liquids, numofInks, numLightInks);
+
+ //Initialize Output...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ conversion_output__init(conversionOutput);
+
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+
+ // Read Color Transformations
+ if (m_colortable == NULL)
+ m_colortable = new ColorTable();
+ readColorTransformations(conversionInput);
+
+ //Set Process Ranges
+ if (conversionInput->n_processranges <= 0)
+ throw std::exception("number of process ranges is zero");
+ else
+ m_nProcessRanges = conversionInput->n_processranges;
+
+ double *tmpVal;
+ /* if (m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i]; */
+
+ if (m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMaxLim[i] = tmpVal[i];
+
+ if (m_GamutRegionMinLim == NULL)
+ m_GamutRegionMinLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetGamutRegionMinLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMinLim[i] = tmpVal[i];
+
+ //read calibration tables and store them in m_CalibCurves
+ InputLiquid **inputliquids = conversionInput->inputcoordinates->inputliquids;
+ // int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids;
+ int n_inputliquids = numofInks - numLightInks;
+ readCalibrationTables(inputliquids, n_inputliquids);
+
+ //Define Parameters for Direct Inversion
+ if(m_colortable->GetTableSubVersion()>0)
+ {
+ C_RGB_XYZ_Lab whitepoint_CT = m_colortable->GetWhitePoint_CT();
+ m_forwardmodel = m_colortable->GetForwardModel();
+ ColorConvert CConvertD65(D65, D65);
+ C_RGB_XYZ_Lab relWP_CT;
+ CConvertD65.ChangeWP(whitepoint_CT, relWP_CT, m_WP, m_whitepointXYZ_Strip);
+ m_forwardmodel->SetFreeTerm(relWP_CT);
+ m_ObjFunction = new ObjectiveFunction(m_forwardmodel);
+ PrepareObjectiveFunctionPars();
+ m_Minimize = new LevMar(m_ObjFunction);
+ m_Minimize->Init();
+ m_Minimize->SetMaxIterations(50);
+ m_Minimize->SetTolerance(0.01);
+ }
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+ //m_Conv02 = DBG_NEW ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ // Compare Strip White point to Color Table White Point
+ //CompareWhitePoints();
+
+ if (n_inputliquids != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables\0");
+
+ //Tables have been filled
+ //Set Process Ranges
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ if (conversionInput->processranges[i]->maxinkuptake <= 0)
+ throw std::exception("Process Range is zero\0");
+ }
+ double diff = 0;
+ for (int i = 1; i < m_nProcessRanges; ++i)
+ {
+ diff = conversionInput->processranges[i]->maxinkuptake - conversionInput->processranges[i - 1]->maxinkuptake;
+ if (diff < 0)
+ throw std::exception("Process Ranges are not monotonic\0");
+ }
+ if (m_ProcessRangesMaxP == NULL)
+ m_ProcessRangesMaxP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMaxP[i] = conversionInput->processranges[i]->maxinkuptake;
+ }
+ if (m_ProcessRangesMinP == NULL)
+ m_ProcessRangesMinP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMinP[i] = conversionInput->processranges[i]->mininkuptake;
+ }
+
+ if (m_CurrentProcessRangesMax == NULL)
+ m_CurrentProcessRangesMax = new double[m_nProcessRanges];
+ if (m_CurrentProcessRangesMin == NULL)
+ m_CurrentProcessRangesMin = new double[m_nProcessRanges];
+
+ //define Low Volume threshold and Light Inks Threshold
+ m_LightInksThr = conversionInput->vmax;
+ m_LowVolumeThreshold = m_LightInksThr / DilutionFactor;
+ m_LowVolHalf = m_LowVolumeThreshold / 2;
+ //SetLowVolThr_nlcm();
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+ VectorXd VolumeOut(m_nInks);
+ //set maxNlPerCM
+ VectorXd NlperCM(m_nInks);
+ NlperCM.setZero();
+ m_maxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ SetMaxNLperCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter, i);
+ m_CTmaxNlPerCM = NlperCM;
+ double *tmpLF = new double[m_nInks];
+ tmpLF = m_colortable->GetCTLiquidFactors();
+ for (int i = 0; i < m_nInks; ++i)
+ m_CTmaxNlPerCM(i) = tmpLF[i];
+ if (tmpLF != NULL)
+ {
+ delete[] tmpLF;
+ tmpLF = NULL;
+ }
+
+ // Set Calibration mode 0 up tp 100%, 1 with High Volume Calib
+ SetCalibMode();
+ //Calculate normalization per ink
+ SetCalibFactorization();
+ m_nVolumes = m_nInks;
+ int GamutRegion = 0;
+ //Convert input data to linear inks
+ ColorSpace colorspace = conversionInput->colorspace;
+ InputCoordinates *IC = conversionInput->inputcoordinates;
+ VectorXd VolumeLI(m_TotalNumberofInks);
+
+ if (conversionInput->colorspace == COLOR_SPACE__Volume)
+ {
+ ConvertVolumeToRGBDisplay(IC, conversionInput->n_processranges, colorspace, Volume, RGBOut, LabOut, GamutRegion);
+ InGamut = true;
+ }
+ else if (conversionInput->colorspace == COLOR_SPACE__Catalog)
+ {
+ IC->inputliquids[0]->volume = IC->cyan;
+ IC->inputliquids[1]->volume = IC->magenta;
+ IC->inputliquids[2]->volume = IC->yellow;
+ IC->inputliquids[3]->volume = IC->key;
+ for (int i_hv = 0; i_hv < 4; ++i_hv)
+ IC->inputliquids[i_hv]->has_volume = true;
+
+ ConvertVolumeToRGBDisplay(IC, conversionInput->n_processranges, colorspace, Volume, RGBOut, LabOut, GamutRegion);
+ InGamut = true;
+ }
+ else
+ {
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ DirectInversion(IC, colorspace, InkOut, RGBOut, Volume, LabOut,
+ GamutRegion, InGamut, sur, CS);
+ PercentagetoNLcm(Volume, Volume);
+ GetClosestInk(Volume, GamutRegion, Volume); //Input Volume is in [nl/cm] Output Volume is in [%]
+ ConfineVolumes(Volume);
+ }
+ else
+ {
+ ConvertColorToLinearInks(conversionInput->inputcoordinates, conversionInput->colorspace, InkOut, RGBOut,
+ LabOut, GamutRegion, InGamut);
+ //Inks are in Linear Space , convert to nonlinear by using Calibration Tables,
+ //data is in full range of color table %
+ //convert data to the thread range in %
+ ColorTable2Threadunits(InkOut, InkOut);
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_CurrentProcessRangesMax[i] = m_ProcessRangesMaxP[i];
+ m_CurrentProcessRangesMin[i] = m_ProcessRangesMinP[i];
+ }
+ if (m_CalibMode == 1)
+ {
+ ConvertToNLInks(InkOut, NLInkOut);
+ LimitNLInks2Volume(NLInkOut, GamutRegion, Volume);
+ }
+ else
+ LimitNLInks2Volume(InkOut, GamutRegion, Volume);
+ }
+ //Split Volume into inks and Light Inks
+ if (m_UseLightInks)
+ {
+ SplitVolume(Volume, VolumeLI, GamutRegion);
+ }
+ else
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ VolumeLI(i) = Volume(i);
+ for (int i = m_nInks; i < m_TotalNumberofInks; ++i)
+ VolumeLI(i) = 0.0;
+ }
+ }
+ OutputCoordinates *outputCoords = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(outputCoords);
+ fillRGB(outputCoords, RGBOut);
+ fillLab(outputCoords, LabOut);
+ outputCoords->has_processparameterstableindex = true;
+ outputCoords->processparameterstableindex = GamutRegion;
+ fillVolume(outputCoords, VolumeLI);
+ conversionOutput->has_outofgamut = true;
+ conversionOutput->outofgamut = !(InGamut);
+ conversionOutput->singlecoordinates = outputCoords;
+
+ if (conversionInput->generatehive)
+ {
+ //input was processed.
+ //process neighboring values
+ //nhive includes 2 outer neighbors of the central Lab value, chroma + delta, chroma + 2delta
+ // and variation in L positioned on the side of the beehive.
+ //The set is arrange in a 5x6 matrix, where the 5x5 contains the variation in (Hue, chroma)
+ // and the last 5 contain the variation in L
+ int nHive = 18; //22; // 18;
+ int MatHive = 25;// 30; //25;
+
+ MatrixXd RGBHive(MatHive, 3);
+ VectorXd RGBHive1(3);
+ VectorXd LabHive1(3);
+ VectorXd VolumeHive1(m_TotalNumberofInks);
+ MatrixXd VolumeHive(MatHive, m_TotalNumberofInks);
+ MatrixXd LabHive(MatHive, 3);
+
+ int *GamutRegionV = new int[MatHive];
+ //int *GamutRegionV = DBG_NEW int[MatHive];
+ for (int i = 0; i < MatHive; ++i)
+ GamutRegionV[i] = -1;
+
+ int indDataMax[2];
+ int j = 0;
+ // Matrix values are initially set to -1;
+ RGBHive.setConstant(NegValue);
+ VolumeHive.setConstant(NegValue);
+
+ ProcessHiveNeighbors(conversionInput, LabOut, RGBOut, Volume, GamutRegion, RGBHive, LabHive, VolumeHive, nHive, GamutRegionV, indDataMax);
+ OutputCoordinates** hiveData = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * MatHive);
+ conversionOutput->hivecoordinates = hiveData;
+ conversionOutput->n_hivecoordinates = MatHive;
+ conversionOutput->n_triplecoordinates = 3;
+ for (int i = 0; i < MatHive; i++)
+ {
+ hiveData[i] = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(hiveData[i]);
+ if (RGBHive(i, 0) != NegValue)
+ {
+ for (j = 0; j < 3; ++j)
+ RGBHive1(j) = RGBHive(i, j);
+ fillRGB(hiveData[i], RGBHive1);
+ for (j = 0; j < m_TotalNumberofInks; ++j)
+ VolumeHive1(j) = VolumeHive(i, j);
+ fillVolume(hiveData[i], VolumeHive1);
+ for (j = 0; j < 3; ++j)
+ LabHive1(j) = LabHive(i, j);
+ fillLab(hiveData[i], LabHive1);
+ hiveData[i]->has_processparameterstableindex = true;
+ hiveData[i]->processparameterstableindex = GamutRegionV[i];
+ hiveData[i]->n_outputliquids = m_TotalNumberofInks;
+ }
+ conversionOutput->hivecoordinates[i] = hiveData[i];
+ }
+
+
+ //Triplet
+ OutputCoordinates** TripletData = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * 3);
+ conversionOutput->triplecoordinates = TripletData;
+ int tripletIndex[3] = { indDataMax[0] , (int)(12), indDataMax[1] };
+ for (int i = 0; i < 3; ++i)
+ {
+ // OutputCoordinates SingleCell = OUTPUT_COORDINATES__INIT;
+ TripletData[i] = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(TripletData[i]);
+ for (j = 0; j < 3; ++j)
+ RGBHive1(j) = RGBHive(tripletIndex[i], j);
+ fillRGB(TripletData[i], RGBHive1);
+ for (j = 0; j < m_nVolumes; ++j)
+ VolumeHive1(j) = VolumeHive(tripletIndex[i], j);
+ fillVolume(TripletData[i], VolumeHive1);
+ for (j = 0; j < 3; ++j)
+ LabHive1(j) = LabHive(tripletIndex[i], j);
+ fillLab(TripletData[i], LabHive1);
+ TripletData[i]->has_processparameterstableindex = true;
+ TripletData[i]->processparameterstableindex = GamutRegionV[tripletIndex[i]];
+ TripletData[i]->n_outputliquids = m_TotalNumberofInks;
+ conversionOutput->triplecoordinates[i] = TripletData[i];
+ }
+
+ //Clean up
+ if (GamutRegionV != NULL)
+ {
+ delete[] GamutRegionV;
+ GamutRegionV = NULL;
+ }
+
+ }
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+ catch (const std::exception& e)
+ {
+ //Notify Error...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ conversion_output__init(conversionOutput);
+
+ conversionOutput->has_haserror = true;
+ conversionOutput->haserror = true;
+
+ const char* what = e.what();
+ int nWhat = strlen(what);
+ conversionOutput->errormessage = (char*)malloc(nWhat);
+ //conversionOutput->errormessage = new char[nWhat];
+ for (int i = 0; i < nWhat; ++i)
+ conversionOutput->errormessage[i] = what[i];
+ //strcpy_s(conversionOutput->errormessage, nWhat, what);
+
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+}
+
+void Tango::ColorLib::ColorConverter::CountNumberofInks(GradientConversionInput* conversionInput, int &numInks, int &numLightInks)
+{
+ int nLiquids = conversionInput->n_inputliquids;
+ // int numberofInks = 0;
+ //Cyan
+ int nCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Cyan)
+ nCyan++;
+ }
+ if (nCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Magenta)
+ nMagenta++;
+ }
+ if (nMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Yellow)
+ nYellow++;
+ }
+ if (nYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nBlack = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Black)
+ nBlack++;
+ }
+ if (nBlack > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightCyan)
+ nLightCyan++;
+ }
+ if (nLightCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightMagenta)
+ nLightMagenta++;
+ }
+ if (nLightMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightYellow)
+ nLightYellow++;
+ }
+ if (nLightYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ numInks = nCyan + nMagenta + nYellow + nBlack + nLightCyan + nLightMagenta + nLightYellow;
+ numLightInks = nLightCyan + nLightMagenta + nLightYellow;;
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::CountNumberofInks(OutOfGamutInput* conversionInput, int &numInks, int &numLightInks)
+{
+ int nLiquids = conversionInput->inputcoordinates->n_inputliquids;
+ // int numberofInks = 0;
+ //Cyan
+ int nCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Cyan)
+ nCyan++;
+ }
+ if (nCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Magenta)
+ nMagenta++;
+ }
+ if (nMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Yellow)
+ nYellow++;
+ }
+ if (nYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nBlack = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Black)
+ nBlack++;
+ }
+ if (nBlack > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightCyan)
+ nLightCyan++;
+ }
+ if (nLightCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightMagenta)
+ nLightMagenta++;
+ }
+ if (nLightMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightYellow)
+ nLightYellow++;
+ }
+ if (nLightYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ numInks = nCyan + nMagenta + nYellow + nBlack + nLightCyan + nLightMagenta + nLightYellow;
+ numLightInks = nLightCyan + nLightMagenta + nLightYellow;;
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::CountNumberofInks(RecommendedProcessTableInput* conversionInput, int &numInks, int &numLightInks)
+{
+ int nLiquids = conversionInput->n_inputliquids;
+ // int numberofInks = 0;
+ //Cyan
+ int nCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Cyan)
+ nCyan++;
+ }
+ if (nCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Magenta)
+ nMagenta++;
+ }
+ if (nMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Yellow)
+ nYellow++;
+ }
+ if (nYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nBlack = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__Black)
+ nBlack++;
+ }
+ if (nBlack > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightCyan)
+ nLightCyan++;
+ }
+ if (nLightCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightMagenta)
+ nLightMagenta++;
+ }
+ if (nLightMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputliquids[i]->liquidtype == LIQUID_TYPE__LightYellow)
+ nLightYellow++;
+ }
+ if (nLightYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ numInks = nCyan + nMagenta + nYellow + nBlack + nLightCyan + nLightMagenta + nLightYellow;
+ numLightInks = nLightCyan + nLightMagenta + nLightYellow;;
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::CountNumberofInks(ConversionInput* conversionInput, int &numInks, int &numLightInks)
+{
+ int nLiquids = conversionInput->inputcoordinates->n_inputliquids;
+ std::map< LiquidType, int> liquidsToCountMap;
+ std::map< LiquidType, int> lightLiquidsToCountMap;
+ numInks = -1;
+ numLightInks = -1;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ LiquidType liquidType = conversionInput->inputcoordinates->inputliquids[i]->liquidtype;
+ if (liquidType == LiquidType::LIQUID_TYPE__LightCyan || liquidType == LiquidType::LIQUID_TYPE__LightMagenta || liquidType == LiquidType::LIQUID_TYPE__LightYellow)
+ {
+ if (lightLiquidsToCountMap.find(liquidType) == lightLiquidsToCountMap.end())
+ {
+ lightLiquidsToCountMap[liquidType] = 1;
+ }
+ else {
+ return;
+ }
+ }
+ else if(liquidType == LiquidType::LIQUID_TYPE__Cyan || liquidType == LiquidType::LIQUID_TYPE__Magenta || liquidType == LiquidType::LIQUID_TYPE__Yellow || liquidType == LiquidType::LIQUID_TYPE__Black)
+ {
+ if (liquidsToCountMap.find(liquidType) == liquidsToCountMap.end())
+ {
+ liquidsToCountMap[liquidType] = 1;
+ }
+ else {
+ return;
+ }
+ }
+ }
+ numInks = liquidsToCountMap.size() + lightLiquidsToCountMap.size();
+ numLightInks = lightLiquidsToCountMap.size();
+ /*int nCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Cyan)
+ nCyan++;
+ }
+ if (nCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Magenta)
+ nMagenta++;
+ }
+ if (nMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Yellow)
+ nYellow++;
+ }
+ if (nYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nBlack = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Black)
+ nBlack++;
+ }
+ if (nBlack > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightCyan = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightCyan)
+ nLightCyan++;
+ }
+ if (nLightCyan > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightMagenta)
+ nLightMagenta++;
+ }
+ if (nLightMagenta > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ int nLightYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__LightYellow)
+ nLightYellow++;
+ }
+ if (nLightYellow > 1)
+ {
+ numInks = -1;
+ numLightInks = -1;
+ return;
+ }
+ numInks = nCyan + nMagenta + nYellow + nBlack + nLightCyan + nLightMagenta + nLightYellow;
+ numLightInks = nLightCyan + nLightMagenta + nLightYellow;;*/
+ return;
+}
+
+bool Tango::ColorLib::ColorConverter::IsInGamut(double *InLab, SURROUND sur, CAM02CS CS, double *LabCoord)
+{
+ int nInLab = 3;
+ double *xCoord = new double[nInLab];
+ //double *xCoord = DBG_NEW double[nInLab];
+ //Convert InLab to CIECam02 coordinates
+ bool InGamut = true;
+ if (InLab[0] > 100 || InLab[0] < 0 || InLab[1] > 127 || InLab[1] < -128 || InLab[2] > 127 || InLab[2] < -128)
+ {
+ InGamut = false;
+ LimitLab(InLab);
+ }
+
+ double ctr[3];
+ C_RGB_XYZ_Lab center = m_colortable->m_GBD->getCenter();
+ VectorXd JInLab(3);
+ JInLab << InLab[0], InLab[1], InLab[2];
+ VectorXd JLab = m_Conv02->LabToJab(JInLab, sur);
+ ctr[0] = -JLab(0) + center.Get_x();
+ ctr[1] = -JLab(1) + center.Get_y();
+ ctr[2] = -JLab(2) + center.Get_z();
+ double *dJLab = new double[3];
+ //double *dJLab = DBG_NEW double[3];
+ VectorToDouble(JLab, dJLab);
+ bool intersect = false;
+ m_colortable->m_GBD->TriangleRayIntersection(dJLab, ctr, intersect, xCoord);
+ if (intersect)
+ {
+ VectorXd V1(3);
+ VectorXd V2(3);
+ V1 << JLab[0], JLab[1], JLab[2];
+ V2 << xCoord[0], xCoord[1], xCoord[2];
+ double dECMC;
+ m_Conv02->SymmetricaldECMC(V1, V2, dECMC);
+ if (dECMC < dETol)
+ InGamut = true;
+ else
+ InGamut = false;
+ VectorXd JabV(3);
+ JabV = DoubleToVector(xCoord, 3);
+ VectorXd LabV(3);
+ LabV = m_Conv02->Jab_2_Lab(JabV, CS);
+ VectorToDouble(LabV, LabCoord);
+ }
+ else
+ {
+ InGamut = true;
+ for (int i = 0; i < 3; ++i)
+ LabCoord[i] = InLab[i];
+ }
+ //Convert back to Lab
+
+ if (xCoord != NULL)
+ {
+ delete[] xCoord;
+ xCoord = NULL;
+ }
+ if (dJLab != NULL)
+ {
+ delete[]dJLab;
+ dJLab = NULL;
+ }
+ return(InGamut);
+}
+
+
+
+
+void Tango::ColorLib::ColorConverter::read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput)
+{
+ /*
+ 0 - 3 'prec1', 'prec2'
+ 4 - 7 reserved, must be 0
+ 8 number of input channels, uint8
+ 9 number of output channels, uint8
+ 10 number of CLUT grid points, uint8
+ 11 number of Shift Bits
+ 12 Number of gamut regions
+ 13 - n CLUT values, uint16
+
+ 13 - n output tables, uint8
+ */
+ if (data_size < 32)
+ {
+ throw std::exception(" LUT size missmatch");
+ return;
+ }
+ int bytesread = 0;
+ // Check for signature
+ uint8_t *buff = &conversionInput->forwarddata.data[offset];
+ Transf->InitData(buff, data_size);
+ return;
+}
+
+
+
+
+
+
+
+/*void Tango::ColorLib::ColorConverter::CompareWhitePoints()
+{
+ ColorConvert ColConv(D65, D65);
+ C_RGB_XYZ_Lab Lab_CT;
+ C_RGB_XYZ_Lab Lab_Strip;
+ Lab_CT = ColConv.XYZToLab(m_whitepointXYZ_CT);
+ Lab_Strip = ColConv.XYZToLab(m_whitepointXYZ_Strip);
+ VectorXd VLab_CT(3);
+ VectorXd VLab_Strip(3);
+ VLab_CT(0) = Lab_CT.Get_x();
+ VLab_CT(1) = Lab_CT.Get_y();
+ VLab_CT(2) = Lab_CT.Get_z();
+ VLab_Strip(0) = Lab_Strip.Get_x();
+ VLab_Strip(1) = Lab_Strip.Get_y();
+ VLab_Strip(2) = Lab_Strip.Get_z();
+ double dECMC;
+ ColConv.SymmetricaldECMC(VLab_CT, VLab_Strip, dECMC);
+ if (dECMC > WPTol)
+ m_AdaptWP = true;
+ if (m_whitepointXYZ_Strip.Get_x() <= 0 || m_whitepointXYZ_Strip.Get_y() <= 0 || m_whitepointXYZ_Strip.Get_z()<=0)
+ m_AdaptWP = false;
+ return;
+} */ /* not used*/
+
+//size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+//{
+// //Unpack conversion input...
+// ConversionInput* conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+//
+// //Initialize Output...
+// ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT;
+//
+// //The request is for RGB to Volume...
+// if (conversionInput->colorspace == COLOR_SPACE__RGB)
+// {
+// //Get RGB values...
+// int r = conversionInput->inputcoordinates->red;
+// int g = conversionInput->inputcoordinates->green;
+// int b = conversionInput->inputcoordinates->blue;
+//
+// //iterate over input liquids...
+// for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+// {
+// InputLiquid* inputLiquid = conversionInput->inputcoordinates->inputliquids[i];
+//
+// //Get cyan liquid for example...
+// if (inputLiquid->liquidtype == LIQUID_TYPE__Cyan)
+// {
+// //Get liquid max nl per cm.
+// double maxNlPerCM = inputLiquid->maxnanoliterpercentimeter;
+//
+// //Get liquid calibration data.
+// CalibrationData* calibrationData = inputLiquid->calibrationdata;
+//
+// //Iterate over calibration points..
+// for (size_t j = 0; j < calibrationData->n_calibrationpoints; j++)
+// {
+// //Calibration Point
+// CalibrationPoint* point = calibrationData->calibrationpoints[j];
+//
+// double x = point->x;
+// double y = point->y;
+// }
+// }
+// }
+//
+// //Set conversion output with proper volumes...
+//
+// //Set Cyan liquid volume...
+// OutputLiquid cyanLiquid = OUTPUT_LIQUID__INIT;
+// cyanLiquid.has_volume = true;
+// cyanLiquid.has_liquidtype = true;
+// cyanLiquid.liquidtype = LIQUID_TYPE__Cyan;
+// cyanLiquid.volume = 20;
+//
+// //Set Magenta liquid volume...
+// OutputLiquid magentaLiquid = OUTPUT_LIQUID__INIT;
+// magentaLiquid.has_volume = true;
+// magentaLiquid.has_liquidtype = true;
+// magentaLiquid.liquidtype = LIQUID_TYPE__Magenta;
+// magentaLiquid.volume = 30;
+//
+// OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * 2);
+//
+// //Add cyan and magenta to output liquids array.
+// outputLiquids[0] = &cyanLiquid;
+// outputLiquids[1] = &magentaLiquid;
+//
+// OutputCoordinates outCoords;
+// outCoords.outputliquids = outputLiquids;
+//
+// conversionOutput.singlecoordinates = &outCoords;
+// }
+//
+//
+//
+// //The request is for volumes to RGB...
+// else if (conversionInput->colorspace == COLOR_SPACE__Volume)
+// {
+// //iterate over input liquids...
+// for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+// {
+// InputLiquid* inputLiquid = conversionInput->inputcoordinates->inputliquids[i];
+//
+// //Get cyan liquid for example...
+// if (inputLiquid->liquidtype == LIQUID_TYPE__Cyan)
+// {
+// //Get liquid max nl per cm.
+// double maxNlPerCM = inputLiquid->maxnanoliterpercentimeter;
+//
+// //Get liquid volume.
+// double volume = inputLiquid->volume;
+//
+// //Get liquid calibration data.
+// CalibrationData* calibrationData = inputLiquid->calibrationdata;
+//
+// //Iterate over calibration points..
+// for (size_t j = 0; j < calibrationData->n_calibrationpoints; j++)
+// {
+// //Calibration Point
+// CalibrationPoint* point = calibrationData->calibrationpoints[j];
+//
+// double x = point->x;
+// double y = point->y;
+// }
+// }
+// else if (inputLiquid->liquidtype == LIQUID_TYPE__Magenta)
+// {
+// //Same as above...
+// }
+// }
+//
+// //Set conversion output (single) with proper RGB values...
+// OutputCoordinates outputCoords = OUTPUT_COORDINATES__INIT;
+// outputCoords.has_red = true;
+// outputCoords.has_green = true;
+// outputCoords.has_blue = true;
+// outputCoords.red = 50;
+// outputCoords.green = 100;
+// outputCoords.blue = 150;
+//
+// conversionOutput.singlecoordinates = &outputCoords;
+//
+// //Set conversion output (hive) with proper RGB values...
+//
+// int hiveCellCount = 10;
+//
+// OutputCoordinates** hiveCoordinates = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * hiveCellCount);
+//
+// for (size_t i = 0; i < hiveCellCount; i++)
+// {
+// OutputCoordinates cellCoords = OUTPUT_COORDINATES__INIT;
+// cellCoords.has_red = true;
+// cellCoords.has_green = true;
+// cellCoords.has_blue = true;
+// cellCoords.red = 10;
+// cellCoords.green = 20;
+// cellCoords.blue = 30;
+//
+// hiveCoordinates[i] = &cellCoords;
+// }
+//
+// conversionOutput.hivecoordinates = hiveCoordinates;
+// }
+//
+// //Pack output...
+// output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(&conversionOutput));
+//
+// return conversion_output__pack(&conversionOutput, output_buffer);
+//}
+
+
+
+size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+
+ //Get Input
+ ConversionInput* conversionInput = (ConversionInput*)malloc(sizeof(ConversionInput));
+
+ conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+
+
+
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+ /*int expected_liquids = 3;
+
+ InputLiquid** filteredInputLiquids = (InputLiquid**)malloc(sizeof(InputLiquid*) * expected_liquids);
+
+ for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+ {
+ InputLiquid* liquid = conversionInput->inputcoordinates->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ break;
+ }
+ }
+
+ conversionInput->inputcoordinates->inputliquids = filteredInputLiquids;
+ conversionInput->inputcoordinates->n_inputliquids = expected_liquids;
+ //Filter and arrange colors
+
+ */
+
+ //Initialize Output...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ if (conversionOutput != NULL)
+ conversion_output__init(conversionOutput);
+ else
+ return(0);
+
+ // ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT;
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+ //count number if inks
+ int numofInks = 0;
+ int numLightInks = 0;
+ if (m_colortable == NULL)
+ m_colortable = new ColorTable();
+
+
+ CountNumberofInks(conversionInput, numofInks, numLightInks);
+ readColorTransformations(conversionInput);
+
+ //read calibration tables and store them in m_CalibCurves
+ int n_inputliquids = numofInks - numLightInks;
+ InputLiquid **inputliquid = conversionInput->inputcoordinates->inputliquids;
+ //Read CMYK Calibration Tables only. Light Inks have no calibration tables
+
+ readCalibrationTables(inputliquid, n_inputliquids);
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ if ((numofInks - numLightInks) != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables");
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+
+ C_RGB_XYZ_Lab DataLab;
+ switch (conversionInput->colorspace)
+ {
+ case (COLOR_SPACE__RGB):
+ {
+ // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric,
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread
+ //The workflow is a follows:
+ //1. Convert RGB to Lab (Whitepoint is D65, same as tables)
+ //2.Fiond if Lab is InGamut
+
+ RGBOut(0) = conversionInput->inputcoordinates->red;
+ RGBOut(1) = conversionInput->inputcoordinates->green;
+ RGBOut(2) = conversionInput->inputcoordinates->blue;
+ //convert to Lab
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+
+ double *LabIn = new double[3];
+ double *RGBOutP = new double[3];
+ VectorToDouble(RGBOut, RGBOutP);
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Absolute Colorimetric, D65
+ double *LabInFinal2 = new double[3];
+ LimitLab(LabIn);
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip);
+ //Is In Gamut?
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabInFinal2);
+ LimitLab(LabInFinal2);
+
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ if(LabInFinal2 != NULL)
+ {
+ delete[] LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ break;
+ }
+ case (COLOR_SPACE__LAB):
+ {
+ // Basic assumption: Lab data has the same whitepoint as the STRIP thread.
+ //The workflow is a follows:
+ //1. Convert Lab to Relative colorimetric. check if there is a match between STRIP and Color Tables
+ //2. Find if Lab is InGamut
+
+ double *LabIn = new double[3];
+ //double *LabIn = DBG_NEW double[3];
+ LabIn[0] = conversionInput->inputcoordinates->l;
+ LabIn[1] = conversionInput->inputcoordinates->a;
+ LabIn[2] = conversionInput->inputcoordinates->b;
+ //the assumption is that the color space has illumination that matches the whitepoint of the Strip
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+
+ double *LabInFinal2 = new double[3];
+ //double *LabInFinal2 = DBG_NEW double[3];
+ // CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //to Relative
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //to Relative
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabInFinal2);
+ LimitLab(LabInFinal2);
+
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (LabInFinal2 != NULL)
+ {
+ delete[]LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ break;
+ }
+ case(COLOR_SPACE__CMYK):
+ case(COLOR_SPACE__Volume):
+ case(COLOR_SPACE__Catalog):
+ {//no conversion
+ //missing from structure light inks or special colors
+ // just convert Lab for rgb display
+ InGamut = true;
+ }
+ default:
+ {
+ throw std::exception(" Unsupported Color Space");
+ return(0);
+ }
+ }
+
+ //Pack data
+ OutputCoordinates *outputCoords = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(outputCoords);
+ conversionOutput->has_outofgamut = true;
+ conversionOutput->outofgamut = !(InGamut);
+ conversionOutput->singlecoordinates = outputCoords;
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ //conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ //conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+}
+
+
+size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ GradientConversionInput* conversionInput = NULL;
+ GradientConversionOutput *conversionOutput = NULL;
+ InputLiquid** original_input_liquids = NULL;
+ int original_input_liquids_count = 0;
+ try
+ {
+ //Get Input...
+ GradientConversionInput* conversionInput = (GradientConversionInput*)malloc(sizeof(GradientConversionInput));
+ conversionInput = gradient_conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+ //Initialize Output...
+ GradientConversionOutput *conversionOutput = (GradientConversionOutput*)malloc(sizeof(GradientConversionOutput));
+ gradient_conversion_output__init(conversionOutput);
+
+ conversionOutput->haserror = false;
+ conversionOutput->has_haserror = false;
+ //Get segment length...
+ double segmentLength = conversionInput->segmentlength;
+ if (m_colortable == NULL)
+ m_colortable = new ColorTable();
+ PrepareGradient(conversionInput, conversionOutput);
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(gradient_conversion_output__get_packed_size(conversionOutput));
+ int size = gradient_conversion_output__pack(conversionOutput, output_buffer);
+
+ //RELEASE MEMORY HERE !!!
+#pragma region Free Conversion Input & Output
+
+ gradient_conversion_input__free_unpacked(conversionInput, NULL);
+
+ gradient_conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return size;
+ }
+ catch (const std::exception& e)
+ {
+ //Notify Error...
+ GradientConversionOutput *conversionOutput = (GradientConversionOutput*)malloc(sizeof(GradientConversionOutput));
+ gradient_conversion_output__init(conversionOutput);
+
+ conversionOutput->has_haserror = true;
+ conversionOutput->haserror = true;
+
+ const char* what = e.what();
+ int nWhat = strlen(what);
+ conversionOutput->errormessage = (char*)malloc(nWhat);
+ //conversionOutput->errormessage = new char[nWhat];
+ for (int i = 0; i < nWhat; ++i)
+ conversionOutput->errormessage[i] = what[i];
+
+ output_buffer = (uint8_t*)malloc(gradient_conversion_output__get_packed_size(conversionOutput));
+ int size = gradient_conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+ if (conversionInput != NULL)
+ {
+ conversionInput->inputliquids = original_input_liquids;
+ conversionInput->n_inputliquids = original_input_liquids_count;
+
+ gradient_conversion_input__free_unpacked(conversionInput, NULL);
+ }
+ gradient_conversion_output__free_unpacked(conversionOutput, NULL);
+
+
+#pragma endregion
+
+ return (size);
+ }
+}
+
+void Tango::ColorLib::ColorConverter::fillGradientStops(GradientConversionInput *conversionInput)
+{
+ C_RGB_XYZ_Lab RGB;
+ C_RGB_XYZ_Lab Lab;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ switch (conversionInput->stops[i]->colorspace)
+ {
+ case COLOR_SPACE__RGB: //Case RGB
+ RGB = C_RGB_XYZ_Lab(conversionInput->stops[i]->red, conversionInput->stops[i]->green, conversionInput->stops[i]->blue);
+ m_GradStops[i].Set_RGB(RGB);
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__RGB);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ break;
+ case COLOR_SPACE__LAB: //Case LAB
+ Lab = C_RGB_XYZ_Lab(conversionInput->stops[i]->l, conversionInput->stops[i]->a, conversionInput->stops[i]->b);
+ m_GradStops[i].Set_Lab(Lab);
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__LAB);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ break;
+ case COLOR_SPACE__Catalog:
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__Catalog);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ m_GradStops[i].SetCatalogInkValues(conversionInput->stops[i]->cyan, 0);
+ m_GradStops[i].SetCatalogInkValues(conversionInput->stops[i]->magenta, 1);
+ m_GradStops[i].SetCatalogInkValues(conversionInput->stops[i]->yellow,2);
+ m_GradStops[i].SetCatalogInkValues(conversionInput->stops[i]->key, 3);
+ break;
+ case COLOR_SPACE__Volume: //Case Volume // No Light Inks implementation for Volume
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__Volume);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ for (int j = 0; j < m_TotalNumberofInks; j++)
+ {
+ LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];
+
+ switch (liquidVolume->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ case LIQUID_TYPE__LightCyan:
+ case LIQUID_TYPE__LightMagenta:
+ case LIQUID_TYPE__LightYellow:
+ {
+ m_GradStops[i].SetVolumeValue(liquidVolume->volume, j);
+ break;
+ }
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::findStops(Gradient &GradStop1, Gradient &GradStop2, double dEThr, int ninterstops,
+ int &nOut, double **VecRGBOut, double **VecLabOut, double *posOut)
+{
+ ColorConvert CConvertD65(D65, D65);
+ C_RGB_XYZ_Lab RGBStart = GradStop1.Get_RGB();
+ C_RGB_XYZ_Lab RGBEnd = GradStop2.Get_RGB();
+ C_RGB_XYZ_Lab LowLab(0, -128, -128);
+ C_RGB_XYZ_Lab HighLab(100, 127, 127);
+ C_RGB_XYZ_Lab LowRGB(0, 0, 0);
+ C_RGB_XYZ_Lab HighRGB(255, 255, 255);
+ C_RGB_XYZ_Lab LabStart = GradStop1.Get_Lab();
+ C_RGB_XYZ_Lab LabEnd = GradStop2.Get_Lab();
+ int nsubdiv = 101;
+ C_RGB_XYZ_Lab dRGB((RGBEnd.Get_x() - RGBStart.Get_x()) / (nsubdiv - 1), (RGBEnd.Get_y() - RGBStart.Get_y()) / (nsubdiv - 1),
+ (RGBEnd.Get_z() - RGBStart.Get_z()) / (nsubdiv - 1));
+ C_RGB_XYZ_Lab dLab((LabEnd.Get_x() - LabStart.Get_x()) / (nsubdiv - 1), (LabEnd.Get_y() - LabStart.Get_y()) / (nsubdiv - 1),
+ (LabEnd.Get_z() - LabStart.Get_z()) / (nsubdiv - 1));
+
+ C_RGB_XYZ_Lab *VecLabOut_tmp = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecRGBOut_tmp = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecLabOut_fin = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecRGBOut_fin = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab RGBTmp;
+ C_RGB_XYZ_Lab LabTmp;
+ // make a vector of RGB values with 100 subdivisions
+ // make a matching Lab vector;
+
+ VecRGBOut_tmp[0] = C_RGB_XYZ_Lab(RGBStart);
+ VecLabOut_tmp[0] = C_RGB_XYZ_Lab(GradStop1.Get_Lab());
+ int Stop1Index = 0;
+ int Stop2Index = nsubdiv;
+ if ((!GradStop1.Get_InRGBLimits()) && (!GradStop2.Get_InRGBLimits()))
+ {
+ //use Lab Coords
+ for (int i = 1; i < nsubdiv; ++i)
+ {
+ VecLabOut_tmp[i].Set(VecLabOut_tmp[i - 1].Get_x() + dLab.Get_x(),
+ VecLabOut_tmp[i - 1].Get_y() + dLab.Get_y(),
+ VecLabOut_tmp[i - 1].Get_z() + dLab.Get_z());
+ VecRGBOut_tmp[i] = m_Conv02->LabtoRGB(VecLabOut_tmp[i]);
+ }
+ Stop1Index = nsubdiv;
+ Stop2Index = 0;
+ }
+ else
+ {
+ if (!GradStop1.Get_InRGBLimits())
+ {
+ bool retValue = false;
+ int i_index = 0;
+ LabTmp.Set(GradStop1.Get_Lab().Get_x() + i_index * dLab.Get_x(),
+ GradStop1.Get_Lab().Get_y() + i_index * dLab.Get_y(),
+ GradStop1.Get_Lab().Get_z() + i_index * dLab.Get_z());
+ while ((!retValue) & (i_index < nsubdiv))
+ {
+ retValue = CheckLabInRGBGamut(LabTmp);
+ i_index++;
+ LabTmp.Set(GradStop1.Get_Lab().Get_x() + i_index * dLab.Get_x(),
+ GradStop1.Get_Lab().Get_y() + i_index * dLab.Get_y(),
+ GradStop1.Get_Lab().Get_z() + i_index * dLab.Get_z());
+ }
+ Stop1Index = i_index;
+ }
+
+ if (!GradStop2.Get_InRGBLimits())
+ {
+ bool retValue = false;
+ int i_index = 0;
+ LabTmp.Set(GradStop2.Get_Lab().Get_x() - i_index * dLab.Get_x(),
+ GradStop2.Get_Lab().Get_y() - i_index * dLab.Get_y(),
+ GradStop2.Get_Lab().Get_z() - i_index * dLab.Get_z());
+ while ((!retValue) & (i_index < nsubdiv))
+ {
+ retValue = CheckLabInRGBGamut(LabTmp);
+ i_index++;
+ LabTmp.Set(GradStop2.Get_Lab().Get_x() - i_index * dLab.Get_x(),
+ GradStop2.Get_Lab().Get_y() - i_index * dLab.Get_y(),
+ GradStop2.Get_Lab().Get_z() - i_index * dLab.Get_z());
+ }
+ Stop2Index -= (i_index - 1);
+ }
+ //Base vector on Lab
+ for (int i = 1; i < Stop1Index; ++i)
+ {
+ VecLabOut_tmp[i].Set(VecLabOut_tmp[i - 1].Get_x() + dLab.Get_x(),
+ VecLabOut_tmp[i - 1].Get_y() + dLab.Get_y(),
+ VecLabOut_tmp[i - 1].Get_z() + dLab.Get_z());
+ VecRGBOut_tmp[i] = m_Conv02->LabtoRGB(VecLabOut_tmp[i]);
+ }
+ //recalculate dRGB
+ int SI1 = Stop1Index;
+ int SI2 = Stop2Index;
+ C_RGB_XYZ_Lab LabStop1(LabStart.Get_x() + SI1 * dLab.Get_x(),
+ LabStart.Get_y() + SI1 * dLab.Get_y(), LabStart.Get_z() + SI1 * dLab.Get_z());
+ C_RGB_XYZ_Lab LabStop2(LabStart.Get_x() + (SI2 - 1) * dLab.Get_x(),
+ LabStart.Get_y() + (SI2 - 1) * dLab.Get_y(), LabStart.Get_z() + (SI2 - 1) * dLab.Get_z());
+ C_RGB_XYZ_Lab RGBStop1 = m_Conv02->LabtoRGB(LabStop1);
+ C_RGB_XYZ_Lab RGBStop2 = m_Conv02->LabtoRGB(LabStop2);
+ int nelems = Stop2Index - Stop1Index;
+ dRGB = C_RGB_XYZ_Lab((RGBStop2.Get_x() - RGBStop1.Get_x()) / (nelems - 1), (RGBStop2.Get_y() - RGBStop1.Get_y()) / (nelems - 1),
+ (RGBStop2.Get_z() - RGBStop1.Get_z()) / (nelems - 1));
+
+ int STi = 0;
+ for (int i = 0; i < nelems; ++i)
+ {
+ STi = Stop1Index + i;
+ VecRGBOut_tmp[STi].Set(RGBStop1.Get_x() + i * dRGB.Get_x(),
+ RGBStop1.Get_y() + i * dRGB.Get_y(),
+ RGBStop1.Get_z() + i * dRGB.Get_z());
+ VecLabOut_tmp[STi] = CConvertD65.RGBtoLab(VecRGBOut_tmp[STi]);
+ VecLabOut_tmp[STi].Clamp(LowLab, HighLab);
+ }
+ for (int i = Stop2Index; i < nsubdiv; ++i)
+ {
+ VecLabOut_tmp[i].Set(VecLabOut_tmp[i - 1].Get_x() + dLab.Get_x(),
+ VecLabOut_tmp[i - 1].Get_y() + dLab.Get_y(),
+ VecLabOut_tmp[i - 1].Get_z() + dLab.Get_z());
+ VecRGBOut_tmp[i] = m_Conv02->LabtoRGB(VecLabOut_tmp[i]);
+ }
+ }
+ int indGrad = 0;
+ int *pos = new int[ninterstops];
+ int i1 = 1;
+ int j1 = 1;
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[0];
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[0];
+ pos[indGrad] = 0;
+ double dE = 0.0;
+ double dEOld = 0.0;
+ while ((i1 < nsubdiv) & (indGrad < ninterstops - 1))
+ {
+ dEOld = dE;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE);
+ j1 = i1;
+ while (dE < dEThr && i1 < nsubdiv && j1 < nsubdiv)
+ {
+ j1++;
+ dEOld = dE;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[j1], dE);
+ }
+ if (j1 > i1)
+ {
+ j1--;
+ indGrad++;
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1];
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[j1];
+ pos[indGrad] = j1;
+ dE = dEOld;
+ i1 = j1 + 1;
+ }
+ else
+ {
+ dEOld = dE;
+ if((i1<Stop1Index) | (i1 > Stop2Index))
+ {
+ while (dE >= dEThr && i1 < nsubdiv)
+ {
+ //get intermediate point
+ LabTmp.Set((VecLabOut_tmp[i1].Get_x() + VecLabOut_fin[indGrad].Get_x()) / 2.0,
+ (VecLabOut_tmp[i1].Get_y() + VecLabOut_fin[indGrad].Get_y()) / 2.0,
+ (VecLabOut_tmp[i1].Get_z() + VecLabOut_fin[indGrad].Get_z()) / 2.0);
+ RGBTmp = CConvertD65.LabtoRGB(LabTmp); // Lab is in Relative Colorimetric
+ LabTmp.Clamp(LowLab, HighLab);
+ //move vectors down by one
+ for (int i = nsubdiv - 1; i >= i1; --i)
+ {
+ VecRGBOut_tmp[i + 1] = VecRGBOut_tmp[i];
+ VecLabOut_tmp[i + 1] = VecLabOut_tmp[i];
+ }
+ VecRGBOut_tmp[i1] = RGBTmp;
+ VecLabOut_tmp[i1] = LabTmp;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE);
+ nsubdiv++;
+ if(i1 < Stop1Index)
+ {
+ Stop1Index++;
+ Stop2Index++;
+ }
+ }
+ }
+ else
+ {
+ while (dE >= dEThr && i1 < nsubdiv)
+ {
+ //get intermediate point
+ RGBTmp.Set((VecRGBOut_tmp[i1].Get_x() + VecRGBOut_fin[indGrad].Get_x()) / 2.0,
+ (VecRGBOut_tmp[i1].Get_y() + VecRGBOut_fin[indGrad].Get_y()) / 2.0,
+ (VecRGBOut_tmp[i1].Get_z() + VecRGBOut_fin[indGrad].Get_z()) / 2.0);
+ LabTmp = CConvertD65.RGBtoLab(RGBTmp); // Lab is in Relative Colorimetric
+ LabTmp.Clamp(LowLab, HighLab);
+ //move vectors down by one
+ for (int i = nsubdiv - 1; i >= i1; --i)
+ {
+ VecRGBOut_tmp[i + 1] = VecRGBOut_tmp[i];
+ VecLabOut_tmp[i + 1] = VecLabOut_tmp[i];
+ }
+ VecRGBOut_tmp[i1] = RGBTmp;
+ VecLabOut_tmp[i1] = LabTmp;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE);
+ nsubdiv++;
+ Stop2Index++;
+ }
+ }
+ indGrad++;
+
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1];
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[j1];
+ pos[indGrad] = j1;
+ i1 = j1 + 1;
+ }
+ }
+ if (indGrad < ninterstops)
+ nOut = indGrad + 1;
+ else
+ {
+ throw std::exception("Number of subdivisions exceeds allocation");
+ if (VecLabOut_tmp != NULL)
+ {
+ delete[] VecLabOut_tmp;
+ VecLabOut_tmp = NULL;
+ }
+ if (VecRGBOut_tmp != NULL)
+ {
+ delete[] VecRGBOut_tmp;
+ VecRGBOut_tmp = NULL;
+ }
+ if (VecLabOut_fin != NULL)
+ {
+ delete[] VecLabOut_fin;
+ VecLabOut_fin = NULL;
+ }
+ if (VecRGBOut_fin != NULL)
+ {
+ delete[] VecRGBOut_fin;
+ VecRGBOut_fin = NULL;
+ }
+ if (pos != NULL)
+ {
+ delete[] pos;
+ pos = NULL;
+ }
+ }
+
+ for (int i = 0; i < nOut; ++i)
+ {
+ VecLabOut[i][0] = VecLabOut_fin[i].Get_x();
+ VecLabOut[i][1] = VecLabOut_fin[i].Get_y();
+ VecLabOut[i][2] = VecLabOut_fin[i].Get_z();
+ VecRGBOut[i][0] = VecRGBOut_fin[i].Get_x();
+ VecRGBOut[i][1] = VecRGBOut_fin[i].Get_y();
+ VecRGBOut[i][2] = VecRGBOut_fin[i].Get_z();
+ posOut[i] = pos[i];
+ }
+ //free allocs
+ if (VecLabOut_tmp != NULL)
+ {
+ delete[] VecLabOut_tmp;
+ VecLabOut_tmp = NULL;
+ }
+ if (VecRGBOut_tmp != NULL)
+ {
+ delete[] VecRGBOut_tmp;
+ VecRGBOut_tmp = NULL;
+ }
+ if (VecLabOut_fin != NULL)
+ {
+ delete[] VecLabOut_fin;
+ VecLabOut_fin = NULL;
+ }
+ if (VecRGBOut_fin != NULL)
+ {
+ delete[] VecRGBOut_fin;
+ VecRGBOut_fin = NULL;
+ }
+ if (pos != NULL)
+ {
+ delete[] pos;
+ pos = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &Volume, int &GamutRegion, bool same_regions)
+{
+ size_t nInks = 0;
+
+ C_RGB_XYZ_Lab DataLab;
+ VectorXd InkOut(m_nInks);
+ double *normFactor = new double[m_nInks];
+ if (!same_regions)
+ normFactor = m_colortable->GetNormFactor();
+ else
+ {
+ for (int iInks = 0; iInks < m_nInks; ++iInks)
+ normFactor[iInks] = 1.0;
+ }
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ if (colorspace == COLOR_SPACE__RGB)
+ {
+ //Convert RGB to Volume, no need to calculate RGBOut and LabOut
+ //Data is in Relative Colorimetric color space
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread, but will be shown in Relative Colorimetric to the user
+
+ //convert to Lab
+ double *LabIn = new double[3];
+ double *RGBOutP = new double[3];
+ RGBOutP[0] = inputcoordinates->red;
+ RGBOutP[1] = inputcoordinates->green;
+ RGBOutP[2] = inputcoordinates->blue;
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65
+ LimitLab(LabIn);
+
+ //convert to inks
+ int GamutRegion;
+ double *InkOutP = new double[m_nInks];
+ if (same_regions)
+ {
+ m_colortable->m_B2ARTransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in units of 16 bits
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ ColorTable2Threadunits(InkOut, InkOut);
+ //LimitNLInks2VolumeThr(InkOut, GamutRegion, Volume);
+ }
+ else
+ {
+ m_colortable->m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
+ if (m_CalibMode == 1)
+ {
+ VectorXd NLInkOut(m_nInks);
+ ApplyCTLinearCurves(InkOutP, InkOutP); //Full range Color Table Units
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ ColorTable2Threadunits(InkOut, InkOut); //Full Range Thread Units
+ ConvertToNLInks(InkOut, InkOut);
+ //LimitNLInks2Volume(NLInkOut, GamutRegion, Volume);
+ }
+ else
+ {
+ double *tmpval = m_colortable->GetNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i]; //Full Range
+ ColorTable2Threadunits(DoubleToVector(InkOutP, m_nInks) , InkOut); //Full Range
+ //LimitNLInks2VolumeThr(InkOut, GamutRegion, Volume);
+ }
+ }
+
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ }
+ else if (colorspace == COLOR_SPACE__LAB)
+ {
+ // Basic assumption: Lab data is in relative colorimetric. No Need to convert
+
+ double *LabIn = new double[3];
+ LabIn[0] = inputcoordinates->l; //Relative Colorimetric
+ LabIn[1] = inputcoordinates->a;
+ LabIn[2] = inputcoordinates->b;
+
+ //convert to Inks
+ int GamutRegion;
+ double *InkOutP = new double[m_nInks];
+ if (same_regions)
+ {
+ m_colortable->m_B2ARTransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
+ //for (int i = 0; i < m_nInks; ++i)
+ // InkOutP[i] *= m_colortable->GetNormFactor(); //Full Range Color Table Units
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ ColorTable2Threadunits(InkOut, InkOut); //Full Range Thread Units
+ }
+ else
+ {
+ m_colortable->m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ if (m_CalibMode == 1)
+ {
+ ApplyCTLinearCurves(InkOutP, InkOutP); //full range Color Table Units
+ ColorTable2Threadunits(InkOut, InkOut); //full range Thread Units
+ ConvertToNLInks(InkOut, InkOut);
+ }
+ else
+ {
+ double *tmpval = m_colortable->GetNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i]; //Full Range Color Table units
+ ColorTable2Threadunits(DoubleToVector(InkOutP, m_nInks), InkOut); //full range Thread Units
+ }
+ }
+
+
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ }
+ else
+ {
+ throw std::exception("Unsupported Color Space");
+ return;
+ }
+
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_CurrentProcessRangesMax[i] = m_ProcessRangesMaxP[i];
+ m_CurrentProcessRangesMin[i] = m_ProcessRangesMinP[i];
+ }
+ LimitNLInks2VolumeThr(InkOut, GamutRegion, Volume);
+ return;
+}
+
+
+void Tango::ColorLib::ColorConverter::PrepareGradient(GradientConversionInput* conversionInput, GradientConversionOutput *conversionOutput)
+{
+ //fill input stops...
+ //All calculations are done in Relative Colorimetric Color Space
+ m_nGradStops = conversionInput->n_stops;
+ int numofInks = 0;
+ int numLightInks = 0;
+ CountNumberofInks(conversionInput, numofInks, numLightInks);
+ if (numofInks < 0)
+ throw std::exception("Duplicate inks");
+ m_UseLightInks = false; //Gradients do not use light inks
+ m_TotalNumberofInks = numofInks;
+ m_nInks = numofInks - numLightInks;
+ m_nVolumes = m_TotalNumberofInks;
+ if (m_GradStops == NULL)
+ m_GradStops = new Gradient[m_nGradStops];
+ for (int i = 0; i < m_nGradStops; ++i)
+ m_GradStops[i].SetVolumeSize(m_TotalNumberofInks);
+
+ InputCoordinates **inputcoordinates = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*m_nGradStops);
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ inputcoordinates[i] = (InputCoordinates*)malloc(sizeof(InputCoordinates));
+ input_coordinates__init(inputcoordinates[i]);
+ }
+
+ fillGradientStops(conversionInput);
+ GradInput2InputCoords(conversionInput, inputcoordinates);
+
+ //Global Parameters of gradient
+ SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb);
+ bool has_forwarddata = conversionInput->has_forwarddata;
+ uint8_t *data = conversionInput->forwarddata.data;
+ m_nProcessRanges = conversionInput->n_processranges;
+ m_colortable->InitColorTables(has_forwarddata, data, m_nProcessRanges);
+ SetNumberofInks(m_colortable->GetnA2BnSepIn());
+ double *tmpVal;
+/* if (m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i]; */
+
+ if (m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMaxLim[i] = tmpVal[i];
+
+ //define Low Volume threshold and Light Inks Threshold
+ m_LightInksThr = 5; //Define as part of conversion input!!!!!!!!!!!!!!!!!!!!!!!!!
+ m_LowVolumeThreshold = m_LightInksThr / DilutionFactor;
+ m_LowVolHalf = m_LowVolumeThreshold / 2;
+ //int n_inputliquids = conversionInput->n_inputliquids;
+ InputLiquid **inputliquid = conversionInput->inputliquids;
+ readCalibrationTables(inputliquid, m_nInks);
+ if (m_colortable->GetTableVersion() <= 1)
+ {
+ throw std::exception("Color Table Version does not support gradients\0");
+ }
+
+ //finished reading tables and data
+ //prepare data to construct the gradient
+ //gradient is calculated in RGB space, thinned out or expanded based on dE criteria
+ // returns a vector of volumes and offsets
+ //gradient stops in different gamut region will use regular transformation
+ //if all stops in gamut region 0 the color Table will be suited to this gamut region
+
+ //prepare input
+ //if Color Space = lab, fill rgb and calculate volume + volume region
+ //if color space = rgb, fill lab and calculate volume + volume region
+ //if color space = Volume, fill lab and RGB, calculate volume region
+
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ // Compare Strip White point to Color Table White Point
+ //CompareWhitePoints();
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+
+ if (m_ProcessRangesMaxP == NULL)
+ m_ProcessRangesMaxP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMaxP[i] = conversionInput->processranges[i]->maxinkuptake;
+ }
+ if (m_ProcessRangesMinP == NULL)
+ m_ProcessRangesMinP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMinP[i] = conversionInput->processranges[i]->mininkuptake;
+ }
+ if (m_CurrentProcessRangesMax == NULL)
+ m_CurrentProcessRangesMax = new double[m_nProcessRanges];
+ if (m_CurrentProcessRangesMin == NULL)
+ m_CurrentProcessRangesMin = new double[m_nProcessRanges];
+
+ //SetLowVolThr_nlcm();
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+ VectorXd VolumeOut(m_nInks);
+ //set maxNlPerCM
+ VectorXd NlperCM(m_nInks);
+ NlperCM.setZero();
+ m_maxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ SetMaxNLperCM(conversionInput->inputliquids[i]->maxnanoliterpercentimeter, i);
+ double *tmpLF = new double[m_nInks];
+ tmpLF = m_colortable->GetCTLiquidFactors();
+ m_CTmaxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ m_CTmaxNlPerCM(i) = tmpLF[i];
+ if (tmpLF != NULL)
+ {
+ delete[] tmpLF;
+ tmpLF = NULL;
+ }
+
+ if (m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nInks];
+ if (m_GamutRegionMinLim == NULL)
+ m_GamutRegionMinLim = new double[m_nInks];
+
+ // Set Calibration mode 0 up tp 100%, 1 with High Volume Calib
+ SetCalibMode();
+ //Calculate normalization per ink
+ SetCalibFactorization();
+
+ //m_nVolumes = m_nB2AnSepOut;
+ int GamutRegion = 0;
+/* for (int i = 0; i < m_nGradStops; ++i)
+ {
+ inputcoordinates[i]->n_inputliquids = m_nInks;
+ inputcoordinates[i]->inputliquids = (InputLiquid**)malloc(sizeof(InputLiquid*) *m_nInks);
+ for (int j = 0; j < m_nInks; j++)
+ {
+ inputcoordinates[i]->inputliquids[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(inputcoordinates[i]->inputliquids[j]);
+ }
+ }*/
+ ProcessGradientStops(inputcoordinates);
+
+ //are all stops in the same region?
+ int maxreg = -10;
+ int minreg = 10;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ GamutRegion = m_GradStops[i].Get_GamutRegion();
+ maxreg = std::max(maxreg, GamutRegion);
+ minreg = std::min(minreg, GamutRegion);
+ }
+ //Choose Gamut Region for Gradient calculation
+
+ bool same_regions = true;
+ if ((maxreg != minreg) | (maxreg > 0))
+ same_regions = false;
+ double dEThr = 0.8;
+ //find intermediate points
+ int ninterstops = 300;
+ double **VecRGBOut = new double*[ninterstops];
+ double **VecLabOut = new double*[ninterstops];
+ double *posOut = new double[ninterstops];
+ for (int i = 0; i < ninterstops; ++i)
+ {
+ VecLabOut[i] = new double[3];
+ VecRGBOut[i] = new double[3];
+ }
+ int nOut = 0;
+
+ int nmaxstops = ninterstops * m_nGradStops;
+
+ //Allocate temporary storage for all stops and positions
+ double **AllRGBOut_tmp = new double*[nmaxstops];
+ double **AllLabOut_tmp = new double*[nmaxstops];
+ double *AllPos_tmp = new double[nmaxstops];
+ for (int i = 0; i < nmaxstops; ++i)
+ {
+ AllRGBOut_tmp[i] = new double[3];
+ AllLabOut_tmp[i] = new double[3];
+ }
+ AllRGBOut_tmp[0][0] = m_GradStops[0].Get_RGB().Get_x();
+ AllRGBOut_tmp[0][1] = m_GradStops[0].Get_RGB().Get_y();
+ AllRGBOut_tmp[0][2] = m_GradStops[0].Get_RGB().Get_z();
+ AllLabOut_tmp[0][0] = m_GradStops[0].Get_Lab().Get_x();
+ AllLabOut_tmp[0][1] = m_GradStops[0].Get_Lab().Get_y();
+ AllLabOut_tmp[0][2] = m_GradStops[0].Get_Lab().Get_z();
+ AllPos_tmp[0] = m_GradStops[0].Get_Offset();
+ int ncountStops = 0;
+ int nPosStops = 0;
+ double dOffset = 0;
+ GradOffset OffsetType = EqSpaced;
+
+ for (int iStop = 0; iStop < m_nGradStops - 1; ++iStop)
+ {
+ findStops(m_GradStops[iStop], m_GradStops[iStop + 1], dEThr, ninterstops, nOut, VecRGBOut, VecLabOut, posOut);
+ switch (OffsetType)
+ {
+ case EqSpaced:
+ if (iStop == m_nGradStops - 2)
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset())*GradientEndThr / (nOut - 1);
+ else
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset()) / (nOut - 1);
+ for (int jPos = 1; jPos < nOut; ++jPos)
+ {
+ nPosStops++;
+ AllPos_tmp[nPosStops] = m_GradStops[iStop].Get_Offset() + dOffset * jPos;
+ }
+ break;
+ case dESpaced:
+ if (iStop == m_nGradStops - 2)
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset())*GradientEndThr / posOut[nOut - 1];
+ else
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset()) / posOut[nOut - 1];
+ for (int jPos = 1; jPos < nOut; ++jPos)
+ {
+ nPosStops++;
+ AllPos_tmp[nPosStops] = m_GradStops[iStop].Get_Offset() + dOffset * posOut[jPos];
+ }
+ break;
+ }
+ //store the stops in temporary vector
+ for (int iCount = 1; iCount < nOut; ++iCount)
+ {
+ ncountStops++;
+ for (int jCS = 0; jCS < 3; ++jCS)
+ {
+ VecRGBOut[iCount][jCS] = std::min(std::max(VecRGBOut[iCount][jCS], 0.0), 255.0);
+ AllRGBOut_tmp[ncountStops][jCS] = VecRGBOut[iCount][jCS];
+ AllLabOut_tmp[ncountStops][jCS] = VecLabOut[iCount][jCS];
+ }
+ }
+ }
+ //add last point
+ ncountStops++;
+ VecRGBOut[nOut][0] = std::min(std::max(m_GradStops[m_nGradStops - 1].Get_RGB().Get_x(), 0.0), 255.0);
+ VecRGBOut[nOut][1] = std::min(std::max(m_GradStops[m_nGradStops - 1].Get_RGB().Get_y(), 0.0), 255.0);
+ VecRGBOut[nOut][2] = std::min(std::max(m_GradStops[m_nGradStops - 1].Get_RGB().Get_z(), 0.0), 255.0);
+ VecLabOut[nOut][0] = m_GradStops[m_nGradStops - 1].Get_Lab().Get_x();
+ VecLabOut[nOut][1] = m_GradStops[m_nGradStops - 1].Get_Lab().Get_y();
+ VecLabOut[nOut][2] = m_GradStops[m_nGradStops - 1].Get_Lab().Get_z();
+ AllPos_tmp[ncountStops] = 1.0;
+ for (int jCS = 0; jCS < 3; ++jCS)
+ {
+ AllRGBOut_tmp[ncountStops][jCS] = VecRGBOut[nOut][jCS];
+ AllLabOut_tmp[ncountStops][jCS] = VecLabOut[nOut][jCS];
+ }
+
+ if (VecRGBOut != NULL)
+ {
+ for (int i = 0; i < ninterstops; ++i)
+ delete[]VecRGBOut[i];
+ delete[]VecRGBOut;
+ }
+ if (VecLabOut != NULL)
+ {
+ for (int i = 0; i < ninterstops; ++i)
+ delete[]VecLabOut[i];
+ delete[]VecLabOut;
+ VecLabOut = NULL;
+ }
+ if (posOut != NULL)
+ {
+ delete[]posOut;
+ posOut = NULL;
+ }
+
+ //Store Gradient intermediate data in Input Coordinates type structure.
+ //Simplify calculations, we only need the ink values, input values are in RGB color space
+ // Use table according to Gamut Regions, all stops in region 0, use 100%table otherwise use regular table, decrease dyeing speed.
+
+ int nTotalStops = ncountStops + 1;
+ InputCoordinates **SubStops = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*(nTotalStops));
+
+ //Calculate and store
+ for (int iTStops = 0; iTStops < nTotalStops; ++iTStops)
+ {
+ SubStops[iTStops] = (InputCoordinates*)malloc(sizeof(InputCoordinates));
+ input_coordinates__init(SubStops[iTStops]);
+ SubStops[iTStops]->l = AllLabOut_tmp[iTStops][0];
+ SubStops[iTStops]->a = AllLabOut_tmp[iTStops][1];
+ SubStops[iTStops]->b = AllLabOut_tmp[iTStops][2];
+ SubStops[iTStops]->red = (int)round(AllRGBOut_tmp[iTStops][0]);
+ SubStops[iTStops]->green = (int)round(AllRGBOut_tmp[iTStops][1]);
+ SubStops[iTStops]->blue = (int)round(AllRGBOut_tmp[iTStops][2]);
+ }
+
+ GradientOutputStop** outputStops = (GradientOutputStop**)malloc(sizeof(GradientOutputStop*) * nTotalStops);
+ conversionOutput->stops = outputStops;
+ conversionOutput->n_stops = nTotalStops;
+
+ ColorSpace SubStopsCS = COLOR_SPACE__LAB;
+ //double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0;
+
+ //Low Volume Threshold will be applied at the end of the sequence
+ //This is to avoid smoothing to reduce the ink % below the LowVolume threshold
+ //In order to keep continuity the simple Low Volume threshold will be applied.
+
+ VectorXd VolumeStop(m_nInks);
+ MatrixXd MatVolume(nTotalStops, m_nInks);
+ for (int iS = 0; iS < nTotalStops; ++iS)
+ {
+ GradientOutputStop *stop = (GradientOutputStop*)malloc(sizeof(GradientOutputStop));
+ gradient_output_stop__init(stop);
+ ConvertGradStoptoVolume(SubStops[iS], SubStopsCS,
+ VolumeStop, GamutRegion, same_regions);
+ //start filling Output
+ fillStop(stop, VolumeStop, GamutRegion, AllPos_tmp[iS]);
+ MatVolume.row(iS) = VolumeStop;
+ outputStops[iS] = stop;
+ }
+ //Smooth Volumes
+ VectorXd VIn(nTotalStops);
+ VectorXd VOut(nTotalStops);
+
+ int FilterWidth = 7;
+ for (int iSep = 0; iSep < m_nInks; ++iSep)
+ {
+ for (int jStop = 0; jStop < nTotalStops; ++jStop)
+ VIn(jStop) = MatVolume(jStop, iSep);
+ SmoothCurveData(VIn, VOut, FilterWidth);
+ for (int jS = 0; jS < nTotalStops; ++jS)
+ outputStops[jS]->outputliquids[iSep]->volume = VOut(jS);
+ }
+
+ //Temp Output
+ for (int i = 0; i < nTotalStops; ++i)
+ {
+ for (int j = 0; j < m_nInks; ++j)
+ VolumeStop(j) = outputStops[i]->outputliquids[j]->volume;
+ LimitLowVolumeP(VolumeStop, GamutRegion, VolumeStop);
+ for (int j = 0; j < m_nInks; ++j)
+ outputStops[i]->outputliquids[j]->volume = VolumeStop(j);
+ }
+ for (int i = 0; i < nTotalStops; ++i)
+ {
+ fprintf(stdout, "%d\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%d\t%d\t%d\n", i,
+ outputStops[i]->offset, outputStops[i]->outputliquids[0]->volume,
+ outputStops[i]->outputliquids[1]->volume, outputStops[i]->outputliquids[2]->volume, outputStops[i]->outputliquids[3]->volume,
+ SubStops[i]->l, SubStops[i]->a, SubStops[i]->b, SubStops[i]->red, SubStops[i]->green, SubStops[i]->blue);
+ }
+ //release memory
+ if (AllLabOut_tmp != NULL)
+ {
+ for (int i = 0; i < nmaxstops; ++i)
+ delete[] AllLabOut_tmp[i];
+ delete[] AllLabOut_tmp;
+ AllLabOut_tmp = NULL;
+ }
+ if (AllRGBOut_tmp != NULL)
+ {
+ for (int i = 0; i < nmaxstops; ++i)
+ delete[] AllRGBOut_tmp[i];
+ delete[] AllRGBOut_tmp;
+ AllRGBOut_tmp = NULL;
+ }
+ if (AllPos_tmp != NULL)
+ {
+ delete[] AllPos_tmp;
+ AllPos_tmp = NULL;
+ }
+
+
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ input_coordinates__free_unpacked(inputcoordinates[i], NULL);
+ }
+
+ free(inputcoordinates);
+ inputcoordinates = NULL;
+ for (int i = 0; i < nTotalStops; ++i)
+ {
+
+ input_coordinates__free_unpacked(SubStops[i], NULL);
+ }
+
+ free(SubStops);
+ SubStops = NULL;
+
+}
+
+
+
+
+void Tango::ColorLib::ColorConverter::fillStop(GradientOutputStop *&stop, VectorXd Volume, int GamutRegion, double Position)
+{
+ OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * m_nVolumes);
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid));
+ output_liquid__init(outputLiquids[i]);
+ switch (m_CalibCurves[i].getInkName())
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ {
+ outputLiquids[i]->has_volume = true;
+ outputLiquids[i]->has_liquidtype = true;
+ outputLiquids[i]->liquidtype = (LiquidType)(m_CalibCurves[i].getInkName());
+ outputLiquids[i]->volume = Volume(i);
+ break;
+ }
+ }
+ }
+ if (m_nVolumes > m_nInks)
+ {
+ for (int i = m_nInks+1; i < m_nVolumes; ++i)
+ {
+ outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid));
+ output_liquid__init(outputLiquids[i]);
+ switch (m_CalibCurves[i].getInkName())
+ {
+ case LIQUID_TYPE__LightCyan:
+ case LIQUID_TYPE__LightMagenta:
+ case LIQUID_TYPE__LightYellow:
+ {
+ outputLiquids[i]->has_volume = true;
+ outputLiquids[i]->has_liquidtype = true;
+ outputLiquids[i]->liquidtype = (LiquidType)(m_CalibCurves[i].getInkName());
+ outputLiquids[i]->volume = 0.0;
+ break;
+ }
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ }
+ stop->outputliquids = outputLiquids;
+ stop->n_outputliquids = m_nVolumes;
+ stop->has_processparameterstableindex = true;
+ stop->processparameterstableindex = GamutRegion;
+ stop->has_offset = true;
+ stop->offset = Position;
+}
+
+void Tango::ColorLib::ColorConverter::GradInput2InputCoords(GradientConversionInput *conversionInput, InputCoordinates **inputcoordinates)
+{
+ for (size_t i = 0; i < conversionInput->n_stops; i++)
+ {
+ switch (conversionInput->stops[i]->colorspace)
+ {
+ case COLOR_SPACE__RGB: //Case RGB
+ inputcoordinates[i]->red = conversionInput->stops[i]->red;
+ inputcoordinates[i]->green = conversionInput->stops[i]->green;
+ inputcoordinates[i]->blue = conversionInput->stops[i]->blue;
+ inputcoordinates[i]->has_red = true;
+ inputcoordinates[i]->has_green = true;
+ inputcoordinates[i]->has_blue = true;
+ break;
+ case COLOR_SPACE__LAB: //Case LAB
+ inputcoordinates[i]->l = conversionInput->stops[i]->l;
+ inputcoordinates[i]->a = conversionInput->stops[i]->a;
+ inputcoordinates[i]->b = conversionInput->stops[i]->b;
+ inputcoordinates[i]->has_l = true;
+ inputcoordinates[i]->has_a = true;
+ inputcoordinates[i]->has_b = true;
+ break;
+ case COLOR_SPACE__Catalog:
+ {
+ InputLiquid** InputLiquidsIC = (InputLiquid**)malloc(sizeof(InputLiquid*) *m_TotalNumberofInks);
+ for (int j = 0; j < m_TotalNumberofInks; j++)
+ {
+ InputLiquidsIC[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(InputLiquidsIC[j]);
+ }
+
+ /*LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];*/
+ GradientInputStop *ColorStop = conversionInput->stops[i];
+ InputLiquidsIC[0]->volume = ColorStop->cyan;
+ InputLiquidsIC[0]->liquidtype = LIQUID_TYPE__Cyan;
+
+ InputLiquidsIC[1]->volume = ColorStop->magenta;
+ InputLiquidsIC[1]->liquidtype = LIQUID_TYPE__Magenta;
+
+ InputLiquidsIC[2]->volume = ColorStop->yellow;
+ InputLiquidsIC[2]->liquidtype = LIQUID_TYPE__Yellow;
+
+ InputLiquidsIC[3]->volume = ColorStop->key;
+ InputLiquidsIC[3]->liquidtype = LIQUID_TYPE__Black;
+
+ inputcoordinates[i]->inputliquids = InputLiquidsIC;
+ inputcoordinates[i]->n_inputliquids = m_TotalNumberofInks;
+ break;
+ }
+ case COLOR_SPACE__Volume: //Case Volume
+ {
+ //int size= (int)conversionInput->stops[i]->n_liquidvolumes;
+ InputLiquid** InputLiquidsIC = (InputLiquid**)malloc(sizeof(InputLiquid*) *m_TotalNumberofInks);
+ for (int j = 0; j < m_TotalNumberofInks; j++)
+ {
+ InputLiquidsIC[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(InputLiquidsIC[j]);
+ }
+ for (size_t j = 0; j < (size_t)m_TotalNumberofInks; j++)
+ {
+ LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];
+ switch (liquidVolume->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ // inputcoordinates[i]->inputliquids[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->liquidtype = LIQUID_TYPE__Cyan;
+ break;
+ case LIQUID_TYPE__Magenta:
+ InputLiquidsIC[1]->volume = liquidVolume->volume;
+ InputLiquidsIC[1]->liquidtype = LIQUID_TYPE__Magenta;
+ break;
+ case LIQUID_TYPE__Yellow:
+ InputLiquidsIC[2]->volume = liquidVolume->volume;
+ InputLiquidsIC[2]->liquidtype = LIQUID_TYPE__Yellow;
+ break;
+ case LIQUID_TYPE__Black:
+ InputLiquidsIC[3]->volume = liquidVolume->volume;
+ InputLiquidsIC[3]->liquidtype = LIQUID_TYPE__Black;
+ break;
+ }
+
+ }
+ inputcoordinates[i]->inputliquids = InputLiquidsIC;
+ inputcoordinates[i]->n_inputliquids = m_TotalNumberofInks;
+ break;
+ }
+ }
+ }
+}
+
+void Tango::ColorLib::ColorConverter::RecommendedProcessTableInput2InputCoordinates
+ (RecommendedProcessTableInput *conversionInput, InputCoordinates **inputcoordinates)
+{
+ for (size_t i = 0; i < conversionInput->n_stops; i++)
+ {
+ switch (conversionInput->stops[i]->colorspace)
+ {
+ case COLOR_SPACE__RGB: //Case RGB
+ inputcoordinates[i]->red = conversionInput->stops[i]->red;
+ inputcoordinates[i]->green = conversionInput->stops[i]->green;
+ inputcoordinates[i]->blue = conversionInput->stops[i]->blue;
+ inputcoordinates[i]->has_red = true;
+ inputcoordinates[i]->has_green = true;
+ inputcoordinates[i]->has_blue = true;
+ break;
+ case COLOR_SPACE__LAB: //Case LAB
+ inputcoordinates[i]->l = conversionInput->stops[i]->l;
+ inputcoordinates[i]->a = conversionInput->stops[i]->a;
+ inputcoordinates[i]->b = conversionInput->stops[i]->b;
+ inputcoordinates[i]->has_l = true;
+ inputcoordinates[i]->has_a = true;
+ inputcoordinates[i]->has_b = true;
+ break;
+ case COLOR_SPACE__Catalog:
+ inputcoordinates[i]->cyan = conversionInput->stops[i]->cyan;
+ inputcoordinates[i]->magenta = conversionInput->stops[i]->magenta;
+ inputcoordinates[i]->yellow = conversionInput->stops[i]->yellow;
+ inputcoordinates[i]->key = conversionInput->stops[i]->key;
+ inputcoordinates[i]->has_cyan = conversionInput->stops[i]->has_cyan;
+ inputcoordinates[i]->has_magenta = conversionInput->stops[i]->has_magenta;
+ inputcoordinates[i]->has_yellow = conversionInput->stops[i]->has_yellow;
+ inputcoordinates[i]->has_key = conversionInput->stops[i]->has_key;
+ break;
+ case COLOR_SPACE__Volume: //Case Volume
+ //int size= (int)conversionInput->stops[i]->n_liquidvolumes;
+ InputLiquid** InputLiquidsIC = (InputLiquid**)malloc(sizeof(InputLiquid*) *m_TotalNumberofInks);
+ for (int j = 0; j < m_TotalNumberofInks; j++)
+ {
+ InputLiquidsIC[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(InputLiquidsIC[j]);
+ }
+ for (size_t j = 0; j < (size_t)m_TotalNumberofInks; j++)
+ {
+ LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];
+ switch (liquidVolume->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ // inputcoordinates[i]->inputliquids[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->liquidtype = LIQUID_TYPE__Cyan;
+ break;
+ case LIQUID_TYPE__Magenta:
+ InputLiquidsIC[1]->volume = liquidVolume->volume;
+ InputLiquidsIC[1]->liquidtype = LIQUID_TYPE__Magenta;
+ break;
+ case LIQUID_TYPE__Yellow:
+ InputLiquidsIC[2]->volume = liquidVolume->volume;
+ InputLiquidsIC[2]->liquidtype = LIQUID_TYPE__Yellow;
+ break;
+ case LIQUID_TYPE__Black:
+ InputLiquidsIC[3]->volume = liquidVolume->volume;
+ InputLiquidsIC[3]->liquidtype = LIQUID_TYPE__Black;
+ break;
+ }
+
+ }
+ inputcoordinates[i]->inputliquids = InputLiquidsIC;
+ inputcoordinates[i]->n_inputliquids = m_TotalNumberofInks;
+ }
+ }
+}
+
+void Tango::ColorLib::ColorConverter::LimitInks(VectorXd inInks, double *BoundedInks)
+{
+ //convert Ink % to [nl/cm]
+ //Bound Ink
+ for (int i = 0; i < m_nInks; ++i)
+ BoundedInks[i] = std::min(inInks(i)*m_currentMaxNLPerCM(i) / 100.0, m_CurrentProcessRangesMax[m_nProcessRanges - 1]);
+}
+
+void Tango::ColorLib::ColorConverter::NLcmtoPercentage(VectorXd InVolume, VectorXd &OutVolume)
+{
+ int nInks = InVolume.size();
+ for (int i = 0; i < m_nInks; ++i)
+ OutVolume(i) = 100 * InVolume(i) / m_currentMaxNLPerCM(i);
+ if (nInks > m_nInks)
+ for (int igt = m_nInks; igt < m_TotalNumberofInks; ++igt)
+ OutVolume(igt) = 100 * InVolume(igt) / m_currentMaxNLPerCM(igt - m_nInks);
+}
+
+void Tango::ColorLib::ColorConverter::PercentagetoNLcm(VectorXd InVolume, VectorXd &OutVolume)
+{
+ int nInks = InVolume.size();
+ for (int i = 0; i < m_nInks; ++i)
+ OutVolume(i) = m_currentMaxNLPerCM(i) * InVolume(i) / 100;
+ if (nInks > m_nInks)
+ for (int igt = m_nInks; igt < m_TotalNumberofInks; ++igt)
+ OutVolume(igt) = m_currentMaxNLPerCM(igt - m_nInks) * InVolume(igt) / 100;
+}
+
+void Tango::ColorLib::ColorConverter::LimitLowVolumeP(VectorXd InVolume, int &GamutRegion, VectorXd &OutVolume)
+{
+ //convert Volume to nl2cm
+ for (int i = 0; i < m_nInks; ++i)
+ InVolume(i) *= (m_maxNlPerCM(i)/100.0);
+ LimitLowVolume(InVolume, GamutRegion, OutVolume);
+ NLcmtoPercentage(OutVolume, OutVolume);
+}
+
+void Tango::ColorLib::ColorConverter::LimitLowVolume(VectorXd InVolume, int &GamutRegion, VectorXd &OutVolume)
+{
+ int indGR = 0;
+ for (int i = 1; i < m_nProcessRanges; ++i)
+ {
+ if (GamutRegion == i)
+ indGR = i;
+ }
+ //InVolume is in [nl/cm]
+ double TotalVolume = 0.0;
+ for (int i = 0; i < m_nInks; ++i)
+ TotalVolume += InVolume(i);
+
+ double low = 0.0;
+ double high = 0.0;
+
+ if (TotalVolume <= m_ProcessRangesMinP[0])
+ {
+ //Calculate minVolumeThreshold based on m_ProcessRangesMinP[0]
+ high = m_LowVolumeThreshold * m_ProcessRangesMinP[0]/100.0;
+ }
+ else if (TotalVolume <= m_ProcessRangesMaxP[0])
+ {
+ //Calculate minVolumeThreshold based on Total Volume
+ high = m_LowVolumeThreshold * TotalVolume/100.0;
+ }
+ else if (TotalVolume <= m_ProcessRangesMinP[1])
+ {
+ //Calculate minVolumeThreshold based on m_ProcessRangesMinP[1]
+ high = m_LightInksThr * m_ProcessRangesMinP[1]/100.0;
+ }
+ else
+ {
+ high = m_LightInksThr * TotalVolume/100.0;
+ }
+ //Limit Volume based on Total Ink Volume
+ double sumVol = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (InVolume(i) >= high)
+ OutVolume(i) = InVolume(i);
+ else if (InVolume(i) < (high / 2.0))
+ OutVolume(i) = 0.0;
+ else
+ OutVolume(i) = high;
+ sumVol += OutVolume(i);
+ }
+ //recalculate GamutRegion
+ if (sumVol <= m_ProcessRangesMaxP[0])
+ GamutRegion = 0;
+ else
+ {
+ for (int i = 1; i < indGR + 1; ++i)
+ {
+ if ((sumVol > m_ProcessRangesMaxP[i - 1]) & (sumVol <= m_ProcessRangesMaxP[i]))
+ GamutRegion = i;
+ }
+ }
+}
+
+
+int Tango::ColorLib::ColorConverter::GetGamutRegion(VectorXd Volume, double *GamutLimits)
+{ // assumes Volume is in [nl/cm]
+ double TotalVolume = 0.0;
+ double Volnlcm = 0.0;
+ int GamutRegion = 0;
+ int nGR = m_colortable->GetnGamutRegions();
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ //Volnlcm = m_maxNlPerCM(i)*Volume(i)/100.0;
+ //TotalVolume += Volnlcm;
+ TotalVolume += Volume(i);
+ }
+ for (int i = 0; i < nGR - 1; ++i)
+ {
+ if (TotalVolume > GamutLimits[i])
+ GamutRegion++;
+ }
+ return(GamutRegion);
+}
+
+void Tango::ColorLib::ColorConverter::SmoothCurveData(VectorXd VIn, VectorXd &VOut, int FilterWidth)
+{
+ int Vlength = VIn.size();
+ VectorXd tmpV(Vlength);
+ int NumIter = (int)(std::max(FilterWidth, 3) - 2);
+ //Smooth the data with repeated applications of a[1 1 1] filter
+ for (int i = 0; i < NumIter; ++i)
+ {
+ for (int j = 0; j < Vlength; ++j)
+ tmpV(j) = VIn(j);
+ for (int k = 1; k < Vlength - 1; ++k)
+ VIn(k) = (tmpV(k - 1) + tmpV(k) + tmpV(k + 1)) / 3;
+ }
+ for (int j = 0; j < Vlength; ++j)
+ VOut(j) = VIn(j);
+}
+
+void Tango::ColorLib::ColorConverter::ProcessGradientStops(InputCoordinates **inputcoordinates)
+{
+ VectorXd Volume(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd InkOut(m_nInks);
+ VectorXd NLInkOut(m_nInks);
+ double * InkOutL = new double[m_nInks];
+ double * LabOutV = new double[3];
+ double * LabOutFinal = new double[3];
+
+ ColorConvert CConvertD65(D65, D65);
+
+ bool InGamut = true;
+ int GamutRegion = 0;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ if (m_GradStops[i].Get_ColorSpace() == COLOR_SPACE__Volume || m_GradStops[i].Get_ColorSpace() == COLOR_SPACE__Catalog)
+ { //Convert volume to Lab
+ //Convert lab to rgb
+ ConvertVolumeToRGBDisplay(inputcoordinates[i], m_nProcessRanges, m_GradStops[i].Get_ColorSpace(), Volume,
+ RGBOut, LabOut, GamutRegion);
+ VectorToDouble(LabOut, LabOutV);
+ CConvertD65.ChangeWP(LabOutV, LabOutV, m_WP, m_whitepointXYZ_Strip); //to Relative Colorimetric Space
+ C_RGB_XYZ_Lab Lab(LabOutV[0], LabOutV[1], LabOutV[2]);
+ C_RGB_XYZ_Lab RGB(RGBOut); // RGB was derived from relative colorimetric Lab Value
+
+ //store data
+ m_GradStops[i].Set_Lab(Lab);
+ m_GradStops[i].Set_RGB(RGB);
+ m_GradStops[i].Set_GamutRegion(GamutRegion);
+ bool retValue = CheckLabInRGBGamut(Lab);
+ m_GradStops[i].SetInRGBLimits(retValue);
+ m_GradStops[i].SetInGamut(true);
+ }
+ else
+ {
+ ConvertColorToLinearInks(inputcoordinates[i], m_GradStops[i].Get_ColorSpace(), InkOut, RGBOut, LabOut, GamutRegion, InGamut);
+ //Inks are in Linear Space , convert to nonlinear by using Calibration Tables,
+ VectorToDouble(LabOut, LabOutV);
+ CConvertD65.ChangeWP(LabOutV, LabOutV, m_WP, m_whitepointXYZ_Strip); //to Relative Colorimetric Space
+ C_RGB_XYZ_Lab Lab(LabOutV[0], LabOutV[1], LabOutV[2]);
+ C_RGB_XYZ_Lab RGB(RGBOut);
+ //convert data to the thread range in %
+ ColorTable2Threadunits(InkOut, InkOut);
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] = m_ProcessRangesMaxP[i];
+ m_CurrentProcessRangesMin[iP] = m_ProcessRangesMinP[i];
+ }
+
+ if (m_CalibMode == 1)
+ {
+ ConvertToNLInks(InkOut, NLInkOut);
+ LimitNLInks2Volume(NLInkOut, GamutRegion, Volume);
+ }
+ else
+ LimitNLInks2Volume(InkOut, GamutRegion, Volume);
+
+ //fill data
+ //fill volume
+ //allocate m_GradStops[i].Volume
+ for (int j = 0; j < m_nInks; ++j)
+ m_GradStops[i].SetVolumeValue(Volume(j), j);
+ m_GradStops[i].Set_GamutRegion(GamutRegion);
+ m_GradStops[i].SetInGamut(InGamut);
+ //LabOut and RGBOut might be different if the input was out of gamut
+ m_GradStops[i].Set_Lab(Lab);
+ m_GradStops[i].Set_RGB(RGB);
+ LabOutFinal[0] = Lab.Get_x();
+ LabOutFinal[1] = Lab.Get_y();
+ LabOutFinal[2] = Lab.Get_z();
+ bool retValue = CheckLabInRGBGamut(DoubleToVector(LabOutFinal, 3));
+ m_GradStops[i].SetInRGBLimits(retValue);
+ }
+ }
+ //free vectors
+ if (LabOutV != NULL)
+ {
+ delete[] LabOutV;
+ LabOutV = NULL;
+ }
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+ if (InkOutL != NULL)
+ {
+ delete[] InkOutL;
+ InkOutL = NULL;
+ }
+}
+
+bool Tango::ColorLib::ColorConverter::CheckLabInRGBGamut(VectorXd Lab)
+{
+ bool retVal = false;
+ C_RGB_XYZ_Lab DataLab;
+ DataLab.Set(Lab);
+ retVal = CheckLabInRGBGamut(DataLab);
+ return(retVal);
+}
+
+bool Tango::ColorLib::ColorConverter::CheckLabInRGBGamut(C_RGB_XYZ_Lab Lab)
+{
+ bool retVal = false;
+ //ColorConvert ColConv(D65, D65);
+ C_RGB_XYZ_Lab DataRGB1;
+ C_RGB_XYZ_Lab DataLab1;
+ //DataRGB1 limited to [0,255]
+ DataRGB1 = m_Conv02->LabtoRGB(Lab);
+ DataLab1 = m_Conv02->RGBtoLab(DataRGB1);
+ double dE = 0;
+ m_Conv02->dE76(DataLab1, Lab, dE);
+ if (dE < 0.01)
+ retVal = true;
+ return(retVal);
+}
+
+//void Tango::ColorLib::ColorConverter::SetLowVolThr_nlcm()
+//{
+// if (m_LowVolThr_nlcm == NULL)
+// m_LowVolThr_nlcm = new double[m_nProcessRanges];
+// if (m_LowVolThrHalf_nlcm == NULL)
+// m_LowVolThrHalf_nlcm = new double[m_nProcessRanges];
+// //fill thresholds
+// for (int i = 0; i < m_nProcessRanges; ++i)
+// {
+// m_LowVolThr_nlcm[i] = m_LowVolumeThreshold * m_ProcessRangesMaxP[i]/100;
+// m_LowVolThrHalf_nlcm[i] = m_LowVolHalf * m_ProcessRangesMaxP[i]/100;
+// }
+//}
+
+void Tango::ColorLib::ColorConverter::LimitNLInks2Volume(VectorXd NLInks, int &GamutRegion, VectorXd &Volume)
+{
+ //VectorXd NLInkOut(m_nInks);
+ double *InkOutL = new double[m_nInks];
+// NLInks are in the full thread range
+ LimitInks(NLInks, InkOutL); // NLInks is in %, InkOutL in [nl/cm]
+ NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume); // InkOutL in [nl/cm] Volume in [nl/cm]
+ GamutRegion = GetGamutRegion(Volume, m_CurrentProcessRangesMax); //Volume in [nl/cm]
+ GetClosestInk(Volume, GamutRegion, Volume); //Input Volume is in [nl/cm] Output Volume is in [%]
+ //NLcmtoPercentage(Volume, Volume);
+ ConfineVolumes(Volume); // Input Volume is in[%] Output Volume is in[%]
+ if (InkOutL != NULL)
+ {
+ delete[]InkOutL;
+ InkOutL = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::LimitNLInks2VolumeNoFix(VectorXd NLInks, int &GamutRegion, VectorXd &Volume)
+{
+ //VectorXd NLInkOut(m_nInks);
+ double *InkOutL = new double[m_nInks];
+ // NLInks are in the full thread range
+ LimitInks(NLInks, InkOutL); // NLInks is in %, InkOutL in [nl/cm]
+ NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume); // InkOutL in [nl/cm] Volume in [nl/cm]
+ GamutRegion = GetGamutRegion(Volume, m_CurrentProcessRangesMax); //Volume in [nl/cm]
+ NLcmtoPercentage(Volume, Volume); //Volume is in %
+ if (InkOutL != NULL)
+ {
+ delete[]InkOutL;
+ InkOutL = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ConfineVolumes(VectorXd &Volume)
+{
+ double TotalVolume = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ TotalVolume += Volume(i)*m_currentMaxNLPerCM(i) / 100.0;
+ int nGR = m_colortable->GetnGamutRegions();
+ double diff = (TotalVolume - m_CurrentProcessRangesMax[nGR - 1]);
+
+ if (diff > 1.e-03)
+ {
+ //find values above Min Volume threshold
+ int *indInks = new int[m_nInks];
+ int ind = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ indInks[i] = -1;
+ if (Volume(i) > m_LowVolumeThreshold)
+ {
+ ind++;
+ indInks[i] = i;
+ }
+ }
+ double exceed_Vol_per_ink = (diff / ind);
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (indInks[i] >= 0)
+ Volume(indInks[i]) = Volume(indInks[i]) - 100 * (exceed_Vol_per_ink) /m_currentMaxNLPerCM(indInks[i]);
+ }
+ if (indInks != NULL)
+ {
+ delete[] indInks;
+ indInks = NULL;
+ }
+ }
+}
+
+void Tango::ColorLib::ColorConverter::LimitNLInks2VolumeThr(VectorXd NLInks, int &GamutRegion, VectorXd &Volume)
+{
+ // VectorXd NLInkOut(m_nInks);
+ double *InkOutL = new double[m_nInks];
+ LimitInks(NLInks, InkOutL); // InkOutL in [nl/cm]
+ NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume); // [nl/cm]
+ GamutRegion = GetGamutRegion(Volume, m_CurrentProcessRangesMax);
+ LimitLowVolume(Volume, GamutRegion, Volume); // [nl/cm]
+ NLcmtoPercentage(Volume, Volume); // output volume in %
+
+ if (InkOutL != NULL)
+ {
+ delete[]InkOutL;
+ InkOutL = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::GetClosestInk(VectorXd Volume, int &GamutRegion, VectorXd &BestVolume)
+{
+ VectorXd LabOut(3);
+ NumConversions D2B;
+ double *diffVolume = new double[m_nInks];
+ int *LVThrIndex = new int[m_nInks];
+ int indCount = -1;
+ double low = 0.0;
+ double high = 0.0;
+ double TotalVolume = 0.0;
+ for (int i = 0; i < m_nInks; ++i)
+ TotalVolume += Volume(i);
+ DefineSplitLimits(low, high, TotalVolume);
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (Volume(i) > 1.e-05)
+ diffVolume[i] = std::abs(Volume(i) - std::max(Volume(i), low));
+ else
+ diffVolume[i] = 0;
+ if (diffVolume[i] > 1.0E-04)
+ {
+ indCount++;
+ LVThrIndex[indCount] = i;
+ }
+ }
+
+ if (diffVolume != NULL)
+ {
+ delete[]diffVolume;
+ diffVolume = NULL;
+ }
+
+ NLcmtoPercentage(Volume, Volume);
+ indCount++;
+ if (indCount > 0)
+ {
+ double LabTarget[3];
+
+ ConvertVolumeToLabRel(Volume, LabOut, GamutRegion);
+ VectorToDouble(LabOut, LabTarget);
+ int pwr2LVThr = (int)pow(2, indCount);
+ double **VolumeComb = new double*[pwr2LVThr];
+ for (int i = 0; i < pwr2LVThr; ++i)
+ {
+ VolumeComb[i] = new double[m_nInks];
+ for (int j = 0; j < m_nInks; ++j)
+ VolumeComb[i][j] = Volume(j);
+ }
+ int **binPerm = new int*[pwr2LVThr];
+ for (int i = 0; i < pwr2LVThr; ++i)
+ {
+ binPerm[i] = new int[indCount];
+ for (int k = 0; k < indCount; ++k)
+ binPerm[i][k] = -1;
+ D2B.DecToBinary(i, binPerm[i], indCount);
+ }
+ double *dE = new double[pwr2LVThr];
+ double mindE = 10000.0;
+ int indMindE = -1;
+ for (int i = 0; i < pwr2LVThr; ++i)
+ {
+ for (int j=0; j<indCount ; ++j)
+ VolumeComb[i][LVThrIndex[j]] = (double)(binPerm[i][j])*low/(m_currentMaxNLPerCM[LVThrIndex[j]]/100);
+ }
+ //find the volume with smallest dE from Target.
+ //Convert Volume to Lab and calculate dE from Volume
+ double sumVolComb = 0;
+ for (int isum = 0; isum < m_nInks; ++isum)
+ sumVolComb += VolumeComb[0][isum];
+ int istart = 0;
+ if (sumVolComb < 1.0e-04)
+ istart = 1;
+
+ for (int i = istart; i < pwr2LVThr; ++i)
+ {
+ ConvertVolumeToLabRel(DoubleToVector(VolumeComb[i], m_nInks), LabOut, GamutRegion );
+ m_Conv02->SymmetricaldECMC(LabOut, DoubleToVector(LabTarget, 3), dE[i]);
+ if (dE[i] < mindE)
+ {
+ mindE = dE[i];
+ indMindE = i;
+ BestVolume = DoubleToVector(VolumeComb[i], m_nInks);
+ }
+ }
+
+ if (binPerm != NULL)
+ {
+ for (int i = 0; i < pwr2LVThr; ++i)
+ delete[]binPerm[i];
+ delete[]binPerm;
+ binPerm = NULL;
+ }
+ if (VolumeComb != NULL)
+ {
+ for (int i = 0; i < pwr2LVThr; ++i)
+ delete[]VolumeComb[i];
+ delete[]VolumeComb;
+ VolumeComb = NULL;
+ }
+ if (dE != NULL)
+ {
+ delete[]dE;
+ dE = NULL;
+ }
+ }
+ else
+ BestVolume = Volume;
+ if (LVThrIndex != NULL)
+ {
+ delete[] LVThrIndex;
+ LVThrIndex = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ConvertVolumeToLabRel(VectorXd &Volume, VectorXd &LabOut, int GamutRegion)
+{
+ VectorXd NLInkP(m_nInks);
+ VectorXd LInkP(m_nInks);
+ VectorXd InkOut((int)(m_nInks));
+
+ //Convert to Nonlinear Inks
+ double SumVol_Ink = 0.0;
+ //Volume is in [nl/cm]
+ VolumeToNLInkP(Volume, NLInkP);
+ double *InkOutP = new double[m_nInks];
+
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+
+ LimitInks(NLInkP, InkOutP); //InkOutP is in [nl/cm]
+ NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Volume); //Volume is in [nl/cm]
+ GamutRegion = GetGamutRegion(Volume, m_CurrentProcessRangesMax);
+ NLcmtoPercentage(Volume, Volume); //Volume is back to percentage
+ VolumeToNLInkP(Volume, NLInkP);
+ //Normalize NLInk to the Color Table Range
+ Thread2ColorTableunits(NLInkP, NLInkP);
+
+ // Convert to Linear
+
+ double *LabOutP = new double[3];
+
+ double *tmpval = m_colortable->GetInverseNormFactor();
+
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ ConvertToLinearInks(NLInkP, LInkP);
+ VectorToDouble(LInkP, InkOutP);
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i];
+ for (int i = 0; i < m_nInks; ++i) // Forward Model in [0-1] interval
+ InkOutP[i] /= 100.0;
+ m_forwardmodel->CalcFM(InkOutP, LabOutP);
+ }
+ else
+ {
+ VectorToDouble(NLInkP, InkOutP);
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= tmpval[i];
+ m_colortable->m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion);
+ }
+ //LabOutP is in Relative Colorimetric
+ ColorConvert CConvertD65(D65, D65);
+// double *LabOutFinal1 = new double[3];
+ double *LabOutFinal = new double[3];
+
+ CConvertD65.ChangeWP(LabOutP, LabOutFinal, m_whitepointXYZ_Strip, m_WP); //To Absolute
+/* for (int i = 0; i < 3; ++i)
+ LabOutFinal[i] = LabOutFinal1[i];*/
+
+ LabOut = DoubleToVector(LabOutFinal, 3);
+
+ if (InkOutP != NULL)
+ {
+ delete[]InkOutP;
+ InkOutP = NULL;
+ }
+
+ if (LabOutP != NULL)
+ {
+ delete[] LabOutP;
+ LabOutP = NULL;
+ }
+
+/* if (LabOutFinal1 != NULL)
+ {
+ delete[] LabOutFinal1;
+ LabOutFinal1 = NULL;
+ } */
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+ return;
+
+}
+
+void Tango::ColorLib::ColorConverter::SplitVolume(VectorXd Volume, VectorXd &VolumeLI, int &GamutRegion)
+{
+ //mark split candidates
+ int ind = 0;
+ VectorXd Vol_nlcm(m_nInks);
+ double InitTotalVolume = 0;
+ double low = 0;
+ double high = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ Vol_nlcm(i) = Volume(i)*m_currentMaxNLPerCM(i) / 100;
+ VolumeLI(i) = Vol_nlcm(i);
+ InitTotalVolume += Vol_nlcm(i);
+ }
+ int indGR = 0;
+ //Find Gamut Region
+ for (int i = 1; i < m_nProcessRanges; ++i)
+ {
+ if (GamutRegion == i)
+ indGR = i;
+ }
+ //Set Limits
+ DefineSplitLimits(low, high, InitTotalVolume);
+ //Verify there are no inks below the split limits
+ //This might happen because of a previous rounding step that changes the low limit by a small amount
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if ((Vol_nlcm(i) < low) & (Vol_nlcm(i) > 0))
+ Vol_nlcm(i) = low;
+ }
+ //Apply 1st Split
+ for (int i = 0; i < m_nInks - 1; ++i)
+ {
+ if ((Vol_nlcm(i) >= low) & (Vol_nlcm(i) <= high))
+ {
+ VolumeLI(i + m_nInks) = DilutionFactor * Vol_nlcm(i);
+ VolumeLI(i) = 0.0;
+ }
+ else
+ {
+ VolumeLI(i) = Vol_nlcm(i);
+ VolumeLI(i + m_nInks) = 0;
+ }
+ }
+ double UpperLimit = m_CurrentProcessRangesMax[m_nProcessRanges - 1];
+ double TotalVolume = 0.0;
+
+ bool resplit = true;
+ VectorXd PrevVolume(m_TotalNumberofInks);
+ VectorXd VolumeNoLI(m_nInks);
+ for (int i = 0; i < m_nInks; ++i)
+ PrevVolume(i) = Vol_nlcm(i);
+ for (int i = m_nInks; i < m_TotalNumberofInks; ++i)
+ PrevVolume(i) = 0.0;
+ int PrevGamutRegion = GamutRegion;
+ double PrevHigh = high;
+ double PrevLow = low;
+ while (resplit == true)
+ {
+ for (int i = 0; i < m_TotalNumberofInks; ++i)
+ TotalVolume += VolumeLI(i);
+ if (TotalVolume > UpperLimit)
+ {
+ VolumeLI = PrevVolume;
+ GamutRegion = PrevGamutRegion;
+ resplit = false;
+ }
+ else if (TotalVolume > InitTotalVolume)
+ {
+ DefineSplitLimits(low, high, TotalVolume);
+ //recalculate Gamut Region
+ indGR = 0;
+ findGamutRegion(GamutRegion, TotalVolume);
+ if (((low - PrevLow) > 0) & ((high - PrevHigh) > 0))
+ {
+ //set Previous Volume
+ for (int i = 0; i < m_TotalNumberofInks; ++i)
+ PrevVolume(i) = VolumeLI(i);
+ PrevGamutRegion = GamutRegion;
+ PrevLow = low;
+ PrevHigh = high;
+ InitTotalVolume = TotalVolume;
+ //go back to no light inks volumes
+ for (int i = 0; i < m_nInks - 1; ++i)
+ {
+ if ((VolumeLI(i) == 0) & (VolumeLI(i + m_nInks) > 0))
+ {
+ VolumeNoLI(i) = VolumeLI(i + m_nInks) / DilutionFactor;
+ }
+ else
+ {
+ VolumeNoLI(i) = VolumeLI(i);
+ }
+ }
+ VolumeNoLI(m_nInks - 1) = VolumeLI(m_nInks - 1);
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if ((VolumeNoLI(i) < low) & (VolumeNoLI(i) > 0))
+ VolumeNoLI(i) = low;
+ }
+ for (int i = 0; i < m_nInks - 1; ++i)
+ {
+ if ((VolumeNoLI(i) >= low) & (VolumeNoLI(i) <= high))
+ {
+ VolumeLI(i + m_nInks) = DilutionFactor * VolumeNoLI(i);
+ VolumeLI(i) = 0.0;
+ }
+ else
+ {
+ VolumeLI(i + m_nInks) = 0;
+ }
+ }
+ VolumeLI(m_nInks - 1) = VolumeNoLI(m_nInks - 1);
+ //recalculate Gamut Region
+ for (int i = 0; i < m_TotalNumberofInks; ++i)
+ TotalVolume += VolumeLI(i);
+ resplit = true;
+ }
+ else
+ resplit = false;
+ }
+ else
+ resplit = false;
+ }
+ NLcmtoPercentage(VolumeLI, VolumeLI);
+}
+
+void Tango::ColorLib::ColorConverter::DefineSplitLimits(double &low, double &high, double InitTotalVolume)
+{
+ //Set Limits
+ //1st Region
+ double lim1 = 0;
+ double lim2 = m_CurrentProcessRangesMax[0];
+ double lim3 = m_CurrentProcessRangesMin[0];
+ int ProcessRangeInd = 0;
+ //Regions 1 to n-1
+ for (int iReg = 0; iReg < m_nProcessRanges - 1; ++iReg)
+ {
+ ProcessRangeInd = iReg;
+ if ((InitTotalVolume >= lim1) & (InitTotalVolume <= lim2))
+ {
+ //Calculate Ink Split Based on m_ProcessRangesMinP[iReg]
+ low = m_LowVolumeThreshold * m_CurrentProcessRangesMin[iReg] / 100.0;
+ high = m_LightInksThr * m_CurrentProcessRangesMin[iReg] / 100.0;
+ }
+ else if ((InitTotalVolume <= lim3) & (InitTotalVolume > lim2))
+ {
+ //Calculate Ink Split Based on Total Volume
+ low = m_LowVolumeThreshold * InitTotalVolume / 100.0;
+ high = m_LightInksThr * InitTotalVolume / 100.0;
+ }
+ lim1 = m_CurrentProcessRangesMax[iReg];
+ lim2 = m_CurrentProcessRangesMin[iReg + 1];
+ lim3 = m_CurrentProcessRangesMax[iReg + 1];
+ }
+ //Last Region
+ if ((InitTotalVolume >= lim1) & (InitTotalVolume <= lim2))
+ {
+ //Calculate Ink Split Based on m_ProcessRangesMinP[iReg]
+ low = m_LowVolumeThreshold * m_CurrentProcessRangesMin[ProcessRangeInd] / 100.0;
+ high = m_LightInksThr * m_CurrentProcessRangesMin[ProcessRangeInd] / 100.0;
+ }
+ else if ((InitTotalVolume <= lim3) & (InitTotalVolume > lim2))
+ {
+ //Calculate Ink Split Based on Total Volume
+ low = m_LowVolumeThreshold * InitTotalVolume / 100.0;
+ high = m_LightInksThr * InitTotalVolume / 100.0;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::findGamutRegion(int &GamutRegion, double TotalVolume)
+{
+ if (TotalVolume <=m_CurrentProcessRangesMax[0])
+ GamutRegion = 0;
+ else
+ {
+ for (int i = 1; i < m_nProcessRanges; ++i)
+ {
+ if ((TotalVolume > m_CurrentProcessRangesMax[i - 1]) & (TotalVolume <= m_CurrentProcessRangesMax[i]))
+ GamutRegion = i;
+ }
+ }
+}
+
+size_t Tango::ColorLib::ColorConverter::GetRecommendedProcessParameters(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ RecommendedProcessTableInput* Input = recommended_process_table_input__unpack(NULL, input_buffer_size, input_buffer);
+
+ try
+ {
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+ int numofInks = 0;
+ int numLightInks = 0;
+ CountNumberofInks(Input, numofInks, numLightInks);
+ if (numofInks < 0)
+ throw std::exception("Duplicate inks");
+ m_UseLightInks = Input->uselightinks;
+ if ((numLightInks <= 0) & (m_UseLightInks == true))
+ throw std::exception("Light Inks not defined");
+
+ int expected_liquids = numofInks;
+ m_TotalNumberofInks = numofInks;
+ int original_input_liquids_count = Input->n_inputliquids;
+ InputLiquid** original_input_liquids = Input->inputliquids;
+ if(m_InkNames == NULL)
+ m_InkNames = new LiquidType[m_TotalNumberofInks];
+ InputLiquid** filteredInputLiquids = new InputLiquid*[m_TotalNumberofInks];
+
+ for (size_t i = 0; i < Input->n_inputliquids; i++)
+ {
+ InputLiquid* liquid = Input->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ m_InkNames[0] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ m_InkNames[1] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ m_InkNames[2] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Black:
+ filteredInputLiquids[3] = liquid;
+ m_InkNames[3] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightCyan:
+ filteredInputLiquids[4] = liquid;
+ m_InkNames[4] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightMagenta:
+ filteredInputLiquids[5] = liquid;
+ m_InkNames[5] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightYellow:
+ filteredInputLiquids[6] = liquid;
+ m_InkNames[6] = liquid->liquidtype;
+ break;
+ }
+ }
+
+ Input->inputliquids = filteredInputLiquids;
+ if (expected_liquids <= 0)
+ throw std::exception("expected_liquids is zero");
+ else
+ Input->n_inputliquids = expected_liquids;
+
+ //Filter and arrange colors
+
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+
+
+ if (m_colortable == NULL)
+ m_colortable = new ColorTable();
+ readColorTransformations(Input);
+ if (Input->n_processranges <= 0)
+ throw std::exception("number of process ranges is zero");
+ else
+ m_nProcessRanges = Input->n_processranges;
+
+ double *tmpVal;
+ /* if (m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i]; */
+
+ if (m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMaxLim[i] = tmpVal[i];
+
+ if (m_GamutRegionMinLim == NULL)
+ m_GamutRegionMinLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetGamutRegionMinLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMinLim[i] = tmpVal[i];
+
+ //read calibration tables and store them in m_CalibCurves
+ InputLiquid **inputliquids = Input->inputliquids;
+ // int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids;
+ int n_inputliquids = numofInks - numLightInks;
+ readCalibrationTables(inputliquids, n_inputliquids);
+
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ C_RGB_XYZ_Lab whitepoint_CT = m_colortable->GetWhitePoint_CT();
+ m_forwardmodel = m_colortable->GetForwardModel();
+ ColorConvert CConvertD65(D65, D65);
+ C_RGB_XYZ_Lab relWP_CT;
+ CConvertD65.ChangeWP(whitepoint_CT, relWP_CT, m_WP, m_whitepointXYZ_Strip);
+ m_forwardmodel->SetFreeTerm(relWP_CT);
+ m_ObjFunction = new ObjectiveFunction(m_forwardmodel);
+ PrepareObjectiveFunctionPars();
+ m_Minimize = new LevMar(m_ObjFunction);
+ m_Minimize->Init();
+ m_Minimize->SetMaxIterations(50);
+ m_Minimize->SetTolerance(0.01);
+ }
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ if (n_inputliquids != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables\0");
+
+ //Set Process Ranges
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ if (Input->processranges[i]->maxinkuptake <= 0)
+ throw std::exception("Process Range is zero\0");
+ }
+ double diff = 0;
+ for (int i = 1; i < m_nProcessRanges; ++i)
+ {
+ diff = Input->processranges[i]->maxinkuptake - Input->processranges[i - 1]->maxinkuptake;
+ if (diff < 0)
+ throw std::exception("Process Ranges are not monotonic\0");
+ }
+ if (m_ProcessRangesMaxP == NULL)
+ m_ProcessRangesMaxP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMaxP[i] = Input->processranges[i]->maxinkuptake;
+ }
+ if (m_ProcessRangesMinP == NULL)
+ m_ProcessRangesMinP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMinP[i] = Input->processranges[i]->mininkuptake;
+ }
+
+ //SetLowVolThr_nlcm();
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+ VectorXd Volume_nlcm(m_nInks);
+ VectorXd VolumeLi(m_TotalNumberofInks);
+ VectorXd VolumeOut(m_nInks);
+ //set maxNlPerCM
+ VectorXd NlperCM(m_nInks);
+ NlperCM.setZero();
+ m_maxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ SetMaxNLperCM(Input->inputliquids[i]->maxnanoliterpercentimeter, i);
+
+ m_CTmaxNlPerCM = NlperCM;
+ double *tmpLF = new double[m_nInks];
+ tmpLF = m_colortable->GetCTLiquidFactors();
+ for (int i = 0; i < m_nInks; ++i)
+ m_CTmaxNlPerCM(i) = tmpLF[i];
+ if (tmpLF != NULL)
+ {
+ delete[] tmpLF;
+ tmpLF = NULL;
+ }
+
+ // Set Calibration mode 0 up tp 100%, 1 with High Volume Calib
+ SetCalibMode();
+ //Calculate normalization per ink
+ SetCalibFactorization();
+
+ m_nVolumes = m_nInks;
+
+ int nstops = Input->n_stops;
+ int *GamutRegion = new int[nstops];
+ InputCoordinates **inputcoordinates = new InputCoordinates*[nstops];
+ for (int i = 0; i < nstops; ++i)
+ {
+ inputcoordinates[i] = (InputCoordinates*)malloc(sizeof(InputCoordinates));
+ input_coordinates__init(inputcoordinates[i]);
+ }
+
+ RecommendedProcessTableInput2InputCoordinates(Input, inputcoordinates);
+
+ //Convert input data to linear inks
+ ColorSpace colorspace;
+
+ int32_t processparameterstableindex = 0;
+ if (m_CurrentProcessRangesMax == NULL)
+ m_CurrentProcessRangesMax = new double[m_nProcessRanges];
+ if (m_CurrentProcessRangesMin == NULL)
+ m_CurrentProcessRangesMin = new double[m_nProcessRanges];
+
+ for (int istops = 0; istops < nstops; ++istops)
+ {
+ colorspace = Input->stops[istops]->colorspace;
+ if (Input->stops[istops]->colorspace == COLOR_SPACE__Volume)
+ {
+ //Assumption: Input is given without light inks
+ //The volumes are given in Thread units in %
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] = m_ProcessRangesMaxP[iP];
+ m_CurrentProcessRangesMin[iP] = m_ProcessRangesMinP[iP];
+ }
+ for (int jV = 0; jV < m_nInks; ++jV)
+ {
+ Volume(jV) = inputcoordinates[istops]->inputliquids[jV]->volume; //volumes are in [%]
+ Volume_nlcm(jV) = m_maxNlPerCM(jV)*Volume(jV) / 100.0; //Volume_nlcm is in [nl/cm]
+ }
+ if (Input->uselightinks)
+ { //Convert to light inks
+ GamutRegion[istops] = GetGamutRegion(Volume_nlcm, m_CurrentProcessRangesMax);//Volume is in [nl/cm]
+ SplitVolume(Volume, VolumeLi, GamutRegion[istops]); //VolumeLi is in [%]
+ }
+ else
+ {
+ GamutRegion[istops] = GetGamutRegion(Volume_nlcm, m_CurrentProcessRangesMax);//Volume is in [nl/cm]
+ }
+ }
+ else if (Input->stops[istops]->colorspace == COLOR_SPACE__Catalog)
+ {
+ //The volumes are given in %, in Color Table Units, use Color Tables parameters to calculate gamut region
+ InputCoordinates *IC = inputcoordinates[istops];
+ IC->n_inputliquids = m_nInks;
+ IC->inputliquids = (InputLiquid**)malloc(sizeof(InputLiquid*) *m_nInks);
+ for (int j = 0; j < m_nInks; j++)
+ {
+ IC->inputliquids[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(IC->inputliquids[j]);
+ }
+ IC->inputliquids[0]->volume = IC->cyan;
+ IC->inputliquids[0]->liquidtype = LIQUID_TYPE__Cyan;
+ IC->inputliquids[0]->has_volume =IC-> has_cyan;
+ IC->inputliquids[1]->volume = IC->magenta;
+ IC->inputliquids[1]->liquidtype =LIQUID_TYPE__Magenta;
+ IC->inputliquids[1]->has_volume =IC->has_magenta;
+ IC->inputliquids[2]->volume = IC->yellow;
+ IC->inputliquids[2]->liquidtype = LIQUID_TYPE__Yellow;
+ IC->inputliquids[2]->has_volume = IC->has_yellow;
+ IC->inputliquids[3]->volume = IC->key;
+ IC->inputliquids[3]->liquidtype = LIQUID_TYPE__Black;
+ IC->inputliquids[3]->has_volume = IC->has_key;
+
+ for (int jV = 0; jV < m_nInks; ++jV)
+ {
+ Volume(jV) =IC->inputliquids[jV]->volume;
+ Volume_nlcm(jV) = m_maxNlPerCM(jV)*Volume(jV) / 100.0; //Volume_nlcm is in [nl/cm]
+ }
+
+ m_currentMaxNLPerCM = m_CTmaxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] =m_GamutRegionMaxLim[iP];
+ m_CurrentProcessRangesMin[iP] = m_GamutRegionMinLim[iP];
+ }
+ if (Input->uselightinks)
+ { //Convert to light inks
+ GamutRegion[istops] = GetGamutRegion(Volume_nlcm, m_CurrentProcessRangesMax);//Volume_nlcm is in [nl/cm]
+ SplitVolume(Volume, VolumeLi, GamutRegion[istops]); //VolumeLi is in [%]
+ }
+ else
+ {
+ GamutRegion[istops] = GetGamutRegion(Volume_nlcm, m_GamutRegionMaxLim); //Volume_nlcm is in [nl/cm]
+ }
+ }
+ else
+ {
+ colorspace = Input->stops[istops]->colorspace;
+
+ if (m_colortable->GetTableSubVersion() > 0)
+ {
+ DirectInversion(inputcoordinates[istops], colorspace, InkOut, RGBOut, Volume, LabOut,
+ GamutRegion[istops], InGamut, sur, CS);
+ PercentagetoNLcm(Volume, Volume);
+ GetClosestInk(Volume, GamutRegion[istops], Volume); //Input Volume is in [nl/cm] Output Volume is in [%]
+ ConfineVolumes(Volume);
+ }
+ else
+ {
+ ConvertColorToLinearInks(inputcoordinates[istops], colorspace, InkOut, RGBOut,
+ LabOut, GamutRegion[istops], InGamut); //full range Color Table Units
+ //Inks are in their initial state in %
+ //Inks are in Linear Space , convert to nonlinear by using Calibration Tables,
+ //convert data to the thread range in %
+ ColorTable2Threadunits(InkOut, InkOut);
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (int iP = 0; iP < m_nProcessRanges; ++iP)
+ {
+ m_CurrentProcessRangesMax[iP] = m_ProcessRangesMaxP[iP];
+ m_CurrentProcessRangesMin[iP] = m_ProcessRangesMinP[iP];
+ }
+ if (m_CalibMode == 1)
+ {
+ ConvertToNLInks(InkOut, NLInkOut);
+ LimitNLInks2Volume(NLInkOut, GamutRegion[istops], Volume); //Volume is in [%]
+ }
+ else
+ LimitNLInks2Volume(InkOut, GamutRegion[istops], Volume); //Volume is in [%]
+ }
+ if (Input->uselightinks)
+ { //Convert to light inks
+ SplitVolume(Volume, VolumeLi, GamutRegion[istops]);
+ }
+ }
+ if (istops == 0 || processparameterstableindex < GamutRegion[istops])
+ {
+ processparameterstableindex = GamutRegion[istops];
+ }
+ }
+ delete[] GamutRegion;
+ GamutRegion = NULL;
+ // all gamut regions were evaluated, pack data
+
+ //Initialize Output...
+ RecommendedProcessTableOutput *Output = (RecommendedProcessTableOutput*)malloc(sizeof(RecommendedProcessTableOutput));
+ recommended_process_table_output__init(Output);
+ Output->has_processparameterstableindex = true;
+ Output->processparameterstableindex = processparameterstableindex;
+ output_buffer = (uint8_t*)malloc(recommended_process_table_output__get_packed_size(Output));
+ int size = recommended_process_table_output__pack(Output, output_buffer);
+
+#pragma region Free Conversion Input & Output
+ Input->inputliquids = original_input_liquids;;
+ Input->n_inputliquids = original_input_liquids_count;
+ for (int i=0; i<nstops; ++i)
+ input_coordinates__free_unpacked(inputcoordinates[i], NULL);
+ delete[] inputcoordinates;
+ inputcoordinates = NULL;
+
+ delete[] filteredInputLiquids;
+ filteredInputLiquids = NULL;
+
+
+ recommended_process_table_input__free_unpacked(Input, NULL);
+ recommended_process_table_output__free_unpacked(Output, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+ catch (const std::exception& e)
+ {
+ RecommendedProcessTableOutput *output = (RecommendedProcessTableOutput*)malloc(sizeof(RecommendedProcessTableOutput));
+ recommended_process_table_output__init(output);
+
+ output->has_haserror = true;
+ output->haserror = true;
+
+ const char* what = e.what();
+ int nWhat = strlen(what);
+ output->errormessage = (char*)malloc(nWhat);
+ for (int i = 0; i < nWhat; ++i)
+ output->errormessage[i] = what[i];
+
+ output_buffer = (uint8_t*)malloc(recommended_process_table_output__get_packed_size(output));
+ int size = recommended_process_table_output__pack(output, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ recommended_process_table_input__free_unpacked(Input, NULL);
+ recommended_process_table_output__free_unpacked(output, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+}
+
+size_t Tango::ColorLib::ColorConverter::CheckOutOfGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ //Get Input
+ OutOfGamutInput* Input = out_of_gamut_input__unpack(NULL, input_buffer_size, input_buffer);
+
+ try
+ {
+ InputLiquid** original_input_liquids = NULL;
+ int original_input_liquids_count = 0;
+
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+ int numofInks = 0;
+ int numLightInks = 0;
+ CountNumberofInks(Input, numofInks, numLightInks);
+ if (numofInks < 0)
+ throw std::exception("Duplicate inks");
+
+ int expected_liquids = numofInks;
+ m_TotalNumberofInks = numofInks;
+ original_input_liquids_count = Input->inputcoordinates->n_inputliquids;
+ original_input_liquids = Input->inputcoordinates->inputliquids;
+ if(m_InkNames == NULL)
+ m_InkNames = new LiquidType[m_TotalNumberofInks];
+ InputLiquid** filteredInputLiquids = new InputLiquid*[m_TotalNumberofInks];
+
+ for (int i = 0; i < original_input_liquids_count; i++)
+ {
+ InputLiquid* liquid = Input->inputcoordinates->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ m_InkNames[0] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ m_InkNames[1] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ m_InkNames[2] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Black:
+ filteredInputLiquids[3] = liquid;
+ m_InkNames[3] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightCyan:
+ filteredInputLiquids[4] = liquid;
+ m_InkNames[4] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightMagenta:
+ filteredInputLiquids[5] = liquid;
+ m_InkNames[5] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightYellow:
+ filteredInputLiquids[6] = liquid;
+ m_InkNames[6] = liquid->liquidtype;
+ break;
+ }
+ }
+
+ Input->inputcoordinates->inputliquids = filteredInputLiquids;
+ if (expected_liquids <= 0)
+ throw std::exception("expected_liquids is zero");
+ else
+ Input->inputcoordinates->n_inputliquids = expected_liquids;
+
+ //Filter and arrange colors
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+
+
+ if (m_colortable == NULL)
+ m_colortable = new ColorTable();
+ readColorTransformations(Input);
+ if (Input->n_processranges <= 0)
+ throw std::exception("number of process ranges is zero");
+ else
+ m_nProcessRanges = Input->n_processranges;
+
+ double *tmpVal;
+ /*if (m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i]; */
+
+ if (m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nProcessRanges];
+ if (m_GamutRegionMinLim == NULL)
+ m_GamutRegionMinLim = new double[m_nProcessRanges];
+ m_GamutRegionMinLim[0] = GamutMinReg0;
+ m_GamutRegionMinLim[1] = GamutMinReg1;
+ tmpVal = m_colortable->GetGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_GamutRegionMaxLim[i] = tmpVal[i];
+
+ //read calibration tables and store them in m_CalibCurves
+ InputLiquid **inputliquids = Input->inputcoordinates->inputliquids;
+ // int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids;
+ int n_inputliquids = numofInks - numLightInks;
+ readCalibrationTables(inputliquids, n_inputliquids);
+ // Set Calibration mode 0 up tp 100%, 1 with High Volume Calib
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ if (n_inputliquids != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables\0");
+
+ //Tables have been filled
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ //Convert input data to linear inks
+ if (Input->colorspace == COLOR_SPACE__Volume || Input->colorspace == COLOR_SPACE__Catalog)
+ {
+ InGamut = true;
+ }
+ else
+ {
+ double LabIn[3];
+ switch (Input->colorspace)
+ {
+ case (COLOR_SPACE__RGB):
+ {
+ RGBOut(0) = Input->inputcoordinates->red;
+ RGBOut(1) = Input->inputcoordinates->green;
+ RGBOut(2) = Input->inputcoordinates->blue;
+ //convert to Lab
+ double RGBOutP[3];
+ VectorToDouble(RGBOut, RGBOutP);
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65
+ LimitLab(LabIn);
+ //Is In Gamut?
+ double LabOnGamut[3];
+ InGamut = IsInGamut(LabIn, sur, CS, LabOnGamut);
+ break;
+ }
+ case (COLOR_SPACE__LAB):
+ {
+ LabIn[0] = Input->inputcoordinates->l; //Absolute Colorimetric
+ LabIn[1] = Input->inputcoordinates->a;
+ LabIn[2] = Input->inputcoordinates->b;
+ //the assumption is that the color space has illumination that matches the whitepoint of the Strip
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ double LabInFinal2[3];
+ double LabOnGamut[3];
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //LabInFinal2 is in Relative Colorimetric Space
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut);
+ break;
+ }
+ default:
+ {
+ throw std::exception(" Unsupported Color Space");
+ break;
+ }
+ }
+ }
+
+ //Initialize Output...
+ OutOfGamutOutput *Output = (OutOfGamutOutput*)malloc(sizeof(OutOfGamutOutput));
+ out_of_gamut_output__init(Output);
+ Output->has_outofgamut = true;
+ Output->outofgamut = !(InGamut);
+
+ output_buffer = (uint8_t*)malloc(out_of_gamut_output__get_packed_size(Output));
+ int size = out_of_gamut_output__pack(Output, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ Input->inputcoordinates->inputliquids = original_input_liquids;
+ Input->inputcoordinates->n_inputliquids = original_input_liquids_count;
+ delete[] filteredInputLiquids;
+ filteredInputLiquids = NULL;
+
+ out_of_gamut_input__free_unpacked(Input, NULL);
+
+ out_of_gamut_output__free_unpacked(Output, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+ catch (const std::exception& e)
+ {
+ //Notify Error...
+ OutOfGamutOutput *Output = (OutOfGamutOutput*)malloc(sizeof(OutOfGamutOutput));
+ out_of_gamut_output__init(Output);
+
+ Output->has_haserror = true;
+ Output->haserror = true;
+
+ const char* what = e.what();
+ int nWhat = strlen(what);
+ Output->errormessage = (char*)malloc(nWhat);
+ //conversionOutput->errormessage = new char[nWhat];
+ for (int i = 0; i < nWhat; ++i)
+ Output->errormessage[i] = what[i];
+
+ output_buffer = (uint8_t*)malloc(out_of_gamut_output__get_packed_size(Output));
+ int size = out_of_gamut_output__pack(Output, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ out_of_gamut_input__free_unpacked(Input, NULL);
+ out_of_gamut_output__free_unpacked(Output, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+}
+
+void Tango::ColorLib::ColorConverter::DirectInversion(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut, VectorXd &VolOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ //Split the calculation into RGB and Lab Color Space
+ int i = 0;
+ int k = 0;
+ double *LabIn = new double[3];
+ double *RGBIn = new double[3];
+ ColorConvert ColConv(D65, D65);
+
+ if (colorspace == COLOR_SPACE__RGB)
+ {
+ RGBIn[0] = inputcoordinates->red;
+ RGBIn[1] = inputcoordinates->green;
+ RGBIn[2] = inputcoordinates->blue;
+ ColConv.RGBtoLab(RGBIn, LabIn);
+ }
+ else if (colorspace == COLOR_SPACE__LAB)
+ {
+ LabIn[0] = inputcoordinates->l; //Absolute Colorimetric
+ LabIn[1] = inputcoordinates->a;
+ LabIn[2] = inputcoordinates->b;
+ }
+ else
+ {
+ throw std::exception(" Unsupported Color Space");
+ }
+
+ DirectInversionCalc(LabIn, InkOut, RGBOut, VolOut,
+ LabOut, GamutRegion, InGamut, sur, CS);
+
+
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBIn != NULL)
+ {
+ delete[] RGBIn;
+ RGBIn = NULL;
+ }
+
+}
+
+void Tango::ColorLib::ColorConverter::DirectInversionCalc(double *LabIn, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &VolOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ //Declarations
+ ColorConvert ColConv(D65, D65);
+ int i, k;
+ int nfree = m_ObjFunction->GetNumFreeParams();
+ double *InitCMY = new double[nfree];
+ int nfixed = m_ObjFunction->GetNumFixedParams();
+ int npars = nfree + nfixed;
+ if (npars != m_nInks)
+ throw std::exception("Number of parameters does not match number of inks");
+ double *ValK = new double[nfixed];
+ int nk = 100 + 1;
+ double dK = 1.0 / (double)(nk - 1);
+ for (i = 0; i < nfixed; ++i)
+ ValK[i] = 0;
+ double **SolVector = new double*[nk];
+ double **finalLab = new double *[nk];
+ double **Vol = new double*[nk];
+ int *FeasibleSolutionsInd = new int[nk];
+ int *VecGamutRegion = new int[nk];
+
+ VectorXd VolumeTmp(npars);
+ C_RGB_XYZ_Lab LabTmp;
+ double *dECMC = new double[nk];
+ C_RGB_XYZ_Lab LabInVec;
+
+ LabInVec.Set(LabIn[0], LabIn[1], LabIn[2]);
+ C_RGB_XYZ_Lab LabOutVec;
+ m_currentMaxNLPerCM = m_maxNlPerCM;
+ for (i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_CurrentProcessRangesMax[i] = m_ProcessRangesMaxP[i];
+ m_CurrentProcessRangesMin[i] = m_ProcessRangesMinP[i];
+ }
+ for (i = 0; i < nk; ++i)
+ {
+ SolVector[i] = new double[npars];
+ finalLab[i] = new double[3];
+ Vol[i] = new double[npars];
+ }
+ double *LabInFinal2 = new double[3];
+ double *LabOnGamut = new double[3];
+
+ ColConv.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //LabInFinal2 is in Relative Colorimetric Space
+ LimitLab(LabInFinal2);
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+
+ LabTmp.Set(LabOnGamut[0], LabOnGamut[1], LabOnGamut[2]);
+ m_ObjFunction->SetLabGoal(LabOnGamut);
+ //convert to Inks
+ unsigned int nIterations;
+
+ for (i = 0; i < nfree; ++i)
+ InitCMY[i] = 0.0;
+ for (i = 0; i < nfixed; ++i)
+ ValK[i] = 0.0;
+ m_Minimize->SetLabIn(LabOnGamut);
+ for (k = 0; k < nk; ++k)
+ {
+ ValK[0] = (double)k * dK;
+ m_Minimize->MinimizationAlgorithm(InitCMY, ValK, nIterations); //result is returned in InitCMY
+ LabOut = DoubleToVector(LabOnGamut, 3);
+ LabOut += DoubleToVector(m_Minimize->GetLabOut(), 3);
+ for (int i = 0; i < nfree; ++i)
+ SolVector[k][i] = std::min(std::max(100 * InitCMY[i], 0.0), 100.0);
+ SolVector[k][nfree] = std::min(std::max(100 * ValK[0], 0.0), 100.0); //Solution Vector is in linear units in the interval [0,100]
+
+ for (int i = 0; i < 3; ++i)
+ finalLab[k][i] = LabOut[i];
+ LabOutVec.Set(LabOut[0], LabOut[1], LabOut[2]);
+
+ ColConv.dEcmc(LabTmp, LabOutVec, dECMC[k]);
+ //Result is in Linear Inks
+ //apply Nonlinear curves of Loaded thread
+ // in order to calculate volume
+ // Volume is used to calculate the feasible solutions
+
+ InkOut = DoubleToVector(SolVector[k], m_nInks);
+ double *tmpval = m_colortable->GetNormFactor();
+ for (int i = 0; i < m_nInks; ++i)
+ InkOut(i) *= tmpval[i];
+ ColorTable2Threadunits(InkOut, InkOut); //in %
+
+ if (m_CalibMode == 1)
+ {
+ ConvertToNLInks(InkOut, InkOut); // in %
+ LimitNLInks2VolumeNoFix(InkOut, GamutRegion, VolumeTmp); //VolumeTmp is in %
+ // NLInkPToVolume(InkOut, VolumeTmp); // in %
+ //LimitNLInks2Volume(InkOut, GamutRegion, VolumeTmp);
+ }
+ else
+ {
+ LimitNLInks2VolumeNoFix(InkOut, GamutRegion, VolumeTmp);
+ }
+ VecGamutRegion[k] = GamutRegion;
+ // NLInkPToVolume(InkOut, VolumeTmp); // in %
+ for (i = 0; i < npars; ++i)
+ Vol[k][i] = VolumeTmp(i);
+ VectorToDouble(InkOut, SolVector[k]);
+ }
+
+ //find feasible solutions
+ int nfeas = -1;
+
+ for (k = 0; k < nk; ++k)
+ {
+ bool FSInd = true;
+ for (i = 0; i < npars - 1; ++i)
+ FSInd = FSInd & ((Vol[k][i] < 0.05) | (Vol[k][i] > m_LowVolumeThreshold));
+ FSInd = FSInd & ((Vol[k][npars - 1] < 0.05) | (Vol[k][npars - 1] > m_LightInksThr));
+ FSInd = FSInd & (dECMC[k] < 0.5);
+ if (FSInd)
+ {
+ nfeas++;
+ FeasibleSolutionsInd[nfeas] = k;
+ }
+ }
+ double minVal = 1e+05;
+ int minInd = -1;
+ if (nfeas >= 0)
+ {
+ for (i = 0; i < nfeas + 1; ++i)
+ {
+ if (dECMC[i] < minVal)
+ {
+ minVal = dECMC[FeasibleSolutionsInd[i]];
+ minInd = FeasibleSolutionsInd[i];
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < nk; ++i)
+ {
+ if (dECMC[i] < minVal)
+ {
+ minVal = dECMC[i];
+ minInd = i;
+ }
+ }
+ }
+
+ for (i = 0; i < npars; ++i)
+ {
+ InkOut(i) = SolVector[minInd][i];
+ VolOut(i) = Vol[minInd][i];
+ }
+ GamutRegion = VecGamutRegion[minInd];
+
+ double *LabOutFinal = new double[3];
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal[i] = finalLab[minInd][i];
+ //LabOutFinal is in Relative Colorimetric
+ //Reverse the conversion process to bring back Lab to STRIP white point
+ ColConv.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_WP);
+
+ LabOut = DoubleToVector(LabOutFinal, 3);
+ ColConv.SetReferenceWhite(D65);
+ //Convert to RGB
+ double *RGBOutP = new double[3];
+
+ //Use Relative colorimetric to get RGB
+ ColConv.LabtoRGB(finalLab[minInd], RGBOutP);
+ RGBOut = DoubleToVector(RGBOutP, 3);
+
+ //Cleanup
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+
+ if (ValK != NULL)
+ {
+ delete[] ValK;
+ ValK = NULL;
+ }
+
+ if (VecGamutRegion != NULL)
+ {
+ delete[] VecGamutRegion;
+ VecGamutRegion = NULL;
+ }
+
+ if (SolVector != NULL)
+ {
+ for (i = 0; i < npars; ++i)
+ delete[] SolVector[i];
+ delete[] SolVector;
+ SolVector = NULL;
+ }
+
+ if (finalLab != NULL)
+ {
+ for (i = 0; i < 3; ++i)
+ delete[] finalLab[i];
+ delete[] finalLab;
+ finalLab = NULL;
+ }
+
+ if (Vol != NULL)
+ {
+ for (i = 0; i < npars; ++i)
+ delete[] Vol[i];
+ delete[] Vol;
+ Vol = NULL;
+ }
+
+ if (LabInFinal2 != NULL)
+ {
+ delete[] LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+
+ if (LabOnGamut != NULL)
+ {
+ delete[] LabOnGamut;
+ LabOnGamut = NULL;
+ }
+
+
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+
+ if (FeasibleSolutionsInd != NULL)
+ {
+ delete[] FeasibleSolutionsInd;
+ FeasibleSolutionsInd = NULL;
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::PrepareObjectiveFunctionPars()
+{
+ int nFreeParams = 3;
+ int nFixedParams = 1;
+ unsigned int *FreeParamIndex = new unsigned int[nFreeParams];
+ unsigned int *FixedParamIndex = new unsigned int [nFixedParams];
+ FreeParamIndex[0] = 0;
+ FreeParamIndex[1] =1;
+ FreeParamIndex[2] = 2;
+ FixedParamIndex[0] = 3;
+ double *UpperBound = new double[nFreeParams];
+ double *LowerBound = new double[nFreeParams];
+ for (int i = 0; i < nFreeParams; ++i)
+ {
+ UpperBound[i] = 100.0;
+ LowerBound[i] = 0.0;
+ }
+ m_ObjFunction->SetParameters(nFreeParams, nFixedParams, FreeParamIndex, FixedParamIndex, UpperBound, LowerBound);
+}
+
+size_t Tango::ColorLib::ColorConverter::InitConvertLiquids(ConversionInput *conversionInput, InputLiquid** original_input_liquids,
+ int &numofInks, int &numLightInks)
+{
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+
+ int original_input_liquids_count = 0;
+ CountNumberofInks(conversionInput, numofInks, numLightInks);
+ if (numofInks < 0)
+ throw std::exception("Duplicate inks");
+
+ m_UseLightInks = conversionInput->uselightinks;
+ if ((numLightInks <= 0) & (m_UseLightInks == true))
+ throw std::exception("Light Inks not defined");
+
+ int expected_liquids = numofInks;
+ m_TotalNumberofInks = numofInks;
+ original_input_liquids_count = conversionInput->inputcoordinates->n_inputliquids;
+ original_input_liquids = conversionInput->inputcoordinates->inputliquids;
+ if (m_InkNames == NULL)
+ m_InkNames = new LiquidType[m_TotalNumberofInks];
+ InputLiquid** filteredInputLiquids = (InputLiquid**)malloc(sizeof(InputLiquid*) * m_TotalNumberofInks);
+
+ for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+ {
+ InputLiquid* liquid = conversionInput->inputcoordinates->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ m_InkNames[0] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ m_InkNames[1] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ m_InkNames[2] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__Black:
+ filteredInputLiquids[3] = liquid;
+ m_InkNames[3] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightCyan:
+ filteredInputLiquids[4] = liquid;
+ m_InkNames[4] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightMagenta:
+ filteredInputLiquids[5] = liquid;
+ m_InkNames[5] = liquid->liquidtype;
+ break;
+ case LIQUID_TYPE__LightYellow:
+ filteredInputLiquids[6] = liquid;
+ m_InkNames[6] = liquid->liquidtype;
+ break;
+ }
+ }
+ conversionInput->inputcoordinates->inputliquids = filteredInputLiquids;
+ if (expected_liquids <= 0)
+ throw std::exception("expected_liquids is zero");
+ else
+ conversionInput->inputcoordinates->n_inputliquids = expected_liquids;
+ return((size_t)expected_liquids);
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.h
new file mode 100644
index 000000000..ac2dbc29f
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverter.h
@@ -0,0 +1,228 @@
+#include <cstdlib>
+#include <cstdint>
+#include "Dense"
+#include "Core"
+#include "C_RGB_XYZ_Lab.h"
+#include "protobuf-c\protobuf-c.h"
+#include "CalibData.h"
+#include "ColorTransf.h"
+#include "ColorConvert.h"
+#include "ForwardModel.h"
+#include "GBD.h"
+#include "CT_Header.h"
+#include "ConversionOutput.pb-c.h"
+#include "CalibrationData.pb-c.h"
+#include "ConversionInput.pb-c.h"
+#include "GradientInputStop.pb-c.h"
+#include "GradientOutputStop.pb-c.h"
+#include "GradientConversionInput.pb-c.h"
+#include "GradientConversionOutput.pb-c.h"
+#include "OutOfGamutInput.pb-c.h"
+#include "OutOfGamutOutput.pb-c.h"
+#include "RecommendedProcessTableInput.pb-c.h"
+#include "RecommendedProcessTableOutput.pb-c.h"
+#include "ObjectiveFunction.h"
+#include "LevMar.h"
+#include "Interp.h"
+#include "Curves.h"
+#include "Gradient.h"
+#include "ColorTable.h"
+#include <vector>
+
+#pragma once
+namespace Tango
+{
+/* typedef struct
+ {
+ unsigned int TblSIze = 0;
+ unsigned int Version[3] = { 0,0,0 };
+ char * ColorSpace;
+ char * ConnectionSpace;
+ char * DeviceManufacturer;
+ C_RGB_XYZ_Lab Illuminant;
+ unsigned char nGamutRegions=0;
+ double *GRegMaxLim;
+ } CT_Header; */
+
+/* typedef struct
+ {
+ C_RGB_XYZ_Lab Lab;
+ C_RGB_XYZ_Lab RGB;
+ double *Volume;
+ bool InGamut;
+ int GamutRegion;
+ double offset;
+ ColorSpace colorspace;
+ }GradStruct;*/
+
+ /*typedef enum {
+ XYZ,
+ Lab,
+ CMY,
+ CMYK
+ }ColorSpaceH;*/
+
+ typedef enum {
+ EqSpaced,
+ dESpaced
+ }GradOffset;
+
+
+
+ namespace ColorLib
+ {
+ class ColorConverter
+ {
+ public:
+ ColorConverter();
+ ~ColorConverter();
+ // size_t Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ void ConvertColorToLinearInks( InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut,
+ int &GamutRegion, bool &InGamut);
+ void ConvertGradStoptoVolume(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, int &GamutRegion, bool same_regions);
+ void ConvertVolumeToRGBDisplay(InputCoordinates *IC, int n_processRanges,int colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion);
+ void ConvertVolumeToLabRel(VectorXd &Volume, VectorXd &LabOut, int GamutRegion);
+
+ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ size_t Tango::ColorLib::ColorConverter::GetRecommendedProcessParameters(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ size_t Tango::ColorLib::ColorConverter::CheckOutOfGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ void Tango::ColorLib::ColorConverter::DirectInversion(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut, VectorXd &VolOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS);
+ void Tango::ColorLib::ColorConverter::DirectInversionCalc(double *LabIn, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &VolOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS);
+ void ConvertToNLInks(VectorXd InkIn, VectorXd &InkOut);
+ void ConvertToLinearInks(VectorXd InkIn, VectorXd &InkOut);
+ void VolumeToNLInkP(VectorXd Volume, VectorXd &NLInkP);
+ void NLInkPToVolume(VectorXd NLInkP, VectorXd &Volume);
+ void SetMaxNLperCM(double maxNlPerCM, int i);
+ size_t P_IsInGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer);
+ private:
+ ColorTable *m_colortable;
+ ColorConvert *m_Conv02;
+ LiquidType *m_InkNames;
+// Interp *m_LinInterp;
+// Interp *m_InvLinInterp;
+ C_RGB_XYZ_Lab m_whitepointLab;
+ C_RGB_XYZ_Lab m_whitepointXYZ_Strip;
+ double *m_NormGamutRegionMaxLim;
+ double *m_GamutRegionMaxLim;
+ double *m_GamutRegionMinLim;
+ double *m_ProcessRangesMaxP;
+ double *m_CurrentProcessRangesMax;
+ double *m_CurrentProcessRangesMin;
+ double *m_ProcessRangesMinP;
+ int m_nProcessRanges;
+ bool m_UseLightInks;
+ double m_LightInksThr;
+ double m_LowVolumeThreshold;
+ double m_LowVolHalf;
+ double m_NormFactor;
+ double m_InvnormFactor;
+ int m_TotalNumberofInks;
+ double *m_CalibGain;
+ double *m_CalibOffset;
+ double *m_maxCalX;
+ void LimitLab(double* LabIn);
+ int m_nGradStops;
+ Gradient *m_GradStops;
+ bool same_regions;
+ int m_CalibMode;
+// bool m_AdaptWP;
+ CalibData *m_CalibCurves;
+ ForwardModel *m_forwardmodel;
+ int m_nInks;
+ int m_nVolumes;
+ //double *m_ProcessRangesMaxInkUptake;
+ //double *m_ProcessRangesMinInkUptake;
+ C_RGB_XYZ_Lab m_WP;
+ VectorXd m_maxNlPerCM;
+ VectorXd m_CTmaxNlPerCM;
+ VectorXd m_currentMaxNLPerCM;
+ ObjectiveFunction *m_ObjFunction;
+ LevMar *m_Minimize;
+ //double *m_LowVolThr_nlcm;
+ //double *m_LowVolThrHalf_nlcm;
+ size_t InitConvertLiquids(ConversionInput *conversionInput, InputLiquid** original_input_liquids, int &numofInks, int &numLightInks);
+ void readColorTransformations(ConversionInput* conversionInput);
+ void readColorTransformations(OutOfGamutInput* Input);
+ void readColorTransformations(RecommendedProcessTableInput *Input);
+// void readColorTables(bool has_rddata, uint8_t *data, int nprocessranges);
+ void readCalibrationTables(InputLiquid **inputliquids, int n_inputliquids);
+ void SetCalibData(CalibrationData* calibrationData, int i, CalibData *tmpCurve);
+ void SetNumberofInks(int nInks) { m_nInks = nInks; };
+ void SetNumberOfVolumes(int nVol) { m_nVolumes = nVol; };
+ // void InitInterpolations(int numofInks, Interp *linearInterp, Interp *InvLinearInterp);
+ void fillRGB(OutputCoordinates *outputCoords, VectorXd RGBOut);
+ void fillLab(OutputCoordinates *outputCoords, VectorXd LabOut);
+ void fillVolume(OutputCoordinates *&outputCoords, VectorXd Volume);
+ void fillStop(GradientOutputStop *&stop, VectorXd Volume, int GamutRegion, double Position);
+ void fillGradientStops(GradientConversionInput *conversionInput);
+ void ProcessHiveNeighbors(ConversionInput *conversionInput, VectorXd LabC, VectorXd RGBC, VectorXd VolumeC,
+ int InGamutRegion, MatrixXd &RGBOut, MatrixXd & LabOut, MatrixXd &VolumeOut,
+ int nHive, int *&GamutRegion, int *indDataMax);
+ void ArrangeHiveData(MatrixXd LabHive, MatrixXd RGBTmpVec, MatrixXd VolumeHive, int *GamutRegion,
+ VectorXd xpos, VectorXd ypos, int nHive, MatrixXd &OLabHive,
+ MatrixXd &ORGBHive, MatrixXd &OVolumeHive, int *&OGamutRegion);
+ void FindTriplet(VectorXd Lab, MatrixXd Lab1, int nHive, int*indDataMax);
+ void CountNumberofInks(ConversionInput* conversionInput, int &numInks, int &numLightInks);
+ void CountNumberofInks(GradientConversionInput* conversionInput, int &numInks, int &numLightInks);
+ void CountNumberofInks(OutOfGamutInput* conversionInput, int &numInks, int &numLightInks);
+ void CountNumberofInks(RecommendedProcessTableInput* conversionInput, int &numInks, int &numLightInks);
+ void SetStripWhitepoint(double threadl, double threada, double threadb);
+ void VectorToDouble(VectorXd Vec, double *doub);
+// void VectorToDouble(VectorXd VecIn, std::vector<double> &doubOut);
+ VectorXd DoubleToVector(double *doub, int nSize);
+ void CompareWhitePoints();
+ bool IsInGamut(double *InLab, SURROUND sur, CAM02CS CS, double *LabCoord);
+// CT_Header *read_header(uint8_t* data, int &bytesread);
+ void read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput);
+ void findStops(Gradient& m_GradStops1, Gradient& m_GradStops2, double dEThr, int ninterstops, int &nOut,
+ double **VecRGBOut, double **VecLabOut, double *posOut);
+ void RecommendedProcessTableInput2InputCoordinates(RecommendedProcessTableInput *Input, InputCoordinates **inputcoordinates);
+ void GradInput2InputCoords(GradientConversionInput *conversionInput, InputCoordinates **inputcoordinates);
+ void ProcessGradientStops(InputCoordinates **inputcoordinates);
+ void PrepareGradient(GradientConversionInput* conversionInput, GradientConversionOutput *conversionOutput);
+ void LimitInks(VectorXd inInks, double *BoundedInks);
+ void NLcmtoPercentage(VectorXd InVolume, VectorXd &OutVolume);
+ void PercentagetoNLcm(VectorXd InVolume, VectorXd &OutVolume);
+ int GetGamutRegion(VectorXd Volume, double *GamutLimits);
+ bool CheckLabInRGBGamut( VectorXd Lab);
+ bool CheckLabInRGBGamut( C_RGB_XYZ_Lab Lab);
+ void SmoothCurveData(VectorXd VIn, VectorXd &VOut, int FilterWidth);
+ void ConvertRGBColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS);
+ void ConvertLabColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS);
+ /*void ConvertCMYKColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS);*/
+ void LimitLowVolume(VectorXd InVolume, int &GamutRegion, VectorXd &OutVolume);
+ void LimitLowVolumeP(VectorXd InVolume, int &GamutRegion, VectorXd &OutVolume);
+ void LimitNLInks2Volume(VectorXd NLInks, int &GamutRegion, VectorXd &OutVolume);
+ void LimitNLInks2VolumeNoFix(VectorXd NLInks, int &GamutRegion, VectorXd &Volume);
+ void LimitNLInks2VolumeThr(VectorXd NLInks, int &GamutRegion, VectorXd &Volume);
+ void GetClosestInk(VectorXd Volume, int &GamutRegion, VectorXd &BestVolume);
+ bool CheckMonotonicity(CalibrationData *calibdata);
+ void ConfineVolumes(VectorXd &Volume);
+ void SplitVolume(VectorXd Volume, VectorXd &VolumeLI, int &GamutRegion);
+ void DefineSplitLimits(double &low, double &high, double InitTotalVolume);
+ void findGamutRegion(int &GamutRegion, double TotalVolume);
+ void SetCalibMode();
+ void SetCalibFactorization();
+ void ApplyCTLinearCurves(double *InkIn, double* InkOut);
+ void ApplyCTInvLinearCurves(double *InkIn, double* InkOut);
+ void ColorTable2Threadunits(VectorXd InkIn, VectorXd &InkOut);
+ void Thread2ColorTableunits(VectorXd InkIn, VectorXd &InkOut);
+ void PrepareObjectiveFunctionPars();
+ };
+ }
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverterCLipRGB.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverterCLipRGB.cpp
new file mode 100644
index 000000000..789e7f411
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ColorConverterCLipRGB.cpp
@@ -0,0 +1,3219 @@
+#include "ColorConverter.h"
+#include "ColorConvert.h"
+#include "CalibrationPoint.pb-c.h"
+#include "CalibrationData.pb-c.h"
+#include "ColorSpace.pb-c.h"
+#include "ConversionInput.pb-c.h"
+#include "ConversionOutput.pb-c.h"
+#include "InputCoordinates.pb-c.h"
+#include "OutputCoordinates.pb-c.h"
+#include "OutputLiquid.pb-c.h"
+#include "InputLiquid.pb-c.h"
+#include "LiquidType.pb-c.h"
+#include <iostream>
+#include <stdio.h>
+#include "Dense"
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorConvert.h"
+#include "ColorTransf.h"
+#include "NumConversions.h"
+#include "Interp.h"
+#include <cmath>
+#include <algorithm>
+#include <sstream>
+
+#include "GradientConversionInput.pb-c.h"
+#include "GradientConversionOutput.pb-c.h"
+#include "GradientInputStop.pb-c.h"
+#include "GradientOutputStop.pb-c.h"
+#include "LiquidVolume.pb-c.h"
+
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif
+
+#define dL 2.0
+#define dC 2.0
+#define dH6 EIGEN_PI / 3.0
+#define dH12 EIGEN_PI / 6.0
+#define LUMINANCE_PCS 159.16
+#define L_A LUMINANCE_PCS / 5.0
+#define Y_b 20.0
+#define eps 1e-06
+#define NegValue -1000
+#define WPTol 1.0
+#define dETol 2.0
+# define ROUNDINGDigits 2.0
+#define maxPerRegion 100.0
+#define LowVolumeThreshold 0.0
+#define LowVolHalf LowVolumeThreshold/2
+#define GradientEndThr 0.95
+
+
+Tango::ColorLib::ColorConverter::ColorConverter() :
+ m_CalibCurves(NULL), m_Conv02(NULL),
+m_maxNlPerCM(NULL),
+m_nInks(0), m_nVolumes(0),
+ m_GradStops(NULL), m_nGradStops(0), m_colortable(NULL), m_ProcessRangesMaxP(NULL),
+ m_nProcessRanges(0), m_NormGamutRegionMaxLim(NULL)
+{
+ m_whitepointLab.Set(-1, -1, -1);
+ m_whitepointXYZ_Strip.Set(-1, -1, -1);
+ m_WP.Set(-1, -1, -1);
+}
+
+Tango::ColorLib::ColorConverter::~ColorConverter()
+{
+ if (m_Conv02 != NULL)
+ {
+ delete m_Conv02;
+ m_Conv02 = NULL;
+ }
+ if (m_CalibCurves != NULL)
+ {
+ delete[] m_CalibCurves;
+ m_CalibCurves = NULL;
+ }
+ if(m_GradStops != NULL)
+ {
+ delete [] m_GradStops;
+ m_GradStops = NULL;
+ }
+ if (m_colortable != NULL)
+ {
+ delete m_colortable;
+ m_colortable = NULL;
+ }
+ if (m_NormGamutRegionMaxLim != NULL)
+ {
+ delete[] m_NormGamutRegionMaxLim;
+ m_NormGamutRegionMaxLim = NULL;
+ }
+ if (m_ProcessRangesMaxP != NULL)
+ {
+ delete[] m_ProcessRangesMaxP;
+ m_ProcessRangesMaxP = NULL;
+ }
+ /* if (m_ProcessRangesMinP != NULL)
+ {
+ delete[] m_ProcessRangesMinP;
+ m_ProcessRangesMinP = NULL;
+ }*/
+ /*if (m_ProcessRangesMaxInkUptake != NULL)
+ {
+ delete[] m_ProcessRangesMaxInkUptake;
+ m_ProcessRangesMaxInkUptake = NULL;
+ }
+ if (m_ProcessRangesMinInkUptake != NULL)
+ {
+ delete[] m_ProcessRangesMinInkUptake;
+ m_ProcessRangesMinInkUptake = NULL;
+ }*/
+ //_CrtDumpMemoryLeaks();
+}
+
+void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conversionInput, VectorXd Lab,
+ VectorXd RGB, VectorXd Volume, int InGamutRegion, MatrixXd &ORGBHive, MatrixXd &OLabHive,
+ MatrixXd &OVolumeHive, int nHive, int *&OGamutRegion, int *indDataMax)
+{
+ size_t retVal = 0;
+ ColorConvert ColConv(D65, D65);
+ SURROUND sur = m_Conv02->getSurround();
+ CAM02CS CS = m_Conv02->getCAM02CS();
+ VectorXd LabV(3);
+ LabV = Lab;
+
+ //LCH coordinates
+ double hue = 0.0;
+ double chroma = sqrt(Lab(1)*Lab(1) + Lab(2)*Lab(2));
+
+ if ((abs(Lab(1)) < eps) & (abs(Lab(2)) < eps))
+ hue = 0.0;
+ else
+ hue = atan2(Lab(2), Lab(1));
+
+ double d1 = dC;
+ double de = 0;
+ MatrixXd Lab1(nHive, 3);
+ for (int i = 0; i < 6; ++i)
+ {
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + dC * cos(i*dH6);
+ LabV(2) = Lab(2) + dC * sin(i*dH6);
+ //Iterate to get the correct dECMC
+ d1 = dC;
+ de = 0.0;
+ while (abs(de - dC) > 0.01)
+ {
+ ColConv.dEcmc(LabV, Lab, de);
+ d1 = dC * d1 / de;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + d1 * cos(i*dH6);
+ LabV(2) = Lab(2) + d1 * sin(i*dH6);
+ }
+ //fix
+ Lab1(i, 0) = LabV(0);
+ Lab1(i, 1) = Lab(1) + d1 * cos(i*dH6);
+ Lab1(i, 2) = Lab(2) + d1 * sin(i*dH6);
+ }
+
+ int j1 = 0, j2 = 0;
+ double dC2 = dC * 2.0;
+ for (int i = 0; i < 12; ++i)
+ {
+ j1 = i + 6;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + dC2 * cos(i*dH12);
+ LabV(2) = Lab(2) + dC2 * sin(i*dH12);
+ de = 0.0;
+ while (abs(de - dC2) > 0.01)
+ {
+ ColConv.SymmetricaldECMC(LabV, Lab, de);
+ d1 = dC2 * d1 / de;
+ LabV(0) = Lab(0);
+ LabV(1) = Lab(1) + d1 * cos(i*dH12);
+ LabV(2) = Lab(2) + d1 * sin(i*dH12);
+ }
+ //fix
+ Lab1(j1, 0) = LabV(0);
+ Lab1(j1, 1) = Lab(1) + d1 * cos(i*dH12);
+ Lab1(j1, 2) = Lab(2) + d1 * sin(i*dH12);
+ }
+
+ MatrixXd RGBTmpVec(nHive + 1, 3);
+ MatrixXd VolumeHive(nHive + 1, m_nVolumes);
+ MatrixXd LabHive(nHive + 1, 3);
+ VectorXd xyz(3);
+ C_RGB_XYZ_Lab xyzVal, LabVal;
+ double *tmpRGB = new double[3];
+ //double *tmpRGB = DBG_NEW double[3];
+ double *InkOut = new double[m_nInks];
+ //double *InkOut = DBG_NEW double[m_nInks];
+ int *GamutRegion = new int[nHive + 1];
+ //int *GamutRegion = DBG_NEW int[nHive + 1];
+ double *Lab1P = new double[3];
+ //double *Lab1P = DBG_NEW double[3];
+ VectorXd Vol(m_nVolumes);
+ int j = 0;
+ double * LabInFinal1 = new double[3];
+ //double * LabInFinal1 = DBG_NEW double[3];
+ double * LabInFinal2 = new double[3];
+ double * LabOnGamut = new double[3];
+ double *InkOutP = new double[m_nInks];
+ bool InGamut = true;
+ for (int i = 0; i < nHive; ++i)
+ {
+ //Get Lab's inGamut
+ for (j = 0; j < 3; ++j)
+ Lab1P[j] = Lab1(i, j);
+ //Check if whitepoints match
+/* if (m_AdaptWP)
+ {
+ //Convert to CT whitepoint
+ m_Conv02->ChangeWP(Lab1P, Lab1P, m_whitepointXYZ_CT, m_whitepointXYZ_Strip);
+ LimitLab(LabInFinal1);
+ }
+ */
+// ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_CT); //to Relative
+ ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_Strip); //to Relative
+ m_colortable->m_B2ATransform->evalLab2InkP(Lab1P, InkOut, GamutRegion[i]); //InkOut is in units of 16 bits
+ for (int i = 0; i <m_nInks; ++i)
+ {
+ InkOut[i] *= m_colortable->GetNormFactor();
+ if (InkOut[i] <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOut[i] * 655.35, InkOut[i]);
+ InkOut[i] /= 655.35;
+ }
+ }
+ InGamut = IsInGamut(Lab1P, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+ VectorXd NLInkOut(m_nInks);
+ ConvertToNLInks(DoubleToVector(InkOut, m_nInks), NLInkOut);
+
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+ //Output Volume is in %
+ LimitInks(NLInkOut, InkOutP);
+ NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Vol);
+ GamutRegion[i] = GetGamutRegion(Vol, m_ProcessRangesMaxP);
+ NLcmtoPercentage(Vol, Vol);
+ //m_A2BTransform->evalInkP2Lab(InkOut, Lab1P, GamutRegion[i]);
+
+ //Convert to CT WP
+// m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_CT, m_WP); //convert back to Absolute
+ m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_Strip, m_WP); //convert back to Absolute
+ LimitLab(LabInFinal1); //Absolute
+
+ //Check if whitepoints match
+/* if (m_AdaptWP)
+ {
+ //Convert to Strip whitepoint
+ m_Conv02->ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_Strip, m_whitepointXYZ_CT);
+ LimitLab(LabInFinal1);
+ }*/
+ m_Conv02->SetReferenceWhite(D65);
+ for (int j = 0; j < 3; ++j)
+ LabHive(i, j) = LabInFinal1[j];
+
+ //Convert to RGB, relative col is converted
+ m_Conv02->LabtoRGB(LabOnGamut, tmpRGB);
+ //m_Conv02->LabtoRGB(Lab1P, tmpRGB);
+ for (int j = 0; j < 3; ++j)
+ RGBTmpVec(i, j) = std::min(std::max(tmpRGB[j], 0.0), 255.0);
+
+ //make sure the rounded sum does not exceed the limit in the gamut region
+ for (int j = 0; j < m_nInks; ++j)
+ VolumeHive(i, j) = Vol(j);
+ }
+ for (int i = 0; i < 1; ++i)
+ {
+ for (j = 0; j < m_nInks; ++j)
+ VolumeHive(nHive + i, j) = Volume(j);
+ for (j = 0; j < 3; ++j)
+ {
+ RGBTmpVec(nHive + i, j) = RGB(j);
+ LabHive(nHive + i, j) = Lab(j);
+ }
+ GamutRegion[nHive + i] = InGamutRegion;
+ }
+
+ //Organize hive into 5x5 matrix
+ //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),....,
+ //22-(4,2), 23-(4,3), 24-(4,4) not implemented yet
+ //Some of the matrix elements are empty
+ VectorXd xpos(nHive + 1);
+ xpos << 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 1, 2, 3, 3, 4, 3, 3, 2, /*, 5, 5, 5, 5, 5,*/ 2;
+ VectorXd ypos(nHive + 1);
+ ypos << 3, 2, 1, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4,/* 0, 1, 3, 4, 2,*/ 2;
+ ArrangeHiveData(LabHive, RGBTmpVec, VolumeHive, GamutRegion, xpos, ypos, nHive,
+ OLabHive, ORGBHive, OVolumeHive, OGamutRegion);
+ FindTriplet(Lab, Lab1, nHive, indDataMax);
+ indDataMax[0] = (int)(xpos(indDataMax[0]) * 5 + ypos(indDataMax[0]));
+ indDataMax[1] = (int)(xpos(indDataMax[1]) * 5 + ypos(indDataMax[1]));
+
+ if (LabOnGamut != NULL)
+ {
+ delete[]LabOnGamut;
+ LabOnGamut = NULL;
+ }
+ if (InkOut != NULL)
+ {
+ delete[]InkOut;
+ InkOut = NULL;
+ }
+ if (GamutRegion != NULL)
+ {
+ delete[] GamutRegion;
+ GamutRegion = NULL;
+ }
+ if (Lab1P != NULL)
+ {
+ delete[] Lab1P;
+ Lab1P = NULL;
+ }
+ if (tmpRGB != NULL)
+ {
+ delete[] tmpRGB;
+ tmpRGB = NULL;
+ }
+ if (LabInFinal2 != NULL)
+ {
+ delete[]LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ if (LabInFinal1 != NULL)
+ {
+ delete[]LabInFinal1;
+ LabInFinal1 = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::FindTriplet(VectorXd Lab, MatrixXd Lab1, int nHive, int*indDataMax)
+{
+
+ int vecSize = nHive * (nHive - 1) / 2;
+ double *dECMC = new double[vecSize];
+ //double *dECMC = DBG_NEW double[vecSize];
+ int i, j;
+ for (i = 0; i < vecSize; ++i)
+ dECMC[i] = -1;
+ int **indexpairs = new int*[vecSize];
+ //int **indexpairs = DBG_NEW int*[vecSize];
+ for (i = 0; i < vecSize; ++i)
+ {
+ indexpairs[i] = new int[2];
+ for (int j = 0; j < 2; ++j)
+ indexpairs[i][j] = 0;
+ }
+ //indexpairs[i] = DBG_NEW int[2];
+
+ int ind = -1;
+ ColorConvert ColConv(D65, D65);
+ VectorXd Labi(3);
+ VectorXd Labj(3);
+
+ for (i = 0; i < nHive; ++i)
+ {
+ Labi << Lab1(i, 0), Lab1(i, 1), Lab1(i, 2);
+ for (j = i + 1; j < nHive; ++j)
+ {
+ Labj << Lab1(j, 0), Lab1(j, 1), Lab1(j, 2);
+ ind++;
+ ColConv.SymmetricaldECMC(Labi, Labj, dECMC[ind]);
+ indexpairs[ind][0] = i;
+ indexpairs[ind][1] = j;
+ }
+ }
+ double maxdE = dECMC[0];
+ int maxInd = 0;
+ for (int i = 1; i < vecSize; ++i)
+ {
+ if ((maxdE < dECMC[i]) && (dECMC[i] < 5))
+ {
+ maxdE = dECMC[i];
+ maxInd = i;
+ }
+ }
+ indDataMax[0] = indexpairs[maxInd][0];
+ indDataMax[1] = indexpairs[maxInd][1];
+ if (dECMC != NULL)
+ {
+ delete[]dECMC;
+ dECMC = NULL;
+ }
+
+ if (indexpairs != NULL)
+ {
+ for (int i = 0; i < vecSize; ++i)
+ delete[] indexpairs[i];
+ delete[] indexpairs;
+ indexpairs = NULL;
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::ArrangeHiveData(MatrixXd LabHive, MatrixXd RGBTmpVec, MatrixXd VolumeHive, int *GamutRegion,
+ VectorXd xpos, VectorXd ypos, int nHive, MatrixXd &OLabHive, MatrixXd &RGBHive, MatrixXd &OVolumeHive, int *&OGamutRegion)
+{
+ //Hive Vector follows the ordering 0-(0,0) 1-(0,1) 2-(0,2),...., 22-(4,2), 23-(4,3), 24-(4,4)
+ //Some of the matrix elements are empty
+ //Ordering is by hexagon position in a 5x5 grid.
+
+ //VectorXd xpos(nHive + 1);
+ //xpos << 1, 1, 1, 2, 3, 2, 1, 0, 0, 0, 1, 2, 3, 3, 4, 3, 3, 2, /*, 5, 5, 5, 5, 5,*/ 2;
+ //VectorXd ypos(nHive + 1);
+ //ypos << 3, 2, 1, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4,/* 0, 1, 3, 4, 2,*/ 2;
+ int i, j;
+ for (i = 0; i < nHive + 1; ++i)
+ {
+ int index = (int)(xpos(i) * 5 + ypos(i));
+ for (j = 0; j < 3; ++j)
+ OLabHive(index, j) = LabHive(i, j);
+
+ for (j = 0; j < 3; ++j)
+ RGBHive(index, j) = RGBTmpVec(i, j);
+
+ for (j = 0; j < m_nVolumes; ++j)
+ OVolumeHive(index, j) = VolumeHive(i, j);
+
+ OGamutRegion[index] = GamutRegion[i];
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::fillVolume(OutputCoordinates *&outputCoords, VectorXd Volume)
+{
+ int i = 0;
+ OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * m_nVolumes);
+ for (i = 0; i < m_nVolumes; ++i)
+ {
+ // *outputLiquids[0] = OUTPUT_LIQUID__INIT;
+ outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid));
+ output_liquid__init(outputLiquids[i]);
+ switch (m_CalibCurves[i].getInkName())
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ {
+ outputLiquids[i]->has_volume = true;
+ outputLiquids[i]->has_liquidtype = true;
+ outputLiquids[i]->liquidtype = (LiquidType)(m_CalibCurves[i].getInkName());
+ outputLiquids[i]->volume = Volume(i);
+ break;
+ }
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ outputCoords->outputliquids = outputLiquids;
+ outputCoords->n_outputliquids = m_nVolumes;
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::fillRGB(OutputCoordinates *outputCoords, VectorXd RGBOut)
+{
+ outputCoords->has_red = true;
+ outputCoords->red = (int32_t)std::round(RGBOut(0));
+ outputCoords->has_green = true;
+ outputCoords->green = (int32_t)std::round(RGBOut(1));
+ outputCoords->has_blue = true;
+ outputCoords->blue = (int32_t)std::round(RGBOut(2));
+}
+
+void Tango::ColorLib::ColorConverter::fillLab(OutputCoordinates *outputCoords, VectorXd LabOut)
+{
+ outputCoords->has_l = true;
+ outputCoords->l = LabOut(0);
+ outputCoords->has_a = true;
+ outputCoords->a = LabOut(1);
+ outputCoords->has_b = true;
+ outputCoords->b = LabOut(2);
+}
+void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* conversionInput)
+{
+ SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb);
+ bool has_forwarddata = conversionInput->has_forwarddata;
+ uint8_t *data = conversionInput->forwarddata.data;
+ int nprocessranges = conversionInput->n_processranges;
+ m_colortable->InitColorTables(has_forwarddata, data, nprocessranges);
+ SetNumberofInks(m_colortable->GetnA2BnSepOut());
+}
+
+void Tango::ColorLib::ColorConverter::SetStripWhitepoint(double threadl, double threada, double threadb)
+{
+ //Read thread white. Thread White is given in CIELab Space
+ m_whitepointLab.Set(threadl, threada, threadb);
+ //White point in XYZ Color Space
+ ColorConvert CConvert(D65, D65);
+ C_RGB_XYZ_Lab tmpW;
+ tmpW = CConvert.LabToXYZ(m_whitepointLab);
+ m_whitepointXYZ_Strip.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z());
+}
+
+
+
+void Tango::ColorLib::ColorConverter::readCalibrationTables(InputLiquid **inputliquid, int n_inputliquid)
+{
+ SetNumberofInks((int)(n_inputliquid));
+ //CalibData *CalibCurves = new CalibData[m_nInks];
+ if(m_CalibCurves == NULL)
+ m_CalibCurves = new CalibData[m_nInks];
+ //m_CalibCurves = DBG_NEW CalibData[m_nInks];
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InputLiquid* InkType = inputliquid[i];
+
+ m_CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype));
+
+ m_CalibCurves[i].SetMaxNlPerCM(inputliquid[i]->maxnanoliterpercentimeter);
+ switch (InkType->calibrationdata->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ {
+ // calibration data.
+ CalibrationData* calibrationData = InkType->calibrationdata;
+ SetCalibData(calibrationData, i, &m_CalibCurves[i]);
+ m_CalibCurves[i].InitInterpolations();
+ break;
+ }
+ default:
+ {
+ throw std::exception("could not fill all calibration tables");
+ return;
+ }
+ }
+ }
+ return;
+}
+
+
+void Tango::ColorLib::ColorConverter::SetCalibData(CalibrationData *calibrationData, int i, CalibData *tmpCurve)
+{
+ if (calibrationData->calibrationpoints <= 0)
+ {
+ char msg[100];
+ int n =
+ strcpy_s(msg, 100, "No Calibration points in table ");
+
+ throw std::exception(msg);
+ return;
+ }
+
+ tmpCurve->SetCalibCurveSize((int)(calibrationData->n_calibrationpoints));
+ //Iterate over calibration points..
+ double *pointsx = new double[calibrationData->n_calibrationpoints];
+ double *pointsy = new double[calibrationData->n_calibrationpoints];
+ //double *pointsx = DBG_NEW double[calibrationData->n_calibrationpoints];
+ //double *pointsy = DBG_NEW double[calibrationData->n_calibrationpoints];
+ for (size_t j = 0; j < calibrationData->n_calibrationpoints; ++j)
+ {
+ //Calibration Point
+ pointsx[j] = calibrationData->calibrationpoints[j]->x;
+ pointsy[j] = calibrationData->calibrationpoints[j]->y;
+ }
+ tmpCurve->SetXCoords(pointsx);
+ tmpCurve->SetYCoords(pointsy);
+ if (pointsx != NULL)
+ {
+ delete[] pointsx;
+ pointsx = NULL;
+ }
+
+ if (pointsy != NULL)
+ {
+ delete[] pointsy;
+ pointsy = NULL;
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter:: ConvertLabColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ // Basic assumption: Lab data has the same whitepoint as the STRIP thread.
+ //The workflow is a follows:
+ //1. Convert Lab to Relative colorimetric. check if there is a match between STRIP and Color Tables
+ //2. Convert Lab to Inks (B2A tables), Inks to Volume
+ //3. Map the Lab value onto the gamut surface, if it is out of gamut
+ //4. Convert Lab to Absolute colorimetric taking into account the Strip and CT whitepoints
+ //5. Use the Relative Colorimetric Lab to obtain RGB
+ double *LabIn = new double[3];
+ //double *LabIn = DBG_NEW double[3];
+ LabIn[0] = inputcoordinates->l; //Absolute Colorimetric
+ LabIn[1] = inputcoordinates->a;
+ LabIn[2] = inputcoordinates->b;
+ //the assumption is that the color space has illumination that matches the whitepoint of the Strip
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ // double *LabInFinal1 = new double[3];
+ //double *LabInFinal1 = DBG_NEW double[3];
+ // for (int i = 0; i < 3; ++i)
+ // LabInFinal1[i] = LabIn[i];
+ //LabInFinal1 = LabIn;
+ // Lab is assumed to match the color of the STRIP, however the tables could have a different WP
+ //Check if Color Tables and Strip whitepoints are the same, otherwise convert
+/*
+if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables
+ for (int i = 0; i < 3; ++i)
+ LabIn[i] = LabInFinal1[i];
+ }
+ */
+ double *LabInFinal2 = new double[3];
+ double *LabOnGamut = new double[3];
+ //double *LabInFinal2 = DBG_NEW double[3];
+ // CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //LabInFinal2 is in Relative Colorimetric Space
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //LabInFinal2 is in Relative Colorimetric Space
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+
+ //convert to Inks
+ double *InkOutP = new double[m_nInks];
+ //double *InkOutP = DBG_NEW double[m_nB2AnSepOut];
+ m_colortable->m_B2ATransform->evalLab2InkP(LabOnGamut, InkOutP, GamutRegion); //InkOut is in units of 16 bits
+ //Convert Inks to Lab to get the Gamut Mapped Lab
+//m_A2BTransform->evalInkP2Lab(InkOutP, LabIn, GamutRegion);
+//LabOut = DoubleToVector(LabIn, 3);
+//Convert InkOutP to linear in the m_GamutRegionMaxLim[0] range
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InkOutP[i] *= m_colortable->GetNormFactor();
+ if (InkOutP[i] <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]);
+ InkOutP[i] /= 655.35;
+ }
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ double *LabOutFinal = new double[3];
+ //double *LabOutFinal = DBG_NEW double[3];
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal[i] = LabOnGamut[i];
+ //LabOutFinal is in Relative Colorimetric
+ //Reverse the conversion process to bring back Lab to STRIP white point
+ // CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_CT, m_WP);
+ CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_WP);
+/*
+ if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT);
+ }
+ */
+ LabOut = DoubleToVector(LabOutFinal, 3);
+ CConvertD65.SetReferenceWhite(D65);
+ //Convert to RGB
+ double *RGBOutP = new double[3];
+ // double *RGBOutP = DBG_NEW double[3];
+ //Use Relative colorimetric to get RGB
+ CConvertD65.LabtoRGBNoClip(LabOnGamut, RGBOutP);
+ //CConvertD65.LabtoRGB(LabIn, RGBOutP);
+ RGBOut = DoubleToVector(RGBOutP, 3);
+ if (LabOnGamut != NULL)
+ {
+ delete[] LabOnGamut;
+ LabOnGamut = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ /* if (LabInFinal1 != NULL)
+ {
+ delete[]LabInFinal1;
+ LabInFinal1 = NULL;
+ }
+ */
+ if (LabInFinal2 != NULL)
+ {
+ delete[]LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ if (LabOutFinal != NULL)
+ {
+ delete[]LabOutFinal;
+ LabOutFinal = NULL;
+ }
+
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::ConvertRGBColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric,
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread, but will be shown in Relative Colorimetric to the user
+ //The workflow is a follows:
+ //1. Convert RGB to Lab (Whitepoint is D65, same as tables)
+ //2. Convert Lab to Inks (B2A tables), Inks to Volume
+ //3. Convert Inks to Lab (A2B tables) to get the in/on Gamut Lab
+ //4. Convert Lab to Absolute colorimetric taking into account the Strip and Color Table whitepoints
+ //5. Use the Relative Colorimetric Lab to obtain RGB
+
+ RGBOut(0) = inputcoordinates->red;
+ RGBOut(1) = inputcoordinates->green;
+ RGBOut(2) = inputcoordinates->blue;
+ //convert to Lab
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ double *LabIn = new double[3];
+ double *RGBOutP = new double[3];
+ //double *LabIn = DBG_NEW double[3];
+ //double *RGBOutP = DBG_NEW double[3];
+ VectorToDouble(RGBOut, RGBOutP);
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65
+ LimitLab(LabIn);
+ //Is In Gamut?
+ double *LabInFinal = new double[3];
+ double *LabOnGamut = new double[3];
+ InGamut = IsInGamut(LabIn, sur, CS, LabOnGamut);
+ LimitLab(LabOnGamut);
+
+ //convert to inks
+
+ double *InkOutP = new double[m_nInks];
+ //double *InkOutP = DBG_NEW double[m_nB2AnSepOut];
+ //LabInFinal is in Relative Colorimetric, just like the Color Tables
+ m_colortable->m_B2ATransform->evalLab2InkP(LabOnGamut, InkOutP, GamutRegion); //InkOut is inthe [0-100] interval
+
+ //Convert to Lab to get the actual in Gamut Lab
+ //double *LabInP = new double[3];
+ //double *LabInP = DBG_NEW double[3];
+ //m_A2BTransform->evalInkP2Lab(InkOutP, LabInP, GamutRegion); //Lab is in Relative Colorimetric
+ //Convert InkOut to Linear via initial calibration Tables
+ //Initial calibration tables are the ones that were included in the color table
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InkOutP[i] *= m_colortable->GetNormFactor();
+ if (InkOutP[i] <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]);
+ InkOutP[i] /= 655.35;
+ }
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+
+ //Convert to CT thread, LabOnGamut is in Relative Colorimetric Space
+ //CConvertD65.ChangeWP(LabOnGamut, LabInFinal, m_whitepointXYZ_CT, m_WP);
+ CConvertD65.ChangeWP(LabOnGamut, LabInFinal, m_whitepointXYZ_Strip, m_WP);
+ //check if the thread to be used is the same as the one in the color tables
+/*
+ if (m_AdaptWP)
+ {
+ //Convert to Strip White Point
+ CConvertD65.ChangeWP(LabInFinal, LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT);
+ }
+ */
+ LabOut = DoubleToVector(LabInFinal, 3);
+ CConvertD65.SetReferenceWhite(D65);
+ double *RGBOutP1 = new double[3];
+ //double *RGBOutP1 = DBG_NEW double[3];
+ CConvertD65.LabtoRGBNoClip(LabOnGamut, RGBOutP1);
+ //CConvertD65.LabtoRGB(LabInP, RGBOutP1);
+ RGBOut = DoubleToVector(RGBOutP1, 3);
+ if (LabOnGamut != NULL)
+ {
+ delete[] LabOnGamut;
+ LabOnGamut = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ if (RGBOutP1 != NULL)
+ {
+ delete[] RGBOutP1;
+ RGBOutP1 = NULL;
+ }
+ if (LabInFinal != NULL)
+ {
+ delete[] LabInFinal;
+ LabInFinal = NULL;
+ }
+ }
+
+void Tango::ColorLib::ColorConverter::ConvertCMYKColorToLinearInks(InputCoordinates* inputcoordinates,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut, SURROUND sur, CAM02CS CS)
+{
+ //no conversion
+ //missing from structure light inks or special colors
+ // just convert Lab for rgb display
+
+ double *outData = new double[m_nInks];
+ //double *outData = DBG_NEW double[m_nA2BnSepIn];
+ size_t CountSep = 0;
+ outData[0] = (double)(inputcoordinates->cyan);
+ outData[1] = (double)(inputcoordinates->magenta);
+ outData[2] = (double)(inputcoordinates->yellow);
+ outData[3] = (double)(inputcoordinates->key);
+ CountSep = 4;
+
+ if (CountSep != m_nInks)
+ {
+ //mismatch between table and sent data
+ throw std::exception("Mismatch between table and sent data");
+ return;
+ }
+ //Convert to RGB
+ double *InkOutP = new double[m_nInks];
+ //double *InkOutP = DBG_NEW double[m_nA2BnSepIn];
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] = outData[i];
+ double *LabOutP = new double[3];
+ //double *LabOutP = DBG_NEW double[3];
+ m_colortable->m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion);
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+ //LabOut is in relative colorimetric
+ ColorConvert CConvertD65(D65, D65);
+ double *LabOutFinal1 = new double[3];
+ //double *LabOutFinal1 = DBG_NEW double[3];
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal1[i] = LabOutP[i];
+ double *LabOutFinal2 = new double[3];
+ //double *LabOutFinal2 = DBG_NEW double[3];
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal2[i] = LabOutP[i];
+ InGamut = true;
+ //Check if white points match
+// CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute
+ CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_Strip, m_WP); //To Absolute
+/* if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal2, m_whitepointXYZ_Strip, m_whitepointXYZ_CT);
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal1[i] = LabOutFinal2[i];
+ }
+ */
+ LabOut = DoubleToVector(LabOutFinal1, 3);
+ CConvertD65.SetReferenceWhite(D65);
+ //Get RGB
+ double *RGBOutP = new double[3];
+ //double *RGBOutP = DBG_NEW double[3];
+ CConvertD65.LabtoRGB(LabOutP, RGBOutP);
+ //CConvertD65.LabtoRGB(LabOutP, RGBOutP);
+ RGBOut = DoubleToVector(RGBOutP, 3);
+
+ if (outData != NULL)
+ {
+ delete[] outData;
+ outData = NULL;
+ }
+ if (LabOutP != NULL)
+ {
+ delete[] LabOutP;
+ LabOutP = NULL;
+ }
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ if (LabOutFinal1 != NULL)
+ {
+ delete[] LabOutFinal1;
+ LabOutFinal1 = NULL;
+ }
+ if (LabOutFinal2 != NULL)
+ {
+ delete[] LabOutFinal2;
+ LabOutFinal2 = NULL;
+ }
+}
+void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &InkOut, VectorXd &RGBOut,
+ VectorXd &LabOut, int &GamutRegion, bool &InGamut)
+{
+ size_t nInks = 0;
+
+ C_RGB_XYZ_Lab DataLab;
+ SURROUND sur = m_Conv02->getSurround();
+ CAM02CS CS = m_Conv02->getCAM02CS();
+ switch (colorspace)
+ {
+ case (COLOR_SPACE__RGB):
+ {
+ ConvertRGBColorToLinearInks(inputcoordinates,
+ InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+ break;
+ }
+ case (COLOR_SPACE__LAB):
+ {
+ ConvertLabColorToLinearInks(inputcoordinates,
+ InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+ break;
+ }
+
+ case(COLOR_SPACE__CMYK):
+ {
+ ConvertCMYKColorToLinearInks(inputcoordinates,
+ InkOut, RGBOut, LabOut, GamutRegion, InGamut, sur, CS);
+
+ break;
+ }
+ case(COLOR_SPACE__Catalog):
+ {
+ int32_t inData;
+ if (inputcoordinates->has_pantoncode)
+ inData = inputcoordinates->pantoncode;
+ else
+ {
+ //mismatch between color space and data
+ throw std::exception("Mismatch between color space and data");
+ return;
+ }
+ break;
+ //missing calculation method and pantone table, either in terms of RGB or CMY or Lab
+ }
+
+ default:
+ {
+ throw std::exception(" Unsupported Color Space");
+ break;
+ }
+ }
+ //all data is now in linear ink format
+ return;
+}
+
+
+void Tango::ColorLib::ColorConverter::ConvertToNLInks(VectorXd InkIn, VectorXd &InkOut)
+{
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ if (InkIn(i) <= m_NormGamutRegionMaxLim[0])
+ m_CalibCurves[i].m_InvLinearInterp->Eval(InkIn(i), InkOut(i));
+ else
+ InkOut(i) = InkIn(i);
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::ConvertToLinearInks(VectorXd InkIn, VectorXd &InkOut)
+{
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ m_CalibCurves[i].m_LinearInterp->Eval(InkIn(i), InkOut(i));
+ }
+
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::VolumeToNLInkP(VectorXd Volume, VectorXd &NLInkP)
+{
+ //Volume is in %. In order to be compatible with NL to volume it has to be tranlated to nl/cm
+ VectorXd InkP(m_nVolumes);
+ int MaxInd = -1;
+ double InkMax = -1.;
+ double InkSum = 0.;
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ InkP(i) = Volume(i)* m_maxNlPerCM(i)/100; //Volume is in %, InkP is in [nl/cm]
+ if (InkMax < InkP(i))
+ {
+ InkMax = InkP(i);
+ MaxInd = i;
+ }
+ InkSum += InkP(i);
+ }
+ NLInkP(MaxInd) =100* InkSum/ m_maxNlPerCM(MaxInd); //Back to %
+ if (InkSum == 0.0)
+ {
+ for (int i = 0; i < m_nVolumes; ++i)
+ NLInkP(i) = 0.0;
+ return;
+ }
+
+ //Prepare Matrix to get the remainder values
+ MatrixXd MatNLI(m_nVolumes - 1, m_nVolumes - 1);
+ VectorXd RHSide(m_nVolumes - 1);
+ MatrixXd DiagMat(m_nVolumes - 1, m_nVolumes - 1);
+ DiagMat.setZero();
+ int ind = -1;
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ if (i != MaxInd)
+ {
+ ind += 1;
+ RHSide(ind) = InkP(i);
+ DiagMat(ind, ind) = -InkSum;
+ }
+ }
+ for (int i = 0; i < m_nVolumes - 1; ++i)
+ {
+ for (int j = 0; j < m_nVolumes - 1; ++j)
+ {
+ MatNLI(i, j) = RHSide(i) + DiagMat(i, j);
+ }
+ RHSide(i) *= (-InkSum);
+ }
+ //Solve System of Linear Equations
+ MatrixXd MatNLIInv(m_nVolumes - 1, m_nVolumes - 1);
+ MatNLIInv = MatNLI.inverse();
+ VectorXd Result = MatNLIInv * RHSide;
+ //VectorXd Result = MatNLI.colPivHouseholderQr().solve(RHSide);
+ //rearrange solution
+ ind = -1;
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ if (i != MaxInd)
+ {
+ ind += 1;
+ NLInkP(i) =100* Result(ind)/m_maxNlPerCM(i); //Back to %
+ }
+ }
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::NLInkPToVolume(VectorXd NLInk, VectorXd &Volume)
+{
+ //Max Ink Component
+ double MaxInk = -1.;
+ VectorXd InkNorm(m_nInks);
+ double InkSum = 0;
+ int i = 0;
+ for (i = 0; i < m_nInks; ++i)
+ {
+ MaxInk = std::max(MaxInk, NLInk(i));
+ InkSum += NLInk(i);
+ }
+
+ if (MaxInk == 0)
+ for (i = 0; i < m_nInks; ++i)
+ Volume(i) = 0.0;
+ else
+ {
+ for (i = 0; i < m_nInks; ++i)
+ {
+ InkNorm(i) = MaxInk * NLInk(i) / InkSum;
+ Volume(i) = InkNorm(i); // InkNorm(i) * m_maxNlPerCM(i) / 100; // Volume is in %
+ }
+ // Round to k decimal digits, verify that sum in within allowed values.
+ double sumNorm = 0.0;
+ double RsumNorm = 0.0;
+ VectorXd RVolNorm(m_nInks);
+ double ROUNDINGTol = pow(10, ROUNDINGDigits);
+
+ for (i = 0; i < m_nInks; ++i)
+ {
+ sumNorm += Volume(i);
+ RVolNorm(i) = round(Volume(i)*ROUNDINGTol) / ROUNDINGTol;
+ RsumNorm += RVolNorm(i);
+ }
+ if (RsumNorm > m_NormGamutRegionMaxLim[m_nProcessRanges - 1] || abs(sumNorm - RsumNorm) >= 1 / ROUNDINGTol)
+ {
+ VectorXd dd(m_nInks);
+ double maxdd = -1;
+ int maxInd = -1;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ dd(i) = Volume(i) - RVolNorm(i);
+ if (abs(dd(i)) > maxdd)
+ {
+ maxdd = abs(dd(i));
+ maxInd = i;
+ }
+ }
+ int signdd = 0;
+ if (dd(maxInd) > 0)
+ signdd = 1;
+ else if (dd(maxInd) < 0)
+ signdd = -1;
+ else
+ signdd = 0;
+ RVolNorm(maxInd) = RVolNorm(maxInd) + signdd / ROUNDINGTol;
+ }
+ for (int i = 0; i < m_nInks; ++i)
+ Volume(i) = RVolNorm(i);
+ }
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (Volume(i) < LowVolHalf)
+ Volume(i) = 0;
+ else if (Volume(i) >= LowVolHalf && Volume(i) <= LowVolumeThreshold)
+ Volume(i) = LowVolumeThreshold;
+ }
+
+ /* int countBelowThresh=0;
+ int *indBelowThresh= new int[m_nInks];
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (Volume(i) < LowVolumeThreshold)
+ {
+ countBelowThresh++;
+ indBelowThresh[i] = i;
+ }
+ }
+ if (countBelowThresh == 0)
+ {
+ delete[] indBelowThresh;
+ indBelowThresh = NULL;
+ }
+ else
+ {
+ int pow2ThCount = pow(2, countBelowThresh);
+ double **THTable = new double*[pow2ThCount];
+ for (int i = 0; i < pow2ThCount; ++i)
+ THTable[i] = new double[m_nInks];
+ for (int j = 0; j < pow2ThCount; ++j)
+ for (int i = 0; i < m_nInks; ++i)
+ THTable[j][i] = Volume(i);
+
+ int indC = -1;
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ for (int j = 0; j < countBelowThresh; ++i)
+ {
+ indC = indC + 1;
+ THTable[indC][i] = 0;
+ indC = indC + 1;
+ THTable[indC][i] = LowVolumeThreshold;
+ }
+ }
+ //Calculate dE between NLInk and THTable converted to NLInk
+ //Choose the value with the smallest dE
+ VectorXd VolumeTh(m_nInks);
+ VectorXd NLInksTh(m_nInks);
+ for (int j = 0; j < pow2ThCount; ++j)
+ {
+ for (int j = 0; j < m_nInks; ++j)
+ VolumeTh(j) = THTable[j][i];
+ VolumeToNLInkP(VolumeTh, NLInksTh);
+
+
+ }
+
+ }*/
+
+ return;
+}
+
+void Tango::ColorLib::ColorConverter::SetMaxNLperCM(double maxNlPerCM, int i)
+{
+ m_maxNlPerCM(i) = maxNlPerCM;
+}
+
+void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates *inputcoordinates, int n_processRanges,
+ int colorspace, VectorXd &Volume, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion)
+{
+ SetNumberOfVolumes((int)(inputcoordinates->n_inputliquids));
+ // Set Calibration Data
+ LiquidType LQ;
+ if (m_CalibCurves == NULL)
+ {
+ m_CalibCurves = new CalibData[m_nInks];
+ //m_CalibCurves = DBG_NEW CalibData[m_nInks];
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ LQ =inputcoordinates->inputliquids[i]->calibrationdata->liquidtype;
+ if (LQ == LIQUID_TYPE__Cyan || LQ == LIQUID_TYPE__Magenta || LQ == LIQUID_TYPE__Yellow || LQ == LIQUID_TYPE__Black)
+ {
+ //Get calibration data.
+ CalibrationData* calibrationData = inputcoordinates->inputliquids[i]->calibrationdata;
+ SetCalibData(calibrationData, i, &m_CalibCurves[i]);
+ SetMaxNLperCM(inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter, i);
+ m_CalibCurves[i].SetCalibName((int)(inputcoordinates->inputliquids[i]->calibrationdata->liquidtype));
+ }
+ else
+ std::exception("unsupported volume");
+ }
+ }
+
+ //July 29 2020
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+ VectorXd NLInkP((int)(m_nVolumes));
+ VectorXd InkOut((int)(m_nVolumes));
+ //Convert to Nonlinear Inks
+ double SumVol_Ink = 0.0;
+ //Get Gamut Region
+ for (int i = 0; i < m_nVolumes; ++i)
+ Volume(i) = inputcoordinates->inputliquids[i]->volume; //volume is given in %
+
+ GamutRegion = GetGamutRegion(Volume, m_NormGamutRegionMaxLim);
+ VolumeToNLInkP(Volume, NLInkP);
+ //Limit Inks
+ double *InkOutP = new double[m_nInks];
+ VectorToDouble(NLInkP, InkOutP);
+ //for (int i = 0; i < m_nA2BnSepIn; ++i)
+ // InkOutP[i] = NLInkP(i);
+ double *LinInkP = new double[m_nInks];
+//Reflect the Calibration Curves of the thread in Catalog Items
+ if (colorspace == COLOR_SPACE__Catalog)
+ {
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ if (NLInkP(i) <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]);
+ InkOutP[i] /= 655.35;
+ NLInkP(i) = InkOutP[i];
+ }
+
+ }
+ for (int i = 0; i < (int)(m_nVolumes); ++i)
+ {
+ if (NLInkP(i) <= m_NormGamutRegionMaxLim[0])
+ {
+ m_CalibCurves[i].m_InvLinearInterp->Eval(InkOutP[i], InkOutP[i]);
+ NLInkP(i) = InkOutP[i];
+ }
+ }
+ //NLInkPToVolume(NLInkP, Volume);
+ }
+
+ //July 29 2020
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+ //Output Volume is in %
+ LimitInks(NLInkP, InkOutP);
+ NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Volume);
+ GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP);
+ NLcmtoPercentage(Volume, Volume);
+
+ //Convert to RGB
+ //GamutRegion = 0;
+ //Convert to Lab
+
+ double *LabOutP = new double[3];
+ //double *InkOutP = DBG_NEW double[m_nA2BnSepIn];
+ //double *LabOutP = DBG_NEW double[m_nA2BnSepOut];
+ //InkOutP has to be normalized to match the transform units
+ for (int i = 0; i < m_nInks; ++i)
+ InkOutP[i] *= m_colortable->GetInverseNormFactor();
+
+ m_colortable->m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion);
+ //LabOutP is in Relative Colorimetric
+ ColorConvert CConvertD65(D65, D65);
+ double *LabOutFinal1 = new double[3];
+ //double *LabOutFinal1 = DBG_NEW double[3];
+ double *LabOutFinal = new double[3];
+
+ //CConvertD65.ChangeWP(LabOutP, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute
+ CConvertD65.ChangeWP(LabOutP, LabOutFinal1, m_whitepointXYZ_Strip, m_WP); //To Absolute
+ for (int i = 0; i < 3; ++i)
+ LabOutFinal[i] = LabOutFinal1[i];
+
+/*
+ if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT);
+ }
+ */
+ LabOut = DoubleToVector(LabOutFinal, 3);
+
+ CConvertD65.SetReferenceWhite(D65);
+ double *RGBOutP = new double[3];
+ //double *RGBOutP = DBG_NEW double[3];
+ CConvertD65.LabtoRGB(LabOutP, RGBOutP);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ RGBOut(i) = RGBOutP[i];
+ }
+ if (InkOutP != NULL)
+ {
+ delete[]InkOutP;
+ InkOutP = NULL;
+ }
+ if (LinInkP != NULL)
+ {
+ delete[]LinInkP;
+ LinInkP = NULL;
+ }
+ if (LabOutP != NULL)
+ {
+ delete[] LabOutP;
+ LabOutP = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ if (LabOutFinal1 != NULL)
+ {
+ delete[] LabOutFinal1;
+ LabOutFinal1 = NULL;
+ }
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+ return;
+
+}
+
+void Tango::ColorLib::ColorConverter::VectorToDouble(VectorXd VecIn, double * doubOut)
+{
+ int nSize = VecIn.size();
+ for (int i = 0; i < nSize; ++i)
+ doubOut[i] = VecIn(i);
+}
+
+VectorXd Tango::ColorLib::ColorConverter::DoubleToVector(double *doub, int nSize)
+{
+ VectorXd Vec(nSize);
+ for (int i = 0; i < nSize; ++i)
+ Vec(i) = doub[i];
+ return(Vec);
+}
+
+void Tango::ColorLib::ColorConverter::LimitLab(double* LabIn)
+{
+ LabIn[0] = std::min(std::max(LabIn[0], 0.0), 100.0);
+ LabIn[1] = std::min(std::max(LabIn[1], -128.0), 127.0);
+ LabIn[2] = std::min(std::max(LabIn[2], -128.0), 127.0);
+ return;
+}
+
+size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+
+ ConversionInput* conversionInput = NULL;
+ InputLiquid** original_input_liquids = NULL;
+ int original_input_liquids_count = 0;
+
+ try
+ {
+ //Get Input
+ conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+
+ int numofInks = CountNumberofInks(conversionInput);
+ if (numofInks < 0)
+ throw std::exception("Duplicate inks");
+ int expected_liquids = numofInks;
+ original_input_liquids_count = conversionInput->inputcoordinates->n_inputliquids;
+ original_input_liquids = conversionInput->inputcoordinates->inputliquids;
+
+ InputLiquid** filteredInputLiquids = (InputLiquid**)malloc(sizeof(InputLiquid*) * expected_liquids);
+
+ for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+ {
+ InputLiquid* liquid = conversionInput->inputcoordinates->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ break;
+ case LIQUID_TYPE__Black:
+ filteredInputLiquids[3] = liquid;
+ break;
+ }
+ }
+
+ conversionInput->inputcoordinates->inputliquids = filteredInputLiquids;
+ conversionInput->inputcoordinates->n_inputliquids = expected_liquids;
+ //Filter and arrange colors
+
+ //Initialize Output...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ conversion_output__init(conversionOutput);
+ // ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT;
+
+
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+ //count number if inks
+ // int numofInks = CountNumberofInks(conversionInput);
+ if(m_colortable ==NULL)
+ m_colortable = new ColorTable();
+ readColorTransformations(conversionInput);
+ m_nProcessRanges = conversionInput->n_processranges;
+ if(m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ double *tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i];
+ //read calibration tables and store them in m_CalibCurves
+ InputLiquid **inputliquids = conversionInput->inputcoordinates->inputliquids;
+ int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids;
+ readCalibrationTables(inputliquids, n_inputliquids);
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if(m_Conv02 ==NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+ //m_Conv02 = DBG_NEW ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ // Compare Strip White point to Color Table White Point
+ //CompareWhitePoints();
+
+ if (numofInks != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables\0");
+
+ //Tables have been filled
+ //Set Process Ranges
+ if(m_ProcessRangesMaxP == NULL)
+ m_ProcessRangesMaxP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMaxP[i] = conversionInput->processranges[i]->maxinkuptake;
+ }
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+ VectorXd VolumeOut(m_nInks);
+ //set maxNlPerCM
+ VectorXd NlperCM(m_nInks);
+ NlperCM.setZero();
+ m_maxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ SetMaxNLperCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter, i);
+ m_nVolumes = m_nInks;
+ int GamutRegion = 0;
+ //Convert input data to linear inks
+ if (conversionInput->colorspace == COLOR_SPACE__Volume || conversionInput->colorspace == COLOR_SPACE__Catalog)
+ {
+ InputCoordinates *IC = conversionInput->inputcoordinates;
+ int colorspace = conversionInput->colorspace;
+ ConvertVolumeToRGBDisplay(IC, conversionInput->n_processranges, colorspace, Volume, RGBOut, LabOut, GamutRegion);
+ InGamut = true;
+ }
+ else
+ {
+ ConvertColorToLinearInks(conversionInput->inputcoordinates, conversionInput->colorspace, InkOut, RGBOut,
+ LabOut, GamutRegion, InGamut);
+ //Inks are in Linear Space , convert to nonlinear by using Calibration Tables,
+ // Right now calibration is in the [0-100] range, values exceeding [0-100] are not transformed
+ ConvertToNLInks(InkOut, NLInkOut);
+
+ //Limit inks based on m_maxNlpercm
+ //Inks are limited in their nonlinear form
+ //Output Volume is in %
+ double *InkOutP = new double[m_nInks];
+ LimitInks(NLInkOut, InkOutP);
+ NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Volume);
+ GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP);
+ NLcmtoPercentage(Volume, Volume);
+ //OutputCoordinates outputCoords = OUTPUT_COORDINATES__INIT;
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+
+ }
+ OutputCoordinates *outputCoords = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(outputCoords);
+ fillRGB(outputCoords, RGBOut);
+ fillLab(outputCoords, LabOut);
+ outputCoords->has_processparameterstableindex = true;
+ outputCoords->processparameterstableindex = GamutRegion;
+ fillVolume(outputCoords, Volume);
+ conversionOutput->has_outofgamut = true;
+ conversionOutput->outofgamut = !(InGamut);
+ conversionOutput->singlecoordinates = outputCoords;
+
+ if (conversionInput->generatehive)
+ {
+ //input was processed.
+ //process neighboring values
+ //nhive includes 2 outer neighbors of the central Lab value, chroma + delta, chroma + 2delta
+ // and variation in L positioned on the side of the beehive.
+ //The set is arrange in a 5x6 matrix, where the 5x5 contains the variation in (Hue, chroma)
+ // and the last 5 contain the variation in L
+ int nHive = 18; //22; // 18;
+ int MatHive = 25;// 30; //25;
+
+ MatrixXd RGBHive(MatHive, 3);
+ VectorXd RGBHive1(3);
+ VectorXd LabHive1(3);
+ VectorXd VolumeHive1(m_nVolumes);
+ MatrixXd VolumeHive(MatHive, m_nVolumes);
+ MatrixXd LabHive(MatHive, 3);
+
+ int *GamutRegionV = new int[MatHive];
+ //int *GamutRegionV = DBG_NEW int[MatHive];
+ for (int i = 0; i < MatHive; ++i)
+ GamutRegionV[i] = -1;
+
+ int indDataMax[2];
+ int j = 0;
+ // Matrix values are initially set to -1;
+ RGBHive.setConstant(NegValue);
+ VolumeHive.setConstant(NegValue);
+
+ ProcessHiveNeighbors(conversionInput, LabOut, RGBOut, Volume, GamutRegion, RGBHive, LabHive, VolumeHive, nHive, GamutRegionV, indDataMax);
+ OutputCoordinates** hiveData = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * MatHive);
+ conversionOutput->hivecoordinates = hiveData;
+ conversionOutput->n_hivecoordinates = MatHive;
+ conversionOutput->n_triplecoordinates = 3;
+ for (int i = 0; i < MatHive; i++)
+ {
+ hiveData[i] = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(hiveData[i]);
+ if (RGBHive(i, 0) != NegValue)
+ {
+ for (j = 0; j < 3; ++j)
+ RGBHive1(j) = RGBHive(i, j);
+ fillRGB(hiveData[i], RGBHive1);
+ for (j = 0; j < m_nVolumes; ++j)
+ VolumeHive1(j) = VolumeHive(i, j);
+ fillVolume(hiveData[i], VolumeHive1);
+ for (j = 0; j < 3; ++j)
+ LabHive1(j) = LabHive(i, j);
+ fillLab(hiveData[i], LabHive1);
+ hiveData[i]->has_processparameterstableindex = true;
+ hiveData[i]->processparameterstableindex = GamutRegionV[i];
+ hiveData[i]->n_outputliquids = m_nInks;
+ }
+ conversionOutput->hivecoordinates[i] = hiveData[i];
+ }
+
+
+ //Triplet
+ OutputCoordinates** TripletData = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * 3);
+ conversionOutput->triplecoordinates = TripletData;
+ int tripletIndex[3] = { indDataMax[0] , (int)(12), indDataMax[1] };
+ for (int i = 0; i < 3; ++i)
+ {
+ // OutputCoordinates SingleCell = OUTPUT_COORDINATES__INIT;
+ TripletData[i] = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(TripletData[i]);
+ for (j = 0; j < 3; ++j)
+ RGBHive1(j) = RGBHive(tripletIndex[i], j);
+ fillRGB(TripletData[i], RGBHive1);
+ for (j = 0; j < m_nVolumes; ++j)
+ VolumeHive1(j) = VolumeHive(tripletIndex[i], j);
+ fillVolume(TripletData[i], VolumeHive1);
+ for (j = 0; j < 3; ++j)
+ LabHive1(j) = LabHive(tripletIndex[i], j);
+ fillLab(TripletData[i], LabHive1);
+ TripletData[i]->has_processparameterstableindex = true;
+ TripletData[i]->processparameterstableindex = GamutRegionV[tripletIndex[i]];
+ TripletData[i]->n_outputliquids = m_nInks;
+ conversionOutput->triplecoordinates[i] = TripletData[i];
+ }
+
+ //Clean up
+ if (GamutRegionV != NULL)
+ {
+ delete[] GamutRegionV;
+ GamutRegionV = NULL;
+ }
+
+ }
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+ catch (const std::exception& e)
+ {
+ //Notify Error...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ conversion_output__init(conversionOutput);
+
+ conversionOutput->has_haserror = true;
+ conversionOutput->haserror = true;
+
+ const char* what = e.what();
+ int nWhat = strlen(what);
+ conversionOutput->errormessage = (char*)malloc(nWhat);
+ //conversionOutput->errormessage = new char[nWhat];
+ for (int i = 0; i < nWhat; ++i)
+ conversionOutput->errormessage[i] = what[i];
+ //strcpy_s(conversionOutput->errormessage, nWhat, what);
+
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+ }
+}
+
+
+
+/*void Tango::ColorLib::ColorConverter::InitInterpolations(int numofInks, Interp *linearInterp, Interp *InvLinearInterp)
+{
+ double *xCoords;
+ double *yCoords;
+
+ for (int i = 0; i < numofInks; ++i)
+ {
+ xCoords = m_CalibCurves[i].getxCoords();
+ yCoords = m_CalibCurves[i].getyCoords();
+ int npts = m_CalibCurves[i].getSize();
+ linearInterp[i].SetXCoords(xCoords);
+ linearInterp[i].SetYCoords(yCoords);
+ linearInterp[i].SetNPoints(npts);
+ InvLinearInterp[i].SetXCoords(yCoords);
+ InvLinearInterp[i].SetYCoords(xCoords);
+ InvLinearInterp[i].SetNPoints(npts);
+ }
+}*/
+
+int Tango::ColorLib::ColorConverter::CountNumberofInks(ConversionInput* conversionInput)
+{
+ int nLiquids = conversionInput->inputcoordinates->n_inputliquids;
+ int numberofInks = 0;
+ //Cyan
+ int nCyan = 0;;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Cyan)
+ nCyan++;
+ }
+ if (nCyan > 1)
+ {
+ numberofInks = -1;
+ return(numberofInks);
+ }
+ int nMagenta = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Magenta)
+ nMagenta++;
+ }
+ if (nMagenta > 1)
+ {
+ numberofInks = -1;
+ return(numberofInks);
+ }
+ int nYellow = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Yellow)
+ nYellow++;
+ }
+ if (nYellow > 1)
+ {
+ numberofInks = -1;
+ return(numberofInks);
+ }
+ int nBlack = 0;
+ for (int i = 0; i < nLiquids; ++i)
+ {
+ if (conversionInput->inputcoordinates->inputliquids[i]->liquidtype == LIQUID_TYPE__Black)
+ nBlack++;
+ }
+ if (nBlack > 1)
+ {
+ numberofInks = -1;
+ return(numberofInks);
+ }
+ numberofInks = nCyan + nMagenta + nYellow + nBlack;
+ return(numberofInks);
+}
+
+bool Tango::ColorLib::ColorConverter::IsInGamut(double *InLab, SURROUND sur, CAM02CS CS, double *LabCoord)
+{
+ int nInLab = 3;
+ double *xCoord = new double[nInLab];
+ //double *xCoord = DBG_NEW double[nInLab];
+ //Convert InLab to CIECam02 coordinates
+ bool InGamut = true;
+ if (InLab[0] > 100 || InLab[0] < 0 || InLab[1] > 127 || InLab[1] < -128 || InLab[2] > 127 || InLab[2] < -128)
+ {
+ InGamut = false;
+ LimitLab(InLab);
+ }
+
+ double ctr[3];
+ C_RGB_XYZ_Lab center = m_colortable->m_GBD->getCenter();
+ VectorXd JInLab(3);
+ JInLab << InLab[0], InLab[1], InLab[2];
+ VectorXd JLab = m_Conv02->LabToJab(JInLab, sur);
+ ctr[0] = -JLab(0) + center.Get_x();
+ ctr[1] = -JLab(1) + center.Get_y();
+ ctr[2] = -JLab(2) + center.Get_z();
+ double *dJLab = new double[3];
+ //double *dJLab = DBG_NEW double[3];
+ VectorToDouble(JLab, dJLab);
+ bool intersect = false;
+ m_colortable->m_GBD->TriangleRayIntersection(dJLab, ctr, intersect, xCoord);
+ if (intersect)
+ {
+ VectorXd V1(3);
+ VectorXd V2(3);
+ V1 << JLab[0], JLab[1], JLab[2];
+ V2 << xCoord[0], xCoord[1], xCoord[2];
+ double dECMC;
+ m_Conv02->SymmetricaldECMC(V1, V2, dECMC);
+ if (dECMC < dETol)
+ InGamut = true;
+ else
+ InGamut = false;
+ VectorXd JabV(3);
+ JabV = DoubleToVector(xCoord, 3);
+ VectorXd LabV(3);
+ LabV = m_Conv02->Jab_2_Lab(JabV, CS);
+ VectorToDouble(LabV, LabCoord);
+ }
+ else
+ {
+ InGamut = true;
+ for (int i = 0; i < 3; ++i)
+ LabCoord[i] = InLab[i];
+ }
+ //Convert back to Lab
+
+ if (xCoord != NULL)
+ {
+ delete[] xCoord;
+ xCoord = NULL;
+ }
+ if (dJLab != NULL)
+ {
+ delete[]dJLab;
+ dJLab = NULL;
+ }
+ return(InGamut);
+}
+
+
+
+
+void Tango::ColorLib::ColorConverter::read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput)
+{
+ /*
+ 0 - 3 'prec1', 'prec2'
+ 4 - 7 reserved, must be 0
+ 8 number of input channels, uint8
+ 9 number of output channels, uint8
+ 10 number of CLUT grid points, uint8
+ 11 number of Shift Bits
+ 12 Number of gamut regions
+ 13 - n CLUT values, uint16
+
+ 13 - n output tables, uint8
+ */
+ if (data_size < 32)
+ {
+ throw std::exception(" LUT size missmatch");
+ return;
+ }
+ int bytesread = 0;
+ // Check for signature
+ uint8_t *buff = &conversionInput->forwarddata.data[offset];
+ Transf->InitData(buff, data_size);
+ return;
+}
+
+
+
+
+
+
+
+/*void Tango::ColorLib::ColorConverter::CompareWhitePoints()
+{
+ ColorConvert ColConv(D65, D65);
+ C_RGB_XYZ_Lab Lab_CT;
+ C_RGB_XYZ_Lab Lab_Strip;
+ Lab_CT = ColConv.XYZToLab(m_whitepointXYZ_CT);
+ Lab_Strip = ColConv.XYZToLab(m_whitepointXYZ_Strip);
+ VectorXd VLab_CT(3);
+ VectorXd VLab_Strip(3);
+ VLab_CT(0) = Lab_CT.Get_x();
+ VLab_CT(1) = Lab_CT.Get_y();
+ VLab_CT(2) = Lab_CT.Get_z();
+ VLab_Strip(0) = Lab_Strip.Get_x();
+ VLab_Strip(1) = Lab_Strip.Get_y();
+ VLab_Strip(2) = Lab_Strip.Get_z();
+ double dECMC;
+ ColConv.SymmetricaldECMC(VLab_CT, VLab_Strip, dECMC);
+ if (dECMC > WPTol)
+ m_AdaptWP = true;
+ if (m_whitepointXYZ_Strip.Get_x() <= 0 || m_whitepointXYZ_Strip.Get_y() <= 0 || m_whitepointXYZ_Strip.Get_z()<=0)
+ m_AdaptWP = false;
+ return;
+} */ /* not used*/
+
+//size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+//{
+// //Unpack conversion input...
+// ConversionInput* conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+//
+// //Initialize Output...
+// ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT;
+//
+// //The request is for RGB to Volume...
+// if (conversionInput->colorspace == COLOR_SPACE__RGB)
+// {
+// //Get RGB values...
+// int r = conversionInput->inputcoordinates->red;
+// int g = conversionInput->inputcoordinates->green;
+// int b = conversionInput->inputcoordinates->blue;
+//
+// //iterate over input liquids...
+// for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+// {
+// InputLiquid* inputLiquid = conversionInput->inputcoordinates->inputliquids[i];
+//
+// //Get cyan liquid for example...
+// if (inputLiquid->liquidtype == LIQUID_TYPE__Cyan)
+// {
+// //Get liquid max nl per cm.
+// double maxNlPerCM = inputLiquid->maxnanoliterpercentimeter;
+//
+// //Get liquid calibration data.
+// CalibrationData* calibrationData = inputLiquid->calibrationdata;
+//
+// //Iterate over calibration points..
+// for (size_t j = 0; j < calibrationData->n_calibrationpoints; j++)
+// {
+// //Calibration Point
+// CalibrationPoint* point = calibrationData->calibrationpoints[j];
+//
+// double x = point->x;
+// double y = point->y;
+// }
+// }
+// }
+//
+// //Set conversion output with proper volumes...
+//
+// //Set Cyan liquid volume...
+// OutputLiquid cyanLiquid = OUTPUT_LIQUID__INIT;
+// cyanLiquid.has_volume = true;
+// cyanLiquid.has_liquidtype = true;
+// cyanLiquid.liquidtype = LIQUID_TYPE__Cyan;
+// cyanLiquid.volume = 20;
+//
+// //Set Magenta liquid volume...
+// OutputLiquid magentaLiquid = OUTPUT_LIQUID__INIT;
+// magentaLiquid.has_volume = true;
+// magentaLiquid.has_liquidtype = true;
+// magentaLiquid.liquidtype = LIQUID_TYPE__Magenta;
+// magentaLiquid.volume = 30;
+//
+// OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * 2);
+//
+// //Add cyan and magenta to output liquids array.
+// outputLiquids[0] = &cyanLiquid;
+// outputLiquids[1] = &magentaLiquid;
+//
+// OutputCoordinates outCoords;
+// outCoords.outputliquids = outputLiquids;
+//
+// conversionOutput.singlecoordinates = &outCoords;
+// }
+//
+//
+//
+// //The request is for volumes to RGB...
+// else if (conversionInput->colorspace == COLOR_SPACE__Volume)
+// {
+// //iterate over input liquids...
+// for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+// {
+// InputLiquid* inputLiquid = conversionInput->inputcoordinates->inputliquids[i];
+//
+// //Get cyan liquid for example...
+// if (inputLiquid->liquidtype == LIQUID_TYPE__Cyan)
+// {
+// //Get liquid max nl per cm.
+// double maxNlPerCM = inputLiquid->maxnanoliterpercentimeter;
+//
+// //Get liquid volume.
+// double volume = inputLiquid->volume;
+//
+// //Get liquid calibration data.
+// CalibrationData* calibrationData = inputLiquid->calibrationdata;
+//
+// //Iterate over calibration points..
+// for (size_t j = 0; j < calibrationData->n_calibrationpoints; j++)
+// {
+// //Calibration Point
+// CalibrationPoint* point = calibrationData->calibrationpoints[j];
+//
+// double x = point->x;
+// double y = point->y;
+// }
+// }
+// else if (inputLiquid->liquidtype == LIQUID_TYPE__Magenta)
+// {
+// //Same as above...
+// }
+// }
+//
+// //Set conversion output (single) with proper RGB values...
+// OutputCoordinates outputCoords = OUTPUT_COORDINATES__INIT;
+// outputCoords.has_red = true;
+// outputCoords.has_green = true;
+// outputCoords.has_blue = true;
+// outputCoords.red = 50;
+// outputCoords.green = 100;
+// outputCoords.blue = 150;
+//
+// conversionOutput.singlecoordinates = &outputCoords;
+//
+// //Set conversion output (hive) with proper RGB values...
+//
+// int hiveCellCount = 10;
+//
+// OutputCoordinates** hiveCoordinates = (OutputCoordinates**)malloc(sizeof(OutputCoordinates*) * hiveCellCount);
+//
+// for (size_t i = 0; i < hiveCellCount; i++)
+// {
+// OutputCoordinates cellCoords = OUTPUT_COORDINATES__INIT;
+// cellCoords.has_red = true;
+// cellCoords.has_green = true;
+// cellCoords.has_blue = true;
+// cellCoords.red = 10;
+// cellCoords.green = 20;
+// cellCoords.blue = 30;
+//
+// hiveCoordinates[i] = &cellCoords;
+// }
+//
+// conversionOutput.hivecoordinates = hiveCoordinates;
+// }
+//
+// //Pack output...
+// output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(&conversionOutput));
+//
+// return conversion_output__pack(&conversionOutput, output_buffer);
+//}
+
+
+
+size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+
+ //Get Input
+ ConversionInput* conversionInput = (ConversionInput*)malloc(sizeof(ConversionInput));
+
+ conversionInput = conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+
+
+
+ //Filter and arrange colors (Should change from 3 to 4 if black ink is included)
+ /*int expected_liquids = 3;
+
+ InputLiquid** filteredInputLiquids = (InputLiquid**)malloc(sizeof(InputLiquid*) * expected_liquids);
+
+ for (size_t i = 0; i < conversionInput->inputcoordinates->n_inputliquids; i++)
+ {
+ InputLiquid* liquid = conversionInput->inputcoordinates->inputliquids[i];
+
+ switch (liquid->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ filteredInputLiquids[0] = liquid;
+ break;
+ case LIQUID_TYPE__Magenta:
+ filteredInputLiquids[1] = liquid;
+ break;
+ case LIQUID_TYPE__Yellow:
+ filteredInputLiquids[2] = liquid;
+ break;
+ }
+ }
+
+ conversionInput->inputcoordinates->inputliquids = filteredInputLiquids;
+ conversionInput->inputcoordinates->n_inputliquids = expected_liquids;
+ //Filter and arrange colors
+
+ */
+
+ //Initialize Output...
+ ConversionOutput *conversionOutput = (ConversionOutput*)malloc(sizeof(ConversionOutput));
+ if (conversionOutput != NULL)
+ conversion_output__init(conversionOutput);
+ else
+ return(0);
+
+ // ConversionOutput conversionOutput = CONVERSION_OUTPUT__INIT;
+ size_t n_elements = 0;
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+ //count number if inks
+ int numofInks = CountNumberofInks(conversionInput);
+ readColorTransformations(conversionInput);
+
+ //read calibration tables and store them in m_CalibCurves
+ int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids;
+ InputLiquid **inputliquid = conversionInput->inputcoordinates->inputliquids;
+ readCalibrationTables(inputliquid, n_inputliquids);
+
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if(m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+ //m_Conv02 = DBG_NEW ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ // Compare Strip White point to Color Table White Point
+ //CompareWhitePoints();
+
+ if (numofInks != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables");
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+
+ C_RGB_XYZ_Lab DataLab;
+ //SURROUND sur = m_Conv02->getSurround();
+ switch (conversionInput->colorspace)
+ {
+ case (COLOR_SPACE__RGB):
+ {
+ // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric,
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread
+ //The workflow is a follows:
+ //1. Convert RGB to Lab (Whitepoint is D65, same as tables)
+ //2.Fiond if Lab is InGamut
+
+ RGBOut(0) = conversionInput->inputcoordinates->red;
+ RGBOut(1) = conversionInput->inputcoordinates->green;
+ RGBOut(2) = conversionInput->inputcoordinates->blue;
+ //convert to Lab
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ //double *LabIn = DBG_NEW double[3];
+ //double *RGBOutP = DBG_NEW double[3];
+ double *LabIn = new double[3];
+ double *RGBOutP = new double[3];
+ VectorToDouble(RGBOut, RGBOutP);
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65
+
+ //Is In Gamut?
+ InGamut = IsInGamut(LabIn, sur, CS, LabIn);
+
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ break;
+ }
+ case (COLOR_SPACE__LAB):
+ {
+ // Basic assumption: Lab data has the same whitepoint as the STRIP thread.
+ //The workflow is a follows:
+ //1. Convert Lab to Relative colorimetric. check if there is a match between STRIP and Color Tables
+ //2. Find if Lab is InGamut
+
+ double *LabIn = new double[3];
+ //double *LabIn = DBG_NEW double[3];
+ LabIn[0] = conversionInput->inputcoordinates->l;
+ LabIn[1] = conversionInput->inputcoordinates->a;
+ LabIn[2] = conversionInput->inputcoordinates->b;
+ //the assumption is that the color space has illumination that matches the whitepoint of the Strip
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+// double *LabInFinal1 = new double[3];
+ //double *LabInFinal1 = DBG_NEW double[3];
+// for (int i = 0; i < 3; ++i)
+// LabInFinal1[i] = LabIn[i];
+ // Lab is assumed to match the color of the STRIP, however the tables could have a different WP
+ //We relate to the color table as a generic one in Relative Colorimetric Space
+ /*
+ if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables
+ }
+ */
+ double *LabInFinal2 = new double[3];
+ //double *LabInFinal2 = DBG_NEW double[3];
+ // CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //to Relative
+ CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //to Relative
+ InGamut = IsInGamut(LabInFinal2, sur, CS, LabInFinal2);
+ LimitLab(LabInFinal2);
+
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ /* if (LabInFinal1 != NULL)
+ {
+ delete[]LabInFinal1;
+ LabInFinal1 = NULL;
+ } */
+ if (LabInFinal2 != NULL)
+ {
+ delete[]LabInFinal2;
+ LabInFinal2 = NULL;
+ }
+ break;
+ }
+ case(COLOR_SPACE__CMYK):
+ case(COLOR_SPACE__Volume):
+ case(COLOR_SPACE__Catalog):
+ {//no conversion
+ //missing from structure light inks or special colors
+ // just convert Lab for rgb display
+ InGamut = true;
+ }
+ //case(COLOR_SPACE__Catalog):
+ //{
+ // int32_t inData;
+ // if (conversionInput->inputcoordinates->has_pantoncode)
+ // inData = conversionInput->inputcoordinates->pantoncode;
+ // else
+ // {
+ // //mismatch between color space and data
+ // throw std::exception("Mismatch between color space and data");
+ // return(0);
+ // }
+ // break;
+ // //missing calclulation method and pantone table, either in terms of RGB or CMY or Lab
+ //}
+ default:
+ {
+ throw std::exception(" Unsupported Color Space");
+ return(0);
+ }
+ }
+
+ //Pack data
+ OutputCoordinates *outputCoords = (OutputCoordinates*)malloc(sizeof(OutputCoordinates));
+ output_coordinates__init(outputCoords);
+ conversionOutput->has_outofgamut = true;
+ conversionOutput->outofgamut = !(InGamut);
+ conversionOutput->singlecoordinates = outputCoords;
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(conversion_output__get_packed_size(conversionOutput));
+ int size = conversion_output__pack(conversionOutput, output_buffer);
+
+#pragma region Free Conversion Input & Output
+
+ //conversionInput->inputcoordinates->inputliquids = original_input_liquids;
+ //conversionInput->inputcoordinates->n_inputliquids = original_input_liquids_count;
+
+ conversion_input__free_unpacked(conversionInput, NULL);
+
+ conversion_output__free_unpacked(conversionOutput, NULL);
+
+#pragma endregion
+
+ return (size);
+}
+
+
+size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ //Get Input...
+ GradientConversionInput* conversionInput = (GradientConversionInput*)malloc(sizeof(GradientConversionInput));
+ conversionInput = gradient_conversion_input__unpack(NULL, input_buffer_size, input_buffer);
+ //Initialize Output...
+ GradientConversionOutput *conversionOutput = (GradientConversionOutput*)malloc(sizeof(GradientConversionOutput));
+ gradient_conversion_output__init(conversionOutput);
+
+ conversionOutput->haserror = false;
+ conversionOutput->has_haserror = false;
+ //Get segment length...
+ double segmentLength = conversionInput->segmentlength;
+ if(m_colortable == NULL)
+ m_colortable = new ColorTable();
+ PrepareGradient(conversionInput, conversionOutput);
+ //Get liquid types info...
+ /* InputLiquid* cyan = NULL;
+ InputLiquid* magenta = NULL;
+ InputLiquid* yellow = NULL;
+ InputLiquid* black = NULL;
+
+ for (size_t i = 0; i < conversionInput->n_inputliquids; i++)
+ {
+ switch (conversionInput->inputliquids[i]->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ cyan = conversionInput->inputliquids[i];
+ break;
+ case LIQUID_TYPE__Magenta:
+ magenta = conversionInput->inputliquids[i];
+ break;
+ case LIQUID_TYPE__Yellow:
+ yellow = conversionInput->inputliquids[i];
+ break;
+ case LIQUID_TYPE__Black:
+ black = conversionInput->inputliquids[i];
+ break;
+ }
+ }*/
+
+ //Pack output...
+ output_buffer = (uint8_t*)malloc(gradient_conversion_output__get_packed_size(conversionOutput));
+ int size = gradient_conversion_output__pack(conversionOutput, output_buffer);
+
+ //RELEASE MEMORY HERE !!!
+ #pragma region Free Conversion Input & Output
+
+ gradient_conversion_input__free_unpacked(conversionInput, NULL);
+
+ gradient_conversion_output__free_unpacked(conversionOutput, NULL);
+
+ #pragma endregion
+
+ return size;
+
+}
+
+void Tango::ColorLib::ColorConverter::fillGradientStops(GradientConversionInput *conversionInput)
+{
+ C_RGB_XYZ_Lab RGB;
+ C_RGB_XYZ_Lab Lab;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ switch (conversionInput->stops[i]->colorspace)
+ {
+ case COLOR_SPACE__RGB: //Case RGB
+ RGB = C_RGB_XYZ_Lab(conversionInput->stops[i]->red, conversionInput->stops[i]->green, conversionInput->stops[i]->blue);
+ m_GradStops[i].Set_RGB(RGB);
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__RGB);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ break;
+ case COLOR_SPACE__LAB: //Case LAB
+ Lab = C_RGB_XYZ_Lab(conversionInput->stops[i]->l, conversionInput->stops[i]->a, conversionInput->stops[i]->b);
+ m_GradStops[i].Set_Lab(Lab);
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__LAB);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ break;
+ case COLOR_SPACE__Volume: //Case Volume
+ m_GradStops[i].Set_ColorSpace(COLOR_SPACE__Volume);
+ m_GradStops[i].Set_Offset(conversionInput->stops[i]->offset);
+ for (int j = 0; j < (int)conversionInput->stops[i]->n_liquidvolumes; j++)
+ {
+ LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];
+
+ switch (liquidVolume->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+ m_GradStops[i].SetVolumeValue(liquidVolume->volume,0);
+ break;
+ case LIQUID_TYPE__Magenta:
+ m_GradStops[i].SetVolumeValue(liquidVolume->volume, 1);
+ break;
+ case LIQUID_TYPE__Yellow:
+ m_GradStops[i].SetVolumeValue(liquidVolume->volume, 2);
+ break;
+ case LIQUID_TYPE__Black:
+ m_GradStops[i].SetVolumeValue(liquidVolume->volume, 3);
+ break;
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+void Tango::ColorLib::ColorConverter::findStops(Gradient &GradStop1, Gradient &GradStop2, double dEThr, int ninterstops,
+ int &nOut, double **VecRGBOut, double **VecLabOut, double *posOut)
+{
+ ColorConvert CConvertD65(D65, D65);
+ C_RGB_XYZ_Lab RGBStart = GradStop1.Get_RGB();
+ C_RGB_XYZ_Lab RGBEnd = GradStop2.Get_RGB();
+ C_RGB_XYZ_Lab LowLab(0, -128, -128);
+ C_RGB_XYZ_Lab HighLab(100, 127, 127);
+ C_RGB_XYZ_Lab LowRGB(0, 0, 0);
+ C_RGB_XYZ_Lab HighRGB(255, 255, 255);
+ C_RGB_XYZ_Lab LabStart = GradStop1.Get_Lab();
+ C_RGB_XYZ_Lab LabEnd = GradStop2.Get_Lab();
+ int nsubdiv = 101;
+ C_RGB_XYZ_Lab dRGB((RGBEnd.Get_x() - RGBStart.Get_x()) / (nsubdiv-1), (RGBEnd.Get_y() - RGBStart.Get_y()) / (nsubdiv-1),
+ (RGBEnd.Get_z() - RGBStart.Get_z()) / (nsubdiv-1));
+ C_RGB_XYZ_Lab dLab((LabEnd.Get_x() - LabStart.Get_x()) / (nsubdiv - 1), (LabEnd.Get_y() -LabStart.Get_y()) / (nsubdiv - 1),
+ (LabEnd.Get_z() - LabStart.Get_z()) / (nsubdiv - 1));
+
+ C_RGB_XYZ_Lab *VecLabOut_tmp = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecRGBOut_tmp = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecLabOut_fin = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab *VecRGBOut_fin = new C_RGB_XYZ_Lab[ninterstops];
+ C_RGB_XYZ_Lab RGBTmp;
+ C_RGB_XYZ_Lab LabTmp;
+ // make a vector of RGB values with 100 subdivisions
+ // make a matching Lab vector;
+
+ VecRGBOut_tmp[0] = C_RGB_XYZ_Lab(RGBStart);
+ VecLabOut_tmp[0] = C_RGB_XYZ_Lab(GradStop1.Get_Lab());
+ int Stop1Index = 1;
+ if (!GradStop1.Get_InRGBLimits())
+ {
+ bool retValue = false;
+ int i_index = 1;
+ LabTmp.Set(GradStop1.Get_Lab().Get_x() + i_index * dLab.Get_x(),
+ GradStop1.Get_Lab().Get_y() + i_index * dLab.Get_y(),
+ GradStop1.Get_Lab().Get_z() + i_index * dLab.Get_z());
+ while ((!retValue) & (i_index<nsubdiv))
+ {
+ retValue = CheckLabInRGBGamut(LabTmp);
+ i_index++;
+ LabTmp.Set(GradStop1.Get_Lab().Get_x() + i_index * dLab.Get_x(),
+ GradStop1.Get_Lab().Get_y() + i_index * dLab.Get_y(),
+ GradStop1.Get_Lab().Get_z() + i_index * dLab.Get_z());
+ }
+ Stop1Index = i_index;
+ }
+ int Stop2Index = nsubdiv;
+ if (!GradStop2.Get_InRGBLimits())
+ {
+ bool retValue = false;
+ int i_index = 1;
+ LabTmp.Set(GradStop2.Get_Lab().Get_x() - i_index * dLab.Get_x(),
+ GradStop2.Get_Lab().Get_y() - i_index * dLab.Get_y(),
+ GradStop2.Get_Lab().Get_z() - i_index * dLab.Get_z());
+ while ((!retValue) & (i_index < nsubdiv))
+ {
+ retValue = CheckLabInRGBGamut(LabTmp);
+ i_index++;
+ LabTmp.Set(GradStop2.Get_Lab().Get_x() - i_index * dLab.Get_x(),
+ GradStop2.Get_Lab().Get_y() - i_index * dLab.Get_y(),
+ GradStop2.Get_Lab().Get_z() - i_index * dLab.Get_z());
+ }
+ Stop2Index -= (i_index-1);
+ }
+ //Base vector on Lab
+ for (int i = 1; i < Stop1Index; ++i)
+ {
+ VecLabOut_tmp[i].Set(VecLabOut_tmp[i - 1].Get_x() + dLab.Get_x(),
+ VecLabOut_tmp[i - 1].Get_y() + dLab.Get_y(),
+ VecLabOut_tmp[i - 1].Get_z() + dLab.Get_z());
+ VecRGBOut_tmp[i] = m_Conv02->LabtoRGB(VecLabOut_tmp[i]);
+ }
+ //recalculate dRGB
+ int SI1 = Stop1Index ;
+ int SI2 = Stop2Index ;
+ C_RGB_XYZ_Lab LabStop1(LabStart.Get_x() + SI1 * dLab.Get_x(),
+ LabStart.Get_y() + SI1 * dLab.Get_y(), LabStart.Get_z() + SI1 * dLab.Get_z());
+ C_RGB_XYZ_Lab LabStop2(LabStart.Get_x() + (SI2-1) * dLab.Get_x(),
+ LabStart.Get_y() + (SI2-1) * dLab.Get_y(), LabStart.Get_z() + (SI2-1) * dLab.Get_z());
+ C_RGB_XYZ_Lab RGBStop1 = m_Conv02->LabtoRGB(LabStop1);
+ C_RGB_XYZ_Lab RGBStop2 = m_Conv02->LabtoRGB(LabStop2);
+ int nelems = Stop2Index - Stop1Index ;
+ dRGB = C_RGB_XYZ_Lab((RGBStop2.Get_x() - RGBStop1.Get_x()) / (nelems - 1), (RGBStop2.Get_y() - RGBStop1.Get_y()) / (nelems - 1),
+ (RGBStop2.Get_z() - RGBStop1.Get_z()) / (nelems - 1));
+ int STi = 0;
+ for (int i = 0; i < nelems; ++i)
+ {
+ STi = Stop1Index + i;
+ VecRGBOut_tmp[STi].Set(RGBStop1.Get_x() + i*dRGB.Get_x(),
+ RGBStop1.Get_y() + i * dRGB.Get_y(),
+ RGBStop1.Get_z() + i * dRGB.Get_z());
+ VecLabOut_tmp[STi] = CConvertD65.RGBtoLab(VecRGBOut_tmp[STi]);
+ VecLabOut_tmp[STi].Clamp(LowLab, HighLab);
+ }
+ for (int i = Stop2Index; i < nsubdiv; ++i)
+ {
+ VecLabOut_tmp[i].Set(VecLabOut_tmp[i - 1].Get_x() + dLab.Get_x(),
+ VecLabOut_tmp[i - 1].Get_y() + dLab.Get_y(),
+ VecLabOut_tmp[i - 1].Get_z() + dLab.Get_z());
+ VecRGBOut_tmp[i] = m_Conv02->LabtoRGB(VecLabOut_tmp[i]);
+ }
+
+ int indGrad = 0;
+ int *pos = new int[ninterstops];
+ int i1 = 1;
+ int j1 = 1;
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[0];
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[0];
+ pos[indGrad] = 0;
+ double dE = 0.0;
+ double dEOld = 0.0;
+ while (i1 < nsubdiv)
+ {
+ dEOld = dE;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE);
+ j1 = i1;
+ while (dE < dEThr && i1 < nsubdiv && j1 < nsubdiv)
+ {
+ j1++;
+ dEOld = dE;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[j1], dE);
+ }
+ if (j1 > i1)
+ {
+ j1--;
+ indGrad++;
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1];
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[j1];
+ pos[indGrad] = j1;
+ dE = dEOld;
+ i1 = j1 + 1;
+ }
+ else
+ {
+ dEOld = dE;
+ while (dE >= dEThr && i1 <nsubdiv)
+ {
+ //get intermediate point
+ RGBTmp.Set( (VecRGBOut_tmp[i1].Get_x() + VecRGBOut_fin[indGrad].Get_x())/2.0,
+ (VecRGBOut_tmp[i1].Get_y() + VecRGBOut_fin[indGrad].Get_y()) / 2.0,
+ (VecRGBOut_tmp[i1].Get_z() + VecRGBOut_fin[indGrad].Get_z()) / 2.0);
+ LabTmp = CConvertD65.RGBtoLab(RGBTmp);
+ LabTmp.Clamp(LowLab, HighLab);
+ //move vectors down by one
+ for (int i = nsubdiv-1; i >=i1; --i)
+ {
+ VecRGBOut_tmp[i + 1] = VecRGBOut_tmp[i ];
+ VecLabOut_tmp[i + 1] = VecLabOut_tmp[i ];
+ }
+ VecRGBOut_tmp[i1] = RGBTmp;
+ VecLabOut_tmp[i1] = LabTmp;
+ CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE);
+ nsubdiv++;
+ }
+ indGrad++;
+ VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1];
+ VecLabOut_fin[indGrad] = VecLabOut_tmp[j1];
+ pos[indGrad] = j1;
+ i1 = j1 + 1;
+ }
+ }
+ nOut = indGrad;
+
+ for (int i = 0; i < nOut; ++i)
+ {
+ VecLabOut[i][0] = VecLabOut_fin[i].Get_x();
+ VecLabOut[i][1] = VecLabOut_fin[i].Get_y();
+ VecLabOut[i][2] = VecLabOut_fin[i].Get_z();
+ VecRGBOut[i][0] = VecRGBOut_fin[i].Get_x();
+ VecRGBOut[i][1] = VecRGBOut_fin[i].Get_y();
+ VecRGBOut[i][2] = VecRGBOut_fin[i].Get_z();
+ posOut[i] = pos[i];
+ }
+ //free allocs
+ if(VecLabOut_tmp != NULL)
+ {
+ delete[] VecLabOut_tmp;
+ VecLabOut_tmp = NULL;
+ }
+ if (VecRGBOut_tmp != NULL)
+ {
+ delete[] VecRGBOut_tmp;
+ VecRGBOut_tmp = NULL;
+ }
+ if (VecLabOut_fin != NULL)
+ {
+ delete[] VecLabOut_fin;
+ VecLabOut_fin = NULL;
+ }
+ if (VecRGBOut_fin != NULL)
+ {
+ delete[] VecRGBOut_fin;
+ VecRGBOut_fin = NULL;
+ }
+ if (pos != NULL)
+ {
+ delete[] pos;
+ pos = NULL;
+ }
+}
+
+void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates* inputcoordinates, ColorSpace colorspace,
+ VectorXd &Volume, int &GamutRegion, bool same_regions)
+{
+ size_t nInks = 0;
+
+ C_RGB_XYZ_Lab DataLab;
+ VectorXd InkOut(m_nInks);
+ double normFactor = 1;
+ if (!same_regions)
+ normFactor = m_colortable->GetNormFactor();
+
+ if (colorspace ==COLOR_SPACE__RGB)
+ {
+ //Convert RGB to Volume, no nee to calculate RGBOut and LabOut
+ // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric,
+ //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero
+ // and the coverted RGB will refect the color of the thread, but will be shown in Relative Colorimetric to the user
+
+ //convert to Lab
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ double *LabIn = new double[3];
+ double *RGBOutP = new double[3];
+ RGBOutP[0] = inputcoordinates->red;
+ RGBOutP[1] = inputcoordinates->green;
+ RGBOutP[2] = inputcoordinates->blue;
+ //RGB to Lab
+ CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65
+ LimitLab(LabIn);
+
+ //convert to inks
+ int GamutRegion;
+ double *InkOutP = new double[m_nInks];
+ if(same_regions)
+ m_colortable->m_B2ARTransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in units of 16 bits
+ else
+ m_colortable->m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in units of 16 bits
+
+ //Convert InkOut to Linear via initial calibration Tables
+ //Initial calibration tables are the ones that were included in the color table
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InkOutP[i] *= normFactor;
+ if (InkOutP[i] <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]);
+ InkOutP[i] /= 655.35;
+ }
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ if (RGBOutP != NULL)
+ {
+ delete[] RGBOutP;
+ RGBOutP = NULL;
+ }
+ }
+ else if(colorspace ==COLOR_SPACE__LAB)
+ {
+ // Basic assumption: Lab data is in relative colorimetric. No Need to convert
+
+ double *LabIn = new double[3];
+ LabIn[0] = inputcoordinates->l; //Relative Colorimetric
+ LabIn[1] = inputcoordinates->a;
+ LabIn[2] = inputcoordinates->b;
+
+ //convert to Inks
+ int GamutRegion;
+ double *InkOutP = new double[m_nInks];
+ if(same_regions)
+ m_colortable->m_B2ARTransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
+ else
+ m_colortable->m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval
+
+ for (int i = 0; i < m_nInks; ++i)
+ {
+ InkOutP[i] *= normFactor;
+ if (InkOutP[i] <= m_NormGamutRegionMaxLim[0])
+ {
+ m_colortable->m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]);
+ InkOutP[i] /= 655.35;
+ }
+ }
+ InkOut = DoubleToVector(InkOutP, m_nInks);
+
+ if (InkOutP != NULL)
+ {
+ delete[] InkOutP;
+ InkOutP = NULL;
+ }
+ if (LabIn != NULL)
+ {
+ delete[] LabIn;
+ LabIn = NULL;
+ }
+ }
+ else
+ {
+ throw std::exception("Unsupported Color Space");
+ return;
+ }
+ VectorXd NLInkOut(m_nInks);
+ VectorXd VolumeOut(m_nInks);
+ double *InkOutL = new double[m_nInks];
+ ConvertToNLInks(InkOut, NLInkOut);
+ LimitInks(NLInkOut, InkOutL);
+ NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume);
+ GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP);
+ NLcmtoPercentage(Volume, Volume);
+ if (InkOutL != NULL)
+ {
+ delete[] InkOutL;
+ InkOutL = NULL;
+ }
+
+ return;
+}
+
+
+void Tango::ColorLib::ColorConverter::PrepareGradient(GradientConversionInput* conversionInput, GradientConversionOutput *conversionOutput)
+{
+ //fill input stops...
+
+ m_nGradStops = conversionInput->n_stops;
+ int nInks = conversionInput->n_inputliquids;
+ m_nVolumes = nInks;
+ if(m_GradStops == NULL)
+ m_GradStops = new Gradient[m_nGradStops];
+ for (int i = 0; i < m_nGradStops; ++i)
+ m_GradStops[i].SetVolumeSize(nInks);
+
+ InputCoordinates **inputcoordinates = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*m_nGradStops);
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ inputcoordinates[i] = (InputCoordinates*)malloc(sizeof(InputCoordinates));
+ input_coordinates__init(inputcoordinates[i]);
+ }
+
+ fillGradientStops(conversionInput);
+ GradInput2InputCoords(conversionInput, inputcoordinates);
+
+ //Global Parameters of gradient
+ SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb);
+ bool has_forwarddata = conversionInput->has_forwarddata;
+ uint8_t *data = conversionInput->forwarddata.data;
+ m_nProcessRanges = conversionInput->n_processranges;
+ m_colortable->InitColorTables(has_forwarddata, data, m_nProcessRanges);
+ SetNumberofInks(m_colortable->GetnA2BnSepOut());
+ if(m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nProcessRanges];
+ double *tmpVal = m_colortable->GetNormGamutRegionMaxLim();
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = tmpVal[i];
+ int n_inputliquids = conversionInput->n_inputliquids;
+ InputLiquid **inputliquid = conversionInput->inputliquids;
+ readCalibrationTables(inputliquid, n_inputliquids);
+ if (m_colortable->GetTableVersion() <= 1)
+ {
+ throw std::exception("Color Table Version does not support gradients\0");
+ }
+ //finished reading tables and data
+ //prepare data to construct the gradient
+ //gradient is calculated in RGB space, thinned out or expanded based on dE criteria
+ // returns a vector of volumes and offsets
+ //gradient stops in different gamut region will use regular transformation
+ //if all stops in gamut region 0 the color Table will be suited to this gamut region
+
+ //prepare input
+ //if Color Space = lab, fill rgb and calculate volume + volume region
+ //if color space = rgb, fill lab and calculate volue + volume region
+ //if color space = Volume, fill lab and RGB, calculate volume region
+
+ bool InGamut = false;
+ m_WP.Set(0.9505, 1.00, 1.0888); //D65
+ //Initialize CIECAM02 transformation
+ Illum IL = D65;
+ SURROUND sur = average;
+ CAM02CS CS = UCS;
+ if (m_Conv02 == NULL)
+ m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS);
+
+ // Compare Strip White point to Color Table White Point
+ //CompareWhitePoints();
+ ColorConvert CConvertD65(D65, D65); //Destination, source
+ if (n_inputliquids != m_nInks)
+ throw std::exception("Number of available inks does not match ink tables\0");
+
+ if (m_ProcessRangesMaxP == NULL)
+ m_ProcessRangesMaxP = new double[m_nProcessRanges];
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ {
+ m_ProcessRangesMaxP[i] = conversionInput->processranges[i]->maxinkuptake;
+ }
+
+ VectorXd InkOut(m_nInks);
+ VectorXd RGBOut(3);
+ VectorXd LabOut(3);
+ VectorXd NLInkOut(m_nInks);
+ VectorXd Volume(m_nInks);
+ VectorXd VolumeOut(m_nInks);
+ //set maxNlPerCM
+ VectorXd NlperCM(m_nInks);
+ NlperCM.setZero();
+ m_maxNlPerCM = NlperCM;
+ for (int i = 0; i < m_nInks; ++i)
+ SetMaxNLperCM(conversionInput->inputliquids[i]->maxnanoliterpercentimeter, i);
+ //m_nVolumes = m_nB2AnSepOut;
+ int GamutRegion = 0;
+ ProcessGradientStops(inputcoordinates);
+
+ //are all stops in the same region?
+ int maxreg = -10;
+ int minreg = 10;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ GamutRegion = m_GradStops[i].Get_GamutRegion();
+ maxreg = std::max(maxreg, GamutRegion);
+ minreg = std::min(minreg, GamutRegion);
+ }
+ //Choose Gamut Region for Gradient calculation
+
+ bool same_regions = true;
+ if ((maxreg != minreg) & (maxreg > 0))
+ same_regions = false;
+ double dEThr = 0.8;
+ //find intermediate points
+ int ninterstops = 300;
+ double **VecRGBOut = new double*[ninterstops];
+ double **VecLabOut = new double*[ninterstops];
+ double *posOut = new double[ninterstops];
+ for (int i = 0; i < ninterstops; ++i)
+ {
+ VecLabOut[i] = new double[3];
+ VecRGBOut[i] = new double[3];
+ }
+ int nOut = 0;
+
+ int nmaxstops = ninterstops * m_nGradStops;
+
+ //Allocate temporary storage for all stops and positions
+ double **AllRGBOut_tmp = new double*[nmaxstops];
+ double **AllLabOut_tmp = new double*[nmaxstops];
+ double *AllPos_tmp = new double[nmaxstops];
+ for (int i = 0; i < nmaxstops; ++i)
+ {
+ AllRGBOut_tmp[i] = new double[3];
+ AllLabOut_tmp[i] = new double[3];
+ }
+ AllRGBOut_tmp[0][0] = m_GradStops[0].Get_RGB().Get_x();
+ AllRGBOut_tmp[0][1] = m_GradStops[0].Get_RGB().Get_y();
+ AllRGBOut_tmp[0][2] = m_GradStops[0].Get_RGB().Get_z();
+ AllLabOut_tmp[0][0] = m_GradStops[0].Get_Lab().Get_x();
+ AllLabOut_tmp[0][1] = m_GradStops[0].Get_Lab().Get_y();
+ AllLabOut_tmp[0][2] = m_GradStops[0].Get_Lab().Get_z();
+ AllPos_tmp[0] = m_GradStops[0].Get_Offset();
+ int ncountStops = 0;
+ int nPosStops = 0;
+ double dOffset = 0;
+ GradOffset OffsetType = EqSpaced;
+
+ for (int iStop = 0; iStop < m_nGradStops - 1; ++iStop)
+ {
+ findStops(m_GradStops[iStop], m_GradStops[iStop + 1], dEThr, ninterstops, nOut, VecRGBOut, VecLabOut, posOut);
+ switch (OffsetType)
+ {
+ case EqSpaced:
+ if (iStop == m_nGradStops - 2)
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset())*GradientEndThr / (nOut - 1);
+ else
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset()) / (nOut - 1);
+ for (int jPos = 1; jPos < nOut; ++jPos)
+ {
+ nPosStops++;
+ AllPos_tmp[nPosStops] = m_GradStops[iStop].Get_Offset() + dOffset * jPos;
+ }
+ break;
+ case dESpaced:
+ if (iStop == m_nGradStops - 2)
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset())*GradientEndThr / posOut[nOut - 1];
+ else
+ dOffset = (m_GradStops[iStop + 1].Get_Offset() - m_GradStops[iStop].Get_Offset()) / posOut[nOut - 1];
+ for (int jPos = 0; jPos < nOut; ++jPos)
+ {
+ nPosStops++;
+ AllPos_tmp[nPosStops] = m_GradStops[iStop].Get_Offset() + dOffset * posOut[jPos];
+ }
+ break;
+ }
+ //store the stops in temporary vector
+ for (int iCount = 1; iCount < nOut; ++iCount)
+ {
+ ncountStops++;
+ for (int jCS = 0; jCS < 3; ++jCS)
+ {
+ AllRGBOut_tmp[ncountStops][jCS] = VecRGBOut[iCount][jCS];
+ AllLabOut_tmp[ncountStops][jCS] = VecLabOut[iCount][jCS];
+ }
+ }
+ }
+
+ if (VecRGBOut != NULL)
+ {
+ for (int i = 0; i < ninterstops; ++i)
+ delete[]VecRGBOut[i];
+ delete[]VecRGBOut;
+ }
+ if (VecLabOut != NULL)
+ {
+ for (int i = 0; i < ninterstops; ++i)
+ delete[]VecLabOut[i];
+ delete[]VecLabOut;
+ VecLabOut = NULL;
+ }
+ if (posOut != NULL)
+ {
+ delete[]posOut;
+ posOut = NULL;
+ }
+
+ //Store Gradient intermediate data in Input Coordinates type structure.
+ //Simplify calculations, we only need the ink values, input values are in RGB color space
+ // Use table according to Gamut Regions, all stops in region 0, use 100%table otherwise use regular table, decrease dyeing speed.
+
+ int nTotalStops = ncountStops;
+ InputCoordinates **SubStops = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*nTotalStops);
+
+ //Calculate and store
+ for (int iTStops = 0; iTStops < nTotalStops; ++iTStops)
+ {
+ SubStops[iTStops] = (InputCoordinates*)malloc(sizeof(InputCoordinates));
+ input_coordinates__init(SubStops[iTStops]);
+ SubStops[iTStops]->l = AllLabOut_tmp[iTStops][0];
+ SubStops[iTStops]->a = AllLabOut_tmp[iTStops][1];
+ SubStops[iTStops]->b = AllLabOut_tmp[iTStops][2];
+ SubStops[iTStops]->red = (int)round(AllRGBOut_tmp[iTStops][0]);
+ SubStops[iTStops]->green = (int)round(AllRGBOut_tmp[iTStops][1]);
+ SubStops[iTStops]->blue = (int)round(AllRGBOut_tmp[iTStops][2]);
+ }
+
+ GradientOutputStop** outputStops = (GradientOutputStop**)malloc(sizeof(GradientOutputStop*) * nTotalStops);
+ conversionOutput->stops = outputStops;
+ conversionOutput->n_stops = nTotalStops;
+
+ ColorSpace SubStopsCS = COLOR_SPACE__LAB;
+ //double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0;
+ VectorXd VolumeStop(m_nInks);
+ MatrixXd MatVolume(ncountStops, m_nInks);
+ for (int iS = 0; iS < ncountStops; ++iS)
+ {
+ GradientOutputStop *stop = (GradientOutputStop*)malloc(sizeof(GradientOutputStop));
+ gradient_output_stop__init(stop);
+ ConvertGradStoptoVolume(SubStops[iS], SubStopsCS,
+ VolumeStop, GamutRegion, same_regions);
+ //start filling Output
+ fillStop(stop, VolumeStop, GamutRegion, AllPos_tmp[iS]);
+ MatVolume.row(iS) = VolumeStop;
+ outputStops[iS] = stop;
+ }
+ //Smooth Volumes
+ VectorXd VIn(ncountStops);
+ VectorXd VOut(ncountStops);
+ int FilterWidth = 7;
+ for (int iSep = 0; iSep < m_nInks; ++iSep)
+ {
+ for (int jStop = 0; jStop < ncountStops; ++jStop)
+ VIn(jStop) = MatVolume(jStop, iSep);
+ SmoothCurveData(VIn, VOut, FilterWidth);
+ for (int jS = 0; jS < ncountStops; ++jS)
+ outputStops[jS]->outputliquids[iSep]->volume = VOut(jS);
+ }
+ //Temp Output
+ for (int i = 0; i < ncountStops; ++i)
+ {
+ fprintf(stdout, "%d\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%6.3f\t%d\t%d\t%d\n", i,
+ outputStops[i]->offset, outputStops[i]->outputliquids[0]->volume,
+ outputStops[i]->outputliquids[1]->volume, outputStops[i]->outputliquids[2]->volume, outputStops[i]->outputliquids[3]->volume,
+ SubStops[i]->l, SubStops[i]->a, SubStops[i]->b, SubStops[i]->red, SubStops[i]->green, SubStops[i]->blue);
+ }
+ //release memory
+ if (AllLabOut_tmp != NULL)
+ {
+ for (int i = 0; i < nmaxstops; ++i)
+ delete[] AllLabOut_tmp[i];
+ delete[] AllLabOut_tmp;
+ AllLabOut_tmp = NULL;
+ }
+ if (AllRGBOut_tmp != NULL)
+ {
+ for (int i = 0; i < nmaxstops; ++i)
+ delete[] AllRGBOut_tmp[i];
+ delete[] AllRGBOut_tmp;
+ AllRGBOut_tmp = NULL;
+ }
+ if (AllPos_tmp != NULL)
+ {
+ delete[] AllPos_tmp;
+ AllPos_tmp = NULL;
+ }
+
+
+ for (int i = 0; i < m_nGradStops; ++i)
+ input_coordinates__free_unpacked(inputcoordinates[i], NULL);
+ free(inputcoordinates);
+ inputcoordinates = NULL;
+ for (int i = 0; i < nTotalStops; ++i)
+ input_coordinates__free_unpacked(SubStops[i], NULL);
+ free(SubStops);
+ SubStops = NULL;
+
+}
+
+
+
+
+void Tango::ColorLib::ColorConverter::fillStop(GradientOutputStop *&stop, VectorXd Volume, int GamutRegion, double Position)
+{
+ OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * m_nVolumes);
+ for (int i = 0; i < m_nVolumes; ++i)
+ {
+ outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid));
+ output_liquid__init(outputLiquids[i]);
+ switch (m_CalibCurves[i].getInkName())
+ {
+ case LIQUID_TYPE__Cyan:
+ case LIQUID_TYPE__Magenta:
+ case LIQUID_TYPE__Yellow:
+ case LIQUID_TYPE__Black:
+ {
+ outputLiquids[i]->has_volume = true;
+ outputLiquids[i]->has_liquidtype = true;
+ outputLiquids[i]->liquidtype = (LiquidType)(m_CalibCurves[i].getInkName());
+ outputLiquids[i]->volume = Volume(i);
+ break;
+ }
+ default:
+ throw std::exception("could not fill all volumes");
+ }
+ }
+ stop->outputliquids = outputLiquids;
+ stop->n_outputliquids = m_nVolumes;
+ stop->has_processparameterstableindex = true;
+ stop->processparameterstableindex = GamutRegion;
+ stop->has_offset = true;
+ stop->offset = Position;
+}
+
+void Tango::ColorLib::ColorConverter::GradInput2InputCoords(GradientConversionInput *conversionInput, InputCoordinates **inputcoordinates)
+{
+ for (size_t i = 0; i < conversionInput->n_stops; i++)
+ {
+ switch (conversionInput->stops[i]->colorspace)
+ {
+ case COLOR_SPACE__RGB: //Case RGB
+ inputcoordinates[i]->red = conversionInput->stops[i]->red;
+ inputcoordinates[i]->green = conversionInput->stops[i]->green;
+ inputcoordinates[i]->blue = conversionInput->stops[i]->blue;
+ inputcoordinates[i]->has_red = true;
+ inputcoordinates[i]->has_green = true;
+ inputcoordinates[i]->has_blue = true;
+ break;
+ case COLOR_SPACE__LAB: //Case LAB
+ inputcoordinates[i]->l = conversionInput->stops[i]->l;
+ inputcoordinates[i]->a = conversionInput->stops[i]->a;
+ inputcoordinates[i]->b = conversionInput->stops[i]->b;
+ inputcoordinates[i]->has_l = true;
+ inputcoordinates[i]->has_a = true;
+ inputcoordinates[i]->has_b = true;
+ break;
+ case COLOR_SPACE__Volume: //Case Volume
+ int size= (int)conversionInput->stops[i]->n_liquidvolumes;
+ InputLiquid** InputLiquidsIC = (InputLiquid**)malloc(sizeof(InputLiquid*) *size);
+ for (int j = 0; j < size; j++)
+ {
+ InputLiquidsIC[j] = (InputLiquid*)malloc(sizeof(InputLiquid));
+ input_liquid__init(InputLiquidsIC[j]);
+ }
+ for (size_t j= 0; j< (int)conversionInput->stops[i]->n_liquidvolumes; j++)
+ {
+ LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j];
+ switch (liquidVolume->liquidtype)
+ {
+ case LIQUID_TYPE__Cyan:
+// inputcoordinates[i]->inputliquids[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->volume = liquidVolume->volume;
+ InputLiquidsIC[0]->liquidtype = LIQUID_TYPE__Cyan;
+ break;
+ case LIQUID_TYPE__Magenta:
+ InputLiquidsIC[1]->volume = liquidVolume->volume;
+ InputLiquidsIC[1]->liquidtype = LIQUID_TYPE__Magenta;
+ break;
+ case LIQUID_TYPE__Yellow:
+ InputLiquidsIC[2]->volume = liquidVolume->volume;
+ InputLiquidsIC[2]->liquidtype = LIQUID_TYPE__Yellow;
+ break;
+ case LIQUID_TYPE__Black:
+ InputLiquidsIC[3]->volume = liquidVolume->volume;
+ InputLiquidsIC[3]->liquidtype = LIQUID_TYPE__Black;
+ break;
+ }
+
+ }
+ inputcoordinates[i]->inputliquids = InputLiquidsIC;
+ inputcoordinates[i]->n_inputliquids = size;
+ }
+ }
+}
+
+void Tango::ColorLib::ColorConverter::LimitInks(VectorXd inInks, double *BoundedInks)
+{
+ //convert Ink % to [nl/cm]
+ //Bound Ink
+ for (int i = 0; i < m_nInks; ++i)
+ BoundedInks[i] = std::min(inInks(i)*m_maxNlPerCM(i)/100.0, m_ProcessRangesMaxP[m_nProcessRanges - 1]);
+}
+
+void Tango::ColorLib::ColorConverter::NLcmtoPercentage(VectorXd InVolume, VectorXd &OutVolume)
+{
+ for (int i = 0; i < m_nInks; ++i)
+ OutVolume(i) =100* InVolume(i) / m_maxNlPerCM(i);
+}
+
+int Tango::ColorLib::ColorConverter::GetGamutRegion(VectorXd Volume, double *GamutLimits)
+{
+ double TotalVolume = 0.0;
+ int GamutRegion = 0;
+ for (int i = 0; i < m_nInks; ++i)
+ TotalVolume += Volume(i);
+ for (int i=0; i< m_colortable->GetnGamutRegions(); ++i)
+ {
+ if (TotalVolume > GamutLimits[i])
+ GamutRegion++;
+ }
+ return(GamutRegion);
+}
+
+void Tango::ColorLib::ColorConverter::SmoothCurveData(VectorXd VIn, VectorXd &VOut, int FilterWidth)
+{
+ int Vlength = VIn.size();
+ VectorXd tmpV(Vlength);
+ int NumIter = (int)(std::max(FilterWidth, 3) - 2);
+ //Smooth the data with repeated applications of a[1 1 1] filter
+ for (int i = 0; i < NumIter; ++i)
+ {
+ for (int j=0; j< Vlength; ++j)
+ tmpV(j) = VIn(j);
+ for (int k=1; k< Vlength-1; ++k)
+ VIn(k) = (tmpV(k-1) + tmpV(k) + tmpV(k+1)) / 3;
+ }
+ for (int j = 0; j < Vlength; ++j)
+ VOut(j) = VIn(j);
+}
+
+void Tango::ColorLib::ColorConverter::ProcessGradientStops(InputCoordinates **inputcoordinates)
+{
+ VectorXd Volume(m_nInks);
+ VectorXd RGBOut(m_nInks);
+ VectorXd LabOut(m_nInks);
+ VectorXd InkOut(m_nInks);
+ VectorXd NLInkOut(m_nInks);
+ double * InkOutL = new double[m_nInks];
+ double * LabOutV = new double[3];
+ double * LabOutFinal = new double[3];
+
+ ColorConvert CConvertD65(D65, D65);
+
+ bool InGamut = true;
+ int GamutRegion = 0;
+ for (int i = 0; i < m_nGradStops; ++i)
+ {
+ if (m_GradStops[i].Get_ColorSpace() == COLOR_SPACE__Volume || m_GradStops[i].Get_ColorSpace() == COLOR_SPACE__Catalog)
+ { //Convert volume to Lab
+ //Convert lab to rgb
+ ConvertVolumeToRGBDisplay(inputcoordinates[i], m_nProcessRanges, m_GradStops[i].Get_ColorSpace(), Volume, RGBOut, LabOut, GamutRegion);
+ //RGB has to be calculate from Absolute Colorimetric, in the above function it is calculated from relative.
+ //Recalculate RGB and do not clip values below zero or above 255
+ C_RGB_XYZ_Lab Lab(LabOut);
+ C_RGB_XYZ_Lab RGB(RGBOut);
+ RGB = CConvertD65.LabtoRGBNoClip(Lab); // RGB is not clipped and was derived from absolute colorimetric Lab Value
+ RGBOut = VectorXd(RGB.Get_x(), RGB.Get_y(), RGB.Get_z());
+ //store data
+ m_GradStops[i].Set_Lab(LabOut);
+ m_GradStops[i].Set_RGB(RGBOut);
+ m_GradStops[i].Set_GamutRegion( GamutRegion);
+ bool retValue = CheckLabInRGBGamut(LabOut);
+ m_GradStops[i].SetInRGBLimits(retValue);
+ m_GradStops[i].SetInGamut (true);
+ }
+ else
+ {
+ ConvertColorToLinearInks(inputcoordinates[i], m_GradStops[i].Get_ColorSpace(), InkOut, RGBOut, LabOut, GamutRegion, InGamut);
+ //Inks are in Linear Space , convert to nonlinear by using Calibration Tables,
+ // Right now calibration is in the [0-100] range, values exceeding [0-100] are not transformed
+ C_RGB_XYZ_Lab Lab(LabOut);
+ C_RGB_XYZ_Lab RGB(RGBOut);
+ if (m_GradStops[i].Get_ColorSpace() == COLOR_SPACE__RGB)
+ {
+ RGB = CConvertD65.LabtoRGBNoClip(Lab); // RGB is not clipped and was derived from absolute colorimetric Lab Value
+ RGBOut = VectorXd(RGB.Get_x(), RGB.Get_y(), RGB.Get_z());
+ }
+ ConvertToNLInks(InkOut, NLInkOut);
+ LimitInks(NLInkOut, InkOutL);
+ NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume);
+ GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP);
+ NLcmtoPercentage(Volume, Volume);
+ //fill data
+ //fill volume
+ //allocate m_GradStops[i].Volume
+ for (int j = 0; j < m_nInks; ++j)
+ m_GradStops[i].SetVolumeValue(Volume[j], j);
+ m_GradStops[i].Set_GamutRegion(GamutRegion);
+ m_GradStops[i].SetInGamut(InGamut);
+ //LabOut and RGBOut might be different if the input was out of gamut
+ m_GradStops[i].Set_Lab(LabOut);
+ m_GradStops[i].Set_RGB(RGBOut);
+ }
+ //Convert Lab Values to Relative Colorimetric. These values will be used in the Gradient Volume calculation.
+ VectorToDouble(LabOut, LabOutV);
+ /* if (m_AdaptWP)
+ {
+ CConvertD65.ChangeWP(LabOutV, LabOutV, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables
+ }
+ */
+ //double *LabInFinal2 = DBG_NEW double[3];
+ // CConvertD65.ChangeWP(LabOutV, LabOutFinal, m_WP, m_whitepointXYZ_CT); //LabInFinal is in Relative Colorimetric Space
+ CConvertD65.ChangeWP(LabOutV, LabOutFinal, m_WP, m_whitepointXYZ_Strip); //LabInFinal is in Relative Colorimetric Space
+ C_RGB_XYZ_Lab LabOut1(LabOutFinal[0], LabOutFinal[1], LabOutFinal[2]);
+
+ m_GradStops[i].Set_Lab(LabOut1);
+ bool retValue = CheckLabInRGBGamut( DoubleToVector(LabOutFinal,3));
+ m_GradStops[i].SetInRGBLimits(retValue);
+ }
+ //free vectors
+ if (LabOutV != NULL)
+ {
+ delete[] LabOutV;
+ LabOutV = NULL;
+ }
+ if (LabOutFinal != NULL)
+ {
+ delete[] LabOutFinal;
+ LabOutFinal = NULL;
+ }
+ if (InkOutL != NULL)
+ {
+ delete[] InkOutL;
+ InkOutL = NULL;
+ }
+}
+
+bool Tango::ColorLib::ColorConverter::CheckLabInRGBGamut(VectorXd Lab)
+{
+ bool retVal = false;
+ C_RGB_XYZ_Lab DataLab;
+ DataLab.Set(Lab);
+ retVal = CheckLabInRGBGamut(DataLab);
+ return(retVal);
+}
+
+bool Tango::ColorLib::ColorConverter::CheckLabInRGBGamut( C_RGB_XYZ_Lab Lab)
+{
+ bool retVal = false;
+ //ColorConvert ColConv(D65, D65);
+ C_RGB_XYZ_Lab DataRGB1;
+ C_RGB_XYZ_Lab DataLab1;
+ //DataRGB1 limited to [0,255]
+ DataRGB1 = m_Conv02->LabtoRGB(Lab);
+ DataLab1 = m_Conv02->RGBtoLab(DataRGB1);
+ double dE = 0;
+ m_Conv02->dE76(DataLab1, Lab, dE);
+ if (dE < 0.01)
+ retVal = true;
+ return(retVal);
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.cpp
new file mode 100644
index 000000000..b70acbda1
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.cpp
@@ -0,0 +1,68 @@
+#include <cstdlib>
+#include "Exports.h"
+#include "ColorConverter.h"
+#include "ColorCalibrator.h"
+//#include <vld.h>
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif*/
+//#include <vld.h>
+#pragma once
+
+#define EXPORT_API __declspec(dllexport)
+
+using namespace std;
+using namespace Tango::ColorLib;
+
+extern "C" EXPORT_API size_t __cdecl Convert(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorConverter converter;
+ return converter.Convert(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl P_IsInGamut(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer)
+{
+ ColorConverter converter;
+ return converter.P_IsInGamut(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl GetLiquidFactor(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorCalibrator calibrator;
+ return calibrator.GetLiquidFactor(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl GenerateGradient(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorConverter converter;
+ return converter.GenerateGradient(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl GetLinearizationMeasurements(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorCalibrator calibrator;
+ return calibrator.GetLinearizationMeasurements(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl GetRecommendedProcessParameters(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorConverter converter;
+ return converter.GetRecommendedProcessParameters(input_buffer, input_buffer_size, output_buffer);
+}
+
+extern "C" EXPORT_API size_t __cdecl CheckOutOfGamut(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer)
+{
+ ColorConverter converter;
+ return converter.CheckOutOfGamut(input_buffer, input_buffer_size, output_buffer);
+}
+
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.h
new file mode 100644
index 000000000..3f386f303
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Exports.h
@@ -0,0 +1,6 @@
+#include <cstdlib>
+#include <cstdint>
+
+#define EXPORT_API __declspec(dllexport)
+
+extern "C" EXPORT_API size_t Convert(uint8_t* input_buffer, size_t input_buffer_size, uint8_t*& output_buffer);
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.cpp
new file mode 100644
index 000000000..076064f66
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.cpp
@@ -0,0 +1,217 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+#include "ForwardModel.h"
+#include <iostream>
+#include <stdio.h>
+#include "NumConversions.h"
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorConvert.h"
+
+using namespace std;
+
+ForwardModel::ForwardModel() :
+ m_nChannels(0), m_nPCSChannels(0), m_whiteptLab(NULL), m_prec(0),
+ m_nEntries(0), m_CoeffList(NULL), m_expList(NULL), m_Vandermonde(NULL)
+{
+
+}
+
+ForwardModel::~ForwardModel()
+{
+ if (m_CoeffList != NULL)
+ {
+ for (int i=0; i< m_nPCSChannels; ++i)
+ delete[] m_CoeffList[i];
+ delete[] m_CoeffList;
+ m_CoeffList = NULL;
+ }
+
+ if (m_expList != NULL)
+ {
+ for (int i = 0; i < m_nChannels; ++i)
+ delete[] m_expList[i];
+ delete[] m_expList;
+ m_expList = NULL;
+ }
+
+ if (m_Vandermonde != NULL)
+ {
+ delete[] m_Vandermonde;
+ m_Vandermonde = NULL;
+ }
+
+ if (m_whiteptLab != NULL)
+ {
+ delete[] m_whiteptLab;
+ m_whiteptLab = NULL;
+ }
+
+}
+
+void ForwardModel::InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize)
+{
+ // 0 - 3 prec
+ //4 - 7 reserved, must be 0
+ // 8 number of input channels, uint8
+ // 9 number of output channels, uint8
+ // 10 - 11 number of coefficients
+ // 12 - 13 LH Limit
+ // 14 - 15 RH Limit
+ // 16 - 19 reserved for padding
+ // 20 - n Model data data + exponent
+
+ if (colorTransformFileSize < 32)
+ {
+ throw std::exception("Init Forward Model, invalid size");
+ }
+
+ // Check for signature
+ unsigned char *buffer = colorTransformBuffer;
+ if (buffer == NULL)
+ {
+ throw std::exception("Memory Error, ForwardModel::InitData");
+ }
+ NumConversions Conv;
+ //Table precision
+ int bytesread = 0;
+ int tmpB = Conv.ByteToInt(buffer, 0);
+ bytesread += 4;
+
+ char FMType[sizeof(tmpB) + 1];
+ Conv.getchar(tmpB, *FMType);
+ //char *luttype = DBG_NEW char[n + 1];
+// strcpy(Curvetype, tmpC);
+ int FMPrecision;
+ if (strncmp(FMType, "prc1", sizeof(tmpB)) == 0)
+ FMPrecision = 1;
+ else if (strncmp(FMType, "prc2", sizeof(tmpB)) == 0)
+ FMPrecision = 2;
+ else
+ {
+ throw std::exception("Wrong precision in Forward Model");
+ return;
+ }
+
+ // Skip past reserved padding bytes
+ bytesread += 4;
+
+ uint8_t num_channels = buffer[bytesread];
+ Set_nChannels((int)num_channels); //Numer of channels
+ bytesread += 1;
+
+ uint8_t num_PCSchannels = buffer[bytesread];
+ Set_nPCSChannels((int)num_PCSchannels); //Numer of PCS channels
+ bytesread += 1;
+
+ unsigned short nEntries = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ Set_nEntries((int)nEntries);
+ double Interval = (double)(Conv.ByteToShort(buffer, bytesread));
+ bytesread += 2;
+ double RHLim = (double)(Conv.ByteToShort(buffer, bytesread));
+ bytesread += 2;
+ double LHLim = RHLim - Interval;
+ double Gain = RHLim - LHLim;
+ double Offset = LHLim;
+
+ if (m_CoeffList == NULL)
+ {
+ m_CoeffList = new double*[m_nEntries];
+ for (int i = 0; i < m_nEntries; ++i)
+ m_CoeffList[i] = new double[m_nPCSChannels];
+ }
+ if (m_expList == NULL)
+ {
+ m_expList = new double*[m_nEntries];
+ for (int i = 0; i < m_nEntries; ++i)
+ m_expList[i] = new double[m_nChannels];
+ }
+
+ if (m_Vandermonde == NULL)
+ {
+ m_Vandermonde = new double[m_nEntries];
+ for (int i = 0; i < m_nEntries; ++i)
+ m_Vandermonde[i] = 1.0;
+ }
+
+ //read Coefficients Tag
+ if (m_prec == 1)
+ {
+ for (int i = 0; i < m_nChannels; ++i)
+ {
+ for (int j = 0; j < m_nEntries; ++j)
+ {
+ m_CoeffList[j][i] = (double)(buffer[bytesread]);
+ bytesread += 1;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < m_nPCSChannels; ++i)
+ {
+ for (int j = 0; j < nEntries; ++j)
+ {
+ m_CoeffList[j][i] = (double)(Conv.ByteToShort(buffer, bytesread));
+ bytesread += 2;
+
+ m_CoeffList[j][i] = Gain * (double(m_CoeffList[j][i]) / 65535) + Offset;
+ }
+ }
+ }
+ //Read Exponents List
+ for (int i = 0; i < m_nChannels; ++i)
+ {
+ for (int j = 0; j < m_nEntries; ++j)
+ {
+ m_expList[j][i] = (double)(buffer[bytesread]);
+ bytesread += 1;
+ }
+ }
+}
+
+void ForwardModel::CalcFM(double *InInk, double *OutLab)
+{
+ int i, k;
+ //Calculate Vandermonde Vector [1 x number of entries]
+ for ( i = 0; i < m_nEntries; ++i)
+ {
+ m_Vandermonde[i] = 1.0;
+ for ( k = 0; k < m_nChannels; ++k)
+ m_Vandermonde[i] *= std::pow( InInk[k], m_expList[i][k]);
+ }
+
+ //calculate Lab Vandermodex Coeefficients + FreeTerm
+ for (i = 0; i < m_nPCSChannels; ++i)
+ {
+ OutLab[i] = m_whiteptLab[i];
+ for (k = 0; k < m_nEntries; ++k)
+ OutLab[i] += m_Vandermonde[k] * m_CoeffList[k][i] ;
+ }
+}
+
+void ForwardModel::SetFreeTerm(C_RGB_XYZ_Lab whiteptLab)
+{
+ if (m_whiteptLab == NULL)
+ m_whiteptLab = new double[m_nPCSChannels];
+
+ m_whiteptLab[0] = whiteptLab.Get_x();
+ m_whiteptLab[1] = whiteptLab.Get_y();
+ m_whiteptLab[2] = whiteptLab.Get_z();
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.h
new file mode 100644
index 000000000..5a310548f
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ForwardModel.h
@@ -0,0 +1,32 @@
+#ifndef _ForwardModel_H_
+#define _ForwardModel_H_
+
+#include <stdlib.h>
+#include "C_RGB_XYZ_Lab.h"
+class ForwardModel {
+public:
+ ForwardModel();
+ ~ForwardModel();
+ int Get_nChannels() { return(m_nChannels); };
+ int Get_nPCSChannels() { return(m_nPCSChannels); };
+ int Get_nEntries() { return(m_nEntries); };
+ void InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize);
+ void CalcFM(double *InInk, double *OutLab);
+ void SetFreeTerm(C_RGB_XYZ_Lab whiteptLab);
+
+private:
+ int m_prec;
+ int m_nChannels;
+ int m_nPCSChannels;
+ int m_nEntries;
+ double *m_whiteptLab;
+ void Set_nChannels(int nChannels) { m_nChannels = nChannels; };
+ void Set_nPCSChannels(int nPCSChannels) { m_nPCSChannels = nPCSChannels; };
+ void Set_nEntries(int nEntries) { m_nEntries = nEntries; };
+
+ double **m_CoeffList;
+ double **m_expList;
+ double *m_Vandermonde;
+};
+
+#endif
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.c
new file mode 100644
index 000000000..981988d99
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.c
@@ -0,0 +1,105 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationData.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "CalibrationData.pb-c.h"
+void calibration_data__init
+ (CalibrationData *message)
+{
+ static const CalibrationData init_value = CALIBRATION_DATA__INIT;
+ *message = init_value;
+}
+size_t calibration_data__get_packed_size
+ (const CalibrationData *message)
+{
+ assert(message->base.descriptor == &calibration_data__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t calibration_data__pack
+ (const CalibrationData *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &calibration_data__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t calibration_data__pack_to_buffer
+ (const CalibrationData *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &calibration_data__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CalibrationData *
+ calibration_data__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CalibrationData *)
+ protobuf_c_message_unpack (&calibration_data__descriptor,
+ allocator, len, data);
+}
+void calibration_data__free_unpacked
+ (CalibrationData *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &calibration_data__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor calibration_data__field_descriptors[2] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(CalibrationData, has_liquidtype),
+ offsetof(CalibrationData, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "CalibrationPoints",
+ 2,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CalibrationData, n_calibrationpoints),
+ offsetof(CalibrationData, calibrationpoints),
+ &calibration_point__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned calibration_data__field_indices_by_name[] = {
+ 1, /* field[1] = CalibrationPoints */
+ 0, /* field[0] = LiquidType */
+};
+static const ProtobufCIntRange calibration_data__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor calibration_data__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CalibrationData",
+ "CalibrationData",
+ "CalibrationData",
+ "",
+ sizeof(CalibrationData),
+ 2,
+ calibration_data__field_descriptors,
+ calibration_data__field_indices_by_name,
+ 1, calibration_data__number_ranges,
+ (ProtobufCMessageInit) calibration_data__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.h
new file mode 100644
index 000000000..ccecc327e
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationData.pb-c.h
@@ -0,0 +1,76 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationData.proto */
+
+#ifndef PROTOBUF_C_CalibrationData_2eproto__INCLUDED
+#define PROTOBUF_C_CalibrationData_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "CalibrationPoint.pb-c.h"
+#include "LiquidType.pb-c.h"
+
+typedef struct _CalibrationData CalibrationData;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _CalibrationData
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ size_t n_calibrationpoints;
+ CalibrationPoint **calibrationpoints;
+};
+#define CALIBRATION_DATA__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&calibration_data__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, 0,NULL }
+
+
+/* CalibrationData methods */
+void calibration_data__init
+ (CalibrationData *message);
+size_t calibration_data__get_packed_size
+ (const CalibrationData *message);
+size_t calibration_data__pack
+ (const CalibrationData *message,
+ uint8_t *out);
+size_t calibration_data__pack_to_buffer
+ (const CalibrationData *message,
+ ProtobufCBuffer *buffer);
+CalibrationData *
+ calibration_data__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void calibration_data__free_unpacked
+ (CalibrationData *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*CalibrationData_Closure)
+ (const CalibrationData *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor calibration_data__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_CalibrationData_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.c
new file mode 100644
index 000000000..1cf8e00a7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.c
@@ -0,0 +1,145 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "CalibrationInput.pb-c.h"
+void calibration_input__init
+ (CalibrationInput *message)
+{
+ static const CalibrationInput init_value = CALIBRATION_INPUT__INIT;
+ *message = init_value;
+}
+size_t calibration_input__get_packed_size
+ (const CalibrationInput *message)
+{
+ assert(message->base.descriptor == &calibration_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t calibration_input__pack
+ (const CalibrationInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &calibration_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t calibration_input__pack_to_buffer
+ (const CalibrationInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &calibration_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CalibrationInput *
+ calibration_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CalibrationInput *)
+ protobuf_c_message_unpack (&calibration_input__descriptor,
+ allocator, len, data);
+}
+void calibration_input__free_unpacked
+ (CalibrationInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &calibration_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor calibration_input__field_descriptors[5] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(CalibrationInput, has_liquidtype),
+ offsetof(CalibrationInput, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetL",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationInput, has_targetl),
+ offsetof(CalibrationInput, targetl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetA",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationInput, has_targeta),
+ offsetof(CalibrationInput, targeta),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetB",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationInput, has_targetb),
+ offsetof(CalibrationInput, targetb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Measurements",
+ 20,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CalibrationInput, n_measurements),
+ offsetof(CalibrationInput, measurements),
+ &calibration_measurement__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned calibration_input__field_indices_by_name[] = {
+ 0, /* field[0] = LiquidType */
+ 4, /* field[4] = Measurements */
+ 2, /* field[2] = TargetA */
+ 3, /* field[3] = TargetB */
+ 1, /* field[1] = TargetL */
+};
+static const ProtobufCIntRange calibration_input__number_ranges[2 + 1] =
+{
+ { 1, 0 },
+ { 20, 4 },
+ { 0, 5 }
+};
+const ProtobufCMessageDescriptor calibration_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CalibrationInput",
+ "CalibrationInput",
+ "CalibrationInput",
+ "",
+ sizeof(CalibrationInput),
+ 5,
+ calibration_input__field_descriptors,
+ calibration_input__field_indices_by_name,
+ 2, calibration_input__number_ranges,
+ (ProtobufCMessageInit) calibration_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.h
new file mode 100644
index 000000000..be42ed59b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationInput.pb-c.h
@@ -0,0 +1,82 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationInput.proto */
+
+#ifndef PROTOBUF_C_CalibrationInput_2eproto__INCLUDED
+#define PROTOBUF_C_CalibrationInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "CalibrationMeasurement.pb-c.h"
+#include "LiquidType.pb-c.h"
+
+typedef struct _CalibrationInput CalibrationInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _CalibrationInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ protobuf_c_boolean has_targetl;
+ double targetl;
+ protobuf_c_boolean has_targeta;
+ double targeta;
+ protobuf_c_boolean has_targetb;
+ double targetb;
+ size_t n_measurements;
+ CalibrationMeasurement **measurements;
+};
+#define CALIBRATION_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&calibration_input__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, 0, 0, 0, 0, 0, 0, 0,NULL }
+
+
+/* CalibrationInput methods */
+void calibration_input__init
+ (CalibrationInput *message);
+size_t calibration_input__get_packed_size
+ (const CalibrationInput *message);
+size_t calibration_input__pack
+ (const CalibrationInput *message,
+ uint8_t *out);
+size_t calibration_input__pack_to_buffer
+ (const CalibrationInput *message,
+ ProtobufCBuffer *buffer);
+CalibrationInput *
+ calibration_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void calibration_input__free_unpacked
+ (CalibrationInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*CalibrationInput_Closure)
+ (const CalibrationInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor calibration_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_CalibrationInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.c
new file mode 100644
index 000000000..24d499c59
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.c
@@ -0,0 +1,131 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationMeasurement.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "CalibrationMeasurement.pb-c.h"
+void calibration_measurement__init
+ (CalibrationMeasurement *message)
+{
+ static const CalibrationMeasurement init_value = CALIBRATION_MEASUREMENT__INIT;
+ *message = init_value;
+}
+size_t calibration_measurement__get_packed_size
+ (const CalibrationMeasurement *message)
+{
+ assert(message->base.descriptor == &calibration_measurement__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t calibration_measurement__pack
+ (const CalibrationMeasurement *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &calibration_measurement__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t calibration_measurement__pack_to_buffer
+ (const CalibrationMeasurement *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &calibration_measurement__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CalibrationMeasurement *
+ calibration_measurement__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CalibrationMeasurement *)
+ protobuf_c_message_unpack (&calibration_measurement__descriptor,
+ allocator, len, data);
+}
+void calibration_measurement__free_unpacked
+ (CalibrationMeasurement *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &calibration_measurement__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor calibration_measurement__field_descriptors[4] =
+{
+ {
+ "NanoliterPerCentimeter",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationMeasurement, has_nanoliterpercentimeter),
+ offsetof(CalibrationMeasurement, nanoliterpercentimeter),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "L",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationMeasurement, has_l),
+ offsetof(CalibrationMeasurement, l),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "A",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationMeasurement, has_a),
+ offsetof(CalibrationMeasurement, a),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "B",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationMeasurement, has_b),
+ offsetof(CalibrationMeasurement, b),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned calibration_measurement__field_indices_by_name[] = {
+ 2, /* field[2] = A */
+ 3, /* field[3] = B */
+ 1, /* field[1] = L */
+ 0, /* field[0] = NanoliterPerCentimeter */
+};
+static const ProtobufCIntRange calibration_measurement__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 4 }
+};
+const ProtobufCMessageDescriptor calibration_measurement__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CalibrationMeasurement",
+ "CalibrationMeasurement",
+ "CalibrationMeasurement",
+ "",
+ sizeof(CalibrationMeasurement),
+ 4,
+ calibration_measurement__field_descriptors,
+ calibration_measurement__field_indices_by_name,
+ 1, calibration_measurement__number_ranges,
+ (ProtobufCMessageInit) calibration_measurement__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.h
new file mode 100644
index 000000000..5c7c58a64
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationMeasurement.pb-c.h
@@ -0,0 +1,78 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationMeasurement.proto */
+
+#ifndef PROTOBUF_C_CalibrationMeasurement_2eproto__INCLUDED
+#define PROTOBUF_C_CalibrationMeasurement_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _CalibrationMeasurement CalibrationMeasurement;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _CalibrationMeasurement
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_nanoliterpercentimeter;
+ double nanoliterpercentimeter;
+ protobuf_c_boolean has_l;
+ double l;
+ protobuf_c_boolean has_a;
+ double a;
+ protobuf_c_boolean has_b;
+ double b;
+};
+#define CALIBRATION_MEASUREMENT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&calibration_measurement__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, 0 }
+
+
+/* CalibrationMeasurement methods */
+void calibration_measurement__init
+ (CalibrationMeasurement *message);
+size_t calibration_measurement__get_packed_size
+ (const CalibrationMeasurement *message);
+size_t calibration_measurement__pack
+ (const CalibrationMeasurement *message,
+ uint8_t *out);
+size_t calibration_measurement__pack_to_buffer
+ (const CalibrationMeasurement *message,
+ ProtobufCBuffer *buffer);
+CalibrationMeasurement *
+ calibration_measurement__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void calibration_measurement__free_unpacked
+ (CalibrationMeasurement *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*CalibrationMeasurement_Closure)
+ (const CalibrationMeasurement *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor calibration_measurement__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_CalibrationMeasurement_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.c
new file mode 100644
index 000000000..dca0c112b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.c
@@ -0,0 +1,119 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "CalibrationOutput.pb-c.h"
+void calibration_output__init
+ (CalibrationOutput *message)
+{
+ static const CalibrationOutput init_value = CALIBRATION_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t calibration_output__get_packed_size
+ (const CalibrationOutput *message)
+{
+ assert(message->base.descriptor == &calibration_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t calibration_output__pack
+ (const CalibrationOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &calibration_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t calibration_output__pack_to_buffer
+ (const CalibrationOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &calibration_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CalibrationOutput *
+ calibration_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CalibrationOutput *)
+ protobuf_c_message_unpack (&calibration_output__descriptor,
+ allocator, len, data);
+}
+void calibration_output__free_unpacked
+ (CalibrationOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &calibration_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor calibration_output__field_descriptors[3] =
+{
+ {
+ "LiquidFactor",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationOutput, has_liquidfactor),
+ offsetof(CalibrationOutput, liquidfactor),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 20,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(CalibrationOutput, has_haserror),
+ offsetof(CalibrationOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 21,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(CalibrationOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned calibration_output__field_indices_by_name[] = {
+ 2, /* field[2] = ErrorMessage */
+ 1, /* field[1] = HasError */
+ 0, /* field[0] = LiquidFactor */
+};
+static const ProtobufCIntRange calibration_output__number_ranges[2 + 1] =
+{
+ { 1, 0 },
+ { 20, 1 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor calibration_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CalibrationOutput",
+ "CalibrationOutput",
+ "CalibrationOutput",
+ "",
+ sizeof(CalibrationOutput),
+ 3,
+ calibration_output__field_descriptors,
+ calibration_output__field_indices_by_name,
+ 2, calibration_output__number_ranges,
+ (ProtobufCMessageInit) calibration_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.h
new file mode 100644
index 000000000..c60f4f3c8
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationOutput.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationOutput.proto */
+
+#ifndef PROTOBUF_C_CalibrationOutput_2eproto__INCLUDED
+#define PROTOBUF_C_CalibrationOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _CalibrationOutput CalibrationOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _CalibrationOutput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidfactor;
+ double liquidfactor;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define CALIBRATION_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&calibration_output__descriptor) \
+ , 0, 0, 0, 0, NULL }
+
+
+/* CalibrationOutput methods */
+void calibration_output__init
+ (CalibrationOutput *message);
+size_t calibration_output__get_packed_size
+ (const CalibrationOutput *message);
+size_t calibration_output__pack
+ (const CalibrationOutput *message,
+ uint8_t *out);
+size_t calibration_output__pack_to_buffer
+ (const CalibrationOutput *message,
+ ProtobufCBuffer *buffer);
+CalibrationOutput *
+ calibration_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void calibration_output__free_unpacked
+ (CalibrationOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*CalibrationOutput_Closure)
+ (const CalibrationOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor calibration_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_CalibrationOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.c
new file mode 100644
index 000000000..691a97ea6
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.c
@@ -0,0 +1,105 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationPoint.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "CalibrationPoint.pb-c.h"
+void calibration_point__init
+ (CalibrationPoint *message)
+{
+ static const CalibrationPoint init_value = CALIBRATION_POINT__INIT;
+ *message = init_value;
+}
+size_t calibration_point__get_packed_size
+ (const CalibrationPoint *message)
+{
+ assert(message->base.descriptor == &calibration_point__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t calibration_point__pack
+ (const CalibrationPoint *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &calibration_point__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t calibration_point__pack_to_buffer
+ (const CalibrationPoint *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &calibration_point__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CalibrationPoint *
+ calibration_point__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CalibrationPoint *)
+ protobuf_c_message_unpack (&calibration_point__descriptor,
+ allocator, len, data);
+}
+void calibration_point__free_unpacked
+ (CalibrationPoint *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &calibration_point__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor calibration_point__field_descriptors[2] =
+{
+ {
+ "X",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationPoint, has_x),
+ offsetof(CalibrationPoint, x),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Y",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(CalibrationPoint, has_y),
+ offsetof(CalibrationPoint, y),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned calibration_point__field_indices_by_name[] = {
+ 0, /* field[0] = X */
+ 1, /* field[1] = Y */
+};
+static const ProtobufCIntRange calibration_point__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor calibration_point__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CalibrationPoint",
+ "CalibrationPoint",
+ "CalibrationPoint",
+ "",
+ sizeof(CalibrationPoint),
+ 2,
+ calibration_point__field_descriptors,
+ calibration_point__field_indices_by_name,
+ 1, calibration_point__number_ranges,
+ (ProtobufCMessageInit) calibration_point__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.h
new file mode 100644
index 000000000..a58bc1ec6
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/CalibrationPoint.pb-c.h
@@ -0,0 +1,74 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: CalibrationPoint.proto */
+
+#ifndef PROTOBUF_C_CalibrationPoint_2eproto__INCLUDED
+#define PROTOBUF_C_CalibrationPoint_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _CalibrationPoint CalibrationPoint;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _CalibrationPoint
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_x;
+ double x;
+ protobuf_c_boolean has_y;
+ double y;
+};
+#define CALIBRATION_POINT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&calibration_point__descriptor) \
+ , 0, 0, 0, 0 }
+
+
+/* CalibrationPoint methods */
+void calibration_point__init
+ (CalibrationPoint *message);
+size_t calibration_point__get_packed_size
+ (const CalibrationPoint *message);
+size_t calibration_point__pack
+ (const CalibrationPoint *message,
+ uint8_t *out);
+size_t calibration_point__pack_to_buffer
+ (const CalibrationPoint *message,
+ ProtobufCBuffer *buffer);
+CalibrationPoint *
+ calibration_point__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void calibration_point__free_unpacked
+ (CalibrationPoint *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*CalibrationPoint_Closure)
+ (const CalibrationPoint *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor calibration_point__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_CalibrationPoint_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.c
new file mode 100644
index 000000000..8ea22ca90
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.c
@@ -0,0 +1,43 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ColorSpace.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "ColorSpace.pb-c.h"
+static const ProtobufCEnumValue color_space__enum_values_by_number[5] =
+{
+ { "Volume", "COLOR_SPACE__Volume", 0 },
+ { "RGB", "COLOR_SPACE__RGB", 1 },
+ { "CMYK", "COLOR_SPACE__CMYK", 2 },
+ { "LAB", "COLOR_SPACE__LAB", 3 },
+ { "Catalog", "COLOR_SPACE__Catalog", 4 },
+};
+static const ProtobufCIntRange color_space__value_ranges[] = {
+{0, 0},{0, 5}
+};
+static const ProtobufCEnumValueIndex color_space__enum_values_by_name[5] =
+{
+ { "CMYK", 2 },
+ { "Catalog", 4 },
+ { "LAB", 3 },
+ { "RGB", 1 },
+ { "Volume", 0 },
+};
+const ProtobufCEnumDescriptor color_space__descriptor =
+{
+ PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+ "ColorSpace",
+ "ColorSpace",
+ "ColorSpace",
+ "",
+ 5,
+ color_space__enum_values_by_number,
+ 5,
+ color_space__enum_values_by_name,
+ 1,
+ color_space__value_ranges,
+ NULL,NULL,NULL,NULL /* reserved[1234] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.h
new file mode 100644
index 000000000..defb93aa2
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ColorSpace.pb-c.h
@@ -0,0 +1,46 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ColorSpace.proto */
+
+#ifndef PROTOBUF_C_ColorSpace_2eproto__INCLUDED
+#define PROTOBUF_C_ColorSpace_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+
+
+/* --- enums --- */
+
+typedef enum _ColorSpace {
+ COLOR_SPACE__Volume = 0,
+ COLOR_SPACE__RGB = 1,
+ COLOR_SPACE__CMYK = 2,
+ COLOR_SPACE__LAB = 3,
+ COLOR_SPACE__Catalog = 4
+ PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(COLOR_SPACE)
+} ColorSpace;
+
+/* --- messages --- */
+
+/* --- per-message closures --- */
+
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCEnumDescriptor color_space__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_ColorSpace_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.c
new file mode 100644
index 000000000..0defc9edf
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.c
@@ -0,0 +1,261 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ConversionInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "ConversionInput.pb-c.h"
+void conversion_input__init
+ (ConversionInput *message)
+{
+ static const ConversionInput init_value = CONVERSION_INPUT__INIT;
+ *message = init_value;
+}
+size_t conversion_input__get_packed_size
+ (const ConversionInput *message)
+{
+ assert(message->base.descriptor == &conversion_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t conversion_input__pack
+ (const ConversionInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &conversion_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t conversion_input__pack_to_buffer
+ (const ConversionInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &conversion_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+ConversionInput *
+ conversion_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (ConversionInput *)
+ protobuf_c_message_unpack (&conversion_input__descriptor,
+ allocator, len, data);
+}
+void conversion_input__free_unpacked
+ (ConversionInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &conversion_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor conversion_input__field_descriptors[14] =
+{
+ {
+ "ThreadL",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_threadl),
+ offsetof(ConversionInput, threadl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadA",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_threada),
+ offsetof(ConversionInput, threada),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadB",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_threadb),
+ offsetof(ConversionInput, threadb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ColorSpace",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(ConversionInput, has_colorspace),
+ offsetof(ConversionInput, colorspace),
+ &color_space__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InputCoordinates",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_MESSAGE,
+ 0, /* quantifier_offset */
+ offsetof(ConversionInput, inputcoordinates),
+ &input_coordinates__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ForwardData",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BYTES,
+ offsetof(ConversionInput, has_forwarddata),
+ offsetof(ConversionInput, forwarddata),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InverseData",
+ 7,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BYTES,
+ offsetof(ConversionInput, has_inversedata),
+ offsetof(ConversionInput, inversedata),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "SegmentLength",
+ 8,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_segmentlength),
+ offsetof(ConversionInput, segmentlength),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "DeltaChroma",
+ 9,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_deltachroma),
+ offsetof(ConversionInput, deltachroma),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "DeltaL",
+ 10,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_deltal),
+ offsetof(ConversionInput, deltal),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessRanges",
+ 11,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(ConversionInput, n_processranges),
+ offsetof(ConversionInput, processranges),
+ &process_range__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "GenerateHive",
+ 12,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(ConversionInput, has_generatehive),
+ offsetof(ConversionInput, generatehive),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "UseLightInks",
+ 13,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(ConversionInput, has_uselightinks),
+ offsetof(ConversionInput, uselightinks),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "VMax",
+ 14,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ConversionInput, has_vmax),
+ offsetof(ConversionInput, vmax),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned conversion_input__field_indices_by_name[] = {
+ 3, /* field[3] = ColorSpace */
+ 8, /* field[8] = DeltaChroma */
+ 9, /* field[9] = DeltaL */
+ 5, /* field[5] = ForwardData */
+ 11, /* field[11] = GenerateHive */
+ 4, /* field[4] = InputCoordinates */
+ 6, /* field[6] = InverseData */
+ 10, /* field[10] = ProcessRanges */
+ 7, /* field[7] = SegmentLength */
+ 1, /* field[1] = ThreadA */
+ 2, /* field[2] = ThreadB */
+ 0, /* field[0] = ThreadL */
+ 12, /* field[12] = UseLightInks */
+ 13, /* field[13] = VMax */
+};
+static const ProtobufCIntRange conversion_input__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 14 }
+};
+const ProtobufCMessageDescriptor conversion_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "ConversionInput",
+ "ConversionInput",
+ "ConversionInput",
+ "",
+ sizeof(ConversionInput),
+ 14,
+ conversion_input__field_descriptors,
+ conversion_input__field_indices_by_name,
+ 1, conversion_input__number_ranges,
+ (ProtobufCMessageInit) conversion_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.h
new file mode 100644
index 000000000..794ddaaac
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionInput.pb-c.h
@@ -0,0 +1,100 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ConversionInput.proto */
+
+#ifndef PROTOBUF_C_ConversionInput_2eproto__INCLUDED
+#define PROTOBUF_C_ConversionInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "InputCoordinates.pb-c.h"
+#include "ColorSpace.pb-c.h"
+#include "ProcessRange.pb-c.h"
+
+typedef struct _ConversionInput ConversionInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _ConversionInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_threadl;
+ double threadl;
+ protobuf_c_boolean has_threada;
+ double threada;
+ protobuf_c_boolean has_threadb;
+ double threadb;
+ protobuf_c_boolean has_colorspace;
+ ColorSpace colorspace;
+ InputCoordinates *inputcoordinates;
+ protobuf_c_boolean has_forwarddata;
+ ProtobufCBinaryData forwarddata;
+ protobuf_c_boolean has_inversedata;
+ ProtobufCBinaryData inversedata;
+ protobuf_c_boolean has_segmentlength;
+ double segmentlength;
+ protobuf_c_boolean has_deltachroma;
+ double deltachroma;
+ protobuf_c_boolean has_deltal;
+ double deltal;
+ size_t n_processranges;
+ ProcessRange **processranges;
+ protobuf_c_boolean has_generatehive;
+ protobuf_c_boolean generatehive;
+ protobuf_c_boolean has_uselightinks;
+ protobuf_c_boolean uselightinks;
+ protobuf_c_boolean has_vmax;
+ double vmax;
+};
+#define CONVERSION_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&conversion_input__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, COLOR_SPACE__Volume, NULL, 0, {0,NULL}, 0, {0,NULL}, 0, 0, 0, 0, 0, 0, 0,NULL, 0, 0, 0, 0, 0, 0 }
+
+
+/* ConversionInput methods */
+void conversion_input__init
+ (ConversionInput *message);
+size_t conversion_input__get_packed_size
+ (const ConversionInput *message);
+size_t conversion_input__pack
+ (const ConversionInput *message,
+ uint8_t *out);
+size_t conversion_input__pack_to_buffer
+ (const ConversionInput *message,
+ ProtobufCBuffer *buffer);
+ConversionInput *
+ conversion_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void conversion_input__free_unpacked
+ (ConversionInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*ConversionInput_Closure)
+ (const ConversionInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor conversion_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_ConversionInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.c
new file mode 100644
index 000000000..da44f28ac
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.c
@@ -0,0 +1,158 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ConversionOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "ConversionOutput.pb-c.h"
+void conversion_output__init
+ (ConversionOutput *message)
+{
+ static const ConversionOutput init_value = CONVERSION_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t conversion_output__get_packed_size
+ (const ConversionOutput *message)
+{
+ assert(message->base.descriptor == &conversion_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t conversion_output__pack
+ (const ConversionOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &conversion_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t conversion_output__pack_to_buffer
+ (const ConversionOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &conversion_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+ConversionOutput *
+ conversion_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (ConversionOutput *)
+ protobuf_c_message_unpack (&conversion_output__descriptor,
+ allocator, len, data);
+}
+void conversion_output__free_unpacked
+ (ConversionOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &conversion_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor conversion_output__field_descriptors[6] =
+{
+ {
+ "HiveCoordinates",
+ 1,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(ConversionOutput, n_hivecoordinates),
+ offsetof(ConversionOutput, hivecoordinates),
+ &output_coordinates__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TripleCoordinates",
+ 2,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(ConversionOutput, n_triplecoordinates),
+ offsetof(ConversionOutput, triplecoordinates),
+ &output_coordinates__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "SingleCoordinates",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_MESSAGE,
+ 0, /* quantifier_offset */
+ offsetof(ConversionOutput, singlecoordinates),
+ &output_coordinates__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "OutOfGamut",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(ConversionOutput, has_outofgamut),
+ offsetof(ConversionOutput, outofgamut),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(ConversionOutput, has_haserror),
+ offsetof(ConversionOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 7,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(ConversionOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned conversion_output__field_indices_by_name[] = {
+ 5, /* field[5] = ErrorMessage */
+ 4, /* field[4] = HasError */
+ 0, /* field[0] = HiveCoordinates */
+ 3, /* field[3] = OutOfGamut */
+ 2, /* field[2] = SingleCoordinates */
+ 1, /* field[1] = TripleCoordinates */
+};
+static const ProtobufCIntRange conversion_output__number_ranges[2 + 1] =
+{
+ { 1, 0 },
+ { 5, 3 },
+ { 0, 6 }
+};
+const ProtobufCMessageDescriptor conversion_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "ConversionOutput",
+ "ConversionOutput",
+ "ConversionOutput",
+ "",
+ sizeof(ConversionOutput),
+ 6,
+ conversion_output__field_descriptors,
+ conversion_output__field_indices_by_name,
+ 2, conversion_output__number_ranges,
+ (ProtobufCMessageInit) conversion_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.h
new file mode 100644
index 000000000..c85c11bd7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ConversionOutput.pb-c.h
@@ -0,0 +1,81 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ConversionOutput.proto */
+
+#ifndef PROTOBUF_C_ConversionOutput_2eproto__INCLUDED
+#define PROTOBUF_C_ConversionOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "OutputCoordinates.pb-c.h"
+
+typedef struct _ConversionOutput ConversionOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _ConversionOutput
+{
+ ProtobufCMessage base;
+ size_t n_hivecoordinates;
+ OutputCoordinates **hivecoordinates;
+ size_t n_triplecoordinates;
+ OutputCoordinates **triplecoordinates;
+ OutputCoordinates *singlecoordinates;
+ protobuf_c_boolean has_outofgamut;
+ protobuf_c_boolean outofgamut;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define CONVERSION_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&conversion_output__descriptor) \
+ , 0,NULL, 0,NULL, NULL, 0, 0, 0, 0, NULL }
+
+
+/* ConversionOutput methods */
+void conversion_output__init
+ (ConversionOutput *message);
+size_t conversion_output__get_packed_size
+ (const ConversionOutput *message);
+size_t conversion_output__pack
+ (const ConversionOutput *message,
+ uint8_t *out);
+size_t conversion_output__pack_to_buffer
+ (const ConversionOutput *message,
+ ProtobufCBuffer *buffer);
+ConversionOutput *
+ conversion_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void conversion_output__free_unpacked
+ (ConversionOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*ConversionOutput_Closure)
+ (const ConversionOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor conversion_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_ConversionOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.c
new file mode 100644
index 000000000..cd3d79ab6
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.c
@@ -0,0 +1,183 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientConversionInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "GradientConversionInput.pb-c.h"
+void gradient_conversion_input__init
+ (GradientConversionInput *message)
+{
+ static const GradientConversionInput init_value = GRADIENT_CONVERSION_INPUT__INIT;
+ *message = init_value;
+}
+size_t gradient_conversion_input__get_packed_size
+ (const GradientConversionInput *message)
+{
+ assert(message->base.descriptor == &gradient_conversion_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t gradient_conversion_input__pack
+ (const GradientConversionInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &gradient_conversion_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t gradient_conversion_input__pack_to_buffer
+ (const GradientConversionInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &gradient_conversion_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+GradientConversionInput *
+ gradient_conversion_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (GradientConversionInput *)
+ protobuf_c_message_unpack (&gradient_conversion_input__descriptor,
+ allocator, len, data);
+}
+void gradient_conversion_input__free_unpacked
+ (GradientConversionInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &gradient_conversion_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor gradient_conversion_input__field_descriptors[8] =
+{
+ {
+ "ThreadL",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientConversionInput, has_threadl),
+ offsetof(GradientConversionInput, threadl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadA",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientConversionInput, has_threada),
+ offsetof(GradientConversionInput, threada),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadB",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientConversionInput, has_threadb),
+ offsetof(GradientConversionInput, threadb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ForwardData",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BYTES,
+ offsetof(GradientConversionInput, has_forwarddata),
+ offsetof(GradientConversionInput, forwarddata),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "SegmentLength",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientConversionInput, has_segmentlength),
+ offsetof(GradientConversionInput, segmentlength),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Stops",
+ 6,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientConversionInput, n_stops),
+ offsetof(GradientConversionInput, stops),
+ &gradient_input_stop__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InputLiquids",
+ 7,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientConversionInput, n_inputliquids),
+ offsetof(GradientConversionInput, inputliquids),
+ &input_liquid__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessRanges",
+ 8,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientConversionInput, n_processranges),
+ offsetof(GradientConversionInput, processranges),
+ &process_range__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned gradient_conversion_input__field_indices_by_name[] = {
+ 3, /* field[3] = ForwardData */
+ 6, /* field[6] = InputLiquids */
+ 7, /* field[7] = ProcessRanges */
+ 4, /* field[4] = SegmentLength */
+ 5, /* field[5] = Stops */
+ 1, /* field[1] = ThreadA */
+ 2, /* field[2] = ThreadB */
+ 0, /* field[0] = ThreadL */
+};
+static const ProtobufCIntRange gradient_conversion_input__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 8 }
+};
+const ProtobufCMessageDescriptor gradient_conversion_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "GradientConversionInput",
+ "GradientConversionInput",
+ "GradientConversionInput",
+ "",
+ sizeof(GradientConversionInput),
+ 8,
+ gradient_conversion_input__field_descriptors,
+ gradient_conversion_input__field_indices_by_name,
+ 1, gradient_conversion_input__number_ranges,
+ (ProtobufCMessageInit) gradient_conversion_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.h
new file mode 100644
index 000000000..e38d1316c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionInput.pb-c.h
@@ -0,0 +1,89 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientConversionInput.proto */
+
+#ifndef PROTOBUF_C_GradientConversionInput_2eproto__INCLUDED
+#define PROTOBUF_C_GradientConversionInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "ProcessRange.pb-c.h"
+#include "InputLiquid.pb-c.h"
+#include "GradientInputStop.pb-c.h"
+
+typedef struct _GradientConversionInput GradientConversionInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _GradientConversionInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_threadl;
+ double threadl;
+ protobuf_c_boolean has_threada;
+ double threada;
+ protobuf_c_boolean has_threadb;
+ double threadb;
+ protobuf_c_boolean has_forwarddata;
+ ProtobufCBinaryData forwarddata;
+ protobuf_c_boolean has_segmentlength;
+ double segmentlength;
+ size_t n_stops;
+ GradientInputStop **stops;
+ size_t n_inputliquids;
+ InputLiquid **inputliquids;
+ size_t n_processranges;
+ ProcessRange **processranges;
+};
+#define GRADIENT_CONVERSION_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&gradient_conversion_input__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, {0,NULL}, 0, 0, 0,NULL, 0,NULL, 0,NULL }
+
+
+/* GradientConversionInput methods */
+void gradient_conversion_input__init
+ (GradientConversionInput *message);
+size_t gradient_conversion_input__get_packed_size
+ (const GradientConversionInput *message);
+size_t gradient_conversion_input__pack
+ (const GradientConversionInput *message,
+ uint8_t *out);
+size_t gradient_conversion_input__pack_to_buffer
+ (const GradientConversionInput *message,
+ ProtobufCBuffer *buffer);
+GradientConversionInput *
+ gradient_conversion_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void gradient_conversion_input__free_unpacked
+ (GradientConversionInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*GradientConversionInput_Closure)
+ (const GradientConversionInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor gradient_conversion_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_GradientConversionInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.c
new file mode 100644
index 000000000..50c69152f
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.c
@@ -0,0 +1,118 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientConversionOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "GradientConversionOutput.pb-c.h"
+void gradient_conversion_output__init
+ (GradientConversionOutput *message)
+{
+ static const GradientConversionOutput init_value = GRADIENT_CONVERSION_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t gradient_conversion_output__get_packed_size
+ (const GradientConversionOutput *message)
+{
+ assert(message->base.descriptor == &gradient_conversion_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t gradient_conversion_output__pack
+ (const GradientConversionOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &gradient_conversion_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t gradient_conversion_output__pack_to_buffer
+ (const GradientConversionOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &gradient_conversion_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+GradientConversionOutput *
+ gradient_conversion_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (GradientConversionOutput *)
+ protobuf_c_message_unpack (&gradient_conversion_output__descriptor,
+ allocator, len, data);
+}
+void gradient_conversion_output__free_unpacked
+ (GradientConversionOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &gradient_conversion_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor gradient_conversion_output__field_descriptors[3] =
+{
+ {
+ "Stops",
+ 1,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientConversionOutput, n_stops),
+ offsetof(GradientConversionOutput, stops),
+ &gradient_output_stop__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(GradientConversionOutput, has_haserror),
+ offsetof(GradientConversionOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(GradientConversionOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned gradient_conversion_output__field_indices_by_name[] = {
+ 2, /* field[2] = ErrorMessage */
+ 1, /* field[1] = HasError */
+ 0, /* field[0] = Stops */
+};
+static const ProtobufCIntRange gradient_conversion_output__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor gradient_conversion_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "GradientConversionOutput",
+ "GradientConversionOutput",
+ "GradientConversionOutput",
+ "",
+ sizeof(GradientConversionOutput),
+ 3,
+ gradient_conversion_output__field_descriptors,
+ gradient_conversion_output__field_indices_by_name,
+ 1, gradient_conversion_output__number_ranges,
+ (ProtobufCMessageInit) gradient_conversion_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.h
new file mode 100644
index 000000000..48a581c0f
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientConversionOutput.pb-c.h
@@ -0,0 +1,76 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientConversionOutput.proto */
+
+#ifndef PROTOBUF_C_GradientConversionOutput_2eproto__INCLUDED
+#define PROTOBUF_C_GradientConversionOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "GradientOutputStop.pb-c.h"
+
+typedef struct _GradientConversionOutput GradientConversionOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _GradientConversionOutput
+{
+ ProtobufCMessage base;
+ size_t n_stops;
+ GradientOutputStop **stops;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define GRADIENT_CONVERSION_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&gradient_conversion_output__descriptor) \
+ , 0,NULL, 0, 0, NULL }
+
+
+/* GradientConversionOutput methods */
+void gradient_conversion_output__init
+ (GradientConversionOutput *message);
+size_t gradient_conversion_output__get_packed_size
+ (const GradientConversionOutput *message);
+size_t gradient_conversion_output__pack
+ (const GradientConversionOutput *message,
+ uint8_t *out);
+size_t gradient_conversion_output__pack_to_buffer
+ (const GradientConversionOutput *message,
+ ProtobufCBuffer *buffer);
+GradientConversionOutput *
+ gradient_conversion_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void gradient_conversion_output__free_unpacked
+ (GradientConversionOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*GradientConversionOutput_Closure)
+ (const GradientConversionOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor gradient_conversion_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_GradientConversionOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.c
new file mode 100644
index 000000000..7a3002748
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.c
@@ -0,0 +1,248 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientInputStop.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "GradientInputStop.pb-c.h"
+void gradient_input_stop__init
+ (GradientInputStop *message)
+{
+ static const GradientInputStop init_value = GRADIENT_INPUT_STOP__INIT;
+ *message = init_value;
+}
+size_t gradient_input_stop__get_packed_size
+ (const GradientInputStop *message)
+{
+ assert(message->base.descriptor == &gradient_input_stop__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t gradient_input_stop__pack
+ (const GradientInputStop *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &gradient_input_stop__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t gradient_input_stop__pack_to_buffer
+ (const GradientInputStop *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &gradient_input_stop__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+GradientInputStop *
+ gradient_input_stop__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (GradientInputStop *)
+ protobuf_c_message_unpack (&gradient_input_stop__descriptor,
+ allocator, len, data);
+}
+void gradient_input_stop__free_unpacked
+ (GradientInputStop *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &gradient_input_stop__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor gradient_input_stop__field_descriptors[13] =
+{
+ {
+ "Offset",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_offset),
+ offsetof(GradientInputStop, offset),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ColorSpace",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(GradientInputStop, has_colorspace),
+ offsetof(GradientInputStop, colorspace),
+ &color_space__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Red",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(GradientInputStop, has_red),
+ offsetof(GradientInputStop, red),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Green",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(GradientInputStop, has_green),
+ offsetof(GradientInputStop, green),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Blue",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(GradientInputStop, has_blue),
+ offsetof(GradientInputStop, blue),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Cyan",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_cyan),
+ offsetof(GradientInputStop, cyan),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Magenta",
+ 7,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_magenta),
+ offsetof(GradientInputStop, magenta),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Yellow",
+ 8,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_yellow),
+ offsetof(GradientInputStop, yellow),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Key",
+ 9,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_key),
+ offsetof(GradientInputStop, key),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "L",
+ 10,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_l),
+ offsetof(GradientInputStop, l),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "A",
+ 11,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_a),
+ offsetof(GradientInputStop, a),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "B",
+ 12,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientInputStop, has_b),
+ offsetof(GradientInputStop, b),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "LiquidVolumes",
+ 13,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientInputStop, n_liquidvolumes),
+ offsetof(GradientInputStop, liquidvolumes),
+ &liquid_volume__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned gradient_input_stop__field_indices_by_name[] = {
+ 10, /* field[10] = A */
+ 11, /* field[11] = B */
+ 4, /* field[4] = Blue */
+ 1, /* field[1] = ColorSpace */
+ 5, /* field[5] = Cyan */
+ 3, /* field[3] = Green */
+ 8, /* field[8] = Key */
+ 9, /* field[9] = L */
+ 12, /* field[12] = LiquidVolumes */
+ 6, /* field[6] = Magenta */
+ 0, /* field[0] = Offset */
+ 2, /* field[2] = Red */
+ 7, /* field[7] = Yellow */
+};
+static const ProtobufCIntRange gradient_input_stop__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 13 }
+};
+const ProtobufCMessageDescriptor gradient_input_stop__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "GradientInputStop",
+ "GradientInputStop",
+ "GradientInputStop",
+ "",
+ sizeof(GradientInputStop),
+ 13,
+ gradient_input_stop__field_descriptors,
+ gradient_input_stop__field_indices_by_name,
+ 1, gradient_input_stop__number_ranges,
+ (ProtobufCMessageInit) gradient_input_stop__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.h
new file mode 100644
index 000000000..058120b82
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientInputStop.pb-c.h
@@ -0,0 +1,98 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientInputStop.proto */
+
+#ifndef PROTOBUF_C_GradientInputStop_2eproto__INCLUDED
+#define PROTOBUF_C_GradientInputStop_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "ColorSpace.pb-c.h"
+#include "LiquidVolume.pb-c.h"
+
+typedef struct _GradientInputStop GradientInputStop;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _GradientInputStop
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_offset;
+ double offset;
+ protobuf_c_boolean has_colorspace;
+ ColorSpace colorspace;
+ protobuf_c_boolean has_red;
+ int32_t red;
+ protobuf_c_boolean has_green;
+ int32_t green;
+ protobuf_c_boolean has_blue;
+ int32_t blue;
+ protobuf_c_boolean has_cyan;
+ double cyan;
+ protobuf_c_boolean has_magenta;
+ double magenta;
+ protobuf_c_boolean has_yellow;
+ double yellow;
+ protobuf_c_boolean has_key;
+ double key;
+ protobuf_c_boolean has_l;
+ double l;
+ protobuf_c_boolean has_a;
+ double a;
+ protobuf_c_boolean has_b;
+ double b;
+ size_t n_liquidvolumes;
+ LiquidVolume **liquidvolumes;
+};
+#define GRADIENT_INPUT_STOP__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&gradient_input_stop__descriptor) \
+ , 0, 0, 0, COLOR_SPACE__Volume, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,NULL }
+
+
+/* GradientInputStop methods */
+void gradient_input_stop__init
+ (GradientInputStop *message);
+size_t gradient_input_stop__get_packed_size
+ (const GradientInputStop *message);
+size_t gradient_input_stop__pack
+ (const GradientInputStop *message,
+ uint8_t *out);
+size_t gradient_input_stop__pack_to_buffer
+ (const GradientInputStop *message,
+ ProtobufCBuffer *buffer);
+GradientInputStop *
+ gradient_input_stop__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void gradient_input_stop__free_unpacked
+ (GradientInputStop *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*GradientInputStop_Closure)
+ (const GradientInputStop *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor gradient_input_stop__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_GradientInputStop_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.c
new file mode 100644
index 000000000..62b3b744a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.c
@@ -0,0 +1,118 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientOutputStop.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "GradientOutputStop.pb-c.h"
+void gradient_output_stop__init
+ (GradientOutputStop *message)
+{
+ static const GradientOutputStop init_value = GRADIENT_OUTPUT_STOP__INIT;
+ *message = init_value;
+}
+size_t gradient_output_stop__get_packed_size
+ (const GradientOutputStop *message)
+{
+ assert(message->base.descriptor == &gradient_output_stop__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t gradient_output_stop__pack
+ (const GradientOutputStop *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &gradient_output_stop__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t gradient_output_stop__pack_to_buffer
+ (const GradientOutputStop *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &gradient_output_stop__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+GradientOutputStop *
+ gradient_output_stop__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (GradientOutputStop *)
+ protobuf_c_message_unpack (&gradient_output_stop__descriptor,
+ allocator, len, data);
+}
+void gradient_output_stop__free_unpacked
+ (GradientOutputStop *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &gradient_output_stop__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor gradient_output_stop__field_descriptors[3] =
+{
+ {
+ "Offset",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(GradientOutputStop, has_offset),
+ offsetof(GradientOutputStop, offset),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessParametersTableIndex",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(GradientOutputStop, has_processparameterstableindex),
+ offsetof(GradientOutputStop, processparameterstableindex),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "OutputLiquids",
+ 3,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(GradientOutputStop, n_outputliquids),
+ offsetof(GradientOutputStop, outputliquids),
+ &output_liquid__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned gradient_output_stop__field_indices_by_name[] = {
+ 0, /* field[0] = Offset */
+ 2, /* field[2] = OutputLiquids */
+ 1, /* field[1] = ProcessParametersTableIndex */
+};
+static const ProtobufCIntRange gradient_output_stop__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor gradient_output_stop__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "GradientOutputStop",
+ "GradientOutputStop",
+ "GradientOutputStop",
+ "",
+ sizeof(GradientOutputStop),
+ 3,
+ gradient_output_stop__field_descriptors,
+ gradient_output_stop__field_indices_by_name,
+ 1, gradient_output_stop__number_ranges,
+ (ProtobufCMessageInit) gradient_output_stop__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.h
new file mode 100644
index 000000000..4d765a8bf
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/GradientOutputStop.pb-c.h
@@ -0,0 +1,77 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: GradientOutputStop.proto */
+
+#ifndef PROTOBUF_C_GradientOutputStop_2eproto__INCLUDED
+#define PROTOBUF_C_GradientOutputStop_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "OutputLiquid.pb-c.h"
+
+typedef struct _GradientOutputStop GradientOutputStop;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _GradientOutputStop
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_offset;
+ double offset;
+ protobuf_c_boolean has_processparameterstableindex;
+ int32_t processparameterstableindex;
+ size_t n_outputliquids;
+ OutputLiquid **outputliquids;
+};
+#define GRADIENT_OUTPUT_STOP__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&gradient_output_stop__descriptor) \
+ , 0, 0, 0, 0, 0,NULL }
+
+
+/* GradientOutputStop methods */
+void gradient_output_stop__init
+ (GradientOutputStop *message);
+size_t gradient_output_stop__get_packed_size
+ (const GradientOutputStop *message);
+size_t gradient_output_stop__pack
+ (const GradientOutputStop *message,
+ uint8_t *out);
+size_t gradient_output_stop__pack_to_buffer
+ (const GradientOutputStop *message,
+ ProtobufCBuffer *buffer);
+GradientOutputStop *
+ gradient_output_stop__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void gradient_output_stop__free_unpacked
+ (GradientOutputStop *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*GradientOutputStop_Closure)
+ (const GradientOutputStop *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor gradient_output_stop__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_GradientOutputStop_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.c
new file mode 100644
index 000000000..a12759a89
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.c
@@ -0,0 +1,248 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: InputCoordinates.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "InputCoordinates.pb-c.h"
+void input_coordinates__init
+ (InputCoordinates *message)
+{
+ static const InputCoordinates init_value = INPUT_COORDINATES__INIT;
+ *message = init_value;
+}
+size_t input_coordinates__get_packed_size
+ (const InputCoordinates *message)
+{
+ assert(message->base.descriptor == &input_coordinates__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t input_coordinates__pack
+ (const InputCoordinates *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &input_coordinates__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t input_coordinates__pack_to_buffer
+ (const InputCoordinates *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &input_coordinates__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+InputCoordinates *
+ input_coordinates__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (InputCoordinates *)
+ protobuf_c_message_unpack (&input_coordinates__descriptor,
+ allocator, len, data);
+}
+void input_coordinates__free_unpacked
+ (InputCoordinates *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &input_coordinates__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor input_coordinates__field_descriptors[13] =
+{
+ {
+ "Length",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_length),
+ offsetof(InputCoordinates, length),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Red",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(InputCoordinates, has_red),
+ offsetof(InputCoordinates, red),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Green",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(InputCoordinates, has_green),
+ offsetof(InputCoordinates, green),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Blue",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(InputCoordinates, has_blue),
+ offsetof(InputCoordinates, blue),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Cyan",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_cyan),
+ offsetof(InputCoordinates, cyan),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Magenta",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_magenta),
+ offsetof(InputCoordinates, magenta),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Yellow",
+ 7,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_yellow),
+ offsetof(InputCoordinates, yellow),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Key",
+ 8,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_key),
+ offsetof(InputCoordinates, key),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "L",
+ 9,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_l),
+ offsetof(InputCoordinates, l),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "A",
+ 10,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_a),
+ offsetof(InputCoordinates, a),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "B",
+ 11,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputCoordinates, has_b),
+ offsetof(InputCoordinates, b),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "PantonCode",
+ 12,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(InputCoordinates, has_pantoncode),
+ offsetof(InputCoordinates, pantoncode),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InputLiquids",
+ 13,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(InputCoordinates, n_inputliquids),
+ offsetof(InputCoordinates, inputliquids),
+ &input_liquid__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned input_coordinates__field_indices_by_name[] = {
+ 9, /* field[9] = A */
+ 10, /* field[10] = B */
+ 3, /* field[3] = Blue */
+ 4, /* field[4] = Cyan */
+ 2, /* field[2] = Green */
+ 12, /* field[12] = InputLiquids */
+ 7, /* field[7] = Key */
+ 8, /* field[8] = L */
+ 0, /* field[0] = Length */
+ 5, /* field[5] = Magenta */
+ 11, /* field[11] = PantonCode */
+ 1, /* field[1] = Red */
+ 6, /* field[6] = Yellow */
+};
+static const ProtobufCIntRange input_coordinates__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 13 }
+};
+const ProtobufCMessageDescriptor input_coordinates__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "InputCoordinates",
+ "InputCoordinates",
+ "InputCoordinates",
+ "",
+ sizeof(InputCoordinates),
+ 13,
+ input_coordinates__field_descriptors,
+ input_coordinates__field_indices_by_name,
+ 1, input_coordinates__number_ranges,
+ (ProtobufCMessageInit) input_coordinates__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.h
new file mode 100644
index 000000000..0b159cd59
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputCoordinates.pb-c.h
@@ -0,0 +1,97 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: InputCoordinates.proto */
+
+#ifndef PROTOBUF_C_InputCoordinates_2eproto__INCLUDED
+#define PROTOBUF_C_InputCoordinates_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "InputLiquid.pb-c.h"
+
+typedef struct _InputCoordinates InputCoordinates;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _InputCoordinates
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_length;
+ double length;
+ protobuf_c_boolean has_red;
+ int32_t red;
+ protobuf_c_boolean has_green;
+ int32_t green;
+ protobuf_c_boolean has_blue;
+ int32_t blue;
+ protobuf_c_boolean has_cyan;
+ double cyan;
+ protobuf_c_boolean has_magenta;
+ double magenta;
+ protobuf_c_boolean has_yellow;
+ double yellow;
+ protobuf_c_boolean has_key;
+ double key;
+ protobuf_c_boolean has_l;
+ double l;
+ protobuf_c_boolean has_a;
+ double a;
+ protobuf_c_boolean has_b;
+ double b;
+ protobuf_c_boolean has_pantoncode;
+ int32_t pantoncode;
+ size_t n_inputliquids;
+ InputLiquid **inputliquids;
+};
+#define INPUT_COORDINATES__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&input_coordinates__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,NULL }
+
+
+/* InputCoordinates methods */
+void input_coordinates__init
+ (InputCoordinates *message);
+size_t input_coordinates__get_packed_size
+ (const InputCoordinates *message);
+size_t input_coordinates__pack
+ (const InputCoordinates *message,
+ uint8_t *out);
+size_t input_coordinates__pack_to_buffer
+ (const InputCoordinates *message,
+ ProtobufCBuffer *buffer);
+InputCoordinates *
+ input_coordinates__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void input_coordinates__free_unpacked
+ (InputCoordinates *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*InputCoordinates_Closure)
+ (const InputCoordinates *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor input_coordinates__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_InputCoordinates_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.c
new file mode 100644
index 000000000..2d033e2a1
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.c
@@ -0,0 +1,131 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: InputLiquid.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "InputLiquid.pb-c.h"
+void input_liquid__init
+ (InputLiquid *message)
+{
+ static const InputLiquid init_value = INPUT_LIQUID__INIT;
+ *message = init_value;
+}
+size_t input_liquid__get_packed_size
+ (const InputLiquid *message)
+{
+ assert(message->base.descriptor == &input_liquid__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t input_liquid__pack
+ (const InputLiquid *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &input_liquid__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t input_liquid__pack_to_buffer
+ (const InputLiquid *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &input_liquid__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+InputLiquid *
+ input_liquid__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (InputLiquid *)
+ protobuf_c_message_unpack (&input_liquid__descriptor,
+ allocator, len, data);
+}
+void input_liquid__free_unpacked
+ (InputLiquid *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &input_liquid__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor input_liquid__field_descriptors[4] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(InputLiquid, has_liquidtype),
+ offsetof(InputLiquid, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "CalibrationData",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_MESSAGE,
+ 0, /* quantifier_offset */
+ offsetof(InputLiquid, calibrationdata),
+ &calibration_data__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "MaxNanoliterPerCentimeter",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputLiquid, has_maxnanoliterpercentimeter),
+ offsetof(InputLiquid, maxnanoliterpercentimeter),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Volume",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(InputLiquid, has_volume),
+ offsetof(InputLiquid, volume),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned input_liquid__field_indices_by_name[] = {
+ 1, /* field[1] = CalibrationData */
+ 0, /* field[0] = LiquidType */
+ 2, /* field[2] = MaxNanoliterPerCentimeter */
+ 3, /* field[3] = Volume */
+};
+static const ProtobufCIntRange input_liquid__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 4 }
+};
+const ProtobufCMessageDescriptor input_liquid__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "InputLiquid",
+ "InputLiquid",
+ "InputLiquid",
+ "",
+ sizeof(InputLiquid),
+ 4,
+ input_liquid__field_descriptors,
+ input_liquid__field_indices_by_name,
+ 1, input_liquid__number_ranges,
+ (ProtobufCMessageInit) input_liquid__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.h
new file mode 100644
index 000000000..c2a47b166
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/InputLiquid.pb-c.h
@@ -0,0 +1,79 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: InputLiquid.proto */
+
+#ifndef PROTOBUF_C_InputLiquid_2eproto__INCLUDED
+#define PROTOBUF_C_InputLiquid_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "LiquidType.pb-c.h"
+#include "CalibrationData.pb-c.h"
+
+typedef struct _InputLiquid InputLiquid;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _InputLiquid
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ CalibrationData *calibrationdata;
+ protobuf_c_boolean has_maxnanoliterpercentimeter;
+ double maxnanoliterpercentimeter;
+ protobuf_c_boolean has_volume;
+ double volume;
+};
+#define INPUT_LIQUID__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&input_liquid__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, NULL, 0, 0, 0, 0 }
+
+
+/* InputLiquid methods */
+void input_liquid__init
+ (InputLiquid *message);
+size_t input_liquid__get_packed_size
+ (const InputLiquid *message);
+size_t input_liquid__pack
+ (const InputLiquid *message,
+ uint8_t *out);
+size_t input_liquid__pack_to_buffer
+ (const InputLiquid *message,
+ ProtobufCBuffer *buffer);
+InputLiquid *
+ input_liquid__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void input_liquid__free_unpacked
+ (InputLiquid *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*InputLiquid_Closure)
+ (const InputLiquid *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor input_liquid__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_InputLiquid_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.c
new file mode 100644
index 000000000..5d30f6cd5
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.c
@@ -0,0 +1,144 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "LinearizationInput.pb-c.h"
+void linearization_input__init
+ (LinearizationInput *message)
+{
+ static const LinearizationInput init_value = LINEARIZATION_INPUT__INIT;
+ *message = init_value;
+}
+size_t linearization_input__get_packed_size
+ (const LinearizationInput *message)
+{
+ assert(message->base.descriptor == &linearization_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t linearization_input__pack
+ (const LinearizationInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &linearization_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t linearization_input__pack_to_buffer
+ (const LinearizationInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &linearization_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+LinearizationInput *
+ linearization_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (LinearizationInput *)
+ protobuf_c_message_unpack (&linearization_input__descriptor,
+ allocator, len, data);
+}
+void linearization_input__free_unpacked
+ (LinearizationInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &linearization_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor linearization_input__field_descriptors[5] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(LinearizationInput, has_liquidtype),
+ offsetof(LinearizationInput, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetL",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationInput, has_targetl),
+ offsetof(LinearizationInput, targetl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetA",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationInput, has_targeta),
+ offsetof(LinearizationInput, targeta),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "TargetB",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationInput, has_targetb),
+ offsetof(LinearizationInput, targetb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Measurements",
+ 5,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(LinearizationInput, n_measurements),
+ offsetof(LinearizationInput, measurements),
+ &linearization_measurement__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned linearization_input__field_indices_by_name[] = {
+ 0, /* field[0] = LiquidType */
+ 4, /* field[4] = Measurements */
+ 2, /* field[2] = TargetA */
+ 3, /* field[3] = TargetB */
+ 1, /* field[1] = TargetL */
+};
+static const ProtobufCIntRange linearization_input__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 5 }
+};
+const ProtobufCMessageDescriptor linearization_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "LinearizationInput",
+ "LinearizationInput",
+ "LinearizationInput",
+ "",
+ sizeof(LinearizationInput),
+ 5,
+ linearization_input__field_descriptors,
+ linearization_input__field_indices_by_name,
+ 1, linearization_input__number_ranges,
+ (ProtobufCMessageInit) linearization_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.h
new file mode 100644
index 000000000..9cab974c5
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationInput.pb-c.h
@@ -0,0 +1,82 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationInput.proto */
+
+#ifndef PROTOBUF_C_LinearizationInput_2eproto__INCLUDED
+#define PROTOBUF_C_LinearizationInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "LinearizationMeasurement.pb-c.h"
+#include "LiquidType.pb-c.h"
+
+typedef struct _LinearizationInput LinearizationInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _LinearizationInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ protobuf_c_boolean has_targetl;
+ double targetl;
+ protobuf_c_boolean has_targeta;
+ double targeta;
+ protobuf_c_boolean has_targetb;
+ double targetb;
+ size_t n_measurements;
+ LinearizationMeasurement **measurements;
+};
+#define LINEARIZATION_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&linearization_input__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, 0, 0, 0, 0, 0, 0, 0,NULL }
+
+
+/* LinearizationInput methods */
+void linearization_input__init
+ (LinearizationInput *message);
+size_t linearization_input__get_packed_size
+ (const LinearizationInput *message);
+size_t linearization_input__pack
+ (const LinearizationInput *message,
+ uint8_t *out);
+size_t linearization_input__pack_to_buffer
+ (const LinearizationInput *message,
+ ProtobufCBuffer *buffer);
+LinearizationInput *
+ linearization_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void linearization_input__free_unpacked
+ (LinearizationInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*LinearizationInput_Closure)
+ (const LinearizationInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor linearization_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_LinearizationInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.c
new file mode 100644
index 000000000..0a242ee0f
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.c
@@ -0,0 +1,131 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationMeasurement.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "LinearizationMeasurement.pb-c.h"
+void linearization_measurement__init
+ (LinearizationMeasurement *message)
+{
+ static const LinearizationMeasurement init_value = LINEARIZATION_MEASUREMENT__INIT;
+ *message = init_value;
+}
+size_t linearization_measurement__get_packed_size
+ (const LinearizationMeasurement *message)
+{
+ assert(message->base.descriptor == &linearization_measurement__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t linearization_measurement__pack
+ (const LinearizationMeasurement *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &linearization_measurement__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t linearization_measurement__pack_to_buffer
+ (const LinearizationMeasurement *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &linearization_measurement__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+LinearizationMeasurement *
+ linearization_measurement__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (LinearizationMeasurement *)
+ protobuf_c_message_unpack (&linearization_measurement__descriptor,
+ allocator, len, data);
+}
+void linearization_measurement__free_unpacked
+ (LinearizationMeasurement *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &linearization_measurement__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor linearization_measurement__field_descriptors[4] =
+{
+ {
+ "InkPercentage",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationMeasurement, has_inkpercentage),
+ offsetof(LinearizationMeasurement, inkpercentage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "L",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationMeasurement, has_l),
+ offsetof(LinearizationMeasurement, l),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "A",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationMeasurement, has_a),
+ offsetof(LinearizationMeasurement, a),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "B",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationMeasurement, has_b),
+ offsetof(LinearizationMeasurement, b),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned linearization_measurement__field_indices_by_name[] = {
+ 2, /* field[2] = A */
+ 3, /* field[3] = B */
+ 0, /* field[0] = InkPercentage */
+ 1, /* field[1] = L */
+};
+static const ProtobufCIntRange linearization_measurement__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 4 }
+};
+const ProtobufCMessageDescriptor linearization_measurement__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "LinearizationMeasurement",
+ "LinearizationMeasurement",
+ "LinearizationMeasurement",
+ "",
+ sizeof(LinearizationMeasurement),
+ 4,
+ linearization_measurement__field_descriptors,
+ linearization_measurement__field_indices_by_name,
+ 1, linearization_measurement__number_ranges,
+ (ProtobufCMessageInit) linearization_measurement__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.h
new file mode 100644
index 000000000..b4f17f87e
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationMeasurement.pb-c.h
@@ -0,0 +1,78 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationMeasurement.proto */
+
+#ifndef PROTOBUF_C_LinearizationMeasurement_2eproto__INCLUDED
+#define PROTOBUF_C_LinearizationMeasurement_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _LinearizationMeasurement LinearizationMeasurement;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _LinearizationMeasurement
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_inkpercentage;
+ double inkpercentage;
+ protobuf_c_boolean has_l;
+ double l;
+ protobuf_c_boolean has_a;
+ double a;
+ protobuf_c_boolean has_b;
+ double b;
+};
+#define LINEARIZATION_MEASUREMENT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&linearization_measurement__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, 0 }
+
+
+/* LinearizationMeasurement methods */
+void linearization_measurement__init
+ (LinearizationMeasurement *message);
+size_t linearization_measurement__get_packed_size
+ (const LinearizationMeasurement *message);
+size_t linearization_measurement__pack
+ (const LinearizationMeasurement *message,
+ uint8_t *out);
+size_t linearization_measurement__pack_to_buffer
+ (const LinearizationMeasurement *message,
+ ProtobufCBuffer *buffer);
+LinearizationMeasurement *
+ linearization_measurement__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void linearization_measurement__free_unpacked
+ (LinearizationMeasurement *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*LinearizationMeasurement_Closure)
+ (const LinearizationMeasurement *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor linearization_measurement__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_LinearizationMeasurement_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.c
new file mode 100644
index 000000000..5bd04b218
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.c
@@ -0,0 +1,119 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "LinearizationOutput.pb-c.h"
+void linearization_output__init
+ (LinearizationOutput *message)
+{
+ static const LinearizationOutput init_value = LINEARIZATION_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t linearization_output__get_packed_size
+ (const LinearizationOutput *message)
+{
+ assert(message->base.descriptor == &linearization_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t linearization_output__pack
+ (const LinearizationOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &linearization_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t linearization_output__pack_to_buffer
+ (const LinearizationOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &linearization_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+LinearizationOutput *
+ linearization_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (LinearizationOutput *)
+ protobuf_c_message_unpack (&linearization_output__descriptor,
+ allocator, len, data);
+}
+void linearization_output__free_unpacked
+ (LinearizationOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &linearization_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor linearization_output__field_descriptors[3] =
+{
+ {
+ "InkPercentage",
+ 1,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LinearizationOutput, n_inkpercentage),
+ offsetof(LinearizationOutput, inkpercentage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 20,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(LinearizationOutput, has_haserror),
+ offsetof(LinearizationOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 21,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(LinearizationOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned linearization_output__field_indices_by_name[] = {
+ 2, /* field[2] = ErrorMessage */
+ 1, /* field[1] = HasError */
+ 0, /* field[0] = InkPercentage */
+};
+static const ProtobufCIntRange linearization_output__number_ranges[2 + 1] =
+{
+ { 1, 0 },
+ { 20, 1 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor linearization_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "LinearizationOutput",
+ "LinearizationOutput",
+ "LinearizationOutput",
+ "",
+ sizeof(LinearizationOutput),
+ 3,
+ linearization_output__field_descriptors,
+ linearization_output__field_indices_by_name,
+ 2, linearization_output__number_ranges,
+ (ProtobufCMessageInit) linearization_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.h
new file mode 100644
index 000000000..b0ab54e12
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LinearizationOutput.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LinearizationOutput.proto */
+
+#ifndef PROTOBUF_C_LinearizationOutput_2eproto__INCLUDED
+#define PROTOBUF_C_LinearizationOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _LinearizationOutput LinearizationOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _LinearizationOutput
+{
+ ProtobufCMessage base;
+ size_t n_inkpercentage;
+ double *inkpercentage;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define LINEARIZATION_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&linearization_output__descriptor) \
+ , 0,NULL, 0, 0, NULL }
+
+
+/* LinearizationOutput methods */
+void linearization_output__init
+ (LinearizationOutput *message);
+size_t linearization_output__get_packed_size
+ (const LinearizationOutput *message);
+size_t linearization_output__pack
+ (const LinearizationOutput *message,
+ uint8_t *out);
+size_t linearization_output__pack_to_buffer
+ (const LinearizationOutput *message,
+ ProtobufCBuffer *buffer);
+LinearizationOutput *
+ linearization_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void linearization_output__free_unpacked
+ (LinearizationOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*LinearizationOutput_Closure)
+ (const LinearizationOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor linearization_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_LinearizationOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.c
new file mode 100644
index 000000000..d6d4117b7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.c
@@ -0,0 +1,53 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LiquidType.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "LiquidType.pb-c.h"
+static const ProtobufCEnumValue liquid_type__enum_values_by_number[10] =
+{
+ { "Cyan", "LIQUID_TYPE__Cyan", 0 },
+ { "Magenta", "LIQUID_TYPE__Magenta", 1 },
+ { "Yellow", "LIQUID_TYPE__Yellow", 2 },
+ { "Black", "LIQUID_TYPE__Black", 3 },
+ { "TransparentInk", "LIQUID_TYPE__TransparentInk", 4 },
+ { "Lubricant", "LIQUID_TYPE__Lubricant", 5 },
+ { "Cleaner", "LIQUID_TYPE__Cleaner", 6 },
+ { "LightCyan", "LIQUID_TYPE__LightCyan", 7 },
+ { "LightMagenta", "LIQUID_TYPE__LightMagenta", 8 },
+ { "LightYellow", "LIQUID_TYPE__LightYellow", 9 },
+};
+static const ProtobufCIntRange liquid_type__value_ranges[] = {
+{0, 0},{0, 10}
+};
+static const ProtobufCEnumValueIndex liquid_type__enum_values_by_name[10] =
+{
+ { "Black", 3 },
+ { "Cleaner", 6 },
+ { "Cyan", 0 },
+ { "LightCyan", 7 },
+ { "LightMagenta", 8 },
+ { "LightYellow", 9 },
+ { "Lubricant", 5 },
+ { "Magenta", 1 },
+ { "TransparentInk", 4 },
+ { "Yellow", 2 },
+};
+const ProtobufCEnumDescriptor liquid_type__descriptor =
+{
+ PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
+ "LiquidType",
+ "LiquidType",
+ "LiquidType",
+ "",
+ 10,
+ liquid_type__enum_values_by_number,
+ 10,
+ liquid_type__enum_values_by_name,
+ 1,
+ liquid_type__value_ranges,
+ NULL,NULL,NULL,NULL /* reserved[1234] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.h
new file mode 100644
index 000000000..eba52c4a7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidType.pb-c.h
@@ -0,0 +1,51 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LiquidType.proto */
+
+#ifndef PROTOBUF_C_LiquidType_2eproto__INCLUDED
+#define PROTOBUF_C_LiquidType_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+
+
+/* --- enums --- */
+
+typedef enum _LiquidType {
+ LIQUID_TYPE__Cyan = 0,
+ LIQUID_TYPE__Magenta = 1,
+ LIQUID_TYPE__Yellow = 2,
+ LIQUID_TYPE__Black = 3,
+ LIQUID_TYPE__TransparentInk = 4,
+ LIQUID_TYPE__Lubricant = 5,
+ LIQUID_TYPE__Cleaner = 6,
+ LIQUID_TYPE__LightCyan = 7,
+ LIQUID_TYPE__LightMagenta = 8,
+ LIQUID_TYPE__LightYellow = 9
+ PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LIQUID_TYPE)
+} LiquidType;
+
+/* --- messages --- */
+
+/* --- per-message closures --- */
+
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCEnumDescriptor liquid_type__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_LiquidType_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.c
new file mode 100644
index 000000000..118d5b92d
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.c
@@ -0,0 +1,105 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LiquidVolume.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "LiquidVolume.pb-c.h"
+void liquid_volume__init
+ (LiquidVolume *message)
+{
+ static const LiquidVolume init_value = LIQUID_VOLUME__INIT;
+ *message = init_value;
+}
+size_t liquid_volume__get_packed_size
+ (const LiquidVolume *message)
+{
+ assert(message->base.descriptor == &liquid_volume__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t liquid_volume__pack
+ (const LiquidVolume *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &liquid_volume__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t liquid_volume__pack_to_buffer
+ (const LiquidVolume *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &liquid_volume__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+LiquidVolume *
+ liquid_volume__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (LiquidVolume *)
+ protobuf_c_message_unpack (&liquid_volume__descriptor,
+ allocator, len, data);
+}
+void liquid_volume__free_unpacked
+ (LiquidVolume *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &liquid_volume__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor liquid_volume__field_descriptors[2] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(LiquidVolume, has_liquidtype),
+ offsetof(LiquidVolume, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Volume",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(LiquidVolume, has_volume),
+ offsetof(LiquidVolume, volume),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned liquid_volume__field_indices_by_name[] = {
+ 0, /* field[0] = LiquidType */
+ 1, /* field[1] = Volume */
+};
+static const ProtobufCIntRange liquid_volume__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor liquid_volume__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "LiquidVolume",
+ "LiquidVolume",
+ "LiquidVolume",
+ "",
+ sizeof(LiquidVolume),
+ 2,
+ liquid_volume__field_descriptors,
+ liquid_volume__field_indices_by_name,
+ 1, liquid_volume__number_ranges,
+ (ProtobufCMessageInit) liquid_volume__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.h
new file mode 100644
index 000000000..82ee62dfb
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/LiquidVolume.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: LiquidVolume.proto */
+
+#ifndef PROTOBUF_C_LiquidVolume_2eproto__INCLUDED
+#define PROTOBUF_C_LiquidVolume_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "LiquidType.pb-c.h"
+
+typedef struct _LiquidVolume LiquidVolume;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _LiquidVolume
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ protobuf_c_boolean has_volume;
+ double volume;
+};
+#define LIQUID_VOLUME__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&liquid_volume__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, 0, 0 }
+
+
+/* LiquidVolume methods */
+void liquid_volume__init
+ (LiquidVolume *message);
+size_t liquid_volume__get_packed_size
+ (const LiquidVolume *message);
+size_t liquid_volume__pack
+ (const LiquidVolume *message,
+ uint8_t *out);
+size_t liquid_volume__pack_to_buffer
+ (const LiquidVolume *message,
+ ProtobufCBuffer *buffer);
+LiquidVolume *
+ liquid_volume__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void liquid_volume__free_unpacked
+ (LiquidVolume *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*LiquidVolume_Closure)
+ (const LiquidVolume *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor liquid_volume__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_LiquidVolume_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.c
new file mode 100644
index 000000000..e51e63783
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.c
@@ -0,0 +1,170 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutOfGamutInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "OutOfGamutInput.pb-c.h"
+void out_of_gamut_input__init
+ (OutOfGamutInput *message)
+{
+ static const OutOfGamutInput init_value = OUT_OF_GAMUT_INPUT__INIT;
+ *message = init_value;
+}
+size_t out_of_gamut_input__get_packed_size
+ (const OutOfGamutInput *message)
+{
+ assert(message->base.descriptor == &out_of_gamut_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t out_of_gamut_input__pack
+ (const OutOfGamutInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &out_of_gamut_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t out_of_gamut_input__pack_to_buffer
+ (const OutOfGamutInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &out_of_gamut_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+OutOfGamutInput *
+ out_of_gamut_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (OutOfGamutInput *)
+ protobuf_c_message_unpack (&out_of_gamut_input__descriptor,
+ allocator, len, data);
+}
+void out_of_gamut_input__free_unpacked
+ (OutOfGamutInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &out_of_gamut_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor out_of_gamut_input__field_descriptors[7] =
+{
+ {
+ "ThreadL",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutOfGamutInput, has_threadl),
+ offsetof(OutOfGamutInput, threadl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadA",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutOfGamutInput, has_threada),
+ offsetof(OutOfGamutInput, threada),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadB",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutOfGamutInput, has_threadb),
+ offsetof(OutOfGamutInput, threadb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ColorSpace",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(OutOfGamutInput, has_colorspace),
+ offsetof(OutOfGamutInput, colorspace),
+ &color_space__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InputCoordinates",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_MESSAGE,
+ 0, /* quantifier_offset */
+ offsetof(OutOfGamutInput, inputcoordinates),
+ &input_coordinates__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ForwardData",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BYTES,
+ offsetof(OutOfGamutInput, has_forwarddata),
+ offsetof(OutOfGamutInput, forwarddata),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessRanges",
+ 7,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(OutOfGamutInput, n_processranges),
+ offsetof(OutOfGamutInput, processranges),
+ &process_range__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned out_of_gamut_input__field_indices_by_name[] = {
+ 3, /* field[3] = ColorSpace */
+ 5, /* field[5] = ForwardData */
+ 4, /* field[4] = InputCoordinates */
+ 6, /* field[6] = ProcessRanges */
+ 1, /* field[1] = ThreadA */
+ 2, /* field[2] = ThreadB */
+ 0, /* field[0] = ThreadL */
+};
+static const ProtobufCIntRange out_of_gamut_input__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 7 }
+};
+const ProtobufCMessageDescriptor out_of_gamut_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "OutOfGamutInput",
+ "OutOfGamutInput",
+ "OutOfGamutInput",
+ "",
+ sizeof(OutOfGamutInput),
+ 7,
+ out_of_gamut_input__field_descriptors,
+ out_of_gamut_input__field_indices_by_name,
+ 1, out_of_gamut_input__number_ranges,
+ (ProtobufCMessageInit) out_of_gamut_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.h
new file mode 100644
index 000000000..bcaec7a85
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutInput.pb-c.h
@@ -0,0 +1,86 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutOfGamutInput.proto */
+
+#ifndef PROTOBUF_C_OutOfGamutInput_2eproto__INCLUDED
+#define PROTOBUF_C_OutOfGamutInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "InputCoordinates.pb-c.h"
+#include "ColorSpace.pb-c.h"
+#include "ProcessRange.pb-c.h"
+
+typedef struct _OutOfGamutInput OutOfGamutInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _OutOfGamutInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_threadl;
+ double threadl;
+ protobuf_c_boolean has_threada;
+ double threada;
+ protobuf_c_boolean has_threadb;
+ double threadb;
+ protobuf_c_boolean has_colorspace;
+ ColorSpace colorspace;
+ InputCoordinates *inputcoordinates;
+ protobuf_c_boolean has_forwarddata;
+ ProtobufCBinaryData forwarddata;
+ size_t n_processranges;
+ ProcessRange **processranges;
+};
+#define OUT_OF_GAMUT_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&out_of_gamut_input__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, COLOR_SPACE__Volume, NULL, 0, {0,NULL}, 0,NULL }
+
+
+/* OutOfGamutInput methods */
+void out_of_gamut_input__init
+ (OutOfGamutInput *message);
+size_t out_of_gamut_input__get_packed_size
+ (const OutOfGamutInput *message);
+size_t out_of_gamut_input__pack
+ (const OutOfGamutInput *message,
+ uint8_t *out);
+size_t out_of_gamut_input__pack_to_buffer
+ (const OutOfGamutInput *message,
+ ProtobufCBuffer *buffer);
+OutOfGamutInput *
+ out_of_gamut_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void out_of_gamut_input__free_unpacked
+ (OutOfGamutInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*OutOfGamutInput_Closure)
+ (const OutOfGamutInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor out_of_gamut_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_OutOfGamutInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.c
new file mode 100644
index 000000000..fbd1854ab
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.c
@@ -0,0 +1,118 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutOfGamutOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "OutOfGamutOutput.pb-c.h"
+void out_of_gamut_output__init
+ (OutOfGamutOutput *message)
+{
+ static const OutOfGamutOutput init_value = OUT_OF_GAMUT_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t out_of_gamut_output__get_packed_size
+ (const OutOfGamutOutput *message)
+{
+ assert(message->base.descriptor == &out_of_gamut_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t out_of_gamut_output__pack
+ (const OutOfGamutOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &out_of_gamut_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t out_of_gamut_output__pack_to_buffer
+ (const OutOfGamutOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &out_of_gamut_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+OutOfGamutOutput *
+ out_of_gamut_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (OutOfGamutOutput *)
+ protobuf_c_message_unpack (&out_of_gamut_output__descriptor,
+ allocator, len, data);
+}
+void out_of_gamut_output__free_unpacked
+ (OutOfGamutOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &out_of_gamut_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor out_of_gamut_output__field_descriptors[3] =
+{
+ {
+ "OutOfGamut",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(OutOfGamutOutput, has_outofgamut),
+ offsetof(OutOfGamutOutput, outofgamut),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(OutOfGamutOutput, has_haserror),
+ offsetof(OutOfGamutOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(OutOfGamutOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned out_of_gamut_output__field_indices_by_name[] = {
+ 2, /* field[2] = ErrorMessage */
+ 1, /* field[1] = HasError */
+ 0, /* field[0] = OutOfGamut */
+};
+static const ProtobufCIntRange out_of_gamut_output__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor out_of_gamut_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "OutOfGamutOutput",
+ "OutOfGamutOutput",
+ "OutOfGamutOutput",
+ "",
+ sizeof(OutOfGamutOutput),
+ 3,
+ out_of_gamut_output__field_descriptors,
+ out_of_gamut_output__field_indices_by_name,
+ 1, out_of_gamut_output__number_ranges,
+ (ProtobufCMessageInit) out_of_gamut_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.h
new file mode 100644
index 000000000..21bfa08ca
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutOfGamutOutput.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutOfGamutOutput.proto */
+
+#ifndef PROTOBUF_C_OutOfGamutOutput_2eproto__INCLUDED
+#define PROTOBUF_C_OutOfGamutOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _OutOfGamutOutput OutOfGamutOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _OutOfGamutOutput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_outofgamut;
+ protobuf_c_boolean outofgamut;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define OUT_OF_GAMUT_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&out_of_gamut_output__descriptor) \
+ , 0, 0, 0, 0, NULL }
+
+
+/* OutOfGamutOutput methods */
+void out_of_gamut_output__init
+ (OutOfGamutOutput *message);
+size_t out_of_gamut_output__get_packed_size
+ (const OutOfGamutOutput *message);
+size_t out_of_gamut_output__pack
+ (const OutOfGamutOutput *message,
+ uint8_t *out);
+size_t out_of_gamut_output__pack_to_buffer
+ (const OutOfGamutOutput *message,
+ ProtobufCBuffer *buffer);
+OutOfGamutOutput *
+ out_of_gamut_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void out_of_gamut_output__free_unpacked
+ (OutOfGamutOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*OutOfGamutOutput_Closure)
+ (const OutOfGamutOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor out_of_gamut_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_OutOfGamutOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.c
new file mode 100644
index 000000000..85aeb6ee5
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.c
@@ -0,0 +1,183 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutputCoordinates.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "OutputCoordinates.pb-c.h"
+void output_coordinates__init
+ (OutputCoordinates *message)
+{
+ static const OutputCoordinates init_value = OUTPUT_COORDINATES__INIT;
+ *message = init_value;
+}
+size_t output_coordinates__get_packed_size
+ (const OutputCoordinates *message)
+{
+ assert(message->base.descriptor == &output_coordinates__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t output_coordinates__pack
+ (const OutputCoordinates *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &output_coordinates__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t output_coordinates__pack_to_buffer
+ (const OutputCoordinates *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &output_coordinates__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+OutputCoordinates *
+ output_coordinates__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (OutputCoordinates *)
+ protobuf_c_message_unpack (&output_coordinates__descriptor,
+ allocator, len, data);
+}
+void output_coordinates__free_unpacked
+ (OutputCoordinates *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &output_coordinates__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor output_coordinates__field_descriptors[8] =
+{
+ {
+ "Red",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(OutputCoordinates, has_red),
+ offsetof(OutputCoordinates, red),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Green",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(OutputCoordinates, has_green),
+ offsetof(OutputCoordinates, green),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Blue",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(OutputCoordinates, has_blue),
+ offsetof(OutputCoordinates, blue),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "OutputLiquids",
+ 4,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(OutputCoordinates, n_outputliquids),
+ offsetof(OutputCoordinates, outputliquids),
+ &output_liquid__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessParametersTableIndex",
+ 5,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(OutputCoordinates, has_processparameterstableindex),
+ offsetof(OutputCoordinates, processparameterstableindex),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "L",
+ 6,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutputCoordinates, has_l),
+ offsetof(OutputCoordinates, l),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "A",
+ 7,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutputCoordinates, has_a),
+ offsetof(OutputCoordinates, a),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "B",
+ 8,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutputCoordinates, has_b),
+ offsetof(OutputCoordinates, b),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned output_coordinates__field_indices_by_name[] = {
+ 6, /* field[6] = A */
+ 7, /* field[7] = B */
+ 2, /* field[2] = Blue */
+ 1, /* field[1] = Green */
+ 5, /* field[5] = L */
+ 3, /* field[3] = OutputLiquids */
+ 4, /* field[4] = ProcessParametersTableIndex */
+ 0, /* field[0] = Red */
+};
+static const ProtobufCIntRange output_coordinates__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 8 }
+};
+const ProtobufCMessageDescriptor output_coordinates__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "OutputCoordinates",
+ "OutputCoordinates",
+ "OutputCoordinates",
+ "",
+ sizeof(OutputCoordinates),
+ 8,
+ output_coordinates__field_descriptors,
+ output_coordinates__field_indices_by_name,
+ 1, output_coordinates__number_ranges,
+ (ProtobufCMessageInit) output_coordinates__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.h
new file mode 100644
index 000000000..749ba3e7b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputCoordinates.pb-c.h
@@ -0,0 +1,87 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutputCoordinates.proto */
+
+#ifndef PROTOBUF_C_OutputCoordinates_2eproto__INCLUDED
+#define PROTOBUF_C_OutputCoordinates_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "OutputLiquid.pb-c.h"
+
+typedef struct _OutputCoordinates OutputCoordinates;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _OutputCoordinates
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_red;
+ int32_t red;
+ protobuf_c_boolean has_green;
+ int32_t green;
+ protobuf_c_boolean has_blue;
+ int32_t blue;
+ protobuf_c_boolean has_l;
+ double l;
+ protobuf_c_boolean has_a;
+ double a;
+ protobuf_c_boolean has_b;
+ double b;
+ size_t n_outputliquids;
+ OutputLiquid **outputliquids;
+ protobuf_c_boolean has_processparameterstableindex;
+ int32_t processparameterstableindex;
+};
+#define OUTPUT_COORDINATES__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&output_coordinates__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,NULL, 0, 0 }
+
+
+/* OutputCoordinates methods */
+void output_coordinates__init
+ (OutputCoordinates *message);
+size_t output_coordinates__get_packed_size
+ (const OutputCoordinates *message);
+size_t output_coordinates__pack
+ (const OutputCoordinates *message,
+ uint8_t *out);
+size_t output_coordinates__pack_to_buffer
+ (const OutputCoordinates *message,
+ ProtobufCBuffer *buffer);
+OutputCoordinates *
+ output_coordinates__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void output_coordinates__free_unpacked
+ (OutputCoordinates *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*OutputCoordinates_Closure)
+ (const OutputCoordinates *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor output_coordinates__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_OutputCoordinates_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.c
new file mode 100644
index 000000000..73f47bb20
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.c
@@ -0,0 +1,106 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutputLiquid.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "OutputLiquid.pb-c.h"
+void output_liquid__init
+ (OutputLiquid *message)
+{
+ static const OutputLiquid init_value = OUTPUT_LIQUID__INIT;
+ *message = init_value;
+}
+size_t output_liquid__get_packed_size
+ (const OutputLiquid *message)
+{
+ assert(message->base.descriptor == &output_liquid__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t output_liquid__pack
+ (const OutputLiquid *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &output_liquid__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t output_liquid__pack_to_buffer
+ (const OutputLiquid *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &output_liquid__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+OutputLiquid *
+ output_liquid__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (OutputLiquid *)
+ protobuf_c_message_unpack (&output_liquid__descriptor,
+ allocator, len, data);
+}
+void output_liquid__free_unpacked
+ (OutputLiquid *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &output_liquid__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor output_liquid__field_descriptors[2] =
+{
+ {
+ "LiquidType",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_ENUM,
+ offsetof(OutputLiquid, has_liquidtype),
+ offsetof(OutputLiquid, liquidtype),
+ &liquid_type__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Volume",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(OutputLiquid, has_volume),
+ offsetof(OutputLiquid, volume),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned output_liquid__field_indices_by_name[] = {
+ 0, /* field[0] = LiquidType */
+ 1, /* field[1] = Volume */
+};
+static const ProtobufCIntRange output_liquid__number_ranges[2 + 1] =
+{
+ { 1, 0 },
+ { 4, 1 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor output_liquid__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "OutputLiquid",
+ "OutputLiquid",
+ "OutputLiquid",
+ "",
+ sizeof(OutputLiquid),
+ 2,
+ output_liquid__field_descriptors,
+ output_liquid__field_indices_by_name,
+ 2, output_liquid__number_ranges,
+ (ProtobufCMessageInit) output_liquid__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.h
new file mode 100644
index 000000000..5401b8114
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/OutputLiquid.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: OutputLiquid.proto */
+
+#ifndef PROTOBUF_C_OutputLiquid_2eproto__INCLUDED
+#define PROTOBUF_C_OutputLiquid_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "LiquidType.pb-c.h"
+
+typedef struct _OutputLiquid OutputLiquid;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _OutputLiquid
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_liquidtype;
+ LiquidType liquidtype;
+ protobuf_c_boolean has_volume;
+ double volume;
+};
+#define OUTPUT_LIQUID__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&output_liquid__descriptor) \
+ , 0, LIQUID_TYPE__Cyan, 0, 0 }
+
+
+/* OutputLiquid methods */
+void output_liquid__init
+ (OutputLiquid *message);
+size_t output_liquid__get_packed_size
+ (const OutputLiquid *message);
+size_t output_liquid__pack
+ (const OutputLiquid *message,
+ uint8_t *out);
+size_t output_liquid__pack_to_buffer
+ (const OutputLiquid *message,
+ ProtobufCBuffer *buffer);
+OutputLiquid *
+ output_liquid__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void output_liquid__free_unpacked
+ (OutputLiquid *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*OutputLiquid_Closure)
+ (const OutputLiquid *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor output_liquid__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_OutputLiquid_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.c
new file mode 100644
index 000000000..f1caa25dc
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.c
@@ -0,0 +1,105 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ProcessRange.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "ProcessRange.pb-c.h"
+void process_range__init
+ (ProcessRange *message)
+{
+ static const ProcessRange init_value = PROCESS_RANGE__INIT;
+ *message = init_value;
+}
+size_t process_range__get_packed_size
+ (const ProcessRange *message)
+{
+ assert(message->base.descriptor == &process_range__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t process_range__pack
+ (const ProcessRange *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &process_range__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t process_range__pack_to_buffer
+ (const ProcessRange *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &process_range__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+ProcessRange *
+ process_range__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (ProcessRange *)
+ protobuf_c_message_unpack (&process_range__descriptor,
+ allocator, len, data);
+}
+void process_range__free_unpacked
+ (ProcessRange *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &process_range__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor process_range__field_descriptors[2] =
+{
+ {
+ "MinInkUptake",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ProcessRange, has_mininkuptake),
+ offsetof(ProcessRange, mininkuptake),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "MaxInkUptake",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(ProcessRange, has_maxinkuptake),
+ offsetof(ProcessRange, maxinkuptake),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned process_range__field_indices_by_name[] = {
+ 1, /* field[1] = MaxInkUptake */
+ 0, /* field[0] = MinInkUptake */
+};
+static const ProtobufCIntRange process_range__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor process_range__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "ProcessRange",
+ "ProcessRange",
+ "ProcessRange",
+ "",
+ sizeof(ProcessRange),
+ 2,
+ process_range__field_descriptors,
+ process_range__field_indices_by_name,
+ 1, process_range__number_ranges,
+ (ProtobufCMessageInit) process_range__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.h
new file mode 100644
index 000000000..c7eedfd8a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/ProcessRange.pb-c.h
@@ -0,0 +1,74 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: ProcessRange.proto */
+
+#ifndef PROTOBUF_C_ProcessRange_2eproto__INCLUDED
+#define PROTOBUF_C_ProcessRange_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _ProcessRange ProcessRange;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _ProcessRange
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_mininkuptake;
+ double mininkuptake;
+ protobuf_c_boolean has_maxinkuptake;
+ double maxinkuptake;
+};
+#define PROCESS_RANGE__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&process_range__descriptor) \
+ , 0, 0, 0, 0 }
+
+
+/* ProcessRange methods */
+void process_range__init
+ (ProcessRange *message);
+size_t process_range__get_packed_size
+ (const ProcessRange *message);
+size_t process_range__pack
+ (const ProcessRange *message,
+ uint8_t *out);
+size_t process_range__pack_to_buffer
+ (const ProcessRange *message,
+ ProtobufCBuffer *buffer);
+ProcessRange *
+ process_range__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void process_range__free_unpacked
+ (ProcessRange *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*ProcessRange_Closure)
+ (const ProcessRange *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor process_range__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_ProcessRange_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.c
new file mode 100644
index 000000000..12a349283
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.c
@@ -0,0 +1,183 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: RecommendedProcessTableInput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "RecommendedProcessTableInput.pb-c.h"
+void recommended_process_table_input__init
+ (RecommendedProcessTableInput *message)
+{
+ static const RecommendedProcessTableInput init_value = RECOMMENDED_PROCESS_TABLE_INPUT__INIT;
+ *message = init_value;
+}
+size_t recommended_process_table_input__get_packed_size
+ (const RecommendedProcessTableInput *message)
+{
+ assert(message->base.descriptor == &recommended_process_table_input__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t recommended_process_table_input__pack
+ (const RecommendedProcessTableInput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &recommended_process_table_input__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t recommended_process_table_input__pack_to_buffer
+ (const RecommendedProcessTableInput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &recommended_process_table_input__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+RecommendedProcessTableInput *
+ recommended_process_table_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (RecommendedProcessTableInput *)
+ protobuf_c_message_unpack (&recommended_process_table_input__descriptor,
+ allocator, len, data);
+}
+void recommended_process_table_input__free_unpacked
+ (RecommendedProcessTableInput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &recommended_process_table_input__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor recommended_process_table_input__field_descriptors[8] =
+{
+ {
+ "ThreadL",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(RecommendedProcessTableInput, has_threadl),
+ offsetof(RecommendedProcessTableInput, threadl),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadA",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(RecommendedProcessTableInput, has_threada),
+ offsetof(RecommendedProcessTableInput, threada),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ThreadB",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_DOUBLE,
+ offsetof(RecommendedProcessTableInput, has_threadb),
+ offsetof(RecommendedProcessTableInput, threadb),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ForwardData",
+ 4,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BYTES,
+ offsetof(RecommendedProcessTableInput, has_forwarddata),
+ offsetof(RecommendedProcessTableInput, forwarddata),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "Stops",
+ 5,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(RecommendedProcessTableInput, n_stops),
+ offsetof(RecommendedProcessTableInput, stops),
+ &gradient_input_stop__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "InputLiquids",
+ 6,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(RecommendedProcessTableInput, n_inputliquids),
+ offsetof(RecommendedProcessTableInput, inputliquids),
+ &input_liquid__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ProcessRanges",
+ 7,
+ PROTOBUF_C_LABEL_REPEATED,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(RecommendedProcessTableInput, n_processranges),
+ offsetof(RecommendedProcessTableInput, processranges),
+ &process_range__descriptor,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "UseLightInks",
+ 8,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(RecommendedProcessTableInput, has_uselightinks),
+ offsetof(RecommendedProcessTableInput, uselightinks),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned recommended_process_table_input__field_indices_by_name[] = {
+ 3, /* field[3] = ForwardData */
+ 5, /* field[5] = InputLiquids */
+ 6, /* field[6] = ProcessRanges */
+ 4, /* field[4] = Stops */
+ 1, /* field[1] = ThreadA */
+ 2, /* field[2] = ThreadB */
+ 0, /* field[0] = ThreadL */
+ 7, /* field[7] = UseLightInks */
+};
+static const ProtobufCIntRange recommended_process_table_input__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 8 }
+};
+const ProtobufCMessageDescriptor recommended_process_table_input__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "RecommendedProcessTableInput",
+ "RecommendedProcessTableInput",
+ "RecommendedProcessTableInput",
+ "",
+ sizeof(RecommendedProcessTableInput),
+ 8,
+ recommended_process_table_input__field_descriptors,
+ recommended_process_table_input__field_indices_by_name,
+ 1, recommended_process_table_input__number_ranges,
+ (ProtobufCMessageInit) recommended_process_table_input__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.h
new file mode 100644
index 000000000..98b4e1613
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableInput.pb-c.h
@@ -0,0 +1,89 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: RecommendedProcessTableInput.proto */
+
+#ifndef PROTOBUF_C_RecommendedProcessTableInput_2eproto__INCLUDED
+#define PROTOBUF_C_RecommendedProcessTableInput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+#include "ProcessRange.pb-c.h"
+#include "InputLiquid.pb-c.h"
+#include "GradientInputStop.pb-c.h"
+
+typedef struct _RecommendedProcessTableInput RecommendedProcessTableInput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _RecommendedProcessTableInput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_threadl;
+ double threadl;
+ protobuf_c_boolean has_threada;
+ double threada;
+ protobuf_c_boolean has_threadb;
+ double threadb;
+ protobuf_c_boolean has_forwarddata;
+ ProtobufCBinaryData forwarddata;
+ size_t n_stops;
+ GradientInputStop **stops;
+ size_t n_inputliquids;
+ InputLiquid **inputliquids;
+ size_t n_processranges;
+ ProcessRange **processranges;
+ protobuf_c_boolean has_uselightinks;
+ protobuf_c_boolean uselightinks;
+};
+#define RECOMMENDED_PROCESS_TABLE_INPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&recommended_process_table_input__descriptor) \
+ , 0, 0, 0, 0, 0, 0, 0, {0,NULL}, 0,NULL, 0,NULL, 0,NULL, 0, 0 }
+
+
+/* RecommendedProcessTableInput methods */
+void recommended_process_table_input__init
+ (RecommendedProcessTableInput *message);
+size_t recommended_process_table_input__get_packed_size
+ (const RecommendedProcessTableInput *message);
+size_t recommended_process_table_input__pack
+ (const RecommendedProcessTableInput *message,
+ uint8_t *out);
+size_t recommended_process_table_input__pack_to_buffer
+ (const RecommendedProcessTableInput *message,
+ ProtobufCBuffer *buffer);
+RecommendedProcessTableInput *
+ recommended_process_table_input__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void recommended_process_table_input__free_unpacked
+ (RecommendedProcessTableInput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*RecommendedProcessTableInput_Closure)
+ (const RecommendedProcessTableInput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor recommended_process_table_input__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_RecommendedProcessTableInput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.c
new file mode 100644
index 000000000..0ef6e7f9e
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.c
@@ -0,0 +1,118 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: RecommendedProcessTableOutput.proto */
+
+/* Do not generate deprecated warnings for self */
+#ifndef PROTOBUF_C__NO_DEPRECATED
+#define PROTOBUF_C__NO_DEPRECATED
+#endif
+
+#include "RecommendedProcessTableOutput.pb-c.h"
+void recommended_process_table_output__init
+ (RecommendedProcessTableOutput *message)
+{
+ static const RecommendedProcessTableOutput init_value = RECOMMENDED_PROCESS_TABLE_OUTPUT__INIT;
+ *message = init_value;
+}
+size_t recommended_process_table_output__get_packed_size
+ (const RecommendedProcessTableOutput *message)
+{
+ assert(message->base.descriptor == &recommended_process_table_output__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t recommended_process_table_output__pack
+ (const RecommendedProcessTableOutput *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &recommended_process_table_output__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t recommended_process_table_output__pack_to_buffer
+ (const RecommendedProcessTableOutput *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &recommended_process_table_output__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+RecommendedProcessTableOutput *
+ recommended_process_table_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (RecommendedProcessTableOutput *)
+ protobuf_c_message_unpack (&recommended_process_table_output__descriptor,
+ allocator, len, data);
+}
+void recommended_process_table_output__free_unpacked
+ (RecommendedProcessTableOutput *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &recommended_process_table_output__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+static const ProtobufCFieldDescriptor recommended_process_table_output__field_descriptors[3] =
+{
+ {
+ "ProcessParametersTableIndex",
+ 1,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_INT32,
+ offsetof(RecommendedProcessTableOutput, has_processparameterstableindex),
+ offsetof(RecommendedProcessTableOutput, processparameterstableindex),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "HasError",
+ 2,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_BOOL,
+ offsetof(RecommendedProcessTableOutput, has_haserror),
+ offsetof(RecommendedProcessTableOutput, haserror),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ErrorMessage",
+ 3,
+ PROTOBUF_C_LABEL_OPTIONAL,
+ PROTOBUF_C_TYPE_STRING,
+ 0, /* quantifier_offset */
+ offsetof(RecommendedProcessTableOutput, errormessage),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned recommended_process_table_output__field_indices_by_name[] = {
+ 2, /* field[2] = ErrorMessage */
+ 1, /* field[1] = HasError */
+ 0, /* field[0] = ProcessParametersTableIndex */
+};
+static const ProtobufCIntRange recommended_process_table_output__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 3 }
+};
+const ProtobufCMessageDescriptor recommended_process_table_output__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "RecommendedProcessTableOutput",
+ "RecommendedProcessTableOutput",
+ "RecommendedProcessTableOutput",
+ "",
+ sizeof(RecommendedProcessTableOutput),
+ 3,
+ recommended_process_table_output__field_descriptors,
+ recommended_process_table_output__field_indices_by_name,
+ 1, recommended_process_table_output__number_ranges,
+ (ProtobufCMessageInit) recommended_process_table_output__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.h
new file mode 100644
index 000000000..c836b4074
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/PMR/ColorLab/RecommendedProcessTableOutput.pb-c.h
@@ -0,0 +1,75 @@
+/* Generated by the protocol buffer compiler. DO NOT EDIT! */
+/* Generated from: RecommendedProcessTableOutput.proto */
+
+#ifndef PROTOBUF_C_RecommendedProcessTableOutput_2eproto__INCLUDED
+#define PROTOBUF_C_RecommendedProcessTableOutput_2eproto__INCLUDED
+
+#include <protobuf-c/protobuf-c.h>
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if PROTOBUF_C_VERSION_NUMBER < 1003000
+# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
+#elif 1003000 < PROTOBUF_C_MIN_COMPILER_VERSION
+# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
+#endif
+
+
+typedef struct _RecommendedProcessTableOutput RecommendedProcessTableOutput;
+
+
+/* --- enums --- */
+
+
+/* --- messages --- */
+
+struct _RecommendedProcessTableOutput
+{
+ ProtobufCMessage base;
+ protobuf_c_boolean has_processparameterstableindex;
+ int32_t processparameterstableindex;
+ protobuf_c_boolean has_haserror;
+ protobuf_c_boolean haserror;
+ char *errormessage;
+};
+#define RECOMMENDED_PROCESS_TABLE_OUTPUT__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&recommended_process_table_output__descriptor) \
+ , 0, 0, 0, 0, NULL }
+
+
+/* RecommendedProcessTableOutput methods */
+void recommended_process_table_output__init
+ (RecommendedProcessTableOutput *message);
+size_t recommended_process_table_output__get_packed_size
+ (const RecommendedProcessTableOutput *message);
+size_t recommended_process_table_output__pack
+ (const RecommendedProcessTableOutput *message,
+ uint8_t *out);
+size_t recommended_process_table_output__pack_to_buffer
+ (const RecommendedProcessTableOutput *message,
+ ProtobufCBuffer *buffer);
+RecommendedProcessTableOutput *
+ recommended_process_table_output__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void recommended_process_table_output__free_unpacked
+ (RecommendedProcessTableOutput *message,
+ ProtobufCAllocator *allocator);
+/* --- per-message closures --- */
+
+typedef void (*RecommendedProcessTableOutput_Closure)
+ (const RecommendedProcessTableOutput *message,
+ void *closure_data);
+
+/* --- services --- */
+
+
+/* --- descriptors --- */
+
+extern const ProtobufCMessageDescriptor recommended_process_table_output__descriptor;
+
+PROTOBUF_C__END_DECLS
+
+
+#endif /* PROTOBUF_C_RecommendedProcessTableOutput_2eproto__INCLUDED */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ReadMe.txt b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ReadMe.txt
new file mode 100644
index 000000000..d9b08497d
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/ReadMe.txt
@@ -0,0 +1,48 @@
+========================================================================
+ DYNAMIC LINK LIBRARY : Tango.ColorLib Project Overview
+========================================================================
+
+AppWizard has created this Tango.ColorLib DLL for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your Tango.ColorLib application.
+
+
+Tango.ColorLib.vcxproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+Tango.ColorLib.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+Tango.ColorLib.cpp
+ This is the main DLL source file.
+
+ When created, this DLL does not export any symbols. As a result, it
+ will not produce a .lib file when it is built. If you wish this project
+ to be a project dependency of some other project, you will either need to
+ add code to export some symbols from the DLL so that an export library
+ will be produced, or you can set the Ignore Input Library property to Yes
+ on the General propert page of the Linker folder in the project's Property
+ Pages dialog box.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named Tango.ColorLib.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj
new file mode 100644
index 000000000..ea0b14ca9
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{0F87D32E-B65F-4AE8-862C-29F4CCC38240}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>TangoColorLib</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)Build\ColorLib\Debug</OutDir>
+ <IncludePath>$(ProjectDir);$(IncludePath)</IncludePath>
+ <PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)Build\ColorLib\Release</OutDir>
+ <IncludePath>$(ProjectDir);$(IncludePath)</IncludePath>
+ <PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TANGOCOLORLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)..\EigenDir;$(ProjectDir)..\EigenDir\Eigen;$(ProjectDir)Utils;$(ProjectDir)PMR\ColorLab;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <SDLCheck>
+ </SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <AssemblyDebug>true</AssemblyDebug>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(SolutionDir)Build\Utilities\Debug\proto-tc.exe" -i "$(SolutionDir)..\PMR\Messages" -o "$(ProjectDir)PMR" -l C -c "ColorLab"</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;TANGOCOLORLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TANGOCOLORLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)..\EigenDir;$(ProjectDir)..\EigenDir\Eigen;$(ProjectDir)Utils;$(ProjectDir)PMR\ColorLab;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AssemblyDebug>true</AssemblyDebug>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(SolutionDir)Build\Utilities\Debug\proto-tc.exe" -i "$(SolutionDir)..\PMR\Messages" -o "$(ProjectDir)PMR" -l C -c "ColorLab"</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;TANGOCOLORLIB_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Text Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ColorCalibrator.h" />
+ <ClInclude Include="ColorConverter.h" />
+ <ClInclude Include="Exports.h" />
+ <ClInclude Include="ForwardModel.h" />
+ <ClInclude Include="PMR\ColorLab\CalibrationData.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\CalibrationInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\CalibrationMeasurement.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\CalibrationOutput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\CalibrationPoint.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\ColorSpace.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\ConversionInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\ConversionOutput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\GradientConversionInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\GradientConversionOutput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\GradientInputStop.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\GradientOutputStop.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\InputCoordinates.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\InputLiquid.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\LinearizationInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\LinearizationMeasurement.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\LinearizationOutput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\LiquidType.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\LiquidVolume.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\OutOfGamutInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\OutOfGamutOutput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\OutputCoordinates.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\OutputLiquid.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\ProcessRange.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\RecommendedProcessTableInput.pb-c.h" />
+ <ClInclude Include="PMR\ColorLab\RecommendedProcessTableOutput.pb-c.h" />
+ <ClInclude Include="PMR\Stubs\CalculateRequest.pb-c.h" />
+ <ClInclude Include="PMR\Stubs\CalculateResponse.pb-c.h" />
+ <ClInclude Include="protobuf-c\protobuf-c.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="Utils\CalibData.h" />
+ <ClInclude Include="Utils\ColorConvert.h" />
+ <ClInclude Include="Utils\ColorTable.h" />
+ <ClInclude Include="Utils\ColorTransf.h" />
+ <ClInclude Include="Utils\CT_Header.h" />
+ <ClInclude Include="Utils\Curves.h" />
+ <ClInclude Include="Utils\C_RGB_XYZ_Lab.h" />
+ <ClInclude Include="Utils\GBD.h" />
+ <ClInclude Include="Utils\Gradient.h" />
+ <ClInclude Include="Utils\Interp.h" />
+ <ClInclude Include="Utils\LevMar.h" />
+ <ClInclude Include="Utils\LULinearSolver.h" />
+ <ClInclude Include="Utils\NDInterpUtils.h" />
+ <ClInclude Include="Utils\NumConversions.h" />
+ <ClInclude Include="Utils\ObjectiveFunction.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="ColorCalibrator.cpp" />
+ <ClCompile Include="ColorConverter.cpp" />
+ <ClCompile Include="Exports.cpp" />
+ <ClCompile Include="ForwardModel.cpp" />
+ <ClCompile Include="PMR\ColorLab\CalibrationData.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\CalibrationInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\CalibrationMeasurement.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\CalibrationOutput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\CalibrationPoint.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\ColorSpace.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\ConversionInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\ConversionOutput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\GradientConversionInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\GradientConversionOutput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\GradientInputStop.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\GradientOutputStop.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\InputCoordinates.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\InputLiquid.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\LinearizationInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\LinearizationMeasurement.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\LinearizationOutput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\LiquidType.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\LiquidVolume.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\OutOfGamutInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\OutOfGamutOutput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\OutputCoordinates.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\OutputLiquid.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\ProcessRange.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\RecommendedProcessTableInput.pb-c.c" />
+ <ClCompile Include="PMR\ColorLab\RecommendedProcessTableOutput.pb-c.c" />
+ <ClCompile Include="protobuf-c\protobuf-c.c" />
+ <ClCompile Include="Utils\CalibData.cpp" />
+ <ClCompile Include="Utils\ColorConvert.cpp" />
+ <ClCompile Include="Utils\ColorTable.cpp" />
+ <ClCompile Include="Utils\ColorTransf.cpp" />
+ <ClCompile Include="Utils\CT_Header.cpp" />
+ <ClCompile Include="Utils\Curves.cpp" />
+ <ClCompile Include="Utils\C_RGB_XYZ_Lab.cpp" />
+ <ClCompile Include="Utils\GBD.cpp" />
+ <ClCompile Include="Utils\Gradient.cpp" />
+ <ClCompile Include="Utils\Interp.cpp" />
+ <ClCompile Include="Utils\LevMar.cpp" />
+ <ClCompile Include="Utils\LULinearSolver.cpp" />
+ <ClCompile Include="Utils\NDInterpUtils.cpp" />
+ <ClCompile Include="Utils\NumConversions.cpp" />
+ <ClCompile Include="Utils\ObjectiveFunction.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties BuildVersion_StartDate="2000/1/1" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj.filters b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj.filters
new file mode 100644
index 000000000..aa2eda221
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Tango.ColorLib_v5.vcxproj.filters
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="PMR">
+ <UniqueIdentifier>{0f952433-0681-4d49-9d48-c95684b56970}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Protobuf">
+ <UniqueIdentifier>{51e509a9-ffc2-4cf6-8206-247eff6fa786}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Utils">
+ <UniqueIdentifier>{ba97ff4c-dbb7-4557-921e-b19687f10882}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="targetver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ColorConverter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\ColorSpace.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\ConversionInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\ConversionOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\CalibrationPoint.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\CalibrationData.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="protobuf-c\protobuf-c.h">
+ <Filter>Protobuf</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\InputLiquid.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\LiquidType.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\OutputLiquid.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\InputCoordinates.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\OutputCoordinates.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\CalibData.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\ColorTransf.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\NDInterpUtils.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\Interp.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\C_RGB_XYZ_Lab.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\ColorConvert.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Exports.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\NumConversions.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\GBD.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\ProcessRange.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\Curves.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="ColorCalibrator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\CalibrationInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\CalibrationMeasurement.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\CalibrationOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\GradientConversionInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\GradientConversionOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\Stubs\CalculateRequest.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\Stubs\CalculateResponse.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\GradientInputStop.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\GradientOutputStop.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\LiquidVolume.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\LinearizationInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\LinearizationMeasurement.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\LinearizationOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\Gradient.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\CT_Header.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\ColorTable.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\RecommendedProcessTableOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\RecommendedProcessTableInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\OutOfGamutInput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="PMR\ColorLab\OutOfGamutOutput.pb-c.h">
+ <Filter>PMR</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\LevMar.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\ObjectiveFunction.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="Utils\LULinearSolver.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ <ClInclude Include="ForwardModel.h">
+ <Filter>Utils</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Exports.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ColorConverter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\ConversionInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\ConversionOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\CalibrationPoint.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\ColorSpace.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\CalibrationData.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="protobuf-c\protobuf-c.c">
+ <Filter>Protobuf</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\LiquidType.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\OutputLiquid.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\InputLiquid.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\InputCoordinates.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\OutputCoordinates.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\CalibData.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\ColorTransf.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\NDInterpUtils.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\Interp.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\C_RGB_XYZ_Lab.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\ColorConvert.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\NumConversions.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\GBD.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\ProcessRange.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\Curves.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="ColorCalibrator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\CalibrationInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\CalibrationMeasurement.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\CalibrationOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\GradientConversionInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\GradientConversionOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\GradientInputStop.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\GradientOutputStop.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\LiquidVolume.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\LinearizationInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\LinearizationMeasurement.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\LinearizationOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\Gradient.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\CT_Header.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\ColorTable.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\RecommendedProcessTableOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\RecommendedProcessTableInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\OutOfGamutOutput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="PMR\ColorLab\OutOfGamutInput.pb-c.c">
+ <Filter>PMR</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\LevMar.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\ObjectiveFunction.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="Utils\LULinearSolver.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ <ClCompile Include="ForwardModel.cpp">
+ <Filter>Utils</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.cpp
new file mode 100644
index 000000000..85a82cf0c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.cpp
@@ -0,0 +1,114 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#include "CT_Header.h"
+#include <iostream>
+#include <stdio.h>
+#include <cstring>
+
+CT_Header::CT_Header() :
+ m_Version(NULL), m_ColorSpace(NULL), m_ConnectionSpace(NULL), m_TblSize(0),
+ m_DeviceManufacturer(NULL), m_Illuminant(0), m_nGamutRegions(0), m_GRegMaxLim(NULL),
+ m_GRegMinLim(NULL), m_CTLiquidFactors(NULL)
+{
+
+}
+
+CT_Header::~CT_Header()
+{
+ if (m_Version != NULL)
+ {
+ delete[]m_Version;
+ m_Version = NULL;
+ }
+ if (m_ColorSpace != NULL)
+ {
+ delete m_ColorSpace;
+ m_ColorSpace = NULL;
+ }
+ if (m_ConnectionSpace != NULL)
+ {
+ delete m_ConnectionSpace;
+ m_ConnectionSpace = NULL;
+ }
+ if (m_DeviceManufacturer != NULL)
+ {
+ delete m_DeviceManufacturer;
+ m_DeviceManufacturer = NULL;
+ }
+ if (m_GRegMaxLim != NULL)
+ {
+ delete[]m_GRegMaxLim;
+ m_GRegMaxLim = NULL;
+ }
+ if (m_GRegMinLim != NULL)
+ {
+ delete[]m_GRegMinLim;
+ m_GRegMinLim = NULL;
+ }
+ if (m_CTLiquidFactors != NULL)
+ {
+ delete[]m_CTLiquidFactors;
+ m_CTLiquidFactors = NULL;
+ }
+}
+
+void CT_Header::SetTableVersion(unsigned int *Version)
+{
+ if(m_Version == NULL)
+ m_Version = new unsigned int[3];
+ for (int i = 0; i < 3; ++i)
+ m_Version[i] = Version[i];
+}
+
+C_RGB_XYZ_Lab CT_Header::GetIlluminant() {
+ return(m_Illuminant);
+};
+
+void CT_Header::SetColorSpace(char *ColorSPace)
+{
+ int nsize = sizeof(ColorSPace);
+ if(m_ColorSpace == NULL)
+ m_ColorSpace = new char[nsize+1];
+ strncpy_s(m_ColorSpace, nsize +1,ColorSPace, nsize);
+}
+
+void CT_Header :: SetConnectionSpace(char *ConnectionSpace)
+{
+ int nsize = sizeof(ConnectionSpace);
+ if(m_ConnectionSpace == NULL)
+ m_ConnectionSpace = new char[nsize+1];
+ strncpy_s(m_ConnectionSpace, nsize+1,ConnectionSpace, nsize);
+}
+
+void CT_Header::SetDeviceManufacturer(char *DeviceManufacturer)
+{
+ int nsize = sizeof(DeviceManufacturer);
+ if(m_DeviceManufacturer == NULL)
+ m_DeviceManufacturer = new char[nsize+1];
+ strncpy_s(m_DeviceManufacturer, nsize + 1, DeviceManufacturer, nsize);
+}
+
+void CT_Header::SetGamutRegionsMaxLimit(double *GRegMaxLim)
+{
+ if (m_GRegMaxLim == NULL)
+ m_GRegMaxLim = new double[m_nGamutRegions];
+ for (int i = 0; i < m_nGamutRegions; ++i)
+ m_GRegMaxLim[i] = GRegMaxLim[i];
+}
+
+void CT_Header::SetGamutRegionsMinLimit(double *GRegMinLim)
+{
+ if (m_GRegMinLim == NULL)
+ m_GRegMinLim = new double[m_nGamutRegions];
+ for (int i = 0; i < m_nGamutRegions; ++i)
+ m_GRegMinLim[i] = GRegMinLim[i];
+}
+
+void CT_Header::SetLiquidFactors(double *LF)
+{
+ if (m_CTLiquidFactors == NULL)
+ m_CTLiquidFactors = new double[4];
+ for (int i = 0; i < 4; ++i)
+ m_CTLiquidFactors[i] = LF[i];
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.h
new file mode 100644
index 000000000..3872b55e6
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CT_Header.h
@@ -0,0 +1,63 @@
+#ifndef _CT_HEADER_H_
+#define _CT_HEADER_H_
+#pragma once
+#include <stdlib.h>
+#include "C_RGB_XYZ_Lab.h"
+
+class CT_Header {
+public:
+ CT_Header();
+ ~CT_Header();
+ unsigned int GetTableSize() { return(m_TblSize); };
+ void SetTableSize(unsigned int TableSize) {
+ m_TblSize = TableSize;
+ };
+ unsigned int *GetTableVersion() { return(m_Version); };
+ void SetTableVersion(unsigned int *version);
+ char* GetColorSpace() {
+ return(m_ColorSpace);
+ };
+ void SetColorSpace(char *ColorSPace);
+ char* GetConnectionSpace() {
+ return(m_ConnectionSpace);
+ };
+ void SetConnectionSpace(char *ConnectionSpace);
+
+ char* GetDeviceManufacturer() {
+ return(m_DeviceManufacturer);
+ };
+ void SetDeviceManufacturer(char *DeviceManufacturer);
+
+ C_RGB_XYZ_Lab GetIlluminant();
+
+ void SetIlluminant(C_RGB_XYZ_Lab Illuminant) {
+ m_Illuminant = Illuminant;
+ };
+
+ void SetNGamutRegions(unsigned char GamutRegions) {
+ m_nGamutRegions = GamutRegions;
+ };
+ unsigned char GetNGamutRegions() {
+ return(m_nGamutRegions);
+ };
+ void SetGamutRegionsMaxLimit(double *GRegMaxLim);
+ void SetGamutRegionsMinLimit(double *GRegMinLim);
+ void SetLiquidFactors(double *LF);
+ double *GetGamutRegionsMaxLimit() { return(m_GRegMaxLim); };
+ double *GetGamutRegionsMinLimit() { return(m_GRegMinLim); };
+ double *GetLiquidFactors() { return (m_CTLiquidFactors); };
+
+private:
+ unsigned int *m_Version;
+ char *m_ColorSpace;
+ char * m_ConnectionSpace;
+ char * m_DeviceManufacturer;
+ C_RGB_XYZ_Lab m_Illuminant;
+ unsigned char m_nGamutRegions ;
+ double *m_GRegMaxLim;
+ double *m_GRegMinLim;
+ double *m_CTLiquidFactors;
+ unsigned int m_TblSize;
+};
+
+#endif \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.cpp
new file mode 100644
index 000000000..d14619ff7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.cpp
@@ -0,0 +1,188 @@
+#include "C_RGB_XYZ_Lab.h"
+//#include <cmath>
+//#include <algorithm> // std::min, max
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif*/
+
+
+// Default Constructor ... C_RGB_XYZ_Lab = (0, 0, 0)
+C_RGB_XYZ_Lab::C_RGB_XYZ_Lab(void) :
+ m_x(0.0),
+ m_y(0.0),
+ m_z(0.0)
+{
+}
+
+
+// Constructor from a constant ... C_RGB_XYZ_Lab = (val, val, val)
+C_RGB_XYZ_Lab::C_RGB_XYZ_Lab(const double &val) :
+ m_x(val),
+ m_y(val),
+ m_z(val)
+{
+}
+
+
+// Constructor from 3 values ... C_RGB_XYZ_Lab = (val1, val2, val3)
+C_RGB_XYZ_Lab::C_RGB_XYZ_Lab(const double &val1, const double &val2, const double &val3) :
+ m_x(val1),
+ m_y(val2),
+ m_z(val3)
+{
+}
+
+
+// Constructor from 3 values in a vector
+C_RGB_XYZ_Lab::C_RGB_XYZ_Lab(const VectorXd &Val):
+m_x(Val(0)),
+m_y(Val(1)),
+m_z(Val(2))
+{
+
+}
+
+
+// Copy constructor
+C_RGB_XYZ_Lab::C_RGB_XYZ_Lab(const C_RGB_XYZ_Lab &rhs) :
+ m_x(rhs.m_x),
+ m_y(rhs.m_y),
+ m_z(rhs.m_z)
+{
+}
+
+//Destructor
+C_RGB_XYZ_Lab::~C_RGB_XYZ_Lab()
+{
+}
+
+
+
+// Get a vector from the RGB/XYZ/Lab
+VectorXd C_RGB_XYZ_Lab::Get() const
+{
+ VectorXd vec(3);
+ vec(0) = m_x;
+ vec(1) = m_y;
+ vec(2) = m_z;
+ return vec;
+}
+
+
+// Set RGB/XYZ/Lab from a vector
+void C_RGB_XYZ_Lab::Set(const VectorXd &rhs)
+{
+ m_x = rhs(0);
+ m_y = rhs(1);
+ m_z = rhs(2);
+}
+
+
+// Set RGB/XYZ/Lab from three values
+void C_RGB_XYZ_Lab::Set(const double &val1, const double &val2, const double &val3)
+{
+ m_x = val1;
+ m_y = val2;
+ m_z = val3;
+}
+
+
+// Clip the individual components to the range [low,high]
+void C_RGB_XYZ_Lab::Clamp(C_RGB_XYZ_Lab &low, C_RGB_XYZ_Lab &high)
+{
+ m_x = std::min(std::max(m_x, low.Get_x()), high.Get_x());
+ m_y = std::min(std::max(m_y, low.Get_y()), high.Get_y());
+ m_z = std::min(std::max(m_z, low.Get_z()), high.Get_z());;
+}
+
+C_RGB_XYZ_Lab C_RGB_XYZ_Lab::labuint16_to_labdouble(uint16_t * LabShort)
+{
+ double tmp[3];
+ C_RGB_XYZ_Lab out;
+ tmp[0] = (double(LabShort[0]) * (100.0 + (25500.0 / 65280.0))) / 65535.0;
+ tmp[1] = ((double(LabShort[1]) * (255.0 + (255.0 / 256.0))) / 65535.0) - 128.0;
+ tmp[2] = ((double(LabShort[2]) * (255.0 + (255.0 / 256.0))) / 65535.0) - 128.0;
+ out.Set(tmp[0], tmp[1], tmp[2]);
+ return (out);
+}
+
+C_RGB_XYZ_Lab C_RGB_XYZ_Lab::labdouble_to_labuint16(double* LabDouble)
+{
+//Do the scale and offset and cast to uint16
+ C_RGB_XYZ_Lab out;
+ double tmp[3];
+tmp[0]= round(65535 * LabDouble[0] / (100 + (25500 / 65280)));
+tmp[1] = round(65535 * ((128 + LabDouble[1]) / (255 + (255 / 256))));
+tmp[2] = round(65535 * ((128 + LabDouble[2]) / (255 + (255 / 256))));
+for (int i = 0; i < 3; ++i)
+ tmp[0] = std::min(std::max(tmp[0], 0.0), 65535.0);
+out.Set((uint16_t)tmp[0], (uint16_t)tmp[1], (uint16_t)tmp[2]);
+return (out);
+}
+
+// add to existing value (rgb += rhs)
+C_RGB_XYZ_Lab &C_RGB_XYZ_Lab::operator += (C_RGB_XYZ_Lab &rhs)
+{
+ m_x += rhs.m_x;
+ m_y += rhs.m_y;
+ m_z += rhs.m_z;
+ return (*this);
+}
+
+
+// subtract from existing value (lab -= rhs)
+C_RGB_XYZ_Lab &C_RGB_XYZ_Lab::operator -= (C_RGB_XYZ_Lab &rhs)
+{
+ m_x -= rhs.m_x;
+ m_y -= rhs.m_y;
+ m_z -= rhs.m_z;
+ return (*this);
+}
+
+
+// multiply 2 RGB's (lab *= rhs)
+C_RGB_XYZ_Lab &C_RGB_XYZ_Lab::operator *= (C_RGB_XYZ_Lab &rhs)
+{
+ m_x *= rhs.m_x;
+ m_y *= rhs.m_y;
+ m_z *= rhs.m_z;
+ return (*this);
+}
+
+
+// Divide 2 RGB's (lab /= rhs)
+C_RGB_XYZ_Lab &C_RGB_XYZ_Lab::operator /= (C_RGB_XYZ_Lab &rhs)
+{
+ m_x /= rhs.m_x;
+ m_y /= rhs.m_y;
+ m_z /= rhs.m_z;
+ return (*this);
+}
+
+// isequal (lhs == rhs)
+bool operator == (C_RGB_XYZ_Lab &lhs, C_RGB_XYZ_Lab &rhs)
+{
+ return ((lhs.Get_x() == rhs.Get_x()) && (lhs.Get_y() == rhs.Get_y()) && (lhs.Get_z() == rhs.Get_z()));
+}
+
+
+
+// isnotequal (lhs != rhs)
+bool operator != (C_RGB_XYZ_Lab &lhs, C_RGB_XYZ_Lab &rhs)
+{
+ return (!operator == (lhs, rhs));
+}
+
+
+
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.h
new file mode 100644
index 000000000..a82ba7d5b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/C_RGB_XYZ_Lab.h
@@ -0,0 +1,48 @@
+#ifndef __CRGB_XYZ_Lab_H__
+#define __CRGB_XYZ_Lab_H__
+
+#include "Dense"
+using Eigen::MatrixXd;
+using Eigen::VectorXd;
+
+#define nRGB (3)
+#define nXYZ (3)
+#define nLab (3)
+
+class C_RGB_XYZ_Lab
+ {
+ public:
+
+ C_RGB_XYZ_Lab(void); // (0,0,0)
+ ~C_RGB_XYZ_Lab(void);
+ C_RGB_XYZ_Lab(const double &val); // (x,x,x)
+ C_RGB_XYZ_Lab(const double &rval, const double &gval, const double &bval); // (X,Y,Z)
+ C_RGB_XYZ_Lab(const VectorXd &xyzval);
+ C_RGB_XYZ_Lab(const C_RGB_XYZ_Lab &rhs);
+
+ // Get/Set to/from a vector
+ VectorXd Get() const;
+ void Set(const VectorXd &rhs);
+ void Set (const double &rval, const double &gval, const double &bval);
+ double Get_x() { return (m_x); };
+ double Get_y() { return (m_y); };
+ double Get_z() { return (m_z); };
+ // Clamp the elements to the range [low, high]
+ void Clamp (C_RGB_XYZ_Lab &low, C_RGB_XYZ_Lab &high);
+ C_RGB_XYZ_Lab labuint16_to_labdouble(uint16_t *LabShort);
+ C_RGB_XYZ_Lab labdouble_to_labuint16(double* LabDouble);
+ C_RGB_XYZ_Lab &operator += (C_RGB_XYZ_Lab &rhs);
+ C_RGB_XYZ_Lab &operator -= (C_RGB_XYZ_Lab &rhs);
+ C_RGB_XYZ_Lab &operator *= (C_RGB_XYZ_Lab &rhs);
+ C_RGB_XYZ_Lab &operator /= (C_RGB_XYZ_Lab &rhs);
+
+
+ private:
+
+ double m_x;
+ double m_y;
+ double m_z;
+ };
+
+
+#endif // __C_RGB_XYZ_Lab__ \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.cpp
new file mode 100644
index 000000000..6ec1bf24e
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.cpp
@@ -0,0 +1,90 @@
+#include "CalibData.h"
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+CalibData::CalibData(): m_npoints(0), m_XCoords(NULL),
+m_YCoords(NULL), m_InkName(0), m_maxNlPerCM(0), m_LinearInterp(NULL), m_InvLinearInterp(NULL)
+{
+}
+
+CalibData::CalibData(const CalibData &rhs) : m_npoints(rhs.m_npoints), m_XCoords(rhs.m_XCoords),
+m_YCoords(rhs.m_YCoords), m_InkName(rhs.m_InkName), m_maxNlPerCM(rhs.m_maxNlPerCM),
+m_LinearInterp(rhs.m_LinearInterp), m_InvLinearInterp(rhs.m_InvLinearInterp)
+{
+}
+
+CalibData::~CalibData()
+{
+ if (m_XCoords != NULL)
+ {
+ delete[] m_XCoords;
+ m_XCoords = NULL;
+ }
+ if (m_YCoords != NULL)
+ {
+ delete[] m_YCoords;
+ m_YCoords = NULL;
+ }
+ if (m_LinearInterp != NULL)
+ {
+ delete m_LinearInterp;
+ m_LinearInterp = NULL;
+ }
+ if (m_InvLinearInterp != NULL)
+ {
+ delete m_InvLinearInterp;
+ m_InvLinearInterp = NULL;
+ }
+}
+void CalibData::SetXCoords(double * XCoords)
+{
+ if(m_XCoords ==NULL)
+ {
+ m_XCoords = new double[m_npoints];
+ //m_XCoords = DBG_NEW double[m_npoints];
+ for (int i=0; i<m_npoints; ++i)
+ m_XCoords[i] = XCoords[i];
+ }
+}
+
+void CalibData::SetYCoords(double* YCoords)
+{
+ if (m_YCoords == NULL)
+ {
+ m_YCoords = new double[m_npoints];
+ //m_YCoords = DBG_NEW double[m_npoints];
+ for (int i = 0; i < m_npoints; ++i)
+ m_YCoords[i] = YCoords[i];
+ }
+}
+
+void CalibData::InitInterpolations()
+{
+ if(m_LinearInterp == NULL)
+ m_LinearInterp = new Interp();
+ if(m_InvLinearInterp == NULL)
+ m_InvLinearInterp = new Interp();
+ m_LinearInterp->Init(m_XCoords, m_YCoords, m_npoints);
+ m_InvLinearInterp->Init(m_YCoords, m_XCoords, m_npoints);
+}
+
+double CalibData::GetMaxXValue()
+{
+ int nsize = getSize();
+ double *xval;
+ xval = getxCoords();
+ double maxVal = 0;
+ maxVal = xval[nsize - 1];
+ return(maxVal);
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.h
new file mode 100644
index 000000000..716fd92f2
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/CalibData.h
@@ -0,0 +1,33 @@
+#ifndef __CALIBDATA_H__
+#define __CALIBDATA_H__
+#include <cmath>
+#include <algorithm>
+#include "Interp.h"
+
+class CalibData
+{
+ public:
+ CalibData(void) ;
+ CalibData (const CalibData &rhs);
+ ~CalibData();
+ int getSize() { return(m_npoints); }
+ double GetMaxXValue();
+ double *getxCoords() { return(m_XCoords); }
+ double *getyCoords() { return(m_YCoords); }
+ int getInkName() { return(m_InkName); }
+ void SetCalibName(int InkName) { m_InkName = InkName; }
+ void SetCalibCurveSize(int npoints) { m_npoints = npoints; }
+ void SetXCoords(double* XCoords);
+ void SetYCoords(double* YCoords);
+ void SetMaxNlPerCM(double maxNlPerCM) {m_maxNlPerCM = maxNlPerCM;}
+ Interp *m_LinearInterp;
+ Interp *m_InvLinearInterp;
+ void InitInterpolations();
+ private:
+ int m_npoints;
+ double *m_XCoords;
+ double *m_YCoords;
+ int m_InkName;
+ double m_maxNlPerCM;
+};
+#endif // __CALIBDATA_H__
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.cpp
new file mode 100644
index 000000000..f4f27928c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.cpp
@@ -0,0 +1,1254 @@
+#include "ColorConvert.h"
+#include <cmath>
+#include <algorithm>
+
+using namespace std;
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+//define constants for RGB conversion
+const static double CHROMATICITIES[nRGB*nXYZ] = { 0.0, 0.6400, 0.3300, 0.0, 0.3000, 0.6000, 0.0, 0.1500, 0.0600 };
+static double m_Chromaticities[nRGB*nXYZ] = { 0.0, 0.6400, 0.3300, 0.0, 0.3000, 0.6000, 0.0, 0.1500, 0.0600 };
+static double White2DegreeD50[nXYZ] = { 63190.0 / 65536, 1.0, 54061.0 / 65536 };
+static double White2DegreeD65[nXYZ] = { 0.9505, 1.00, 1.0888 };
+
+static const double kCIELabDelta = (6.0 / 29.0); // = 0.20689
+static const double kCIELabEpsilon = (216.0 / 24389.0); // = 0.008856 (= kCIELabDelta^3)
+static const double kCIELabKappa = (8.0 / kCIELabEpsilon); // = 903.3
+static const double kCIELabScale = (kCIELabKappa / 116.0); // = 7.787
+
+static const double kCIELabOffset = (16.0 / 116.0); // = 16/116
+static const double kCIELabKappaEps = (kCIELabEpsilon * kCIELabKappa);
+static const double kCIELab3Delta2 = (3.0 * kCIELabDelta * kCIELabDelta);
+static const double kCIELabOneThird = (1.0 / 3.0); // = 1/3
+static const C_RGB_XYZ_Lab ZeroVal(0.0, 0.0, 0.0);
+
+static bool m_MatricesInitialized = false;
+static MatrixXd m_RGBtoXYZMatrix = MatrixXd(nXYZ, nRGB);
+static MatrixXd m_XYZtoRGBMatrix = MatrixXd(nRGB, nXYZ);
+C_RGB_XYZ_Lab LowLab(0.0, -128.0, -128.0);
+C_RGB_XYZ_Lab HighLab(100.0, 127.0, 127.0);
+
+// Default Constructor (defaults to reference white of D50, 2 degree)
+ColorConvert::ColorConvert (void)
+{
+ m_ReferenceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ m_SourceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ m_InvReferenceWhite.Set ((1.0/m_ReferenceWhite.Get_x()), (1.0/m_ReferenceWhite.Get_y()), (1.0/m_ReferenceWhite.Get_z()));
+ m_BradfordMatrix << 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0;
+ Initciecam02_parameters();
+ InitJab_parameters();
+}
+
+ColorConvert::ColorConvert(C_RGB_XYZ_Lab DestWhite, Illum D)
+{
+ switch (D) {
+ case D50:
+ {
+ m_SourceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_SourceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ m_ReferenceWhite =DestWhite;
+ m_InvReferenceWhite.Set((1.0 / m_ReferenceWhite.Get_x()), (1.0 / m_ReferenceWhite.Get_y()), (1.0 / m_ReferenceWhite.Get_z()));
+ CAT_BradfordMat();
+ Initciecam02_parameters();
+ InitJab_parameters();
+}
+// Constructor for setting reference white
+ColorConvert::ColorConvert(Illum D, C_RGB_XYZ_Lab SourceWhite)
+{
+ switch (D) {
+ case D50:
+ {
+ m_ReferenceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_ReferenceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ m_InvReferenceWhite.Set((1.0 / m_ReferenceWhite.Get_x()), (1.0 / m_ReferenceWhite.Get_y()), (1.0 / m_ReferenceWhite.Get_z()));
+ m_SourceWhite = SourceWhite;
+ CAT_BradfordMat();
+ Initciecam02_parameters();
+ InitJab_parameters();
+}
+
+ColorConvert::ColorConvert(Illum DDest, Illum DSource)
+{
+ switch (DDest)
+ {
+ case D50:
+ {
+ m_ReferenceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_ReferenceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ m_InvReferenceWhite.Set((1.0 / m_ReferenceWhite.Get_x()), (1.0 / m_ReferenceWhite.Get_y()), (1.0 / m_ReferenceWhite.Get_z()));
+ switch (DSource) {
+ case D50:
+ {
+ m_SourceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_SourceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ CAT_BradfordMat();
+ Initciecam02_parameters();
+ InitJab_parameters();
+}
+
+ColorConvert::ColorConvert(C_RGB_XYZ_Lab DDest, C_RGB_XYZ_Lab DSource)
+{
+
+ m_ReferenceWhite= DDest;
+ m_InvReferenceWhite.Set((1.0 / m_ReferenceWhite.Get_x()), (1.0 / m_ReferenceWhite.Get_y()), (1.0 / m_ReferenceWhite.Get_z()));
+ m_SourceWhite = DSource;
+ CAT_BradfordMat();
+ Initciecam02_parameters();
+ InitJab_parameters();
+}
+
+ColorConvert::ColorConvert(Illum DDest, Illum DSource, double Y_b, double L_A, SURROUND sur, CAM02CS CS)
+{
+ SetCAM02CS(CS);
+ SetSurround(sur);
+ switch (DDest)
+ {
+ case D50:
+ {
+ m_ReferenceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_ReferenceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ m_InvReferenceWhite.Set((1.0 / m_ReferenceWhite.Get_x()), (1.0 / m_ReferenceWhite.Get_y()), (1.0 / m_ReferenceWhite.Get_z()));
+ switch (DSource) {
+ case D50:
+ {
+ m_SourceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_SourceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ CAT_BradfordMat();
+ //m_JabParams =new Jab_Params;
+ //m_ParamsCIECam02 = new CIECAM02Params;
+ InitCiecamParams(Y_b, L_A, sur, CS);
+}
+
+// Copy constructor
+ColorConvert::ColorConvert(const ColorConvert &rhs) :
+ m_ReferenceWhite(rhs.m_ReferenceWhite),
+ m_InvReferenceWhite(rhs.m_InvReferenceWhite),
+ m_SourceWhite(rhs.m_SourceWhite),
+ m_BradfordMatrix(rhs.m_BradfordMatrix),
+ m_JabParams(rhs.m_JabParams),
+ m_ParamsCIECam02(rhs.m_ParamsCIECam02),
+ m_CS(rhs.m_CS),
+ m_sur(rhs.m_sur)
+{
+}
+
+// Assignment operator (cielab = rhs)
+ColorConvert &ColorConvert::operator = (const ColorConvert &rhs)
+{
+ if ( this != &rhs ) {
+ m_ReferenceWhite = rhs.m_ReferenceWhite;
+ m_InvReferenceWhite = rhs.m_InvReferenceWhite;
+ m_SourceWhite = rhs.m_SourceWhite;
+ m_BradfordMatrix = rhs.m_BradfordMatrix;
+ m_JabParams = rhs.m_JabParams;
+ m_ParamsCIECam02 = rhs.m_ParamsCIECam02;
+ }
+ return ( *this );
+}
+
+ColorConvert::~ColorConvert()
+{
+ //delete m_JabParams;
+ //delete m_ParamsCIECam02;
+}
+
+
+// convert from XYZ to Lab using the standard CIE-Lab
+//
+//
+// L* = 116 * f(Y/Yn) = 16
+// a* = 500 * (f(X/Xn) - f(Y/Yn))
+// b* = 200 * (f(Y/Yn) - f(Z/Zn))
+//
+// where
+// f(t) = t^(1/3) t < 0.008856
+// = 7.787 * t - 16/116 otherwise
+//
+C_RGB_XYZ_Lab ColorConvert::XYZToLab (C_RGB_XYZ_Lab xyzVal)
+{
+ double fX, fY, fZ;
+
+ C_RGB_XYZ_Lab LabVal(ZeroVal);
+// if ((xyzVal.Get_x() != 0.0) && (xyzVal.Get_y()) != 0.0 && (xyzVal.Get_z() != 0.0)) {
+
+ C_RGB_XYZ_Lab xyzNorm (xyzVal);
+ xyzNorm *= m_InvReferenceWhite;
+ fX = (xyzNorm.Get_x() > kCIELabEpsilon) ? std::pow (xyzNorm.Get_x(), kCIELabOneThird) :
+ kCIELabScale * xyzNorm.Get_x() + kCIELabOffset;
+ fY = (xyzNorm.Get_y() > kCIELabEpsilon) ? std::pow (xyzNorm.Get_y(), kCIELabOneThird) :
+ kCIELabScale * xyzNorm.Get_y() + kCIELabOffset;
+ fZ = (xyzNorm.Get_z() > kCIELabEpsilon) ? std::pow (xyzNorm.Get_z(), kCIELabOneThird) :
+ kCIELabScale * xyzNorm.Get_z() + kCIELabOffset;
+ LabVal.Set (116.0 * fY - 16.0, 500.0 * (fX - fY), 200.0 * (fY - fZ));
+// }
+
+ return ( LabVal );
+}
+
+
+// Function to convert from Lab to XYZ using standard CIE-Lab
+
+ C_RGB_XYZ_Lab ColorConvert::LabToXYZ ( C_RGB_XYZ_Lab labVal)
+{
+ double fX, fY, fZ;
+ C_RGB_XYZ_Lab xyzNorm;
+
+ C_RGB_XYZ_Lab XyzVal = ZeroVal;
+// if ((labVal.Get_x() != 0.0) && (labVal.Get_y()) != 0.0 && (labVal.Get_z()!=0.0)) {
+
+ C_RGB_XYZ_Lab cieLab (labVal);
+
+ fY = (cieLab.Get_x() + 16.0) / 116.0;
+ fX = fY + cieLab.Get_y() / 500.0;
+ fZ = fY - cieLab.Get_z() / 200.0;
+
+ double X = ((fX > kCIELabDelta) ? fX * fX * fX :
+ kCIELab3Delta2 * (fX - kCIELabOffset));
+ double Y = ((fY > kCIELabDelta) ? fY * fY * fY :
+ kCIELab3Delta2 * (fY - kCIELabOffset));
+ double Z = ((fZ > kCIELabDelta) ? fZ * fZ * fZ :
+ kCIELab3Delta2 * (fZ - kCIELabOffset));
+ xyzNorm.Set(X, Y, Z);
+ XyzVal = xyzNorm;
+ XyzVal *= m_ReferenceWhite;
+// }
+ return ( XyzVal );
+}
+
+// Returns reference white
+const C_RGB_XYZ_Lab &ColorConvert::GetReferenceWhite(void) const
+{
+ return (m_ReferenceWhite);
+}
+
+
+// Sets reference white
+ void ColorConvert::SetReferenceWhite(C_RGB_XYZ_Lab &refWhite)
+{
+ if ((refWhite.Get_x() > 0.0) && (refWhite.Get_y() > 0.0) && (refWhite.Get_z() > 0.0)) {
+ m_ReferenceWhite = refWhite;
+ m_InvReferenceWhite.Set((1.0 / refWhite.Get_x()),(1.0 / refWhite.Get_y()), (1.0 / refWhite.Get_z()));
+ }
+}
+
+
+ void ColorConvert::SetReferenceWhite(Illum D)
+ {
+ switch (D) {
+ case D50:
+ {
+ m_ReferenceWhite.Set(White2DegreeD50[0], White2DegreeD50[1], White2DegreeD50[2]);
+ break;
+ }
+ case D65:
+ {
+ m_ReferenceWhite.Set(White2DegreeD65[0], White2DegreeD65[1], White2DegreeD65[2]);
+ break;
+ }
+ }
+ CAT_BradfordMat();
+ }
+
+ // inverse of a 3x3 matrix: A is the input matrix, B its inverse
+ void ColorConvert::InverseOfThreeByThreeMatrix(const MatrixXd& A, MatrixXd& B)
+ {
+ //det = a00(a22a11-a21a12)-a10(a22a01-a21a02)+a20(a12a01-a11a02)
+ // b00 = (a22a11-a21a12)/det
+ // b01 = -(a22a01-a21a02)/det
+ // b02 = (a12a01-a11a02)/det
+ // b10 = -(a22a10-a20a12)/det
+ // b11 = (a22a00-a20a02)/det
+ // b12 = -(a12a00-a10a02)/det
+ // b20 = (a21a10-a20a11)/det
+ // b21 = -(a21a00-a20a01)/det
+ // b22 = (a11a00-a10a01)/det
+
+ double det = A(0, 0) * (A(2, 2)*A(1, 1) - A(2, 1)*A(1, 2)) - A(1, 0) * (A(2, 2)*A(0, 1) - A(2, 1)*A(0, 2)) + A(2, 0) * (A(1, 2)*A(0, 1) - A(1, 1)*A(0, 2));
+ B(0, 0) = (A(2, 2) * A(1, 1) - A(2, 1) * A(1, 2)) / det;
+ B(0, 1) = -(A(2, 2) * A(0, 1) - A(2, 1) * A(0, 2)) / det;
+ B(0, 2) = (A(1, 2) * A(0, 1) - A(1, 1) * A(0, 2)) / det;
+ B(1, 0) = -(A(2, 2) * A(1, 0) - A(2, 0) * A(1, 2)) / det;
+ B(1, 1) = (A(2, 2) * A(0, 0) - A(2, 0) * A(0, 2)) / det;
+ B(1, 2) = -(A(1, 2) * A(0, 0) - A(1, 0) * A(0, 2)) / det;
+ B(2, 0) = (A(2, 1) * A(1, 0) - A(2, 0) * A(1, 1)) / det;
+ B(2, 1) = -(A(2, 1) * A(0, 0) - A(2, 0) * A(0, 1)) / det;
+ B(2, 2) = (A(1, 1) * A(0, 0) - A(1, 0) * A(0, 1)) / det;
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::RGBtoXYZ(C_RGB_XYZ_Lab& rgbVal)
+ {
+ if (!m_MatricesInitialized) InitializeConversionMatrices();
+ VectorXd rgb;
+ VectorXd xyz(nXYZ);
+ rgb = rgbVal.Get();
+
+//convert to linear RGB
+ for (int i = 0; i < nRGB; ++i)
+ rgb(i) = GammaExpand_sRGB(rgb(i)/255.0);
+
+ xyz = m_RGBtoXYZMatrix * rgb;
+ return (C_RGB_XYZ_Lab(xyz));
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::XYZtoRGB(C_RGB_XYZ_Lab& xyzVal)
+ {
+ if (!m_MatricesInitialized) InitializeConversionMatrices();
+ VectorXd rgb(nRGB);
+ VectorXd xyz;
+ xyz = xyzVal.Get();
+ //XYZ to Linear RGB
+ rgb = m_XYZtoRGBMatrix * xyz;
+ for (int i = 0; i < nRGB; ++i)
+ {
+ rgb(i) = GammaCompress_sRGB(rgb(i));
+ rgb(i) = std::min(std::max(rgb(i), 0.0), 1.0);
+ rgb(i) *= 255;
+ }
+ return(C_RGB_XYZ_Lab(rgb));
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::XYZtoRGBNoClip(C_RGB_XYZ_Lab& xyzVal)
+ {
+ if (!m_MatricesInitialized) InitializeConversionMatrices();
+ VectorXd rgb(nRGB);
+ VectorXd xyz;
+ xyz = xyzVal.Get();
+ //XYZ to Linear RGB
+ rgb = m_XYZtoRGBMatrix * xyz;
+ for (int i = 0; i < nRGB; ++i)
+ {
+ rgb(i) = GammaCompress_sRGB(rgb(i));
+ // rgb(i) = std::min(std::max(rgb(i), 0.0), 1.0);
+ rgb(i) *= 255;
+ }
+ return(C_RGB_XYZ_Lab(rgb));
+ }
+
+ void ColorConvert::LabtoRGB(double*InLab, double *OutRGB)
+ {
+ C_RGB_XYZ_Lab DataLab;
+ DataLab.Set(InLab[0], InLab[1], InLab[2]);
+ C_RGB_XYZ_Lab DataRGB;
+ DataRGB =LabtoRGB(DataLab);
+ // double *RGB = new double[3];
+ OutRGB[0] = DataRGB.Get_x();
+ OutRGB[1] = DataRGB.Get_y();
+ OutRGB[2] = DataRGB.Get_z();
+ }
+
+ void ColorConvert::LabtoRGBNoClip(double*InLab, double *OutRGB)
+ {
+ C_RGB_XYZ_Lab DataLab;
+ DataLab.Set(InLab[0], InLab[1], InLab[2]);
+ C_RGB_XYZ_Lab DataRGB;
+ DataRGB = LabtoRGBNoClip(DataLab);
+ // double *RGB = new double[3];
+ OutRGB[0] = DataRGB.Get_x();
+ OutRGB[1] = DataRGB.Get_y();
+ OutRGB[2] = DataRGB.Get_z();
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::LabtoRGB(C_RGB_XYZ_Lab& LabVal)
+ {
+ C_RGB_XYZ_Lab DataXYZ;
+ DataXYZ = LabToXYZ(LabVal);
+ C_RGB_XYZ_Lab DataRGB;
+ DataRGB = XYZtoRGB(DataXYZ);
+ return(DataRGB);
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::LabtoRGBNoClip(C_RGB_XYZ_Lab& LabVal)
+ {
+ C_RGB_XYZ_Lab DataXYZ;
+ DataXYZ = LabToXYZ(LabVal);
+ C_RGB_XYZ_Lab DataRGB;
+ DataRGB = XYZtoRGBNoClip(DataXYZ);
+ return(DataRGB);
+ }
+
+ void ColorConvert::RGBtoLab(double*InRGB, double *OutLab)
+ {
+ C_RGB_XYZ_Lab DataRGB(InRGB[0], InRGB[1], InRGB[2]);
+ C_RGB_XYZ_Lab DataLab;
+ DataLab = RGBtoLab(DataRGB);
+ //double *LabOut = new double[3];
+ OutLab[0] = DataLab.Get_x();
+ OutLab[1] = DataLab.Get_y();
+ OutLab[2] = DataLab.Get_z();
+ }
+
+ /*void ColorConvert::RGBtoLab(std::vector<double>&InRGB, double *OutLab)
+ {
+ C_RGB_XYZ_Lab DataRGB(InRGB[0], InRGB[1], InRGB[2]);
+ C_RGB_XYZ_Lab DataLab;
+ DataLab = RGBtoLab(DataRGB);
+ //double *LabOut = new double[3];
+ OutLab[0] = DataLab.Get_x();
+ OutLab[1] = DataLab.Get_y();
+ OutLab[2] = DataLab.Get_z();
+ }*/
+
+ C_RGB_XYZ_Lab ColorConvert::RGBtoLab(C_RGB_XYZ_Lab& RGBVal)
+ {
+ C_RGB_XYZ_Lab DataXYZ;
+ //C_RGB_XYZ_Lab LowLab(0.0, -128.0, -128.0);
+ // C_RGB_XYZ_Lab HighLab(100.0, 127.0, 127.0);
+
+ DataXYZ = RGBtoXYZ(RGBVal);
+ C_RGB_XYZ_Lab DataLab;
+ DataLab = XYZToLab(DataXYZ);
+// DataLab.Clamp(LowLab, HighLab);
+ return(DataLab);
+ }
+
+
+ void ColorConvert::ChangeWP(double *LabIn, double *LabOut, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite)
+ {
+ SetReferenceWhite(SourceWhite);
+ C_RGB_XYZ_Lab Lab;
+ Lab.Set(LabIn[0], LabIn[1], LabIn[2]);
+ C_RGB_XYZ_Lab XYZ = LabToXYZ(Lab);
+ SetReferenceWhite(DestWhite);
+ C_RGB_XYZ_Lab LabOut1;
+ LabOut1 = XYZToLab(XYZ);
+ // LabOut1.Clamp(LowLab, HighLab);
+ // double *LabD = new double[3];
+ LabOut[0] = LabOut1.Get_x();
+ LabOut[1] = LabOut1.Get_y();
+ LabOut[2] = LabOut1.Get_z();
+ // SetReferenceWhite(SourceWhite);
+/* C_RGB_XYZ_Lab LabOut2;
+ LabOut2 = XYZToLab(XYZ);
+ double *LabD = new double[3];
+ double x = 100 - Lab.Get_x();
+ double f = 100.0 / (100.0 + pow(x, 3) / 100.0);
+ LabD[0] = f*LabOut1.Get_x() + (1-f) *LabOut2.Get_x();
+ LabD[1] = f*LabOut1.Get_y() + (1 - f) *LabOut2.Get_y();
+ LabD[2] = f*LabOut1.Get_z() + (1 - f) *LabOut2.Get_z();
+ return(LabD); */
+ }
+
+
+ void ColorConvert::ChangeWP(C_RGB_XYZ_Lab XYZIn, C_RGB_XYZ_Lab &LabOut, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite)
+ {
+ SetReferenceWhite(SourceWhite);
+ C_RGB_XYZ_Lab Lab;
+ C_RGB_XYZ_Lab XYZ = XYZIn;
+ SetReferenceWhite(DestWhite);
+ C_RGB_XYZ_Lab LabOut1;
+ LabOut1 = XYZToLab(XYZ);
+ // LabOut1.Clamp(LowLab, HighLab);
+ // double *LabD = new double[3];
+ LabOut = LabOut1;
+ }
+ void ColorConvert::InitializeConversionMatrices()
+ {
+ for (unsigned int i = 0; i<nRGB*nXYZ; i++) {
+ m_Chromaticities[i] = CHROMATICITIES[i];
+ }
+ ComputeRGBtoXYZmatrix();
+ ComputeXYZtoRGBmatrix();
+ m_MatricesInitialized = true;
+ }
+
+ VectorXd ColorConvert::GetChromaticities()
+ {
+ VectorXd chromaticities(2 * nRGB);
+ for (unsigned int i = 0; i<nRGB; i++) {
+ chromaticities(2 * i + 0) = m_Chromaticities[nRGB*i + 1];
+ chromaticities(2 * i + 1) = m_Chromaticities[nRGB*i + 2];
+ }
+ return chromaticities;
+ }
+
+ void ColorConvert::RecalculateConversionMatrices(const VectorXd& chromaticities)
+ {
+ for (unsigned int i = 0; i<nRGB; i++) {
+ m_Chromaticities[nRGB*i + 1] = chromaticities(2 * i + 0);
+ m_Chromaticities[nRGB*i + 2] = chromaticities(2 * i + 1);
+ }
+
+ ComputeRGBtoXYZmatrix();
+ ComputeXYZtoRGBmatrix();
+ m_MatricesInitialized = true;
+ }
+
+ void ColorConvert::ComputeRGBtoXYZmatrix()
+ {
+ VectorXd vChromaticity(nRGB);
+ VectorXd vWhite(nRGB);
+ VectorXd vC(nRGB);
+ MatrixXd CM(nRGB, nXYZ);
+ MatrixXd CMinv(nRGB, nXYZ);
+
+ vWhite(0) = m_ReferenceWhite.Get_y();
+ vWhite(1) = m_ReferenceWhite.Get_x() / (m_ReferenceWhite.Get_x() + m_ReferenceWhite.Get_y() + m_ReferenceWhite.Get_z());
+ vWhite(2) = m_ReferenceWhite.Get_y() / (m_ReferenceWhite.Get_x() + m_ReferenceWhite.Get_y() + m_ReferenceWhite.Get_z());
+
+ for (unsigned int rgbIndex = 0; rgbIndex<nRGB; rgbIndex++) {
+ CM(0, rgbIndex) = m_Chromaticities[rgbIndex*nXYZ + 1] / m_Chromaticities[rgbIndex*nXYZ + 2];
+ CM(1, rgbIndex) = 1.0;
+ CM(2, rgbIndex) = (1.0 - m_Chromaticities[rgbIndex*nXYZ + 1] - m_Chromaticities[rgbIndex*nXYZ + 2]) / m_Chromaticities[rgbIndex*nXYZ + 2];
+ }
+
+ //Inverts explicity the chromaticity matrix
+ InverseOfThreeByThreeMatrix(CM, CMinv);
+
+ vChromaticity(0) = vWhite(1) / vWhite(2);
+ vChromaticity(1) = 1.0;
+ vChromaticity(2) = (1.0 - vWhite(1) - vWhite(2)) / vWhite(2);
+
+ vC = CMinv * vChromaticity;
+
+ for (unsigned int i = 0; i<nXYZ; i++) {
+ for (unsigned int j = 0; j<nRGB; j++) {
+ m_RGBtoXYZMatrix(i, j) = CM(i, j) * vC(j);
+ }
+ }
+ }
+
+ //Assumes RGBtoXYZ matrix already exists
+ void ColorConvert::ComputeXYZtoRGBmatrix()
+ {
+ //Inverts explicity the RGB to XYZ matrix
+ InverseOfThreeByThreeMatrix(m_RGBtoXYZMatrix, m_XYZtoRGBMatrix);
+ }
+
+
+ void ColorConvert::CAT_BradfordMat()
+ {
+ MatrixXd Mcat(3, 3);
+ Mcat << 0.8951, 0.2664, -0.1614,
+ -0.7502, 1.7135, 0.0367,
+ 0.0389, -0.0685, 1.0296;
+ MatrixXd McatInv(3, 3);
+ McatInv << 0.9869929, -0.1470543, 0.1599627,
+ 0.4323053, 0.5183603, 0.0492912,
+ -0.0085287, 0.0400428, 0.9684867;
+ VectorXd WPSourceT(nXYZ);
+ WPSourceT = m_SourceWhite.Get();
+ VectorXd WPDestT(nXYZ);
+ WPDestT = m_ReferenceWhite.Get();
+ VectorXd sWPSource = Mcat*WPSourceT;
+ VectorXd sWPDest = Mcat*WPDestT;
+ double tau = pow(sWPSource(2) / sWPDest(2), 0.0834);// non-linear correction for the blue channel
+ MatrixXd DiagMat;
+ DiagMat.setZero(nXYZ, nXYZ);
+ DiagMat(0, 0) = sWPDest(0) / sWPSource(0);
+ DiagMat(1, 1) = sWPDest(1) / sWPSource(1);
+ //DiagMat(2, 2) = (sWPDest(2) / pow(sWPSource(2), tau))*pow(sWPSource(2), tau-1);
+ DiagMat(2, 2) = sWPDest(2) / sWPSource(2);
+ m_BradfordMatrix = McatInv * DiagMat * Mcat; // Bradford CAT matrix
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::ApplyBradfordMat(C_RGB_XYZ_Lab& xyzVal)
+ {
+ VectorXd xyz = xyzVal.Get();
+ VectorXd RetVal = m_BradfordMatrix*xyz;
+ return(RetVal);
+ }
+
+ C_RGB_XYZ_Lab ColorConvert::NormalizeWPXYZ(C_RGB_XYZ_Lab& xyzVal)
+ {
+ VectorXd xyz = xyzVal.Get();
+ xyz(0) /= xyz(1);
+ xyz(2) /= xyz(1);
+ xyz(1) = 1.0;
+ C_RGB_XYZ_Lab retVal;
+ retVal.Set(xyz);
+ return(retVal);
+ }
+
+ //******************************************************************************
+ // Convert an sRGB color channel to a linear sRGB color channel.
+ //******************************************************************************
+ double ColorConvert::GammaExpand_sRGB(double nonlinear)
+ {
+ return (nonlinear <= 0.03928)
+ ? (nonlinear / 12.92)
+ : (pow((nonlinear + 0.055) / 1.055, 2.4));
+ }
+
+ //******************************************************************************
+ // Convert a linear sRGB color channel to a sRGB color channel.
+ //******************************************************************************
+ double ColorConvert::GammaCompress_sRGB(double linear)
+ {
+ return (linear <= 0.00304)
+ ? (12.92 * linear)
+ : (1.055 * pow(linear, 1.0 / 2.4) - 0.055);
+ }
+ void ColorConvert::SetCIECamWhitePoint(C_RGB_XYZ_Lab ReferenceWhite)
+ {
+ m_ParamsCIECam02.XYZ_WP[0] = 100 * ReferenceWhite.Get_x();
+ m_ParamsCIECam02.XYZ_WP[1] = 100 * ReferenceWhite.Get_y();
+ m_ParamsCIECam02.XYZ_WP[2] =100 * ReferenceWhite.Get_z();
+ }
+
+ void ColorConvert::ciecam02_parameters( double Y_b, double L_A, SURROUND sur)
+ {
+ // Usage:
+ // ParamsCIECam02 = ciecam02_parameters( Y_b, L_A, sur)
+ //
+ // Input and Output Arguments /
+ //
+ //Inputs
+ // wp = WhitePoint in XYZ ColorSpace[Xw, Yw, Zw], (Ymax == 100).
+ //Y_b = relative luminance of reference white in the adapting field.
+ // L_A = adapting field luminance(cd / m ^ 2).
+ // sur = 'average' / 'dim' / 'dark' Surround
+
+ // Output:
+ // ParamsCIECam02 = scalar structure of CIECAM parameter values.
+ //
+ // ParamsCIECam02 = ciecam02_parameters( Y_b, L_A, sur)
+ int i = 0;
+ int j = 0;
+ SetCIECamWhitePoint(m_ReferenceWhite);
+
+ //define surround parameters
+ switch (sur)
+ {
+ case (average):
+ {
+ m_ParamsCIECam02.F = 1.0;
+ m_ParamsCIECam02.c = 0.690;
+ m_ParamsCIECam02.N_c = 1.00;
+ break;
+ }
+ case 'dim':
+ {
+ m_ParamsCIECam02.F = 0.9;
+ m_ParamsCIECam02.c = 0.590;
+ m_ParamsCIECam02.N_c = 1.95;
+ break;
+ }
+ case 'dark':
+ {
+ m_ParamsCIECam02.F = 0.8;
+ m_ParamsCIECam02.c = 0.525;
+ m_ParamsCIECam02.N_c = 1.80;
+ break;
+ }
+ default:
+ m_ParamsCIECam02.F = 1.0;
+ m_ParamsCIECam02.c = 0.690;
+ m_ParamsCIECam02.N_c = 1.00;
+ break;
+ }
+ //Define Matrices
+
+/*double MatCAT02[] = { 0.7328, 0.4296, -0.1624,
+ -0.7036, 1.6975, 0.0061,
+ 0.003, 0.0136, 0.9834 }; */
+ MatrixXd MatCAT02(3, 3);
+ MatCAT02 << 0.7328, 0.4296, -0.1624,
+ -0.7036, 1.6975, 0.0061,
+ 0.003, 0.0136, 0.9834;
+ m_ParamsCIECam02.M_CAT02 = MatCAT02;
+/* m_ParamsCIECam02.M_CAT02.setOnes(3,3);
+ m_ParamsCIECam02.M_CAT02 << 0.7328, 0.4296, -0.1624,
+ -0.7036, 1.6975, 0.0061,
+ 0.003, 0.0136, 0.9834; */
+ MatrixXd MatHPE(3, 3);
+ MatHPE << 0.38971, 0.68898, -0.07868,
+ -0.22981, 1.1834, 0.04641,
+ 0, 0, 1;
+ m_ParamsCIECam02.M_HPE = MatHPE;
+ /* m_ParamsCIECam02.M_HPE.resize(3, 3);
+ m_ParamsCIECam02.M_HPE << 0.38971, 0.68898, -0.07868,
+ -0.22981, 1.1834, 0.04641,
+ 0, 0, 1;
+ */
+ //Hue Data
+ VectorXd Vh_i(5);
+ Vh_i << 20.14, 90.00, 164.25, 237.53, 380.14;
+ m_ParamsCIECam02.h_i = Vh_i;
+ /* m_ParamsCIECam02.h_i << 20.14, 90.00, 164.25, 237.53, 380.14; */
+ VectorXd Ve_i(5);
+ Ve_i << 0.8, 0.7, 1.0, 1.2, 0.8;
+ m_ParamsCIECam02.e_i = Ve_i;
+
+ /* m_ParamsCIECam02.e_i.resize(5);
+ m_ParamsCIECam02.e_i << 0.8, 0.7, 1.0, 1.2, 0.8; */
+ VectorXd VH_i(5);
+ VH_i << 0, 100, 200, 300, 400;
+ m_ParamsCIECam02.H_i = VH_i;
+// m_ParamsCIECam02.H_i.resize(5);
+// m_ParamsCIECam02.H_i << 0, 100, 200, 300, 400;
+ VectorXd VLMS_w(3);
+ VLMS_w.setZero();
+ m_ParamsCIECam02.LMS_w = VLMS_w;
+ // m_ParamsCIECam02.LMS_w.resize(3);
+
+ VectorXd XYZtmp(3);
+ XYZtmp << m_ParamsCIECam02.XYZ_WP[0], m_ParamsCIECam02.XYZ_WP[1], m_ParamsCIECam02.XYZ_WP[2];
+ m_ParamsCIECam02.LMS_w = m_ParamsCIECam02.M_CAT02 * XYZtmp;
+ m_ParamsCIECam02.D = m_ParamsCIECam02.F * (1 - (1 / 3.6)*std::exp(-(L_A + 42) / 92));
+ m_ParamsCIECam02.D = std::max(0.0, std::min(1.0, m_ParamsCIECam02.D));
+ // m_ParamsCIECam02.LMS_c.resize(3);
+VectorXd VLMS_c(3);
+VLMS_w.setZero();
+ m_ParamsCIECam02.LMS_c = VLMS_c;
+ for (int i=0; i<3; ++i)
+ m_ParamsCIECam02.LMS_c(i) = m_ParamsCIECam02.D* m_ParamsCIECam02.XYZ_WP[1] / m_ParamsCIECam02.LMS_w(i) + 1 - m_ParamsCIECam02.D;
+// m_ParamsCIECam02.LMSp_w.resize(3);
+ VectorXd VLMSp_w(3);
+ VLMSp_w.setZero();
+ m_ParamsCIECam02.LMSp_w = VLMSp_w;
+ VectorXd cwMult(3);
+ for (int i = 0; i < 3; ++i)
+ cwMult(i) = (m_ParamsCIECam02.LMS_c(i)*m_ParamsCIECam02.LMS_w(i));
+
+ m_ParamsCIECam02.LMSp_w(0) = (0.7409792 * cwMult(0)) + (0.2180250 * cwMult(1)) + (0.0410058 * cwMult(2));
+ m_ParamsCIECam02.LMSp_w(1) = (0.2853532 * cwMult(0)) + (0.6242014 * cwMult(2)) + (0.0904454 * cwMult(2));
+ m_ParamsCIECam02.LMSp_w(2) = (-0.0096280 * cwMult(0)) - (0.0056980 * cwMult(1)) + (1.0153260 * cwMult(2));
+
+ m_ParamsCIECam02.k = 1.0/ (5 * L_A + 1);
+ m_ParamsCIECam02.F_L =0.2* (pow(m_ParamsCIECam02.k ,4) * (5 * L_A)) +
+ 0.1 *(pow((1.0 - pow(m_ParamsCIECam02.k, 4.0)), 2.0)) *(pow((5.0 * L_A), (1.0 / 3.0)));
+
+ m_ParamsCIECam02.n = Y_b / m_ParamsCIECam02.XYZ_WP[1];
+ m_ParamsCIECam02.z = 1.48 + sqrt( m_ParamsCIECam02.n);
+ m_ParamsCIECam02.N_bb = 0.725 * pow( m_ParamsCIECam02.n, -0.2);
+ m_ParamsCIECam02.N_cb = m_ParamsCIECam02.N_bb;
+
+VectorXd tmpVec(3);
+VectorXd VLMSp_aw(3);
+VLMSp_aw.setZero();
+ m_ParamsCIECam02.LMSp_aw = VLMSp_aw;
+// m_ParamsCIECam02.LMSp_aw.resize(3);
+for (int i = 0; i < 3; ++i)
+{
+ tmpVec(i) = pow(( m_ParamsCIECam02.F_L* m_ParamsCIECam02.LMSp_w(i)) / 100, 0.42);
+ m_ParamsCIECam02.LMSp_aw(i) = 400 * (tmpVec(i) / (27.13 + tmpVec(i))) + 0.1;
+}
+ m_ParamsCIECam02.A_w = (2.0 * m_ParamsCIECam02.LMSp_aw(0) + m_ParamsCIECam02.LMSp_aw(1) + ((1.0 / 20.0) * m_ParamsCIECam02.LMSp_aw(2)) - 0.305) * m_ParamsCIECam02.N_bb;
+
+ }
+
+ VectorXd ColorConvert::XYZ_2_ciecam02(VectorXd XYZ)
+ {
+ //XYZ to CIECAM02 conversion .
+
+ //JQCMsHh = XYZ_2_ciecam02(XYZ)
+ // Examples
+
+ // rgbVal = [64, 128, 255];
+ //RGBtoXYZ(C_RGB_XYZ_Lab& rgbVal)*100
+ // wp = reference white D65
+ //ciecam02_parameters(wp, 20, 64 / pi / 5, average)
+ // JQCMsHh = XYZ_2_ciecam02(XYZ)
+ // JQCMsHh = 43.729 81.798 72.617 52.497 80.111 309.38 256.69
+
+ //Input
+ // XYZ = NumericArray, tristimulus values to convert, in 1931 XYZ colorspace(Ymax == 100).
+ // Outputs :
+ // JQCMsHh = CIECAM02 values.
+ // size 7 and is[J, Q, C, M, s, H, h], where :
+ // J = Lightness
+ // Q = Brightness
+ //C = Chroma
+ // M = Colorfulness
+ //s = Saturation
+ // H = Hue
+ // h = Hue Angle
+ VectorXd JQCMsHh(7);
+ //Convert
+ // Step 1: cone responses :
+ VectorXd LMS(3);
+ LMS = m_ParamsCIECam02.M_CAT02 * XYZ;
+
+ //Step 2 : cone responses considering luminance and surround :
+ VectorXd LMS_C(3);
+ for (int i=0; i<3;++i)
+ LMS_C(i) = ( m_ParamsCIECam02.LMS_c(i))*LMS(i);
+
+ //Step 3: Hunt - Pointer - Estevez response :
+ VectorXd LMSp(3);
+ LMSp = ( m_ParamsCIECam02.M_HPE * m_ParamsCIECam02.M_CAT02.inverse())*LMS_C;
+
+ //Step 4 : post - adaption cone response :
+ VectorXd LMSp_signs(3);
+ VectorXd LMSp_a(3);
+ double tmp;
+ for (int i = 0; i < 3; ++i)
+ {
+ if (LMSp(i) == 0)
+ LMSp_signs(i) = 0;
+ else if (LMSp(i) < 0)
+ LMSp_signs(i) = -1;
+ else
+ LMSp_signs(i) = 1;
+ tmp = pow( m_ParamsCIECam02.F_L* (LMSp_signs(i)*LMSp(i)) / 100., 0.42);
+ LMSp_a(i) = 400 * LMSp_signs(i)*(tmp / ((tmp + 27.13))) + 0.1;
+ }
+
+ //Step 5: red - green(a), yellow - blue(b) and hue angle :
+ double a = (LMSp_a(0) * 11 - LMSp_a(1) * 12 + LMSp_a(2)) / 11;
+ double b = (LMSp_a(0) + LMSp_a(1) - 2*LMSp_a(2)) / 9;
+ double h_radian = std::atan2(b, a);
+ double h_degree = (h_radian * 180 / EIGEN_PI);
+ if (h_degree < 0.0)h_degree += 360.0;
+ // Step 6: eccentricity and hue composition :
+ double temp= 0;
+ double H = 0;
+ if (h_degree < 20.14) {
+ temp = ((h_degree + 122.47) / 1.2) + ((20.14 - h_degree) / 0.8);
+ H = 300 + (100 * ((h_degree + 122.47) / 1.2)) / temp;
+ }
+ else if (h_degree < 90.0) {
+ temp = ((h_degree - 20.14) / 0.8) + ((90.00 - h_degree) / 0.7);
+ H = (100 * ((h_degree - 20.14) / 0.8)) / temp;
+ }
+ else if (h_degree < 164.25) {
+ temp = ((h_degree - 90.00) / 0.7) + ((164.25 - h_degree) / 1.0);
+ H = 100 + ((100 * ((h_degree - 90.00) / 0.7)) / temp);
+ }
+ else if (h_degree < 237.53) {
+ temp = ((h_degree - 164.25) / 1.0) + ((237.53 - h_degree) / 1.2);
+ H = 200 + ((100 * ((h_degree - 164.25) / 1.0)) / temp);
+ }
+ else {
+ temp = ((h_degree - 237.53) / 1.2) + ((360 - h_degree + 20.14) / 0.8);
+ H = 300 + ((100 * ((h_degree - 237.53) / 1.2)) / temp);
+ }
+
+//Step 7: achromatic response :
+
+double A = std::max((2*LMSp_a(0) + LMSp_a(1) +(1 / 20)*LMSp_a(2) - 0.305)* m_ParamsCIECam02.N_bb, 0.0);
+
+//Step 8: correlate of lightness :
+
+ double J = 100 * pow((A / m_ParamsCIECam02.A_w), ( m_ParamsCIECam02.c)*( m_ParamsCIECam02.z)); // lightness
+ JQCMsHh[0] = J;
+//Step 9: correlate of brightness :
+
+ double Q = (4. / m_ParamsCIECam02.c)*sqrt(J / 100.) * ( m_ParamsCIECam02.A_w + 4)*pow( m_ParamsCIECam02.F_L,0.25); // brightness
+ JQCMsHh[1] = Q;
+ //Step 10: correlates of chroma, colorfulness, and saturation :
+
+ double e = (12500. / 13.)* m_ParamsCIECam02.N_c* m_ParamsCIECam02.N_cb * (cos(h_radian + 2) + 3.8); // eccentricity
+ tmp = e*sqrt(a*a + b*b) / (LMSp_a(0) + LMSp_a(1) + (21. / 20.)*LMSp_a(2));
+ double C = pow(tmp,0.9)*sqrt(J / 100) * pow(1.64 - pow(0.29, m_ParamsCIECam02.n),0.73); //chroma
+ JQCMsHh[2] = C;
+
+ double M = C*pow( m_ParamsCIECam02.F_L, 0.25); //colorfulness
+ double s = 100 * sqrt(M / Q); // saturation
+ JQCMsHh[3] = M;
+ JQCMsHh[4] = s;
+ JQCMsHh[5] =H;
+ JQCMsHh[6] = h_degree;
+ return(JQCMsHh);
+ }
+
+void ColorConvert::Jab_parameters(CAM02CS CS)
+ {
+ //Parameter values defined in the CAM02 Color Space(UCS / LCD / SCD).
+ //Usage:
+ // Params = Jab_parameters(ColorSapce)
+ // space defined in enum CAM02CS UCS / LCD / SCD which means
+ // UniformColorSpace / LargeColorDifference / SmallColorDifference.
+
+ switch (CS)
+ {
+ case UCS:
+ {
+ m_JabParams.KL = 1.00;
+ m_JabParams.c1 = 0.007;
+ m_JabParams.c2 = 0.0228;
+ m_JabParams.CS = UCS;
+ break;
+ }
+ case LCD:
+ {
+ m_JabParams.KL = 0.77;
+ m_JabParams.c1 = 0.007;
+ m_JabParams.c2 = 0.0053;
+ m_JabParams.CS = LCD;
+ break;
+ }
+ case SCD:
+ {
+ m_JabParams.KL = 1.24;
+ m_JabParams.c1 = 0.007;
+ m_JabParams.c2 = 0.0363;
+ m_JabParams.CS = SCD;
+ break;
+ }
+ default:
+ {
+ m_JabParams.KL = 1.00;
+ m_JabParams.c1 = 0.007;
+ m_JabParams.c2 = 0.0228;
+ m_JabParams.CS = UCS;
+ break;
+ }
+ }
+ }
+
+ VectorXd ColorConvert::JMh_2_Jab(VectorXd JMh)
+ {
+// Convert from CIECAM02 JMh values to the perceptually uniform Jab colorspace
+ // JMH are the lightness, colorfullness and hue angle. (similar to LCH)
+
+ double Jp = (1 + 100 * m_JabParams.c1)*JMh(0) / (1 + m_JabParams.c1*JMh(0));
+ Jp /= m_JabParams.KL;
+ double Mp = (1 / m_JabParams.c2) * log(1 + m_JabParams.c2 * JMh(1));
+ double ap = Mp*cos(JMh(2)*EIGEN_PI/180);
+ double bp = Mp*sin(JMh(2)*EIGEN_PI / 180);
+ VectorXd Jab(3);
+ Jab << Jp, ap, bp;
+ return(Jab);
+ }
+
+ VectorXd ColorConvert::Jab_2_Lab(VectorXd Jab, CAM02CS CS)
+ {
+ VectorXd XYZ(3);
+ XYZ = Jab_2_XYZ(Jab, CS);
+ C_RGB_XYZ_Lab LabOut;
+ C_RGB_XYZ_Lab XYZ1;
+ XYZ1.Set(XYZ/100.0);
+ LabOut = XYZToLab(XYZ1);
+ VectorXd Lab(3);
+ Lab = LabOut.Get();
+ return(Lab);
+ }
+
+
+ VectorXd ColorConvert::Jab_2_XYZ(VectorXd Jab, CAM02CS CS)
+ {
+ //convert from Jab colorspace to the XYZ colorspace.
+
+ // space defined in enum CAM02CS UCS / LCD / SCD which means
+ // UniformColorSpace / LargeColorDifference / SmallColorDifference.
+
+ //XYZ = numeric array of XYZ colorspace values 0 <= rgb <= 1, same size as input <Jab>.
+
+ VectorXd JMh(3);
+ JMh = Jab_2_JMh(Jab);
+ VectorXd XYZ = ciecam02_2_XYZ(JMh);
+ return(XYZ);
+ }
+
+ VectorXd ColorConvert::Jab_2_JMh(VectorXd Jab)
+ { // Convert fromJ'a'b' colorspace to CIECAM02 JMh values.
+
+ double Jp = Jab(0);
+ double ap = Jab(1);
+ double bp = Jab(2);
+
+ Jp = Jp * m_JabParams.KL;
+ double J = -Jp / (m_JabParams.c1 * Jp - 100 * m_JabParams.c1 - 1);
+ double h = 0;
+ if (ap == 0. && bp == 0.)
+ h = 0.;
+ else
+ h = atan2(bp, ap) * 180 / EIGEN_PI;
+ double Mp = sqrt(ap*ap + bp*bp);
+ double M = (exp(m_JabParams.c2*Mp) - 1) / m_JabParams.c2;
+
+ VectorXd JMh(3);
+ JMh << J, M, h;
+ return(JMh);
+ }
+
+ VectorXd ColorConvert::ciecam02_2_XYZ(VectorXd JMh)
+ {
+ //CIECAM02 to XYZ conversion
+
+
+//Step 1: Get Data
+ double J = JMh(0);
+ double C = JMh(1) / pow( m_ParamsCIECam02.F_L, 0.25);
+ double h = JMh(2);
+
+// Step 2:
+ double d = sqrt(J / 100)*pow(1.64 - pow(0.29, m_ParamsCIECam02.n), 0.73);
+ double t =pow (C /d, (1 / 0.9));
+ double et = (cos(EIGEN_PI*h / 180 + 2) + 3.8) / 4;
+ double A = m_ParamsCIECam02.A_w * pow((J / 100) , 1 / ( m_ParamsCIECam02.c* m_ParamsCIECam02.z));
+ double p1 = (50000 / 13) * ( m_ParamsCIECam02.N_c * m_ParamsCIECam02.N_cb) * et / t;
+ double p2 = A / m_ParamsCIECam02.N_bb + 0.305;
+ double p3 = 21. / 20.;
+ double nom = 460 * (p2 * (2 + p3)) / 1403;
+ double den = 220 * (2 + p3) / 1403;
+// Step 3: calculate red - green(a), yellow - blue(b) :
+ double hr = h*EIGEN_PI / 180.;
+ double a, b, tmp;
+ if (abs(sin(hr)) >= abs(cos(hr)))
+ {
+ tmp = cos(hr) / sin(hr);
+ b = nom / ((p1 / sin(hr)) + den*tmp - (27 / 1403) + p3*(6300 / 1403));
+ a = b*tmp;
+ }
+ else
+ {
+ tmp = sin(hr) / cos(hr);
+ a = nom / ((p1 / cos(hr)) + den - ((27 / 1403) - p3*(6300 / 1403))*tmp);
+ b = a*tmp;
+ }
+// Step 4: post - adaption cone response :
+ VectorXd LMSp_a(3);
+ LMSp_a(0) = (460 * p2 + 451 * a + 288 * b) / 1403;
+ LMSp_a(1) = (460 * p2 + -891 * a - 261 * b) / 1403;
+ LMSp_a(2) = (460 * p2 + -220 * a - 6300 * b) / 1403;
+
+// Step 5: Hunt - Pointer - Estevez response :
+ VectorXd LMSp(3);
+ VectorXd SignLMSp_a(3);
+ for (int i = 0; i < 3; ++i)
+ {
+ SignLMSp_a(i) = 0;
+ tmp = (27.13 * abs(LMSp_a(i) - 0.1)) / (400 - abs(LMSp_a(i) - 0.1));
+ if ((LMSp_a(i)-0.1) < 0)
+ SignLMSp_a(i) = -1;
+ else if ((LMSp_a(i)-0.1) > 0)
+ SignLMSp_a(i) = 1;
+ LMSp(i) = SignLMSp_a(i)* (100. / m_ParamsCIECam02.F_L)*pow(tmp, (1 / 0.42));
+ }
+
+//Step 6: cone responses considering luminance and surround :
+
+ VectorXd LMS_C = ( m_ParamsCIECam02.M_CAT02* m_ParamsCIECam02.M_HPE.inverse()) * LMSp;
+
+ //Step 7 : cone responses :
+
+ VectorXd LMS(3);
+ for (int i = 0; i < 3; ++i)
+ LMS(i) = LMS_C(i) / m_ParamsCIECam02.LMS_c(i);
+
+ //Step 8: tristimulus values :
+ VectorXd XYZ(3);
+ XYZ = m_ParamsCIECam02.M_CAT02.inverse()*LMS;
+ return(XYZ);
+ }
+
+ VectorXd ColorConvert::XYZtoJab(VectorXd pColor, SURROUND sur)
+ {
+ C_RGB_XYZ_Lab wp(3);
+ if ( m_ParamsCIECam02.XYZ_WP[1] == 1.)
+ wp.Set( m_ParamsCIECam02.XYZ_WP[0] *100, m_ParamsCIECam02.XYZ_WP[0] * 100, m_ParamsCIECam02.XYZ_WP[2] * 100);
+ else
+ wp.Set( m_ParamsCIECam02.XYZ_WP[0] , m_ParamsCIECam02.XYZ_WP[1] , m_ParamsCIECam02.XYZ_WP[2]);
+
+ VectorXd surParam(3);
+ surParam << 1, 0.69, 1;
+ double LUMINANCE_PCS = 159.16;
+ double L_A = LUMINANCE_PCS / 5.0;
+ double Y_b = 20.0;
+ // ciecam02_parameters( Y_b, 64 / EIGEN_PI / 5, sur);
+ VectorXd XYZ(3);
+ XYZ = 100 * pColor;
+ VectorXd JQCMsHh(7);
+ JQCMsHh = XYZ_2_ciecam02(XYZ);
+ VectorXd JMh(3);
+ JMh << JQCMsHh(0), JQCMsHh(3), JQCMsHh(6);
+// Jab_parameters(UCS);
+ VectorXd Jab(3);
+ Jab = JMh_2_Jab(JMh);
+ return(Jab);
+ }
+
+ double *ColorConvert::LabToJab(double* pColor, SURROUND sur)
+ {
+ VectorXd Vec(3);
+ for (int i = 0; i < 3; ++i)
+ Vec(i) = pColor[i];
+ VectorXd OutVec = LabToJab(Vec, sur);
+ double *Out = new double[3];
+ //double *Out = DBG_NEW double[3];
+ for (int i = 0; i < 3; ++i)
+ Out[i]= OutVec(i);
+ return(Out);
+ }
+
+ VectorXd ColorConvert::LabToJab(VectorXd pColor, SURROUND sur)
+ {
+ C_RGB_XYZ_Lab Color(pColor);
+ C_RGB_XYZ_Lab XYZColor;
+ XYZColor = LabToXYZ(Color);
+ VectorXd OutColor(3);
+ VectorXd InColor(3);
+ InColor << XYZColor.Get_x(), XYZColor.Get_y(), XYZColor.Get_z();
+ OutColor = XYZtoJab(InColor, sur);
+ return(OutColor);
+ }
+ void ColorConvert::InitCiecamParams(double Y_b, double L_A, SURROUND sur, CAM02CS CS)
+ {
+ ciecam02_parameters( Y_b, L_A, sur);
+ Jab_parameters(CS);
+ }
+
+ void ColorConvert::SymmetricaldECMC(VectorXd refX, VectorXd samX, double &dECMCVal)
+ {
+ double dECMC1, dECMC2;
+ dEcmc(refX, samX, dECMC1);
+ dEcmc(samX, refX, dECMC2);
+ dECMCVal = (dECMC1 + dECMC2) / 2;
+ }
+
+ void ColorConvert::dEcmc(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dECMC)
+ {
+ VectorXd refX1 = refX.Get();
+ VectorXd samX1 = samX.Get();
+ dEcmc(samX1, refX1, dECMC);
+ }
+
+ void ColorConvert::dEcmc(VectorXd refX, VectorXd samX, double &dECMC)
+ {
+ //dEcmc(refX, samX) calculates color difference CMC(2:1) in
+ //CIE - L*a*b* colorspace between references(refX) and
+ // samples(samX)
+
+// reference parameter calculations
+ // hue calculation
+ double h1 = atan2(refX(2), refX( 1))*(180 / EIGEN_PI);
+ if (h1<0)
+ h1 = h1 + 360;
+ double h2= atan2(samX( 2), samX( 1))*(180 / EIGEN_PI);
+ if (h2<0)
+ h2 = h2 + 360;
+ double refX_H = h1 ;
+ //chroma calculation
+ double refX_C = sqrt(refX(1)*refX(1) + refX(2)*refX(2));
+ //reference SL parameter
+ double refX_SL;
+ if (refX(1) <= 16)
+ refX_SL = 0.511;
+ else
+ refX_SL = refX(1)*0.040975 / (1 + 0.01765*refX(1));
+ //reference SC parameter
+ double refX_SC = (0.638 + 0.0638*refX_C / (1 + 0.0131*refX_C));
+ //reference CQ parameter
+ double refX_CQ = pow(refX_C, 4);
+ //reference F parameter
+ double refX_F = sqrt(refX_CQ / (refX_CQ + 1900));
+ // reference T parameter
+ double refX_T = 0;
+ if ((refX_H > 164) & (refX_H < 345))
+ refX_T = 0.56 + abs(0.2*cos(EIGEN_PI*(refX_H + 168) / 180));
+ else if ((refX_H >= 345) | (refX_H <= 164))
+ refX_T = 0.36 + abs(0.4*cos(EIGEN_PI*(refX_H + 35) / 180));
+ // reference SH parameter
+ double refX_SH = refX_SC*(refX_T*refX_F + 1 - refX_F);
+
+ //sample parameter calculations
+ //hue calculation
+ double samX_H =h2;
+ //chroma calculation
+ double samX_C = sqrt(samX(1)*samX(1) + samX(2)*samX(2));
+
+ double dL = refX( 0) - samX( 0);
+ double dC = samX_C - refX_C;
+ double da = refX(1) - samX(1);
+ double db = refX(2) - samX(2);
+ double dH = sqrt(std::max(da*da + db * db - dC * dC, 0.0));
+
+ dECMC = sqrt(pow(dL / (2 * refX_SL),2) + pow(dC / refX_SC,2) + pow(dH / refX_SH,2));
+ }
+
+ void ColorConvert::Initciecam02_parameters()
+ {
+ m_ParamsCIECam02.XYZ_WP[0] = 0;
+ m_ParamsCIECam02.XYZ_WP[1] = 0;
+ m_ParamsCIECam02.XYZ_WP[2] = 0;
+ m_ParamsCIECam02.F = 0;
+ m_ParamsCIECam02.c = 0;
+ m_ParamsCIECam02.N_c = 0;
+ m_ParamsCIECam02.M_CAT02 = MatrixXd::Zero(3,3);
+ m_ParamsCIECam02.M_HPE = MatrixXd::Zero(3, 3);
+ m_ParamsCIECam02.h_i = VectorXd::Zero(5);
+ m_ParamsCIECam02.e_i = VectorXd::Zero(5);
+ m_ParamsCIECam02.H_i = VectorXd::Zero(5);
+ m_ParamsCIECam02.LMS_w = VectorXd::Zero(3);
+ m_ParamsCIECam02.D = 0;
+ m_ParamsCIECam02.LMS_c= VectorXd::Zero(3);
+ m_ParamsCIECam02.LMSp_w = VectorXd::Zero(3);
+ m_ParamsCIECam02.k = 0;
+ m_ParamsCIECam02.F_L = 0;
+ m_ParamsCIECam02.n = 0;
+ m_ParamsCIECam02.N_bb = 0;
+ m_ParamsCIECam02.N_cb = 0;
+ m_ParamsCIECam02.z = 0;
+ m_ParamsCIECam02.LMSp_aw = VectorXd::Zero(3);
+ m_ParamsCIECam02.A_w = 0;
+ }
+ void ColorConvert::InitJab_parameters()
+ {
+ m_JabParams.CS = CAM02CS(0);
+ m_JabParams.KL = 0;
+ m_JabParams.c1 = 0;
+ m_JabParams.c2 = 0;
+ }
+
+ void ColorConvert::dE76(VectorXd refX, VectorXd samX, double &dE)
+ {
+ double dEVal = 0;
+ for (int i = 0; i < 3; ++i)
+ {
+ dEVal += pow(refX(i) - samX(i), 2);
+ }
+ dEVal = sqrt(dEVal);
+ dE = dEVal;
+ }
+
+ void ColorConvert::dE76(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dE)
+ {
+ VectorXd refX1 = refX.Get();
+ VectorXd samX1 = samX.Get();
+ dE76(samX1, refX1, dE);
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.h
new file mode 100644
index 000000000..55e1ebc41
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorConvert.h
@@ -0,0 +1,140 @@
+
+#ifndef __COLORCONVERT_H__
+#define __COLORCONVERT_H__
+
+#include "C_RGB_XYZ_Lab.h"
+#include "Dense"
+#include <vector>
+
+using Eigen::MatrixXd;
+using Eigen::VectorXd;
+
+struct CIECAM02Params
+{
+ double XYZ_WP[3];
+ double F;
+ double c;
+ double N_c;
+ MatrixXd M_CAT02;
+ MatrixXd M_HPE;
+ VectorXd h_i;
+ VectorXd e_i;
+ VectorXd H_i;
+ VectorXd LMS_w;
+ double D;
+ VectorXd LMS_c;
+ VectorXd LMSp_w;
+ double k, F_L, n, N_bb, N_cb, z;
+ VectorXd LMSp_aw;
+ double A_w;
+};
+enum Illum { D50, D65 };
+enum SURROUND
+{
+ average,
+ dim,
+ dark
+};
+
+enum CAM02CS
+{
+ UCS,
+ LCD,
+ SCD
+};
+
+struct Jab_Params
+{
+ CAM02CS CS;
+ double KL;
+ double c1;
+ double c2;
+};
+
+class ColorConvert
+{
+ public:
+
+ ColorConvert (void);
+ ColorConvert (Illum D, C_RGB_XYZ_Lab SourceWhite);
+ ColorConvert(C_RGB_XYZ_Lab DestWhite, Illum D );
+ ColorConvert(Illum DDest, Illum DSource);
+ ColorConvert (const ColorConvert &rhs);
+ ColorConvert(C_RGB_XYZ_Lab DDest, C_RGB_XYZ_Lab DSource);
+ ColorConvert &operator = (const ColorConvert &rhs);
+ ColorConvert(Illum DDest, Illum DSource, double Y_b, double L_A, SURROUND sur, CAM02CS CS);
+ ~ColorConvert();
+ C_RGB_XYZ_Lab XYZToLab ( C_RGB_XYZ_Lab xyz);
+ C_RGB_XYZ_Lab LabToXYZ ( C_RGB_XYZ_Lab lab) ;
+
+ const C_RGB_XYZ_Lab &GetReferenceWhite (void) const;
+ void SetReferenceWhite (C_RGB_XYZ_Lab &refWhite);
+ void SetReferenceWhite(Illum D);
+ void CAT_BradfordMat();
+ //Conversion between XYZ and RGB
+ VectorXd GetChromaticities();
+ C_RGB_XYZ_Lab RGBtoXYZ(C_RGB_XYZ_Lab & rgbVal);
+ C_RGB_XYZ_Lab XYZtoRGB(C_RGB_XYZ_Lab& xyzVal);
+ C_RGB_XYZ_Lab XYZtoRGBNoClip(C_RGB_XYZ_Lab& xyzVal);
+ C_RGB_XYZ_Lab LabtoRGBNoClip(C_RGB_XYZ_Lab& LabVal);
+ void LabtoRGBNoClip(double*InLab, double *OutRGB);
+ void LabtoRGB(double*InLab, double* OutRGB );
+ void ChangeWP(double *LabIn, double *LabOut, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite);
+ void ChangeWP(C_RGB_XYZ_Lab LabIn, C_RGB_XYZ_Lab &LabOut, C_RGB_XYZ_Lab SourceWhite, C_RGB_XYZ_Lab DestWhite);
+ C_RGB_XYZ_Lab LabtoRGB(C_RGB_XYZ_Lab& LabVal);
+ void RGBtoLab(double *InRGB, double *OutLab);
+ C_RGB_XYZ_Lab RGBtoLab(C_RGB_XYZ_Lab& RGB);
+ // void RGBtoLab(std::vector<double>&InRGB, double *OutLab);
+ void InitializeConversionMatrices();
+ void RecalculateConversionMatrices(const VectorXd& chromaticites);
+ C_RGB_XYZ_Lab ApplyBradfordMat(C_RGB_XYZ_Lab& xyzVal);
+ C_RGB_XYZ_Lab NormalizeWPXYZ(C_RGB_XYZ_Lab& xyzVal);
+ VectorXd XYZtoJab(VectorXd pColor, SURROUND sur);
+ VectorXd Jab_2_XYZ(VectorXd Jab, CAM02CS CS);
+ VectorXd Jab_2_Lab(VectorXd Jab, CAM02CS CS);
+ VectorXd LabToJab(VectorXd pColor, SURROUND sur);
+ double *LabToJab(double* pColor, SURROUND sur);
+ void InitCiecamParams(double Y_b, double L_A, SURROUND sur, CAM02CS CS);
+ void dEcmc(VectorXd refX, VectorXd samX, double &dE);
+ void dEcmc(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dE);
+ void dE76(VectorXd refX, VectorXd samX, double &dE);
+ void dE76(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dE);
+ void SymmetricaldECMC(VectorXd refX, VectorXd samX, double &dECMC);
+ CAM02CS getCAM02CS() { return(m_CS); };
+ SURROUND getSurround() { return(m_sur); };
+
+ protected:
+
+ private:
+ //Explicit inverse of a 3x3 matrix: A is the input matrix, B its inverse
+ void InverseOfThreeByThreeMatrix(const MatrixXd& A, MatrixXd& B);
+ void ComputeRGBtoXYZmatrix();
+ void ComputeXYZtoRGBmatrix();
+ Jab_Params m_JabParams;
+ CIECAM02Params m_ParamsCIECam02;
+ void Initciecam02_parameters();
+ void InitJab_parameters();
+ void ciecam02_parameters( double Y_b, double L_A, SURROUND sur);
+ VectorXd XYZ_2_ciecam02(VectorXd XYZ);
+ VectorXd Jab_2_JMh(VectorXd Jab);
+ VectorXd JMh_2_Jab(VectorXd JMh);
+ VectorXd ciecam02_2_XYZ(VectorXd JMh);
+ void Jab_parameters(CAM02CS CS);
+ C_RGB_XYZ_Lab m_ReferenceWhite; // Reference white
+ C_RGB_XYZ_Lab m_InvReferenceWhite; // 1.0 / Reference white
+ C_RGB_XYZ_Lab m_SourceWhite; // 1.0 / Reference white
+ CAM02CS m_CS;
+ SURROUND m_sur;
+ MatrixXd m_BradfordMatrix;
+ double GammaExpand_sRGB(double nonlinear);
+ double GammaCompress_sRGB(double linear);
+ void SetCIECamWhitePoint(C_RGB_XYZ_Lab ReferenceWhite);
+ void SetCAM02CS(CAM02CS CS) { m_CS = CS; };
+ void SetSurround(SURROUND sur) { m_sur = sur; };
+
+};
+
+
+
+
+#endif // __CIELABCONVERT_H__
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.cpp
new file mode 100644
index 000000000..768647a0b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.cpp
@@ -0,0 +1,769 @@
+#include "ColorTable.h"
+#include "NumConversions.h"
+
+using namespace std;
+
+//Constructor
+ColorTable::ColorTable() :
+ m_B2ATransform(NULL), m_A2BTransform(NULL),
+m_B2ARTransform(NULL), m_A2BRTransform(NULL),
+m_GBD(NULL), m_GBDR(NULL),
+m_LinCurves(NULL), m_LinCurvesR(NULL),
+m_nB2AnSepIn(0), m_nB2AnSepOut(0),
+m_nA2BnSepIn(0), m_nA2BnSepOut(0),
+m_TableVersion(0), m_TableSubVersion(0), m_NormFactor(NULL), m_InvNormFactor(NULL),
+m_nGamutRegions(0), m_nProcessRanges(0), m_GamutRegionMinLim(NULL),
+m_GamutRegionMaxLim(NULL), m_NormGamutRegionMaxLim(NULL), m_CTLiquidFactors(NULL),
+m_whitepointXYZ_CT(0.0), m_forwardmodel(NULL), m_forwardmodelR(NULL)
+{
+}
+
+ColorTable::~ColorTable()
+{
+ if (m_B2ATransform != NULL)
+ {
+ delete m_B2ATransform;
+ m_B2ATransform = NULL;
+ }
+ if (m_B2ARTransform != NULL)
+ {
+ delete m_B2ARTransform;
+ m_B2ARTransform = NULL;
+ }
+ if (m_A2BTransform != NULL)
+ {
+ delete m_A2BTransform;
+ m_A2BTransform = NULL;
+ }
+ if (m_A2BRTransform != NULL)
+ {
+ delete m_A2BRTransform;
+ m_A2BRTransform = NULL;
+ }
+ if (m_GBD != NULL)
+ {
+ delete m_GBD;
+ m_GBD = NULL;
+ }
+ if (m_GBDR != NULL)
+ {
+ delete m_GBDR;
+ m_GBDR = NULL;
+ }
+ if (m_LinCurves != NULL)
+ {
+ delete m_LinCurves;
+ m_LinCurves = NULL;
+ }
+ if (m_LinCurvesR != NULL)
+ {
+ delete m_LinCurvesR;
+ m_LinCurvesR = NULL;
+ }
+ if (m_GamutRegionMaxLim != NULL)
+ {
+ delete[] m_GamutRegionMaxLim;
+ m_GamutRegionMaxLim = NULL;
+ }
+ if (m_NormGamutRegionMaxLim != NULL)
+ {
+ delete[] m_NormGamutRegionMaxLim;
+ m_NormGamutRegionMaxLim = NULL;
+ }
+ if (m_NormFactor != NULL)
+ {
+ delete[] m_NormFactor;
+ m_NormFactor = NULL;
+ }
+ if (m_InvNormFactor != NULL)
+ {
+ delete[] m_InvNormFactor;
+ m_InvNormFactor = NULL;
+ }
+ /*if (m_CTLiquidFactors != NULL)
+ {
+ delete[] m_CTLiquidFactors;
+ m_CTLiquidFactors = NULL;
+ }*/
+}
+void ColorTable::InitColorTables(bool has_rddata, uint8_t *data, int nprocessranges)
+{
+ readColorTables(has_rddata, data, nprocessranges);
+ SetNormFactor();
+ SetInverseNormFactor();
+ if (m_NormGamutRegionMaxLim == NULL)
+ m_NormGamutRegionMaxLim = new double[m_nGamutRegions];
+ NormGamutRegionMaxLim();
+}
+
+void ColorTable::readColorTables(bool has_data, uint8_t * data, int nprocessranges)
+{
+ //parse Color Tansformations, placed in forward data
+ int bytesread = 0;
+ NumConversions conv;
+ int tag_count = 0;
+ int TblVer = 0;
+ int TblSubVer = 0;
+ if (has_data)
+ {
+ //Read Header
+ CT_Header *header = read_header(data, bytesread);
+ SetnGamutRegions((int)(header->GetNGamutRegions()));
+ TblVer = (int)header->GetTableVersion()[0];
+ TblSubVer = (int)header->GetTableVersion()[1];
+ SetTableVersion(TblVer);
+ SetTableSubVersion(TblSubVer);
+
+ if (m_nGamutRegions != nprocessranges)
+ {
+ throw std::exception("Number of gamut regions in table does not match STRIP\0");
+ return;
+ }
+ double *tmpGamutRegionsLim = header->GetGamutRegionsMaxLimit();
+ if(m_GamutRegionMaxLim == NULL)
+ m_GamutRegionMaxLim = new double[m_nGamutRegions];
+ for (int i = 0; i < m_nGamutRegions; ++i)
+ {
+ if(tmpGamutRegionsLim[i]<=0)
+ {
+ throw std::exception("Gamut region Limit is zero or negative\0");
+ return;
+ }
+ else
+ m_GamutRegionMaxLim[i] = tmpGamutRegionsLim[i]; //in[nl/cm]
+ }
+ m_nProcessRanges = (int)(nprocessranges);
+ double *tmpLF = header->GetLiquidFactors();
+ if (m_CTLiquidFactors == NULL)
+ m_CTLiquidFactors = new double[4];
+ for (int i = 0; i < 4; ++i)
+ {
+ if (tmpLF[i] <= 0)
+ {
+ throw std::exception("Color Table Liquid Factors are 0 or negative\0");
+ return;
+ }
+ else
+ m_CTLiquidFactors[i] = tmpLF[i]; //in [nl/cm]
+ }
+ if (m_GamutRegionMinLim == NULL)
+ m_GamutRegionMinLim = new double[m_nGamutRegions];
+ if (m_TableSubVersion > 0)
+ {
+ tmpGamutRegionsLim = header->GetGamutRegionsMinLimit();
+ for (int i = 0; i < m_nGamutRegions; ++i)
+ {
+ if (tmpGamutRegionsLim[i] <= 0)
+ {
+ throw std::exception("Min Gamut region Limit is zero or negative\0");
+ return;
+ }
+ else
+ m_GamutRegionMinLim[i] = tmpGamutRegionsLim[i]; //in [nl/cm]
+ }
+ }
+ else
+ {
+ m_GamutRegionMinLim[0] = 200;
+ m_GamutRegionMinLim[1] = 300;
+ }
+ uint32_t tmp;
+ uint8_t *buff = data;
+ tmp = conv.ByteToInt(buff, bytesread);
+ tag_count = (int)tmp;
+ bytesread += 4;
+ //read Tag Table
+ char **TagNames = new char*[tag_count];
+ //char **TagNames = DBG_NEW char*[tag_count];
+ int **TagSize = new int*[tag_count];
+
+ //int **TagSize = DBG_NEW int*[tag_count];
+ char tmpC[80];
+ int n = 0;
+ int i;
+ for (i = 0; i < tag_count; ++i)
+ {
+ TagSize[i] = new int[2];
+ //TagSize[i] = DBG_NEW int[3];
+ tmp = conv.ByteToInt(buff, bytesread);
+ n = sizeof(tmp);
+ //tmpC = DBG_NEW char[n];
+ conv.getchar(tmp, *tmpC);
+ TagNames[i] = new char[n+1];
+ //TagNames[i] = DBG_NEW char[n];
+ strncpy_s(TagNames[i], n + 1, tmpC, n);
+ bytesread += 4;
+ TagSize[i][0] = conv.ByteToInt(buff, bytesread);
+ bytesread += 4;
+ TagSize[i][1] = conv.ByteToInt(buff, bytesread);
+ bytesread += 4;
+ }
+
+ int *TList = new int[tag_count];
+ //int *TList = DBG_NEW int[tag_count];
+ for (int k = 0; k < tag_count; ++k)
+ {
+ if (strncmp(TagNames[k], "A2B ", 4) == 0)
+ TList[k] = A2B;
+ else if (strncmp(TagNames[k], "A2BR", 4) == 0)
+ TList[k] = A2BR;
+ else if (strncmp(TagNames[k], "B2A ", 4) == 0)
+ TList[k] = B2A;
+ else if (strncmp(TagNames[k], "B2AR ", 4) == 0)
+ TList[k] = B2AR;
+ else if (strncmp(TagNames[k], "wtpt", 4) == 0)
+ TList[k] = wtpt;
+ else if (strncmp(TagNames[k], "desc", 4) == 0)
+ TList[k] = desc;
+ else if (strncmp(TagNames[k], "gbd ", 4) == 0)
+ TList[k] = gbd;
+ else if (strncmp(TagNames[k], "gbdR", 4) == 0)
+ TList[k] = gbdR;
+ else if (strncmp(TagNames[k], "cprt", 4) == 0)
+ TList[k] = cprt;
+ else if (strncmp(TagNames[k], "lcrv", 4) == 0)
+ TList[k] = lcrv;
+ else if (strncmp(TagNames[k], "lcrR", 4) == 0)
+ TList[k] = lcrR;
+ else if (strncmp(TagNames[k], "FMCo", 4) == 0)
+ TList[k] = FMCo;
+ else if (strncmp(TagNames[k], "FMCR", 4) == 0)
+ TList[k] = FMCR;
+ // else if (strncmp(TagNames[k], "GReg", 2) == 0)
+ // TList[k] = GReg;
+ else
+ throw std::exception("Unknown Tag in Color Tables");
+ }
+
+
+ for (int k = 0; k < tag_count; ++k)
+ {
+ switch (TList[k])
+ {
+ case A2B:
+ {
+ uint8_t *A2BLUT = &(data[TagSize[k][0]]);
+ int A2BLutsize = TagSize[k][1];
+ if(m_A2BTransform == NULL)
+ m_A2BTransform = new ColorTransf();
+ //m_A2BTransform = DBG_NEW ColorTransf();
+ m_A2BTransform->InitData(A2BLUT, A2BLutsize);
+ m_nA2BnSepIn = m_A2BTransform->GetSeparationsIn();
+ m_nA2BnSepOut = m_A2BTransform->GetSeparationsOut();
+ break;
+ }
+ case A2BR:
+ {
+ uint8_t *A2BRLUT = &(data[TagSize[k][0]]);
+ int A2BRLutsize = TagSize[k][1];
+ if (m_A2BRTransform == NULL)
+ m_A2BRTransform = new ColorTransf();
+ //m_A2BTransform = DBG_NEW ColorTransf();
+ m_A2BRTransform->InitData(A2BRLUT, A2BRLutsize);
+ break;
+ }
+ case B2A:
+ {
+ uint8_t *B2ALUT = &(data[TagSize[k][0]]);
+ int B2ALutsize = TagSize[k][1];
+ if(m_B2ATransform == NULL)
+ m_B2ATransform = new ColorTransf();
+ //m_B2ATransform = DBG_NEW ColorTransf();
+ m_B2ATransform->InitData(B2ALUT, B2ALutsize);
+ m_nB2AnSepIn = m_B2ATransform->GetSeparationsIn();
+ m_nB2AnSepOut = m_B2ATransform->GetSeparationsOut();
+ break;
+ }
+ case B2AR:
+ {
+ uint8_t *B2ARLUT = &(data[TagSize[k][0]]);
+ int B2ARLutsize = TagSize[k][1];
+ if(m_B2ARTransform == NULL)
+ m_B2ARTransform = new ColorTransf();
+ //m_B2ATransform = DBG_NEW ColorTransf();
+ m_B2ARTransform->InitData(B2ARLUT, B2ARLutsize);
+ break;
+ }
+ /* case GReg:
+ {
+ uint8_t *GRegLUT = &(conversionInput->forwarddata.data[TagSize[k][0]]);
+ int GRegLutsize = TagSize[k][1];
+ m_GRegTransform = new ColorTransf();
+ //m_B2ATransform = DBG_NEW ColorTransf();
+ m_GRegTransform->InitData(GRegLUT, GRegLutsize);
+ break;
+ } */
+ case gbd:
+ {
+ uint8_t *GBDList = &(data[TagSize[k][0]]);
+ if(m_GBD == NULL)
+ m_GBD = new GBD();
+ //m_GBD = DBG_NEW GBD();
+ int GBDSize = TagSize[k][1];
+ m_GBD->InitData(GBDList, GBDSize);
+ break;
+ }
+ case gbdR:
+ {
+ uint8_t *GBDRList = &(data[TagSize[k][0]]);
+ if(m_GBDR == NULL)
+ m_GBDR = new GBD();
+ //m_GBD = DBG_NEW GBD();
+ int GBDRSize = TagSize[k][1];
+ m_GBDR->InitData(GBDRList, GBDRSize);
+ break;
+ }
+ case lcrv:
+ {
+ uint8_t *CurvesData = &(data[TagSize[k][0]]);
+ if(m_LinCurves == NULL)
+ m_LinCurves = new Curves();
+ int CurvesSize = TagSize[k][1];
+ m_LinCurves->InitData(CurvesData, CurvesSize);
+ break;
+ }
+ case lcrR:
+ {
+ uint8_t *CurvesData = &(data[TagSize[k][0]]);
+ if (m_LinCurvesR == NULL)
+ m_LinCurvesR = new Curves();
+ int CurvesSize = TagSize[k][1];
+ m_LinCurvesR->InitData(CurvesData, CurvesSize);
+ break;
+ }
+ case wtpt:
+ {
+ read_xyz_type(TagSize[k][0], TagSize[k][1], &m_whitepointXYZ_CT, data);
+
+ break;
+ }
+ case cprt:
+ {
+ std::string textstr;
+ read_text_type(TagSize[k][0], TagSize[k][1], &textstr, data);
+ break;
+ }
+ case desc:
+ {
+ std::string textdescstr;
+ read_text_description_type(TagSize[k][0], TagSize[k][1], &textdescstr, data);
+ break;
+ }
+ case FMCo:
+ {
+ uint8_t *FMD = &(data[TagSize[k][0]]);
+ if (m_forwardmodel == NULL)
+ m_forwardmodel = new ForwardModel();
+ int FMSize = TagSize[k][1];
+ m_forwardmodel->InitData(FMD, FMSize);
+ break;
+ }
+ case FMCR:
+ {
+ uint8_t *FMD = &(data[TagSize[k][0]]);
+ if (m_forwardmodelR == NULL)
+ m_forwardmodelR = new ForwardModel();
+ int FMSize = TagSize[k][1];
+ m_forwardmodelR->InitData(FMD, FMSize);
+ break;
+ }
+ default:
+ {
+ throw std::exception("Unresolved Tag in Color Tables");
+ return;
+ }
+
+ }
+ }
+ if (TagNames != NULL)
+ {
+ for (int i = 0; i < tag_count; ++i)
+ {
+ delete[] TagNames[i];
+ // TagNames[i] = NULL;
+ }
+ delete[]TagNames;
+ TagNames = NULL;
+ }
+
+ if (TagSize != NULL)
+ {
+ for (int i = 0; i < tag_count; ++i)
+ {
+ delete[] TagSize[i];
+ TagSize[i] = NULL;
+ }
+ delete[]TagSize;
+ TagSize = NULL;
+ }
+ if (TList != NULL)
+ {
+ delete[] TList;
+ TList = NULL;
+ }
+ if (header != NULL)
+ {
+ delete header;
+ header = NULL;
+ }
+ }
+ else
+ throw std::exception("Color Table has no Data");
+
+
+ //Verify all relevant tags had been read
+ if (m_A2BTransform == NULL)
+ {
+ throw std::exception("Missing Forward Transform in Color Tables");
+ return;
+ }
+ if( TblVer > 1 )
+ {
+ if (m_A2BRTransform == NULL)
+ {
+ throw std::exception("Missing Reduced Forward Transform in Color Tables");
+ return;
+ }
+ }
+ if (m_B2ATransform == NULL)
+ {
+ throw std::exception("Missing Inverse Transform in Color Tables");
+ return;
+ }
+ if (TblVer > 1)
+ {
+ if (m_B2ARTransform == NULL)
+ {
+ throw std::exception("Missing Reduced Inverse Transform in Color Tables");
+ return;
+ }
+ }
+ if (m_GBD == NULL)
+ {
+ throw std::exception("Missing Gamut Boundary Descriptor in Color Tables");
+ return;
+ }
+ if (TblVer > 1)
+ {
+ if (m_GBDR == NULL)
+ {
+ throw std::exception("Missing Reduced Gamut Boundary Descriptor in Color Tables");
+ return;
+ }
+ }
+ if ((m_whitepointXYZ_CT.Get_x() == -1) && (m_whitepointXYZ_CT.Get_y() == -1) && (m_whitepointXYZ_CT.Get_z() == -1))
+ {
+ throw std::exception("Missing Whitepoint in Color Tables");
+ return;
+ }
+ if (m_LinCurves == NULL)
+ {
+ throw std::exception("Missing Linear Curves in Color Tables");
+ return;
+ }
+ if( TblVer > 1)
+ {
+ if (m_LinCurvesR == NULL)
+ {
+ throw std::exception("Missing Linear Curves 100 in Color Tables");
+ return;
+ }
+ }
+ if (m_TableSubVersion > 0)
+ {
+ if(m_forwardmodel == NULL)
+ throw std::exception("Missing Forward Model Info in Color Tables");
+ return;
+ if(m_TableVersion > 1)
+ {
+ if (m_forwardmodelR == NULL)
+ throw std::exception("Missing Forward Model 100 Info in Color Tables");
+ return;
+ }
+ }
+ return; // OK
+}
+
+CT_Header *ColorTable::read_header(uint8_t *data, int &bytesread)
+{
+ //CT_Header *Header = new CT_Header;
+ //CT_Header *Header = DBG_NEW CT_Header;
+ CT_Header *Header = new CT_Header;
+
+ // unsigned int tmp = (buffer[2 * i + 1] << 8) | buffer[2 * i];
+ uint8_t *ColorTableData = data;
+ //File Size
+ NumConversions Conv;
+ unsigned int TblSize = Conv.ByteToInt(ColorTableData, bytesread);
+ Header->SetTableSize(TblSize);
+ bytesread = 4;
+ uint8_t versionBCT[2];
+ versionBCT[0] = (unsigned int)ColorTableData[bytesread];
+ bytesread += 1;
+ versionBCT[1] = (unsigned int)ColorTableData[bytesread];
+ unsigned int TVersion[3];
+ TVersion[0] = versionBCT[0];
+ TVersion[1] = versionBCT[1] >> 4;
+ TVersion[2] = versionBCT[1] & 15;
+ Header->SetTableVersion(TVersion);
+
+ bytesread += 1;
+ uint32_t tmp = Conv.ByteToInt(ColorTableData, bytesread);
+ //char *tmpC = DBG_NEW char[n];
+ char tmpC_CS[sizeof(tmp)+1];
+ Conv.getchar(tmp, * tmpC_CS);
+ //Header.ColorSpace = DBG_NEW char[n];
+ Header->SetColorSpace(tmpC_CS);
+
+ bytesread += 4;
+ tmp = Conv.ByteToInt(ColorTableData, bytesread);
+ char tmp_connectionspace[sizeof(tmp)+1];
+ Conv.getchar(tmp, *tmp_connectionspace);
+ //Header.ConnectionSpace = DBG_NEW char[n];
+ Header->SetConnectionSpace(tmp_connectionspace);
+
+ bytesread += 4;
+
+ bytesread += 12;
+ tmp = Conv.ByteToInt(ColorTableData, bytesread);
+ char tmp_DM[sizeof(tmp)+1];
+ Conv.getchar(tmp, *tmp_DM);
+ //Header.DeviceManufacturer = DBG_NEW char[n];
+ Header->SetDeviceManufacturer(tmp_DM);
+
+ bytesread += 4;
+ //read illuminant
+ double xyz[3];
+ for (int j = 0; j < 3; ++j)
+ {
+ tmp = Conv.ByteToInt(ColorTableData, bytesread);
+ xyz[j] = (double)(tmp) / 65536;
+ bytesread += 4;
+ }
+ C_RGB_XYZ_Lab XYZIllum(xyz[0], xyz[1], xyz[2]);
+ Header->SetIlluminant(XYZIllum);
+ //Read Number of Gamut Regions and Max Limits per Region
+ Header->SetNGamutRegions(ColorTableData[bytesread]);
+ bytesread++;
+ int nsize = Header->GetNGamutRegions();
+
+ double *GRegMaxLim = new double[nsize];
+ for (int i = 0; i < nsize; ++i)
+ {
+ tmp = Conv.ByteToShort(ColorTableData, bytesread);
+ bytesread += 2;
+ GRegMaxLim[i] = (double)tmp;
+ }
+ Header->SetGamutRegionsMaxLimit(GRegMaxLim);
+
+ double *LiquidFactors = new double[4];
+ for (int i = 0; i < 4; ++i)
+ {
+ tmp = Conv.ByteToShort(ColorTableData, bytesread);
+ bytesread += 2;
+ LiquidFactors[i] = (double)tmp;
+ }
+ Header->SetLiquidFactors(LiquidFactors);
+ double *GRegMinLim = new double[nsize];
+ if(TVersion[1]>0)
+ {
+ for (int i = 0; i < nsize; ++i)
+ {
+ tmp = Conv.ByteToShort(ColorTableData, bytesread);
+ bytesread += 2;
+ GRegMinLim[i] = (double)tmp;
+ }
+ }
+ else
+ {
+ GRegMinLim[0] = 200;
+ GRegMinLim[1] = 300;
+ }
+ Header->SetGamutRegionsMinLimit(GRegMinLim);
+
+
+ if (GRegMaxLim != NULL)
+ {
+ delete[] GRegMaxLim;
+ GRegMaxLim = NULL;
+ }
+ if (GRegMinLim != NULL)
+ {
+ delete[] GRegMinLim;
+ GRegMinLim = NULL;
+ }
+ if (LiquidFactors != NULL)
+ {
+ delete[] LiquidFactors;
+ LiquidFactors = NULL;
+ }
+ if (bytesread < 128)
+ {
+ bytesread = 128;
+ return(Header);
+ }
+ else
+ {
+ throw std::exception("could not read Color table Header");
+ }
+}
+
+void ColorTable::read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *XYZ, uint8_t *data)
+{
+ // 0 - 3 'XYZ '
+ //4 - 7 reserved, must be 0
+ // 8 - n array of XYZ numbers
+
+ if (data_size < 8)
+ {
+ throw std::exception("not enough data to read xyz");
+ }
+ uint8_t *buff = &(data[offset]);
+ NumConversions Conv;
+ int bytesread = 0;
+ int tmpxyz = Conv.ByteToInt(buff, bytesread);
+
+ //char* tmpC = DBG_NEW char[n];
+ int n = sizeof(tmpxyz);
+ //char tmpC[sizeof(tmpxyz)];
+ char xyztype[sizeof(tmpxyz)+1];
+ Conv.getchar(tmpxyz, *xyztype);
+
+ //char *xyztype = DBG_NEW char[n + 1];
+// strcpy(xyztype, tmpC);
+ if (strncmp(xyztype, "XYZ ", sizeof(tmpxyz)) != 0)
+ {
+ throw std::exception("Wrong Tag Type");
+ return;
+ }
+
+ bytesread = 8;
+ int num_values = (data_size - 8) / 4;
+ if (floor((double)(num_values) / 3) * 3 != num_values)
+ {
+ throw std::exception("not enough Data to read xyz");
+ return;
+ }
+ double xyz[3];
+ int tmp;
+ for (int j = 0; j < 3; ++j)
+ {
+ tmp = Conv.ByteToInt(buff, bytesread);
+ xyz[j] = (double)(tmp) / 65536;
+ bytesread += 4;
+ }
+ XYZ->Set(xyz[0], xyz[1], xyz[2]);
+ return;
+}
+
+void ColorTable::read_text_type(int offset, int data_size, std::string *textstr, uint8_t *data)
+{
+ // 0 - 3 'text'
+ //4 - 7 reserved, must be 0
+ //8 - string of(data_size - 8) 7 - bit ASCII characters, including NULL
+
+ std::stringstream strstr;
+ if (data_size < 8)
+ {
+ throw std::exception("invalid Tag Name");
+ strstr << "";
+ *textstr = strstr.str();
+ return;
+ }
+
+ uint8_t *buff = &(data[offset]);
+ int bytesread = 0;
+ NumConversions Conv;
+ int tmp = Conv.ByteToInt(buff, bytesread);
+ int n = sizeof(tmp);
+ //char *tmpC = DBG_NEW char[n];
+ char tmpC[sizeof(tmp)+1];
+// char tagtype[sizeof(tmp)+1];
+ Conv.getchar(tmp, *tmpC);
+
+ if (strncmp(tmpC, "text", sizeof(tmp)) != 0)
+ {
+ throw std::exception("invalid Tag Name");
+ strstr << "";
+ *textstr = strstr.str();
+ return;
+ }
+
+ bytesread += 8;
+ uint8_t tmp1;
+ for (int i = bytesread; i < data_size; ++i)
+ {
+ tmp1 = buff[i];
+ strstr.put(tmp1);
+ }
+ *textstr = strstr.str();
+ //return;
+}
+
+void ColorTable::read_text_description_type(int offset, int data_size, std::string *textdescstr, uint8_t *data)
+{
+ // 0 - 3 'desc'
+ // 4 - 7 reserved, must be 0
+ // 8 - 11 ASCII invariant description count, including terminating NULL
+ // 12 - ASCII invariant description
+ std::stringstream strstr;
+ uint8_t *buff = &(data[offset]);
+ int bytesread = 0;
+ NumConversions Conv;
+ int tmp = Conv.ByteToInt(buff, bytesread);
+ int n = sizeof(tmp);
+ //char *tmpC= DBG_NEW char[n];
+ char tmpC[sizeof(tmp)+1];
+ Conv.getchar(tmp, *tmpC);
+ //char *tagtype = DBG_NEW char[n + 1];
+
+ if (strncmp(tmpC, "desc", sizeof(tmp)) != 0)
+ {
+ throw std::exception("invalid Tag Name");
+ strstr << "";
+ *textdescstr = strstr.str();
+ return;
+ }
+ bytesread += 8;
+ int count = Conv.ByteToInt(buff, bytesread);
+ bytesread += 4;
+ uint8_t tmp1;
+ for (int i = 0; i < count - 1; ++i)
+ {
+ tmp1 = buff[bytesread + i];
+ strstr << tmp1;
+ }
+ *textdescstr = strstr.str();
+ //return;
+}
+
+void ColorTable::SetNormFactor()
+{
+ if (m_NormFactor == NULL)
+ m_NormFactor = new double[m_nA2BnSepIn];
+ for (int i = 0; i < m_nA2BnSepIn; ++i)
+ m_NormFactor[i] = m_GamutRegionMaxLim[m_nProcessRanges-1]/ m_CTLiquidFactors[i] ;
+}
+
+void ColorTable::SetInverseNormFactor()
+{
+ if (m_InvNormFactor == NULL)
+ m_InvNormFactor = new double[m_nA2BnSepIn];
+ for (int i = 0; i < m_nA2BnSepIn; ++i)
+ {
+ if (m_NormFactor[i] <= 0)
+ throw std::exception("NormFactor is zero or Negative");
+ else
+ m_InvNormFactor[i] = 1.0 / m_NormFactor[i];
+ }
+}
+
+void ColorTable::NormGamutRegionMaxLim()
+{
+ double GamutRegionMaxLim0 = m_GamutRegionMaxLim[0];
+ if(GamutRegionMaxLim0<=0)
+ throw std::exception("Gamut Region Max Limit is zero or Negative");
+ for (int i = 0; i < m_nProcessRanges; ++i)
+ m_NormGamutRegionMaxLim[i] = 100 * m_GamutRegionMaxLim[i] / GamutRegionMaxLim0;
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.h
new file mode 100644
index 000000000..319e10fb7
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTable.h
@@ -0,0 +1,94 @@
+#ifndef _COLORTABLE_H_
+#define _COLORTABLE_H_
+
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorSpace.pb-c.h"
+#include "ColorTransf.h"
+#include "CT_Header.h"
+#include "GBD.h"
+#include "Curves.h"
+#include "ForwardModel.h"
+
+typedef enum {
+ A2B,
+ A2BR,
+ B2A,
+ B2AR,
+ cprt,
+ gbd,
+ gbdR,
+ wtpt,
+ desc,
+ lcrv,
+ lcrR,
+ FMCo,
+ FMCR
+}TagList;
+class ColorTable {
+public:
+ ColorTable();
+ ~ColorTable();
+ void InitColorTables(bool has_rddata, uint8_t *data, int nprocessranges);
+
+ int GetnB2AnSepIn( ){ return(m_nB2AnSepIn); };
+ int GetnB2AnSepOut() { return(m_nB2AnSepOut); };
+ int GetnA2BnSepIn() { return(m_nA2BnSepIn); };
+ int GetnA2BnSepOut() { return(m_nA2BnSepOut); };
+ int GetnGamutRegions() { return(m_nGamutRegions); };
+ double *GetNormFactor() { return(m_NormFactor); };
+ double *GetInverseNormFactor() { return(m_InvNormFactor); };
+ double *GetNormGamutRegionMaxLim() { return(m_NormGamutRegionMaxLim); };
+ double *GetGamutRegionMaxLim() { return(m_GamutRegionMaxLim); };
+ double *GetGamutRegionMinLim() { return(m_GamutRegionMinLim); };
+ double *GetCTLiquidFactors() { return(m_CTLiquidFactors); };
+ C_RGB_XYZ_Lab GetWhitePoint_CT() { return(m_whitepointXYZ_CT); };
+ ForwardModel *GetForwardModel() { return(m_forwardmodel); };
+ int GetTableVersion() { return(m_TableVersion); };
+ int GetTableSubVersion() { return(m_TableSubVersion); };
+ ColorTransf *m_B2ATransform;
+ ColorTransf *m_A2BTransform;
+ ColorTransf *m_B2ARTransform;
+ ColorTransf *m_A2BRTransform;
+ GBD *m_GBD;
+ GBD *m_GBDR;
+ Curves *m_LinCurves;
+ Curves *m_LinCurvesR;
+ ForwardModel *m_forwardmodel;
+ ForwardModel *m_forwardmodelR;
+private:
+ void readColorTables(bool has_rddata, uint8_t *data, int nprocessranges);
+ void SetNormFactor();
+ void SetInverseNormFactor();
+ void NormGamutRegionMaxLim();
+ int m_nB2AnSepIn;
+ int m_nB2AnSepOut;
+ int m_nA2BnSepIn;
+ int m_nA2BnSepOut;
+ int m_nGamutRegions;
+ int m_nProcessRanges;
+ int m_TableVersion;
+ int m_TableSubVersion;
+ double *m_NormFactor;
+ double *m_InvNormFactor;
+ double *m_GamutRegionMaxLim;
+ double *m_GamutRegionMinLim;
+ double*m_NormGamutRegionMaxLim;
+ double *m_CTLiquidFactors;
+ C_RGB_XYZ_Lab m_whitepointXYZ_CT;
+ void SetnB2AnSepIn(int nB2AnSepIn) { m_nB2AnSepIn = nB2AnSepIn; };
+ void SetnB2AnSepOut(int nB2AnSepOut) { m_nB2AnSepOut = nB2AnSepOut; };
+ void SetnA2BnSepIn(int nA2BnSepIn) { m_nA2BnSepIn = nA2BnSepIn; };
+ void SetnA2BnSepOut(int nA2BnSepOut) { m_nA2BnSepOut = nA2BnSepOut; };
+ void SetnGamutRegions(int nGamutRegions) { m_nGamutRegions = nGamutRegions; };
+ void SetTableVersion(int TableVersion) { m_TableVersion = TableVersion; };
+ void SetTableSubVersion(int TableSubVersion) { m_TableSubVersion = TableSubVersion; };
+
+ CT_Header *read_header(uint8_t* data, int &bytesread);
+ void read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *xyz, uint8_t *data);
+ void read_text_type(int offset, int data_size, std::string *textstr,
+ uint8_t *data);
+ void read_text_description_type(int offset, int data_size, std::string *textdescstr,
+ uint8_t *data);
+};
+
+#endif \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.cpp
new file mode 100644
index 000000000..9e59abf4d
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.cpp
@@ -0,0 +1,577 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "ColorTransf.h"
+#include "C_RGB_XYZ_Lab.h"
+#include <iostream>
+#include <stdio.h>
+#include "NumConversions.h"
+#include "Interp.h"
+
+using namespace std;
+#define LFactor 100
+#define abFactor 255
+#define abOffset 128
+#define InkFactor 100
+#define Uint16Factor 65535
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+
+// NHedral interpolation given the NDimensional LUT. N=3 or N=4 are supported.
+//Assumes the right table is loaded
+
+
+ ColorTransf::ColorTransf() :
+ m_MSBShift(0), m_DataBuffer(NULL), m_SeparationsIn(0),
+ m_SeparationsOut(0), m_nGridPoints(0), m_GamutLimitsNlperCM(NULL),
+ m_NGamutRegions(0), m_ByteBuffer(NULL), m_InputCurves(NULL), m_OutputCurves(NULL),
+ m_num_input_table_entries(0), m_num_output_table_entries(0)
+ {
+
+ }
+
+ ColorTransf::~ColorTransf()
+ {
+ if (m_DataBuffer != NULL)
+ {
+ delete[] m_DataBuffer;
+ m_DataBuffer = NULL;
+ }
+ if (m_GamutLimitsNlperCM != NULL)
+ {
+ delete[] m_GamutLimitsNlperCM;
+ m_GamutLimitsNlperCM = NULL;
+ }
+ if (m_ByteBuffer != NULL)
+ {
+ delete[] m_ByteBuffer;
+ m_ByteBuffer = NULL;
+ }
+ if (m_InputCurves != NULL)
+ {
+ delete[] m_InputCurves;
+ m_InputCurves = NULL;
+ }
+ if (m_OutputCurves != NULL)
+ {
+ delete[] m_OutputCurves;
+ m_OutputCurves = NULL;
+ }
+ }
+ void ColorTransf::free_char_array(char* charname)
+ {
+ if (charname != NULL)
+ {
+ delete[] charname;
+ charname = NULL;
+ }
+ }
+ void ColorTransf::InitData(unsigned char *colorTransformBuffer, long colorTransformSize)
+ {
+ /* the whole file is now loaded in the memory buffer. */
+ /*Parse data*/
+ /*
+ 0-3 'prec1', 'prec2'
+ 4-7 reserved, must be 0
+ 8 number of input channels, uint8
+ 9 number of output channels, uint8
+ 10 number of CLUT grid points, uint8
+ 11 Most Significant bits shift
+ 12 Number of gamut regions
+ 13-14 Number of Input Table entries
+ 15-16 Number of Output Table entries
+ prec 2 (16bit)
+ 17-n CLUT values, uint16
+ prec 1
+ 17-n CLUT values, uint8
+ */
+ //long lSize, lSizeHalf;
+
+ // obtain file size:
+ int lSize = colorTransformSize;
+ //lSizeHalf = lSize / 2;
+ // allocate memory to contain the whole file:
+ unsigned char *buffer = colorTransformBuffer;
+ if (buffer == NULL)
+ {
+ throw std::exception("Memory Error, ColorTransf::InitData");
+ }
+ NumConversions Conv;
+ int bytesread = 0;
+ int tmpB =Conv.ByteToInt(buffer, 0);
+ bytesread += 4;
+
+ int n = sizeof(tmpB);
+ //char *tmpC = DBG_NEW char[n] ;
+// char tmpC[sizeof((char*)&tmpB)];
+ char luttype[sizeof(tmpB)+1];
+ Conv.getchar(tmpB, *luttype);
+ //char *luttype = DBG_NEW char[n + 1];
+// strcpy(luttype,tmpC);
+ int TablePrecision;
+ if (strncmp(luttype, "prc1", sizeof(tmpB))==0)
+ TablePrecision = 1;
+ else if (strncmp(luttype, "prc2", sizeof(tmpB))==0)
+ TablePrecision = 2;
+ else
+ {
+ throw std::exception("Wrong precision in Color Tables");
+ return;
+ }
+
+ // Skip past reserved padding bytes
+ bytesread += 4;
+
+ uint8_t num_input_channels = buffer[ bytesread];
+ SetSeparationsIn((int)num_input_channels); //Numer of Separations In
+ bytesread += 1;
+ uint8_t num_output_channels = buffer[ bytesread];
+ SetSeparationsOut((int)num_output_channels); //Numer of Separations Out
+ bytesread += 1;
+ uint8_t num_clut_grid_points = buffer[ bytesread];
+ SetNGridpoints((int)num_clut_grid_points); //Number of Gridpoints
+ bytesread += 1;
+ uint8_t num_Sh4MSB = buffer[ bytesread];
+ bytesread += 1;
+ unsigned short checkMSB = 256 >> (num_Sh4MSB);
+ if (num_clut_grid_points != (checkMSB + 1))
+ {
+ throw std::exception("Wrong Number of MSB's, ColorTransf::InitData");
+ }
+ else
+ SetMSBShift((int)num_Sh4MSB); //Number of MSB's
+
+ unsigned short num_input_table_entries = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ Set_NumInputTableEntries((int)num_input_table_entries);
+
+ unsigned short num_output_table_entries = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ Set_NumOutputTableEntries((int)num_output_table_entries);
+ if(m_InputCurves == NULL)
+ m_InputCurves = new Interp[m_SeparationsIn];
+ double *xIn = new double[m_num_input_table_entries];
+ double *yIn = new double[m_num_input_table_entries];
+ //read Input tables
+ if (TablePrecision == 1)
+ {
+ double deltax = 255.0 / (m_num_input_table_entries - 1);
+ for (int i = 0; i < m_num_input_table_entries; ++i)
+ xIn[i] = deltax * i;
+
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ for (int j = 0; j < m_num_input_table_entries; ++j)
+ {
+ yIn[j] = buffer[bytesread];
+ bytesread += 1;
+ }
+ m_InputCurves[i].Init(xIn, yIn, m_num_input_table_entries);
+ }
+ }
+ else
+ {
+ double deltax = 65535.0 / (m_num_input_table_entries - 1);
+ for (int i = 0; i < m_num_input_table_entries; ++i)
+ xIn[i] = deltax * i;
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ for (int j = 0; j < m_num_input_table_entries; ++j)
+ {
+ yIn[j] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ }
+ m_InputCurves[i].Init(xIn, yIn, m_num_input_table_entries);
+ }
+ }
+
+ int clut_size = (int)pow(double(num_clut_grid_points), m_SeparationsIn)* m_SeparationsOut;
+ // lut8Type and lut16Type
+ if (TablePrecision == 1)
+ {
+// int lsizeH2 = (lSize - bytesread + 1) / 2;
+ if(m_ByteBuffer == NULL)
+ m_ByteBuffer = new unsigned char[clut_size];
+ int lSizeperSep = clut_size / m_SeparationsOut;
+ int indR = 0;
+ for (int i = 0; i < lSizeperSep; ++i)
+ {
+ for (int j = 0; j < m_SeparationsOut; ++j)
+ {
+ //m_ByteBuffer[indR] = Conv.ByteToShort(buffer, bytesread);
+ m_ByteBuffer[indR] = buffer[bytesread];
+ bytesread += 1;
+ indR++;
+ }
+ }
+ m_InterpColor.InitData(m_ByteBuffer, m_SeparationsIn, m_SeparationsOut, m_nGridPoints, m_MSBShift);
+ }
+ else
+ {
+// int lsizeH4 = (lSize - bytesread + 1) / 2;
+ if(m_DataBuffer == NULL)
+ m_DataBuffer = new unsigned short[clut_size];
+ //m_DataBuffer = DBG_NEW unsigned short[lsizeH4];
+ int lSizeperSep = clut_size / m_SeparationsOut;
+ int indR = 0;
+ for (int i = 0; i < lSizeperSep; ++i)
+ {
+ for (int j = 0; j < m_SeparationsOut; ++j)
+ {
+ m_DataBuffer[indR] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ indR++;
+ }
+ }
+ // terminate reading data file
+ m_InterpColor.InitData(m_DataBuffer, m_SeparationsIn, m_SeparationsOut, m_nGridPoints, m_MSBShift);
+ }
+
+ //Read Output Curves
+ double *xOut = new double[m_num_output_table_entries];
+ double *yOut = new double[m_num_output_table_entries];
+ if(m_OutputCurves == NULL)
+ m_OutputCurves = new Interp[m_SeparationsOut];
+ //read Input tables
+ if (TablePrecision == 1)
+ {
+ double deltax = 255.0 / (m_num_output_table_entries - 1);
+ for (int i = 0; i < m_num_output_table_entries; ++i)
+ xOut[i] = deltax * i;
+
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ for (int j = 0; j < m_num_output_table_entries; ++j)
+ {
+ yOut[j] = buffer[bytesread];
+ bytesread += 1;
+ }
+ m_OutputCurves[i].Init(xOut, yOut, m_num_output_table_entries);
+ }
+ }
+ else
+ {
+ double deltax = 65535.0 / (m_num_output_table_entries - 1);
+ for (int i = 0; i < m_num_output_table_entries; ++i)
+ xOut[i] = deltax * i;
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ for (int j = 0; j < m_num_output_table_entries; ++j)
+ {
+ yOut[j] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ }
+ m_OutputCurves[i].Init(xOut, yOut, m_num_output_table_entries);
+ }
+ }
+ //clean up
+ if (xIn != NULL)
+ {
+ delete[] xIn;
+ xIn = NULL;
+ }
+ if (yIn != NULL)
+ {
+ delete[] yIn;
+ yIn = NULL;
+ }
+ if (xOut != NULL)
+ {
+ delete[] xOut;
+ xOut = NULL;
+ }
+ if (yOut != NULL)
+ {
+ delete[] yOut;
+ yOut = NULL;
+ }
+
+ return;
+ }
+
+void ColorTransf::SetGamutLimitsNlperCM(double *GamutLimitsNlperCM)
+{
+ //m_GamutLimitsNlperCM = DBG_NEW double[m_NGamutRegions];
+ if(m_GamutLimitsNlperCM == NULL)
+ m_GamutLimitsNlperCM = new double[m_NGamutRegions];
+
+ for (int i = 0; i < m_NGamutRegions; ++i)
+ m_GamutLimitsNlperCM[i] = GamutLimitsNlperCM[i];
+}
+
+void ColorTransf::evalLab2InkP(double *ColorIn, double *&ColorOut, int &GamutRegion)
+{
+ //double *tmpColorOut = new double[m_SeparationsOut];
+ C_RGB_XYZ_Lab tmpColorOut;
+ tmpColorOut = tmpColorOut.labdouble_to_labuint16(ColorIn);
+ /*Convert ColorIn to uint16 */
+ uint16_t *iColorIn = new uint16_t[m_SeparationsIn];
+ //uint16_t *iColorIn = DBG_NEW uint16_t[m_SeparationsIn];
+ iColorIn[0] = uint16_t(tmpColorOut.Get_x());
+ iColorIn[1] = uint16_t(tmpColorOut.Get_y());
+ iColorIn[2] = uint16_t(tmpColorOut.Get_z());
+ double *tmpColor = new double[m_SeparationsOut];
+ //double *tmpColor = DBG_NEW double[m_SeparationsIn];
+ double tmpIC = 0;
+ //Aply Input Curves
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ m_InputCurves[i].Eval((double)iColorIn[i], tmpIC);
+ iColorIn[i] = (unsigned short)tmpIC;
+ }
+ if (m_SeparationsIn == 3)
+ m_InterpColor.ColorMap3(iColorIn, tmpColor);
+ else if (m_SeparationsIn == 4)
+ {
+ m_InterpColor.ColorMap4(iColorIn, tmpColor);
+ }
+ else
+ throw std::exception("Unsupported Number of Separations in ColorTransf::evalLab2Ink");
+ //Appy Output Curves
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ m_OutputCurves[i].Eval((double)tmpColor[i], tmpIC);
+ tmpColor[i] = (unsigned short)tmpIC;
+ }
+ //tmpColorOut between 0and 255
+ //normalize to [0-100]
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ ColorOut[i] = tmpColor[i] * InkFactor / Uint16Factor;
+ ColorOut[i] = min(max(ColorOut[i], 0.0), 100.0);
+ }
+ GamutRegion = 0;
+ if(iColorIn !=NULL)
+ {
+ delete[] iColorIn;
+ iColorIn = NULL;
+ }
+ if (tmpColor != NULL)
+ {
+ delete[] tmpColor;
+ tmpColor = NULL;
+ }
+
+ return;
+}
+
+void ColorTransf::evalInCurve(double *ColorIn, double *&ColorOut)
+{
+ //To be used to transform Nonlinear Inks to Linear with m_A2B transform
+
+ /*Convert ColorIn to uint16 */
+ uint16_t *iColorIn = new uint16_t[m_SeparationsIn];
+ //uint16_t *iColorIn = DBG_NEW uint16_t[m_SeparationsIn];
+ double tmpIC = 0;
+ double tmpVal = 0.0;
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ //convert to 16 bits
+ tmpVal = double(ColorIn[i] / InkFactor)*Uint16Factor;
+ tmpVal = min(max(tmpVal, 0.0), double(Uint16Factor));
+ iColorIn[i] = uint16_t(tmpVal);
+ //Aply Input Curves
+ m_InputCurves[i].Eval((double)iColorIn[i], tmpIC);
+ ColorOut[i] = tmpIC * InkFactor / Uint16Factor;
+ ColorOut[i] = min(max(ColorOut[i], 0.0), double(InkFactor));
+ }
+
+ if (iColorIn != NULL)
+ {
+ delete[] iColorIn;
+ iColorIn = NULL;
+ }
+
+ return;
+}
+
+void ColorTransf::evalOutCurve(double *ColorIn, double *&ColorOut)
+{
+ //To be used to transform Linear Inks to Nonlinear with m_B2A transform
+
+ /*Convert ColorIn to uint16 */
+ uint16_t *iColorIn = new uint16_t[m_SeparationsOut];
+ //uint16_t *iColorIn = DBG_NEW uint16_t[m_SeparationsIn];
+ double tmpIC = 0;
+ double tmpVal = 0.0;
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ //convert to 16 bits
+ tmpVal = double(ColorIn[i] / InkFactor)*Uint16Factor;
+ tmpVal = min(max(tmpVal, 0.0), double(Uint16Factor));
+ iColorIn[i] = uint16_t(tmpVal);
+ //Aply Output Curves
+ m_OutputCurves[i].Eval((double)iColorIn[i], tmpIC);
+ ColorOut[i] = tmpIC * InkFactor / Uint16Factor;
+ ColorOut[i] = min(max(ColorOut[i], 0.0), double(InkFactor));
+ }
+
+ if (iColorIn != NULL)
+ {
+ delete[] iColorIn;
+ iColorIn = NULL;
+ }
+
+ return;
+}
+
+
+void ColorTransf::evalInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutRegion)
+{
+ double *tmpColorOut = new double[m_SeparationsOut];
+ //double *tmpColorOut = DBG_NEW double[m_SeparationsOut];
+ /*Convert ColorIn to uint16 */
+ uint16_t *iColorIn = new uint16_t[m_SeparationsIn];
+ //uint16_t *iColorIn = DBG_NEW uint16_t[m_SeparationsIn];
+ double tmpIC = 0;
+ double tmpVal = 0.0;
+ //convert to 16 bits
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ tmpVal = min(max(double(ColorIn[i] / InkFactor)*Uint16Factor, 0.0), double(Uint16Factor));
+ iColorIn[i] = uint16_t(tmpVal);
+ }
+
+ //Aply Input Curves
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ m_InputCurves[i].Eval((double)iColorIn[i], tmpIC);
+ iColorIn[i] = (unsigned short)tmpIC;
+ }
+
+ if (m_SeparationsIn == 3)
+ m_InterpColor.ColorMap3(iColorIn, tmpColorOut); // return Value is double in units of 16 bits
+ else if (m_SeparationsIn == 4)
+ m_InterpColor.ColorMap4(iColorIn, tmpColorOut); // return value is double in units on 16 bits
+ else
+ throw std::exception("Unsupported Number of Separations in ColorTransf::evalInkP2Lab");
+ //Appy Output Curves
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ tmpColorOut[i] = min(max(tmpColorOut[i], 0.0), double(Uint16Factor));
+ m_OutputCurves[i].Eval((double)tmpColorOut[i], tmpIC);
+ tmpColorOut[i] = (unsigned short)tmpIC;
+ tmpColorOut[i] = min(max(tmpColorOut[i], 0.0), double(Uint16Factor));
+ }
+
+ //Normalize to Lab Space
+ C_RGB_XYZ_Lab tmpLabOut;
+ uint16_t int16ColorOut[3];
+ for (int i=0; i<3; ++i)
+ int16ColorOut[i] = (uint16_t )(tmpColorOut[i]);
+ tmpLabOut = tmpLabOut.labuint16_to_labdouble(int16ColorOut);
+ ColorOut[0] = tmpLabOut.Get_x();
+ ColorOut[1] = tmpLabOut.Get_y();
+ ColorOut[2] = tmpLabOut.Get_z();
+ //GamutRegion = 0;
+ if (iColorIn != NULL)
+ {
+ delete[] iColorIn;
+ iColorIn = NULL;
+ }
+ if (tmpColorOut != NULL)
+ {
+ delete[] tmpColorOut;
+ tmpColorOut = NULL;
+ }
+
+ return;
+}
+
+void ColorTransf::evalLinearInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutRegion)
+{
+ double *tmpColorOut = new double[m_SeparationsOut];
+ //double *tmpColorOut = DBG_NEW double[m_SeparationsOut];
+ /*Convert ColorIn to uint16 */
+ uint16_t *iColorIn = new uint16_t[m_SeparationsIn];
+ //uint16_t *iColorIn = DBG_NEW uint16_t[m_SeparationsIn];
+ double tmpIC = 0;
+ double tmpVal = 0.0;
+ //convert to 16 bits
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ tmpVal = min(max(double(ColorIn[i] / InkFactor)*Uint16Factor, 0.0), double(Uint16Factor));
+ iColorIn[i] = uint16_t(tmpVal);
+ }
+
+ //Do not apply Input Curves
+
+ if (m_SeparationsIn == 3)
+ m_InterpColor.ColorMap3(iColorIn, tmpColorOut); // return Value is double in units of 16 bits
+ else if (m_SeparationsIn == 4)
+ m_InterpColor.ColorMap4(iColorIn, tmpColorOut); // return value is double in units on 16 bits
+ else
+ throw std::exception("Unsupported Number of Separations in ColorTransf::evalInkP2Lab");
+ //Limit Values, do not apply Output Curves
+ for (int i = 0; i < m_SeparationsOut; ++i)
+ {
+ tmpColorOut[i] = min(max(tmpColorOut[i], 0.0), double(Uint16Factor));
+ }
+
+ //Normalize to Lab Space
+ C_RGB_XYZ_Lab tmpLabOut;
+ uint16_t int16ColorOut[3];
+ for (int i = 0; i < 3; ++i)
+ int16ColorOut[i] = (uint16_t)(tmpColorOut[i]);
+ tmpLabOut = tmpLabOut.labuint16_to_labdouble(int16ColorOut);
+ ColorOut[0] = tmpLabOut.Get_x();
+ ColorOut[1] = tmpLabOut.Get_y();
+ ColorOut[2] = tmpLabOut.Get_z();
+ //GamutRegion = 0;
+ if (iColorIn != NULL)
+ {
+ delete[] iColorIn;
+ iColorIn = NULL;
+ }
+ if (tmpColorOut != NULL)
+ {
+ delete[] tmpColorOut;
+ tmpColorOut = NULL;
+ }
+
+ return;
+}
+
+/* __declspec(dllexport) int ColorTransf::evalCMY2RGB(double *ColorIn, double *ColorOut)
+ {
+ //Assumption: ColorIn is in the interval [0,100]
+ double *tmpColorOut = new double[m_SeparationsIn]; //dimension of RGB
+ //Apply nonlinear transformation convert to linear, inks are in nonlinear space
+ double LinTmp = -1;
+ int ret = evalLinSingleCurve(m_CalCyan, m_nCalCyan, ColorIn[0], &LinTmp);
+ tmpColorOut[0] = LinTmp;
+ ret = evalLinSingleCurve(m_CalMagenta, m_nCalMagenta, ColorIn[1], &LinTmp);
+ tmpColorOut[1] = LinTmp;
+ ret = evalLinSingleCurve(m_CalYellow, m_nCalYellow, ColorIn[2], &LinTmp);
+ tmpColorOut[2] = LinTmp;
+ //tmpColorOut is in the [0,100] interval
+
+ //Convert tmpColorOut to unsigned char
+ unsigned char *iColorOut = new unsigned char[m_SeparationsIn];
+ for (int i = 0; i < m_SeparationsIn; ++i)
+ {
+ iColorOut[i] = (unsigned char)(fmin(fmax(round(tmpColorOut[i] * 2.55), 0), 255));
+ }
+ if (m_SeparationsIn == 3)
+ m_InterpColor.ColorMap3(iColorOut, ColorOut);
+ else if (m_SeparationsIn == 4)
+ m_InterpColor.ColorMap4(iColorOut, ColorOut);
+
+ delete[] iColorOut;
+ delete[] tmpColorOut;
+ return(0);
+ }
+*/ \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.h
new file mode 100644
index 000000000..e61135dae
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ColorTransf.h
@@ -0,0 +1,55 @@
+#ifndef _COLORTRANSF_H_
+#define _COLORTRANSF_H_
+
+#include <stdlib.h>
+#include "NDInterpUtils.h"
+#include "Interp.h"
+
+class ColorTransf {
+public:
+ ColorTransf();
+ ~ColorTransf();
+ int GetNGridPoints() { return(m_nGridPoints); };
+ int GetSeparationsIn() { return(m_SeparationsIn); };
+ int GetSeparationsOut() { return(m_SeparationsOut); };
+ int GetMSBShift() { return(m_MSBShift); };
+ void evalLab2InkP(double *ColorIn, double *&ColorOut, int &GamutRegion);
+ void evalInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutRegion);
+ void evalLinearInkP2Lab(double *ColorIn, double *&ColorOut, int &GamutRegion);
+ void evalInCurve(double *ColorIn, double *&ColorOut);
+ void evalOutCurve(double *ColorIn, double *&ColorOut);
+// int evalCMY2RGB(double *ColorIn, double *ColorOut);
+ void InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize);
+private:
+ int m_MSBShift;
+ int m_SeparationsIn;
+ int m_SeparationsOut;
+ int m_nGridPoints;
+ int m_num_input_table_entries;
+ int m_num_output_table_entries;
+ double *m_GamutLimitsNlperCM;
+ int m_NGamutRegions;
+
+ NDInterpUtils m_InterpColor;
+ Interp *m_InputCurves;
+ Interp *m_OutputCurves;
+ void free_char_array(char* charname);
+
+ unsigned short *m_DataBuffer;
+ unsigned char *m_ByteBuffer;
+
+ void SetNGridpoints(int nGridPoints) { m_nGridPoints = nGridPoints; };
+ void SetSeparationsIn(int SeparationsIn) { m_SeparationsIn = SeparationsIn; };
+ void SetSeparationsOut(int SeparationsOut) { m_SeparationsOut = SeparationsOut; };
+ void SetMSBShift(int MSBShift) { m_MSBShift = MSBShift; };
+ void Set_NumInputTableEntries(int num_input_table_entries) {
+ m_num_input_table_entries = num_input_table_entries;
+ };
+ void Set_NumOutputTableEntries(int num_output_table_entries) {
+ m_num_output_table_entries = num_output_table_entries;
+ };
+ //void SetNGamutRegions(int NGamutRegions) {m_NGamutRegions = NGamutRegions;};
+ void SetGamutLimitsNlperCM(double *GamutLimitsNlperCM);
+};
+
+#endif
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.cpp
new file mode 100644
index 000000000..4efd460ae
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.cpp
@@ -0,0 +1,155 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+#include "Curves.h"
+#include <iostream>
+#include <stdio.h>
+#include "NumConversions.h"
+#include "C_RGB_XYZ_Lab.h"
+
+using namespace std;
+
+Curves::Curves() :
+ m_prec(0), m_nChannels(0),
+ m_nEntries(0), m_InterpCurves(NULL),
+ m_InvInterpCurves(NULL)
+{
+
+}
+
+Curves::~Curves()
+{
+ if (m_InterpCurves != NULL)
+ {
+ delete[] m_InterpCurves;
+ m_InterpCurves = NULL;
+ }
+ if (m_InvInterpCurves != NULL)
+ {
+ delete[] m_InvInterpCurves;
+ m_InvInterpCurves = NULL;
+ }
+
+}
+
+void Curves::InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize)
+{
+ // 0-3 prec
+ //4-7 reserved, must be 0
+ // 8-9 number of channels, uint8
+ // 10-11 number of entry points, uint16
+ // 12-n data
+
+ if (colorTransformFileSize < 32)
+ {
+ throw std::exception("Init Curves, invalid size");
+ }
+
+ // Check for signature
+ unsigned char *buffer = colorTransformBuffer;
+ if (buffer == NULL)
+ {
+ throw std::exception("Memory Error, ColorTransf::InitData");
+ }
+ NumConversions Conv;
+
+ int bytesread = 0;
+ int tmpB = Conv.ByteToInt(buffer, 0);
+ bytesread += 4;
+
+ //char *tmpC = DBG_NEW char[n] ;
+// char tmpC[sizeof((char*)&tmpB)];
+ //char Curvetype[sizeof((char*)&tmpB)+1];
+ char Curvetype[sizeof(tmpB) + 1];
+ Conv.getchar(tmpB, *Curvetype);
+ //char *luttype = DBG_NEW char[n + 1];
+// strcpy(Curvetype, tmpC);
+ int TablePrecision;
+ if (strncmp(Curvetype, "prc1", sizeof(tmpB)) == 0)
+ TablePrecision = 1;
+ else if (strncmp(Curvetype, "prc2", sizeof(tmpB)) == 0)
+ TablePrecision = 2;
+ else
+ {
+ throw std::exception("Wrong precision in Color Tables");
+ return;
+ }
+
+
+ // Skip past reserved padding bytes
+ bytesread += 4;
+
+ uint8_t num_channels = buffer[bytesread];
+ Set_nChannels((int)num_channels); //Numer of channels
+ bytesread += 1;
+ unsigned short nEntries = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ Set_nEntries((int)nEntries);
+ if(m_InterpCurves == NULL)
+ m_InterpCurves = new Interp[m_nChannels];
+ if (m_InvInterpCurves == NULL)
+ m_InvInterpCurves = new Interp[m_nChannels];
+ double *xIn = new double[m_nEntries];
+ double *yIn = new double[m_nEntries];
+ //read Input tables
+ if (TablePrecision == 1)
+ {
+ double deltax = 255.0 / (m_nEntries - 1);
+ for (int i = 0; i < m_nEntries; ++i)
+ xIn[i] = deltax *(double)i;
+
+ for (int i = 0; i < m_nChannels; ++i)
+ {
+ for (int j = 0; j <m_nEntries; ++j)
+ {
+ yIn[j] = (double)(buffer[bytesread]);
+ bytesread += 1;
+ }
+ m_InterpCurves[i].Init(xIn, yIn, m_nEntries);
+ m_InvInterpCurves[i].Init(yIn, xIn, m_nEntries);
+ }
+ }
+ else
+ {
+ double deltax = (double)65535.0 / (m_nEntries - 1);
+ for (int i = 0; i < nEntries; ++i)
+ xIn[i] = deltax * (double)i;
+ for (int i = 0; i < m_nChannels; ++i)
+ {
+ for (int j = 0; j < nEntries; ++j)
+ {
+ yIn[j] = (double)(Conv.ByteToShort(buffer, bytesread));
+ bytesread += 2;
+ }
+ m_InterpCurves[i].Init(xIn, yIn, nEntries);
+ m_InvInterpCurves[i].Init(yIn, xIn, nEntries);
+ }
+ }
+ if (xIn != NULL)
+ {
+ delete[] xIn;
+ xIn = NULL;
+ }
+ if (yIn != NULL)
+ {
+ delete[] yIn;
+ yIn = NULL;
+ }
+
+
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.h
new file mode 100644
index 000000000..36f39181c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Curves.h
@@ -0,0 +1,24 @@
+#ifndef _Curves_H_
+#define _Curves_H_
+
+#include <stdlib.h>
+#include "C_RGB_XYZ_Lab.h"
+#include "Interp.h"
+class Curves {
+public:
+ Curves();
+ ~Curves();
+ int Get_nChannels() { return(m_nChannels); };
+ int Get_nEntries() { return(m_nEntries); };
+ void InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize);
+ Interp *m_InterpCurves;
+ Interp *m_InvInterpCurves;
+private:
+ int m_prec;
+ int m_nChannels;
+ int m_nEntries;
+ void Set_nChannels(int nChannels) { m_nChannels = nChannels; };
+ void Set_nEntries(int nEntries) { m_nEntries = nEntries; };
+};
+
+#endif
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.cpp
new file mode 100644
index 000000000..3e4f49878
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.cpp
@@ -0,0 +1,340 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+#include "GBD.h"
+#include <iostream>
+#include <stdio.h>
+#include "NumConversions.h"
+#include "C_RGB_XYZ_Lab.h"
+
+using namespace std;
+
+#define eps 1.0e-05
+#define dE_Tol 2.0
+#define LargeNumber 1.0e+10
+
+typedef enum {
+ TwoSided,
+ OneSided
+}RTRI;
+
+typedef enum {
+ Line,
+ Ray,
+ Segment
+}LineType;
+
+GBD::GBD() :
+ m_prec(0), m_nPCSChan(0),
+ m_nDevChan(0), m_CenterLab(0), m_nVertices(0), m_Vertices(NULL),
+ m_nTriangles(0), m_vert0(NULL), m_vert1(NULL), m_vert2(NULL)
+{
+
+}
+
+GBD::~GBD()
+{
+ if (m_vert0 != NULL)
+ {
+ for (int i = 0; i < m_nTriangles; ++i)
+ delete[] m_vert0[i];
+ delete[] m_vert0;
+ m_vert0 = NULL;
+ }
+ if (m_vert1 != NULL)
+ {
+ for (int i = 0; i < m_nTriangles; ++i)
+ delete[] m_vert1[i];
+ delete[] m_vert1;
+ m_vert1 = NULL;
+ }
+ if (m_vert2 != NULL)
+ {
+ for (int i = 0; i < m_nTriangles; ++i)
+ delete[] m_vert2[i];
+ delete[] m_vert2;
+ m_vert2 = NULL;
+ }
+ if (m_Vertices != NULL)
+ {
+ delete[] m_Vertices;
+ m_Vertices = NULL;
+ }
+
+}
+
+void GBD::TriangleRayIntersection(double *origin, double *direction, bool &intersect, double *xCoor)
+{
+ int i, j;
+
+ RTRI rtri = TwoSided;
+ LineType lt = Segment;
+ bool ok = false;
+ double border = eps;
+ double t = LargeNumber;
+ double u = t;
+ double v = t;
+ //double *edge1 = new double[3];
+ //double *edge2 = new double[3];
+ VectorXd tvec(3);
+ VectorXd qvec(3);
+ VectorXd pvec(3);
+ VectorXd edge1(3);
+ VectorXd edge2(3);
+ VectorXd VDirection(3);
+ VDirection << direction[0], direction[1], direction[2];
+ //double *tvec = new double[3]; // vector from vert0 to ray origin
+ //double *pvec = new double[3];
+ //double *qvec = new double[3];
+ double det = 0;
+ bool angleOK = false;
+ for (i = 0; i < m_nTriangles; ++i)
+ {
+ for (j = 0; j < 3; ++j)
+ {
+ edge1(j)= m_vert1[i][j] - m_vert0[i][j];
+ edge2(j) = m_vert2[i][j] - m_vert0[i][j];
+ tvec(j) = origin[j] - m_vert0[i][j];
+ }
+ crossProduct(VDirection, edge2, pvec);
+ det = dotProduct(edge1, pvec);
+ // std::cout << "edge1 " << edge1(0) <<" "<< edge1(1) <<" "<< edge1(2) << "\n";
+ // std::cout << "edge2 " << edge2(0) << " " << edge2(1) << " " << edge2(2)<< "\n";
+ // std::cout << "tvec " << tvec(0) << " " << tvec(1) << " " << tvec(2) << "\n";
+ // std::cout << "crossProduct " << pvec(0) << " " << pvec(1) << " " << pvec(2)<< "\n";
+ // std::cout << "Det " << det << "\n";
+
+ switch (rtri)
+ {
+ case TwoSided:
+ if (std::abs(det) > eps)
+ angleOK = true;
+ break;
+ case OneSided:
+ if (det > eps)
+ angleOK = true;
+ break;
+ default:
+ throw std::exception("Wrong Parameterin Ray-TriageIntersetion");
+ }
+ //determinant GT 0
+ if (std::abs(det) > eps)
+ {
+ u = dotProduct(tvec, pvec) / det;
+ crossProduct(tvec, edge1, qvec);
+ v = dotProduct(VDirection, qvec) / det;
+ t = dotProduct(edge2, qvec) / det;
+ ok = (angleOK && (u >= -eps) && (v >= -eps) && ((u + v) <= 1 + eps));
+ // std::cout << "u " << u << "\n";
+ // std::cout << "v " << v << "\n";
+ // std::cout << "Qvec " << qvec(0) << " " << qvec(1) << " " << qvec(2) << "\n";
+ // std::cout << "t " << t << "\n";
+ // std::cout << "OK " << ok << "\n";
+ }
+ else
+ ok = false;
+
+ switch (lt)
+ {
+ case Line:
+ intersect = ok;
+ break;
+ case Ray:
+ intersect = ok && (t >= -eps);
+ break;
+ case Segment:
+ intersect = ok && (t >= -eps) && (t <= 1 + eps);
+ break;
+ default:
+ throw std::exception("Wrong Line Type");
+ break;
+ }
+ if (intersect)
+ {
+ for (j = 0; j < 3; ++j)
+ xCoor[j] = m_vert0[i][j] + edge1(j) * u + edge2(j) * v;
+ return;
+ }
+ }
+
+ return;
+}
+
+void GBD::InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize)
+{
+ // 0-3 prec
+ //4-7 reserved, must be 0
+ // 8-9 number of vertices, uint16
+ // 10-11 number of triangles, uint16
+ // 12 number of PCS Channels, uint8
+ // 13 number of device channels (0, no device data)
+ // prec 2 (16bit)
+ // 14-n triangle vertices arranged as vert0 -> vert1->vert2
+ // each vert is a matrix of size (number of vertices)x3
+ // Gamut is stored in Ciecam02 color space
+ // prec 1
+ // 14-n CLUT values, uint8
+
+ if (colorTransformFileSize < 32)
+ {
+ throw std::exception("Init GB, invalid size");
+ }
+
+ // Check for signature
+ unsigned char *buffer = colorTransformBuffer;
+ if (buffer == NULL)
+ {
+ throw std::exception("Memory Error, ColorTransf::InitData");
+ }
+
+ int i, j;
+ NumConversions Conv;
+ int bytesread = 0;
+ int tmpB = Conv.ByteToInt(buffer, 0);
+ bytesread += 4;
+
+ int n = sizeof(tmpB);
+ //char *tmpC = DBG_NEW char[n];
+ //char tmpC[sizeof((char*)&tmpB)];
+ char tableType[sizeof(tmpB)+1];
+ Conv.getchar(tmpB, *tableType);
+ //char *tableType = DBG_NEW char[n + 1];
+// strcpy(tableType, tmpC);
+
+ int TablePrecision;
+ if (strncmp(tableType, "prc1", sizeof(tmpB)) == 0)
+ TablePrecision = 1;
+ else if (strncmp(tableType, "prc2", sizeof(tmpB)) == 0)
+ TablePrecision = 2;
+ else
+ {
+ throw std::exception("Wrong precision in gbd tables");
+ return;
+ }
+
+ // Skip past reserved padding bytes
+ bytesread += 4;
+ uint16_t num_gbd_points = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ SetNVertices((int)num_gbd_points);
+ uint16_t num_triangles = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ SetNTriangles((int)num_triangles);
+ uint8_t num_PCSChan = buffer[bytesread];
+ bytesread += 1;
+ SetNPCS_Channels((int)num_PCSChan);
+ bytesread += 1;
+ uint8_t num_DevChan = buffer[bytesread];
+ SetNDev_Channels((int)num_DevChan);
+ uint16_t ILab[3];
+ for (j = 0; j < 3; ++j)
+ {
+ ILab[j] = (uint16_t)Conv.ByteToInt(buffer, bytesread);
+ bytesread += 4;
+ }
+ C_RGB_XYZ_Lab tmpCenter;
+ m_CenterLab = tmpCenter.labuint16_to_labdouble(ILab);
+
+ // lut8Type and lut16Type
+ int remsize = colorTransformFileSize - bytesread;
+ int Bsize = (int)((int)(num_gbd_points) * (int)num_PCSChan);
+ if (remsize != Bsize * (int)TablePrecision)
+ {
+ throw std::exception("GBD size missmatch");
+ return;
+ }
+
+ if(m_vert0 == NULL)
+ m_vert0 = new double*[m_nTriangles];
+ if (m_vert1 == NULL)
+ m_vert1 = new double*[m_nTriangles];
+ if (m_vert2 == NULL)
+ m_vert2 = new double*[m_nTriangles];
+
+ /*m_vert0 = DBG_NEW double*[m_nTriangles];
+ m_vert1 = DBG_NEW double*[m_nTriangles];
+ m_vert2 = DBG_NEW double*[m_nTriangles];*/
+ uint16_t tmp[3];
+ C_RGB_XYZ_Lab tmp1;
+ for (i = 0; i < m_nTriangles; ++i)
+ {
+ m_vert0[i] = new double[m_nPCSChan];
+ //m_vert0[i] = DBG_NEW double[m_nPCSChan];
+ for (j = 0; j < m_nPCSChan; ++j)
+ {
+ tmp[j] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ }
+ tmp1 = tmp1.labuint16_to_labdouble(tmp);
+ m_vert0[i][0] = tmp1.Get_x();
+ m_vert0[i][1] = tmp1.Get_y();
+ m_vert0[i][2] = tmp1.Get_z();
+ }
+ for (i = 0; i < m_nTriangles; ++i)
+ {
+ m_vert1[i] = new double[m_nPCSChan];
+ //m_vert1[i] = DBG_NEW double[m_nPCSChan];
+
+ for (j = 0; j < m_nPCSChan; ++j)
+ {
+ tmp[j] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ }
+ tmp1 = tmp1.labuint16_to_labdouble(tmp);
+ m_vert1[i][0] = tmp1.Get_x();
+ m_vert1[i][1] = tmp1.Get_y();
+ m_vert1[i][2] = tmp1.Get_z();
+ }
+ for (i = 0; i < m_nTriangles; ++i)
+ {
+ m_vert2[i] = new double[m_nPCSChan];
+ //m_vert2[i] = DBG_NEW double[m_nPCSChan];
+ for (j = 0; j < m_nPCSChan; ++j)
+ {
+ tmp[j] = Conv.ByteToShort(buffer, bytesread);
+ bytesread += 2;
+ }
+ tmp1 = tmp1.labuint16_to_labdouble(tmp);
+ m_vert2[i][0] = tmp1.Get_x();
+ m_vert2[i][1] = tmp1.Get_y();
+ m_vert2[i][2] = tmp1.Get_z();
+ }
+}
+
+
+// dot product of two vectors.
+double GBD::dotProduct(VectorXd vect_A, VectorXd vect_B)
+{
+ double product = 0.0;
+ // Loop for calculate dot product
+
+ int n = vect_A.size();
+ for (int i = 0; i < n; i++)
+ product = product + vect_A(i) * vect_B(i);
+ return (product);
+}
+
+
+// cross product of two vectors
+void GBD::crossProduct(VectorXd vect_A, VectorXd vect_B, VectorXd &cross_P)
+{
+ cross_P(0) = vect_A(1) * vect_B(2) - vect_A(2) * vect_B(1);
+ cross_P(1) = -vect_A(0) * vect_B(2) + vect_A(2) * vect_B(0);
+ cross_P(2) = vect_A(0) * vect_B(1) - vect_A(1) * vect_B(0);
+ return;
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.h
new file mode 100644
index 000000000..61aadf37a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/GBD.h
@@ -0,0 +1,38 @@
+#ifndef _GBD_H_
+#define _GBD_H_
+
+#include <stdlib.h>
+#include "C_RGB_XYZ_Lab.h"
+
+class GBD {
+public:
+ GBD();
+ ~GBD();
+ int GetNVertices() { return(m_nVertices); };
+ int GetNPCS_Channels() { return(m_nPCSChan); };
+ int GetDev_Channels() { return(m_nDevChan); };
+ int GetNTriangles() { return(m_nTriangles); };
+ C_RGB_XYZ_Lab getCenter(){ return(m_CenterLab);};
+ void InitData(unsigned char* colorTransformBuffer, long colorTransformFileSize);
+ void TriangleRayIntersection(double *origin, double *direction, bool &intersect, double *xCoor);
+private:
+ int m_prec;
+ int m_nDevChan;
+ int m_nPCSChan;
+ int m_nVertices;
+ int m_nTriangles;
+ C_RGB_XYZ_Lab m_CenterLab;
+ C_RGB_XYZ_Lab *m_Vertices;
+ double **m_vert0;
+ double **m_vert1;
+ double **m_vert2;
+ void SetNVertices(int nVertices) { m_nVertices = nVertices; };
+ void SetNPCS_Channels(int nPCSChan) { m_nPCSChan = nPCSChan; };
+ void SetNDev_Channels(int nDevChan) { m_nDevChan = nDevChan; };
+ void SetNTriangles(int nTriangles) { m_nTriangles = nTriangles; };
+ //void SetCenter( C_RGB_XYZ_Lab CenterLab);
+ double dotProduct(VectorXd vect_A, VectorXd vect_B);
+ void crossProduct(VectorXd vect_A, VectorXd vect_B, VectorXd &cross_P);
+};
+
+#endif
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.cpp
new file mode 100644
index 000000000..c2878d156
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.cpp
@@ -0,0 +1,45 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "Gradient.h"
+
+using namespace std;
+Gradient::Gradient() :
+ m_Lab(0), m_RGB(0),
+ m_Volume(NULL), m_GamutRegion(0), m_Offset(0.0), m_colorspace(COLOR_SPACE__RGB),
+ m_InGamut(true), m_CatalogInks(NULL)
+{
+
+}
+
+
+Gradient::~Gradient()
+{
+ if (m_Volume != NULL)
+ {
+ delete[] m_Volume;
+ m_Volume = NULL;
+ }
+ if (m_CatalogInks != NULL)
+ {
+ delete[] m_CatalogInks;
+ m_CatalogInks = NULL;
+ }
+}
+
+void Gradient::SetVolumeSize(int nchannels)
+{
+ if(m_Volume == NULL)
+ m_Volume = new double[nchannels];
+}
+
+void Gradient::SetVolumeValue(double val, int ind)
+{
+ m_Volume[ind] = val;
+}
+
+void Gradient::SetCatalogInkValues(double val, int ind)
+{
+ m_Volume[ind] = val;
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.h
new file mode 100644
index 000000000..92e66bb18
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Gradient.h
@@ -0,0 +1,39 @@
+#ifndef _GRADIENT_H_
+#define _GRADIENT_H_
+
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorSpace.pb-c.h"
+class Gradient {
+public:
+ Gradient();
+ ~Gradient();
+ int Get_GamutRegion() { return(m_GamutRegion); };
+ double Get_Offset() { return(m_Offset); };
+ ColorSpace Get_ColorSpace() {return(m_colorspace);};
+ C_RGB_XYZ_Lab Get_Lab() { return(m_Lab); };
+ C_RGB_XYZ_Lab Get_RGB() { return(m_RGB); };
+ bool Get_InGamut() { return(m_InGamut); };
+ void Set_GamutRegion(int GamutRegion) { m_GamutRegion = GamutRegion; };
+ void Set_Lab(C_RGB_XYZ_Lab Lab) { m_Lab = Lab; };
+ void Set_RGB(C_RGB_XYZ_Lab RGB) { m_RGB = RGB; };
+ void Set_Offset(double Offset) { m_Offset = Offset; };
+ void Set_ColorSpace(ColorSpace colorspace) { m_colorspace = colorspace; };
+ void SetVolumeSize(int nchannels);
+ void SetVolumeValue(double val, int ind);
+ void SetInGamut(bool InGamut) { m_InGamut = InGamut; };
+ void SetCatalogInkValues(double val, int ind);
+ void SetInRGBLimits(bool InRGBLimits) { m_InRGBLimits = InRGBLimits; };
+ bool Get_InRGBLimits() { return(m_InRGBLimits); };
+private:
+ C_RGB_XYZ_Lab m_Lab;
+ C_RGB_XYZ_Lab m_RGB;
+ double *m_Volume;
+ int m_GamutRegion;
+ double m_Offset;
+ ColorSpace m_colorspace;
+ bool m_InGamut;
+ bool m_InRGBLimits;
+ double *m_CatalogInks;
+};
+
+#endif \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.cpp
new file mode 100644
index 000000000..ba66ca114
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.cpp
@@ -0,0 +1,127 @@
+#include "Interp.h"
+#include <cmath>
+#include <cstdlib>
+#include <cstdint>
+#include <iostream>
+#include <stdio.h>
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+#define epsTol 0.05
+
+Interp::Interp(void):m_xValues(NULL), m_yValues(NULL) , m_length(0)
+{
+}
+
+Interp::Interp(const Interp &rhs):m_xValues(NULL), m_yValues(NULL), m_length(0)
+{
+}
+
+Interp::~Interp()
+{
+ if (m_xValues != NULL)
+ {
+ delete[] m_xValues;
+ m_xValues = NULL;
+ }
+ if (m_yValues != NULL)
+ {
+ delete[] m_yValues;
+ m_yValues = NULL;
+ }
+}
+
+void Interp::Init(double *xValues, double *yValues, int nlength)
+{
+ m_length = nlength;
+ if (m_xValues == NULL)
+ //m_xValues = DBG_NEW double(m_length);
+ m_xValues = new double[m_length];
+ if (m_yValues == NULL)
+ //m_yValues = DBG_NEW double(m_length);
+ m_yValues = new double[m_length];
+
+ for (int i=0; i<m_length; ++i)
+ {
+ m_xValues[i] = double(xValues[i]);
+ m_yValues[i] = double(yValues[i]);
+ }
+}
+
+void Interp::Eval(double InValue, double &OutValue)
+{
+ int m, ind;
+ int errType = 0;
+
+ ind = -1;
+ //Check Bounds
+ if((InValue<m_xValues[0] - epsTol) || (InValue >m_xValues[m_length - 1] + epsTol))
+ throw std::exception("Interp Eval: Value out of Bounds");
+ if ((InValue > m_xValues[0] - epsTol) && (InValue < m_xValues[0]))
+ InValue = m_xValues[0];
+
+ if ((InValue > m_xValues[m_length - 1] ) && (InValue < m_xValues[m_length - 1]+ epsTol))
+ InValue = m_xValues[m_length - 1];
+
+ for (m = 0; m < m_length - 1; ++m)
+ {
+ if (m_xValues[m] <= InValue && m_xValues[m + 1] >= InValue)
+ {
+ ind = m;
+ break;
+ }
+ }
+ if (ind == -1)
+ {
+ throw std::exception ("Could not find interpolation interval");
+ }
+ OutValue = ((InValue - m_xValues[m])*m_yValues[m + 1] + (m_xValues[m + 1] - InValue)*m_yValues[m])
+ / (m_xValues[m + 1] - m_xValues[m]);
+ return;
+}
+
+void Interp::Eval(int InValue, int &OutValue)
+{
+ int m;
+ int errType = 0;
+ int ind = 0;
+ double d_InValue;
+
+ ind = -1;
+ d_InValue = (double)InValue;
+ //Check Bounds
+ if ((d_InValue<m_xValues[0] - epsTol) || (d_InValue >m_xValues[m_length - 1] + epsTol))
+ throw std::exception("Interp Eval: Value out of Bounds");
+ if ((d_InValue > m_xValues[0] - epsTol) && (d_InValue < m_xValues[0]))
+ d_InValue = m_xValues[0];
+
+ if ((d_InValue > m_xValues[m_length - 1]) && (d_InValue < m_xValues[m_length - 1] + epsTol))
+ d_InValue = m_xValues[m_length - 1];
+ for (m = 0; m < m_length - 1; ++m)
+ {
+ if (m_xValues[m] <= d_InValue && m_xValues[m + 1] >= d_InValue)
+ {
+ ind = m;
+ break;
+ }
+ }
+ if (ind == -1)
+ {
+ throw std::exception("Could not find interpolation interval");
+ }
+ OutValue= (int)round(((d_InValue - m_xValues[m])*m_yValues[m + 1] + (m_xValues[m + 1] - d_InValue)*m_yValues[m])
+ / (m_xValues[m + 1] - m_xValues[m]));
+ return;
+
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.h
new file mode 100644
index 000000000..eef16546e
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/Interp.h
@@ -0,0 +1,24 @@
+#ifndef __INTERP_H__
+#define __INTERP_H__
+
+class Interp
+{
+ public:
+ Interp(void);
+ Interp(const Interp &rhs);
+ ~Interp();
+ void Eval(double InValue, double &OutValue);
+ void Eval(int InValue, int &OutValue);
+ void Init(double *xValues, double *yValues, int nlength);
+ void SetXCoords(double* xCoords) {m_xValues = xCoords;};
+ void SetYCoords(double * yCoords) { m_yValues = yCoords; };
+ void SetNPoints(int npts) { m_length = npts; };
+ private:
+ double *m_xValues;
+ double* m_yValues;
+ int m_length;
+
+};
+#endif // __INTERP_H__
+
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.cpp
new file mode 100644
index 000000000..4d33ca9b9
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.cpp
@@ -0,0 +1,129 @@
+#include <cmath>
+#include "LULinearSolver.h"
+#include <stdio.h>
+
+LULinearSolver::LULinearSolver()
+{
+
+}
+
+LULinearSolver::~LULinearSolver()
+{
+
+}
+
+void LULinearSolver::LUBacksubstitution(double **a, int *indx, double *b, int nSize)
+{
+ int i, ii = 0, ip, j;
+ double sum;
+
+ for (i = 0; i < nSize; i++) {
+ ip = indx[i];
+ sum = b[ip];
+ b[ip] = b[i];
+ if (ii != 0) {
+ for (j = ii - 1; j < i; j++) {
+ sum -= a[i][j] * b[j];
+ }
+ }
+ else if (sum != 0.0) {
+ ii = i + 1;
+ }
+ b[i] = sum;
+ }
+ for (i = nSize - 1; i >= 0; i--) {
+ sum = b[i];
+ for (j = i + 1; j < nSize; j++) {
+ sum -= a[i][j] * b[j];
+ }
+ b[i] = sum / a[i][i];
+ }
+ return;
+}
+
+
+
+bool LULinearSolver::LUDecomposition(double **a, int *indx, int nSize)
+{
+ const double k_dTiny = 1.0e-20;
+ int i, imax = 0, j, k;
+ double d, big, dum, sum, temp;
+
+ double *vv = new double[nSize];
+ d = 1.0;
+ for (i = 0; i < nSize; i++) {
+ big = 0.0;
+ for (j = 0; j < nSize; j++) {
+ if ((temp = fabs(a[i][j])) > big) {
+ big = temp;
+ }
+ }
+ if (big == 0.0) {
+ // matrix is singular or nearly so
+ if (vv != NULL)
+ delete[] vv;
+ return (false);
+ }
+ vv[i] = 1.0 / big;
+ }
+ for (j = 0; j < nSize; j++) {
+ for (i = 0; i < j; i++) {
+ sum = a[i][j];
+ for (k = 0; k < i; k++) {
+ sum -= a[i][k] * a[k][j];
+ }
+ a[i][j] = sum;
+ }
+ big = 0.0;
+ for (i = j; i < nSize; i++) {
+ sum = a[i][j];
+ for (k = 0; k < j; k++) {
+ sum -= a[i][k] * a[k][j];
+ }
+ a[i][j] = sum;
+ if ((dum = vv[i] * fabs(sum)) >= big) {
+ big = dum;
+ imax = i;
+ }
+ }
+ if (j != imax) {
+ for (k = 0; k < nSize; k++) {
+ dum = a[imax][k];
+ a[imax][k] = a[j][k];
+ a[j][k] = dum;
+ }
+ d = -d;
+ vv[imax] = vv[j];
+ }
+ indx[j] = imax;
+ if (a[j][j] == 0.0) {
+ a[j][j] = k_dTiny;
+ }
+ if (j != nSize - 1) {
+ dum = 1.0 / (a[j][j]);
+ for (i = j + 1; i < nSize; i++) {
+ a[i][j] *= dum;
+ }
+ }
+ }
+ if (vv != NULL)
+ delete[] vv;
+ return(true);
+}
+
+
+
+// Solve linear system A.x=b based on L-U decomposition. A and b are destroyed in the process. x is returned in b.
+bool LULinearSolver::LUSolver(double **A, double *b, unsigned int nSize)
+{
+ int *indx = new int[nSize];
+ if (!LUDecomposition(A, indx, nSize)) {
+ if (indx != NULL)
+ delete[] indx;
+ return(false);
+ }
+ LUBacksubstitution(A, indx, b, nSize);
+ if (indx != NULL)
+ delete[] indx;
+ return(true);
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.h
new file mode 100644
index 000000000..c3d13be27
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LULinearSolver.h
@@ -0,0 +1,13 @@
+#ifndef __LULINEARSOLVER_H__
+#define __LULINEARSOLVER_H__
+
+class LULinearSolver
+{
+public:
+ LULinearSolver();
+ ~LULinearSolver();
+ void LUBacksubstitution(double **a, int *indx, double *b, int nSize);
+ bool LUDecomposition(double **a, int *indx, int nSize);
+ bool LUSolver(double **A, double *b, unsigned int nSize);
+};
+#endif // __LULINEARSOLVER_H__
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.cpp
new file mode 100644
index 000000000..865713737
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.cpp
@@ -0,0 +1,457 @@
+#include "LevMar.h"
+#include "C_RGB_XYZ_Lab.h"
+#include "ObjectiveFunction.h"
+#include "LULinearSolver.h"
+#include <cmath>
+#include <cstdlib>
+#include <cstdint>
+#include <iostream>
+#include <stdio.h>
+
+const double kLarge = 1e+20;
+const double kTiny = 1e-20;
+const double kIllegalValue = -1.0;
+const double kLimitFraction = (0.9);
+
+#define MaxNumIterations 100
+#define InitialLamda 0.001
+#define Delta 5.0E-4
+
+LevMar::LevMar(ObjectiveFunction *func) :
+ m_InitialLamda(0.001),
+ m_NData(0),
+ m_Delta(5.0E-4),
+ m_Epsilon(1.0E-1),
+ m_Iterations(0),
+ m_nFreeParams(0),
+ m_nFixedParams(0),
+ m_FreeParams(NULL),
+ m_FixedParams(NULL),
+ m_FreeParamIndex(NULL),
+ m_FixedParamIndex(NULL),
+ m_Params(NULL),
+ m_Ycalc(NULL),
+ m_YRef(NULL),
+ m_beta(NULL),
+ m_RHS(NULL),
+ m_alpha(NULL),
+ m_Matrix(NULL),
+ m_currentVec(NULL),
+ m_tryVec(NULL),
+ m_UpperBound(NULL),
+ m_LowerBound(NULL),
+ m_PartialDerivatives(NULL),
+ m_func(func),
+ m_LULS(NULL)
+{
+ SetMaxIterations(100); // useid in Minimization
+ SetTolerance(1.0E-6); // Convergence tolerance
+}
+
+
+LevMar::~LevMar()
+{
+ if (m_beta != NULL) {
+ delete[] m_beta;
+ m_beta = NULL;
+ }
+ if (m_RHS != NULL) {
+ delete[] m_RHS;
+ m_RHS = NULL;
+ }
+ if(m_alpha != NULL)
+ {
+ for (int i = 0; i < (int)m_nFreeParams; i++)
+ {
+ delete[] m_alpha[i];
+ }
+ delete[] m_alpha;
+ m_alpha = NULL;
+ }
+ if (m_Matrix != NULL)
+ {
+ for (int i = 0; i < (int)m_nFreeParams; i++)
+ {
+ delete[] m_Matrix[i];
+ }
+ delete[] m_Matrix;
+ m_Matrix = NULL;
+ }
+
+ if (m_Ycalc != NULL) {
+ delete[] m_Ycalc;
+ m_Ycalc = NULL;
+ }
+ if (m_Params != NULL) {
+ delete[] m_Params;
+ m_Params = NULL;
+ }
+ if (m_currentVec != NULL) {
+ delete[] m_currentVec;
+ m_currentVec = NULL;
+ }
+ if (m_tryVec != NULL) {
+ delete[] m_tryVec;
+ m_tryVec = NULL;
+ }
+ if (m_YRef != NULL) {
+ delete[] m_YRef;
+ m_YRef = NULL;
+ }
+ if (m_PartialDerivatives != NULL) {
+ for (int i = 0; i < (int)m_nFreeParams; i++)
+ delete[] m_PartialDerivatives[i];
+ delete[] m_PartialDerivatives;
+ m_PartialDerivatives = NULL;
+ }
+ if (m_LULS != NULL)
+ {
+ delete[] m_LULS;
+ m_LULS = NULL;
+ }
+}
+
+void LevMar::Init()
+{
+ //Set parameters
+ int i = 0;
+ m_nFreeParams = m_func->GetNumFreeParams();
+ m_nFixedParams = m_func->GetNumFixedParams();
+ m_FreeParams = NULL;
+ m_NData = m_func->GetNumOutResult();
+ m_Ycalc = new double[m_NData];
+ m_Params = new double[m_nFixedParams + m_nFreeParams];
+ m_FreeParamIndex = m_func->GetFreeParamsIndex();
+ m_FixedParamIndex = m_func->GetFixedParamsIndex();
+ m_LULS = new LULinearSolver();
+ //allocate work arrays
+ m_currentVec = new double[m_nFreeParams];
+ m_tryVec = new double[m_nFreeParams];
+ m_YRef = new double[m_NData];
+ //Upper and Lower Bounds
+#if 0
+ m_UpperBound = new double[m_numFreeParams];
+ m_LowerBound = new double[m_numFreeParams];
+#endif
+ // Partial Derivatives
+ m_PartialDerivatives = new double*[m_nFreeParams];
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ m_PartialDerivatives[i] = new double[m_NData];
+
+ m_UpperBound = m_func->GetUpperBound();
+ m_LowerBound = m_func->GetLowerBound();
+
+ m_beta = new double[m_nFreeParams];
+ m_RHS = new double[m_nFreeParams];
+ m_alpha = new double*[m_nFreeParams];
+ m_Matrix = new double*[m_nFreeParams];
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ m_alpha[i] = new double[m_nFreeParams];
+ m_Matrix[i] = new double[m_nFreeParams];
+ }
+}
+
+double LevMar::ResidualSumSquares()
+{
+ int i;
+ double fVal = 0.0; // objective function
+
+ // Limit Parameters to Upper and Lower Bounds
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ m_tryVec[i] = m_currentVec[i] + m_RHS[i]; //m_RHS contains the solution to the system of linear equations
+ //Check Lower Bound
+ if (m_tryVec[i] < m_LowerBound[i])
+ {
+ m_tryVec[i] = m_currentVec[i] - kLimitFraction * (m_currentVec[i] - m_LowerBound[i]);
+ m_RHS[i] = m_tryVec[i] - m_currentVec[i];
+ }
+ // Check Upper Bound
+ if (m_tryVec[i] > m_UpperBound[i])
+ {
+ m_tryVec[i] = m_currentVec[i] + kLimitFraction * (m_UpperBound[i] - m_currentVec[i]);
+ m_RHS[i] = m_tryVec[i] - m_currentVec[i];
+ }
+ }
+ //Set parameters values
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ m_Params[m_FreeParamIndex[i]] = m_tryVec[i];
+ m_func->EvaluateObjectiveFunction(m_Params, m_Ycalc);
+
+ for (i = 0; i < (int)m_NData; i++)
+ m_YRef[i] = m_Ycalc[i];
+
+ // Sum up squares
+ for (i = 0; i < (int)m_NData; i++)
+ fVal += m_Ycalc[i] * m_Ycalc[i];
+
+ return (fVal);
+}
+
+
+void LevMar::Eval_alpha_and_beta()
+{
+ int iRows, jCols, k;
+ double dx; //used to calculate the partial derivatives
+
+ // zero out matrix Alpha and Vector Beta
+ for (iRows = 0; iRows < (int)m_nFreeParams; iRows++)
+ {
+ for (jCols = 0; jCols < (int)m_nFreeParams; jCols++)
+ m_alpha[iRows][jCols] = 0.0;
+ m_beta[iRows] = 0.0;
+ }
+
+ // Calculate Partial Derivatives
+ for (iRows = 0; iRows < (int)m_nFreeParams; iRows++) {
+ // avoid upper and lower bounds
+ dx = fabs(m_currentVec[iRows] - m_LowerBound[iRows]) < fabs(m_UpperBound[iRows] - m_currentVec[iRows]) ?
+ m_Epsilon : -m_Epsilon;
+
+ for (jCols = 0; jCols < (int)m_nFreeParams; jCols++)
+ {
+ m_Params[jCols] = m_currentVec[jCols];
+ }
+ m_Params[iRows] += dx; // add dx to the ith parameter
+
+ m_func->EvaluateObjectiveFunction(m_Params, m_Ycalc);
+
+ // Calculate the derivative in the ith direction
+ for (k = 0; k < (int)m_NData; k++) {
+ m_PartialDerivatives[iRows][k] = (m_Ycalc[k] - m_YRef[k]) / dx; //Partial Derivative of individual Components
+ for (jCols = 0; jCols <= iRows; jCols++) { //Fill up the lower triangle
+ m_alpha[iRows][jCols] += m_PartialDerivatives[iRows][k] * m_PartialDerivatives[jCols][k]; //Sum up the elements
+ }
+ m_beta[iRows] -= m_PartialDerivatives[iRows][k] * m_YRef[k]; //Sum up the elements
+ }
+ } // iRows
+
+
+ // check for ill-behaved matrix components to avoid matrix-inversion problems
+ for (iRows = 0; iRows < (int)m_nFreeParams; iRows++) {
+ // ~zero slope = local minimum in this parameter
+ // --> set up mAlpha, mBeta for a ~zero-length parameter step
+ if (fabs(m_beta[iRows]) < kTiny) {
+ m_alpha[iRows][iRows] = 1.0;
+ }
+
+ // ~infinite slope = objective function is 'hypersensitive' to this parameter
+ // --> set up mAlpha, mBeta for parameter step that changes parameter value
+ // by one order of magnitude in the appropriate direction
+ if (fabs(m_beta[iRows]) > kLarge) {
+ m_beta[iRows] = ((m_beta[iRows] > 0.0 ? 10.0 : 0.1) - 1.0) * m_currentVec[iRows];
+ for (jCols = 0; jCols < iRows; ++jCols);
+ m_alpha[iRows][jCols] = 0.0;
+ m_alpha[iRows][iRows] = kIllegalValue;
+ }
+ }
+
+ // Complete the Upper triangular side of m_Alpha
+ for (iRows = 1; iRows < (int)m_nFreeParams; iRows++)
+ for (jCols = 0; jCols < iRows; jCols++)
+ m_alpha[jCols][iRows] = m_alpha[iRows][jCols];
+}
+
+double LevMar::IncreaseStep()
+{
+ int i;
+ //Calculate the angle between the Search Direction and Negative Gradient, if there is good agreement,
+ //the angle is zero and cos(angle)=1, set the stepsize factor 2,
+ //if there is no agreement, cos(angle) = -1,
+ //set the stepsize factor to 2*10^2, a very large step
+ double innerProd = 0.0;
+ double StepLength2 = 0.0;
+ double GradLength2 = 0.0;
+ double cos_angle;
+
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ StepLength2 += m_RHS[i] * m_RHS[i] * m_alpha[i][i];
+ GradLength2 += 4.0 * m_beta[i] * m_beta[i]/ m_alpha[i][i];
+ innerProd += m_RHS[i] * 2.0 * m_beta[i];
+ }
+ cos_angle = innerProd / sqrt(StepLength2 * GradLength2);
+
+ return (2.0 * pow(10.0, 1.0 - cos_angle));
+}
+
+
+double LevMar::ReduceStep(const double &d_f, const double &uphill, const double &downhill) const
+{
+// extend step by making lambda smaller according to how well f approximates
+// a quadratic;
+//calculate the reduction factor for lambda
+ int i, j;
+ double d_f_quadr_proj = 0.0; // d_f predicted by quadratic extrapolation
+ double match; // indicates deviation from quadratic shape
+
+ // check how well f matches a quadratic function over last step
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ d_f_quadr_proj += -2.0 * m_beta[i] * m_RHS[i];
+ for (j = 0; j < (int)m_nFreeParams; j++)
+ {
+ d_f_quadr_proj += m_alpha[i][j] * m_RHS[i] * m_RHS[j];
+ }
+ }
+
+ // match gains in significance as lambda-->small, i.e, for large steps
+ match = d_f_quadr_proj / d_f;
+ if (fabs(match) > 1.0)
+ {
+ match = 1.0 / match; // 0 < match <= 1
+ }
+
+ // decrease lambda according to--
+ // (1) how well the minimization went on average over the last few iterations
+ // (2) how well f approximates a quadratic over the last step
+ return (pow(downhill / uphill, -match));
+}
+
+
+double LevMar::MinimizationAlgorithm(double *FreeParams, double *FixedParams, unsigned int &n_iterations)
+{
+
+ int i, j;
+ double fmin = kLarge;
+ double fRSS;
+ double Lambda;
+ double uphill = 0.1, downhill = 1.0; // moving averages tracking recent history
+ double fbest = kLarge;
+ bool improved = true;
+ m_FreeParams = FreeParams;
+ m_FixedParams = FixedParams;
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ m_Params[m_FreeParamIndex[i]] = FreeParams[i];
+ for (i = 0; i < (int)m_nFixedParams; ++i)
+ m_Params[m_FixedParamIndex[i]] = FixedParams[i];
+
+ //Evaluate Function
+ m_Iterations = 0;
+//double funVal;
+// funVal = m_func->EvaluateObjectiveFunction(m_Params, m_Ycalc);
+
+// for (j = 0; j < (int)m_NData; j++)
+// m_YRef[j] = 0.0;
+
+ // Init Partial Derivatives
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ for (j = 0; j < (int)m_NData; j++)
+ m_PartialDerivatives[i][j] = 0;
+ }
+ // Init Alpha, Beta, Matrix and Right Hand Side (see Numerical Recipes)
+
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ for (j = 0; j < (int)m_nFreeParams; j++)
+ {
+ m_alpha[i][j] = 0.0;
+ m_Matrix[i][j] = 0.0;
+ }
+ m_currentVec[i] = 0.0;
+ m_tryVec[i] = 0.0;
+ m_beta[i] = 0.0;
+ m_RHS[i] = 0.0;
+ }
+
+ double df;
+
+ while (fabs(fmin) > m_Tolerance && improved && m_Iterations < m_MaxNumIterations)
+ {
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ m_currentVec[i] = m_Params[m_FreeParamIndex[i]];
+ //zero out Right Hand Side of the equation
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ m_RHS[i] = 0.0;
+ fmin = ResidualSumSquares();
+ Lambda = m_InitialLamda;
+ improved = false;
+ //Eval alpha and Beta at initial point
+ Eval_alpha_and_beta();
+ //Iterate
+ while (m_Iterations < m_MaxNumIterations)
+ {
+ m_Iterations++;
+ //Prepare data for Solution of Linear Equations
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ m_RHS[i] = m_beta[i];
+ //prepare m_Matrix matrix = Alpha.(1+Lambda.I)
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ {
+ for (j = 0; j < (int)m_nFreeParams; j++)
+ {
+ if (i == j)
+ {
+ if (m_alpha[i][i] == kIllegalValue)
+ m_Matrix[i][i] = 1.0;
+ else
+ m_Matrix[i][i] = m_alpha[i][i] * (1 + Lambda);
+ }
+ else
+ m_Matrix[i][j] = m_alpha[i][j];
+ }
+ }
+
+ bool bRet = m_LULS->LUSolver(m_Matrix, m_RHS, m_nFreeParams);
+ if (bRet != true)
+ return(-1);
+
+ uphill *= 0.8;
+ downhill *= 0.8; // update moving averages
+ fRSS = ResidualSumSquares();
+ if (fRSS > fmin)
+ {
+ //increase step Lambda
+ uphill += 0.2;
+ double Factor = IncreaseStep();
+ Lambda *= Factor;
+ }
+ else
+ {
+ //update data, check convergence, calculate next step
+ downhill += 0.2;
+ df = fRSS - fmin; // d_f is <= 0.
+ fmin = fRSS;
+ for (i = 0; i < (int)m_nFreeParams; i++)
+ m_currentVec[i] = m_tryVec[i];
+
+ // check if done
+ if (((2.0 * fabs(df)) <= (m_Delta * (fabs(fRSS) + fabs(fmin)))) || (fabs(fmin) < m_Tolerance)) {
+ break; // exit after convergence
+ }
+
+ // if not done yet, try a bolder step--
+ // decrease lambda according to how well f approximates a quadratic
+ Lambda *= ReduceStep(df, uphill, downhill);
+
+ // get curvature matrix mAlpha and vector mBeta at new minimum
+ Eval_alpha_and_beta();
+ }
+ }//end iterations
+ // Save in parameter vectors
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ m_Params[m_FreeParamIndex[i]] = m_currentVec[i];
+
+ if (fabs(fmin) < fabs(fbest)) {
+ for (i = 0; i < (int)m_nFreeParams; ++i)
+ FreeParams[i] = m_currentVec[m_FreeParamIndex[i]];
+ }
+
+ if ((fbest - fmin) > (m_Delta * fabs(fmin))) {
+ fbest = fmin;
+ improved = true;
+ }
+ } //end outer loop
+ n_iterations = m_Iterations;
+ return (fmin);
+}
+
+void LevMar::SetLabIn(double * LabIn)
+{
+ for (int i = 0; i < 3; ++i)
+ m_YRef[i] = LabIn[i];
+}
+
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.h
new file mode 100644
index 000000000..fff02fe0a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/LevMar.h
@@ -0,0 +1,66 @@
+#ifndef __LEVMAR_H__
+#define __LEVMAR_H__
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorTable.h"
+#include "ObjectiveFunction.h"
+#include "LULinearSolver.h"
+
+class LevMar
+{
+public:
+ LevMar(ObjectiveFunction *func);
+ ~LevMar();
+ double MinimizationAlgorithm(double *FreeParams, double *Fixedparams, unsigned int &n_iterations);
+ void SetMaxIterations(unsigned int MaxIterations) { m_MaxNumIterations = MaxIterations; };
+ void SetTolerance(const double &Tol) { m_Tolerance = Tol; };
+ void SetDerivH(double Epsilon) { m_Epsilon = Epsilon; };
+ double *GetLabOut() { return(m_Ycalc); };
+ void SetLabIn(double * LabIn);
+ void Init();
+ void SetInverseFunction(ObjectiveFunction *func) { m_func = func; };
+
+private:
+ double m_Tolerance;
+ unsigned int m_MaxNumIterations;
+ unsigned int m_Iterations;
+ unsigned int m_NData;
+ double m_InitialLamda;
+ double m_Delta;
+ double m_Epsilon;
+
+ unsigned int m_nFreeParams;
+ unsigned int m_nFixedParams;
+ unsigned int m_nParams;
+ unsigned int *m_FreeParamIndex;
+ unsigned int * m_FixedParamIndex;
+ double *m_UpperBound;
+ double *m_LowerBound;
+ double *m_FreeParams;
+ double *m_FixedParams;
+ double *m_Params;
+ double *m_Ycalc;
+ double *m_YRef;
+ double *m_beta;
+ double *m_RHS;
+ double ** m_alpha;
+ double **m_Matrix;
+ double *m_currentVec;
+ double *m_tryVec;
+ double **m_PartialDerivatives;
+ ObjectiveFunction *m_func;
+ C_RGB_XYZ_Lab m_WPLabRel;
+ C_RGB_XYZ_Lab m_WPTarget;
+ VectorXd m_distWeights;
+ ColorTable m_ColorTable;
+ double *m_ValsIn;
+ double *m_Lab_Iter;
+ double *m_difLab;
+ LULinearSolver *m_LULS;
+
+ double ReduceStep(const double &d_f, const double &uphill, const double &downhill)const;
+ double ResidualSumSquares(void);
+ double IncreaseStep();
+
+ void Eval_alpha_and_beta();
+};
+#endif // __LEVMAR_H__ \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.cpp
new file mode 100644
index 000000000..ccdff3e9d
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.cpp
@@ -0,0 +1,333 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "NDInterpUtils.h"
+#include <stdio.h>
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+extern "C"
+{
+
+ NDInterpUtils::NDInterpUtils() :
+ m_MSBShift(Sh4MSB), m_DataBuffer(NULL), m_nSeparationsIn(nSeparationsIn), m_Point(NULL),
+ m_nSeparationsOut(nSeparationsOut), m_nGridPoints(0), m_SubCubeSize(0), m_LastCubeComp(0),
+ m_tmpResult(NULL)
+ {
+ }
+
+ /*__declspec(dllexport) */void NDInterpUtils::InitData(unsigned short *DataBuffer, int SeparationsIn, int SeparationsOut, int nGridPoints, int MSBShift)
+ {
+ SetMSBShift(MSBShift);
+ SetNDData(DataBuffer);
+ SetSeparationsIn(SeparationsIn);
+ SetSeparationsOut(SeparationsOut);
+ SetNGridpoints(nGridPoints);
+ SetSubCubeSize();
+ SetLastCubeComp();
+ if(m_Point == NULL)
+ m_Point = new unsigned short[m_nSeparationsIn + 1];
+ if(m_tmpResult == NULL)
+ m_tmpResult = new int[m_nSeparationsOut];
+ //m_Point = DBG_NEW unsigned short[m_nSeparationsIn + 1];
+ //m_tmpResult = DBG_NEW int[m_nSeparationsOut];
+ }
+
+ void NDInterpUtils::InitData(unsigned char *DataBuffer, int SeparationsIn, int SeparationsOut, int nGridPoints, int MSBShift)
+ {
+ SetMSBShift(MSBShift);
+ SetNDData((unsigned short *)DataBuffer);
+ SetSeparationsIn(SeparationsIn);
+ SetSeparationsOut(SeparationsOut);
+ SetNGridpoints(nGridPoints);
+ SetSubCubeSize();
+ SetLastCubeComp();
+ if(m_Point == NULL)
+ m_Point = new unsigned short[m_nSeparationsIn + 1];
+ if(m_tmpResult == NULL)
+ m_tmpResult = new int[m_nSeparationsOut];
+ //m_Point = DBG_NEW unsigned short[m_nSeparationsIn + 1];
+ //m_tmpResult = DBG_NEW int[m_nSeparationsOut];
+ }
+
+ NDInterpUtils::~NDInterpUtils()
+ {
+ if (m_Point != NULL)
+ delete m_Point;
+ if (m_tmpResult != NULL)
+ delete m_tmpResult;
+
+ }
+
+
+
+ void NDInterpUtils::ColorMap4(const unsigned short * ValIn, double * ValOut)
+ {
+ //ValIn is in 8 bits, ValOut is floating point, scale 256
+ unsigned short iC, iM, iY, iK; //input values
+ unsigned char HC, HM, HY, HK; //subcube coordinates
+ unsigned char LC, LM, LY, LK; // position within subcube
+ int p0, p1, p2, p3, p4; //position
+ int w0, w1, w2, w3, w4; //weights
+
+ int maxVal, midVal1, midVal2, minVal;
+ int maxPos, midPos1, midPos2, minPos;
+
+ // Extract Input Pixel
+ iC = ValIn[0];
+ iM = ValIn[1];
+ iY = ValIn[2];
+ iK = ValIn[3];
+
+ // Extract MSB for LUT access
+ unsigned char MSBShift = m_MSBShift + 8;
+ HC = iC >> MSBShift;
+ HM = iM >> MSBShift;
+ HY = iY >> MSBShift;
+ HK = iK >> MSBShift;
+
+ // Extract LSB for interpolation
+ LC = iC & m_SubCubeSize;
+ LM = iM & m_SubCubeSize;
+ LY = iY & m_SubCubeSize;
+ LK = iK & m_SubCubeSize;
+
+ // Last cube compensation
+ if (iC >= m_LastCubeComp) LC++;
+ if (iM >= m_LastCubeComp) LM++;
+ if (iY >= m_LastCubeComp) LY++;
+ if (iK >= m_LastCubeComp) LK++;
+
+ //get minimum, mid & maximum LSBs
+ getOrdering4((int)LC, (int)LM, (int)LY, (int)LK, maxVal, midVal1, midVal2, minVal,
+ maxPos, midPos1, midPos2, minPos);
+
+ // Lut position for the vertices
+ p0 = (HC*m_nGridPoints*m_nGridPoints*m_nGridPoints) + (HM*m_nGridPoints*m_nGridPoints) + (HY*m_nGridPoints) + HK;
+
+ p1 = (maxPos == 3) ? (p0 + m_nGridPoints*m_nGridPoints*m_nGridPoints) : ((maxPos == 2) ? p0 + m_nGridPoints*m_nGridPoints :
+ (maxPos == 1) ? p0 + m_nGridPoints : p0 + 1);
+
+ p2 = (midPos1 == 3) ? (p1 + m_nGridPoints*m_nGridPoints*m_nGridPoints) : ((midPos1 == 2) ? p1 + m_nGridPoints*m_nGridPoints :
+ (midPos1 == 1) ? p1 + m_nGridPoints : p1 + 1);
+
+ p3 = (midPos2 == 3) ? (p2 + m_nGridPoints*m_nGridPoints*m_nGridPoints) : ((midPos2 == 2) ? p2 + m_nGridPoints*m_nGridPoints :
+ (midPos2 == 1) ? p2 + m_nGridPoints : p2 + 1);
+
+ p4 = (minPos == 3) ? (p3 + m_nGridPoints*m_nGridPoints*m_nGridPoints) : ((minPos == 2) ? p3 + m_nGridPoints*m_nGridPoints :
+ (minPos == 1) ? p3 + m_nGridPoints : p3 + 1);
+
+ p0 *= m_nSeparationsOut;
+ p1 *= m_nSeparationsOut;
+ p2 *= m_nSeparationsOut;
+ p3 *= m_nSeparationsOut;
+ p4 *= m_nSeparationsOut;
+
+ // Calculate weights
+ w0 = m_SubCubeSize + 1 - maxVal;
+ w1 = maxVal - midVal1;
+ w2 = midVal1 - midVal2;
+ w3 = midVal2 - minVal;
+ w4 = minVal;
+
+ for (int p = 0; p < m_nSeparationsOut; p++)
+ {
+ // Extract vertices from LUT
+ m_Point[0] = m_DataBuffer[p0 + p];
+ m_Point[1] = m_DataBuffer[p1 + p];
+ m_Point[2] = m_DataBuffer[p2 + p];
+ m_Point[3] = m_DataBuffer[p3 + p];
+ m_Point[4] = m_DataBuffer[p4 + p];
+ // Compute output
+ m_tmpResult[p] = w0*m_Point[0] + w1*m_Point[1] + w2*m_Point[2] + w3*m_Point[3] + w4*m_Point[4];
+ m_tmpResult[p] = m_tmpResult[p] >> m_MSBShift;
+
+ if (m_tmpResult[p] >= 0x10000)
+ {
+ m_tmpResult[p] = 0xFFFF;
+ }
+
+ ValOut[p] = m_tmpResult[p];
+
+
+ // if (debug)
+ // {
+ // logger.note(" COLORMAP: plane=%d, cmyk=(0x%0x,0x%0x,0x%0x,0x%0x) Addr=(0x%0x,0x%0x,0x%0x,0x%0x,0x%0x) Lut=(0x%0x,0x%0x,0x%0x,0x%0x, 0x%0x) Weight=(0x%0x,0x%0x,0x%0x,0x%0x,0x%0x), out=0x%0x",
+ // p, iC, iM, iY, iK
+ // p0, p1, p2, p3, p4, Point[0], Point[1], Point[2],
+ // Point[3], Point[4], w0, w1, w2, w3, w4, ValOut[p]);
+ // }
+ }
+ }
+
+ void NDInterpUtils::ColorMap3(const unsigned short * ValIn, double * ValOut)
+ {
+ //ValIn is in 8 bits, ValOut is floating point, scale 256
+ unsigned short iC, iM, iY; //input values
+ unsigned char HC, HM, HY; //subcube coordinates
+ unsigned char LC, LM, LY; // position within subcube
+ int p0, p1, p2, p3; //position
+ int w0, w1, w2, w3; //weights
+
+ int maxVal, midVal1, minVal;
+ int maxPos, midPos1, minPos;
+ // Extract Input Pixel
+ iC = ValIn[0];
+ iM = ValIn[1];
+ iY = ValIn[2];
+
+ // Extract MSB for LUT access
+ unsigned char MSBShift = m_MSBShift + 8;
+ HC = iC >> MSBShift;
+ HM = iM >> MSBShift;
+ HY = iY >> MSBShift;
+
+ // Extract LSB for interpolation
+ LC = (iC>> 8)& m_SubCubeSize;
+ LM = (iM>>8) & m_SubCubeSize;
+ LY =( iY>>8) & m_SubCubeSize;
+
+ // Last cube compensation
+ if ((iC >> 8) >= m_LastCubeComp) LC++;
+ if ((iM >> 8) >= m_LastCubeComp) LM++;
+ if ((iY >> 8) >= m_LastCubeComp) LY++;
+
+ //get minimum, mid & maximum LSBs
+ getOrdering3((int)LC, (int)LM, (int)LY, maxVal, midVal1, minVal,
+ maxPos, midPos1, minPos);
+
+ // Lut position for the vertices
+ p0 = (HC*m_nGridPoints*m_nGridPoints) + (HM*m_nGridPoints) + HY;
+
+ p1 = (maxPos == 2) ? (p0 + m_nGridPoints*m_nGridPoints) : ((maxPos == 1) ? p0 + m_nGridPoints : p0 + 1);
+
+ p2 = (midPos1 == 2) ? (p1 + m_nGridPoints*m_nGridPoints) : ((midPos1 == 1) ? p1 + m_nGridPoints : p1 + 1);
+
+ p3 = (minPos == 2) ? (p2 + m_nGridPoints*m_nGridPoints) : ((minPos == 1) ? p2 + m_nGridPoints : p2 + 1);
+
+ p0 *= m_nSeparationsOut;
+ p1 *= m_nSeparationsOut;
+ p2 *= m_nSeparationsOut;
+ p3 *= m_nSeparationsOut;
+
+ // Calculate weights
+ w0 = m_SubCubeSize + 1 - maxVal;
+ w1 = maxVal - midVal1;
+ w2 = midVal1 - minVal;
+ w3 = minVal;
+
+ for (int p = 0; p < m_nSeparationsOut; p++)
+ {
+ // Extract vertices from LUT
+ m_Point[0] = m_DataBuffer[p0 + p];
+ m_Point[1] = m_DataBuffer[p1 + p];
+ m_Point[2] = m_DataBuffer[p2 + p];
+ m_Point[3] = m_DataBuffer[p3 + p];
+ // Compute output
+ m_tmpResult[p] = w0*m_Point[0] + w1*m_Point[1] + w2*m_Point[2] + w3*m_Point[3];
+ m_tmpResult[p] = m_tmpResult[p] >> m_MSBShift;
+ // Store result in units of 2^16 same as LUT
+ if (m_tmpResult[p] >= 0x10000)
+ {
+ m_tmpResult[p] = 0xFFFF;
+ }
+
+ ValOut[p] = m_tmpResult[p];
+ }
+ }
+
+
+
+ void NDInterpUtils::getMax4(int a, int b, int c, int d, int &max, int &pos)
+ {
+ if ((a >= b) && (a >= c) && (a >= d))
+ {
+ max = a;
+ pos = 3;
+ }
+ else if ((b >= a) && (b >= c) && (b >= d))
+ {
+ max = b;
+ pos = 2;
+ }
+ else if ((c >= a) && (c >= b) && (c >= d))
+ {
+ max = c;
+ pos = 1;
+ }
+ else
+ {
+ max = d;
+ pos = 0;
+ }
+ }
+
+ void NDInterpUtils::getMax3(int a, int b, int c, int &max, int &pos)
+ {
+ if ((a >= b) && (a >= c))
+ {
+ max = a;
+ pos = 2;
+ }
+ else if ((b >= a) && (b >= c))
+ {
+ max = b;
+ pos = 1;
+ }
+ else
+ {
+ max = c;
+ pos = 0;
+ }
+ }
+ void NDInterpUtils::getOrdering4(int a, int b, int c, int d,
+ int &max, int &mid1, int &mid2, int &min, int &maxPos,
+ int &midPos1, int &midPos2, int &minPos)
+ {
+ int v[4] = { d, c, b, a };
+ getMax4(v[3], v[2], v[1], v[0], max, maxPos);
+ v[maxPos] = -1;
+ getMax4(v[3], v[2], v[1], v[0], mid1, midPos1);
+ v[midPos1] = -1;
+ getMax4(v[3], v[2], v[1], v[0], mid2, midPos2);
+ v[midPos2] = -1;
+ getMax4(v[3], v[2], v[1], v[0], min, minPos);
+ }
+
+ void NDInterpUtils::getOrdering3(int a, int b, int c,
+ int &max, int &mid1, int &min, int &maxPos,
+ int &midPos1, int &minPos)
+ {
+ int v[4] = { c, b, a };
+ getMax3(v[2], v[1], v[0], max, maxPos);
+ v[maxPos] = -1;
+ getMax3(v[2], v[1], v[0], mid1, midPos1);
+ v[midPos1] = -1;
+ getMax3(v[2], v[1], v[0], min, minPos);
+ }
+
+
+ void NDInterpUtils::SetSubCubeSize()
+ {
+ int SubCubeSize = (unsigned char)pow((double)2, (int)m_MSBShift);
+ if (SubCubeSize == 16)
+ m_SubCubeSize = 0x0F;
+ else if (SubCubeSize == 32)
+ m_SubCubeSize = 0x1F;
+ else if (SubCubeSize == 8)
+ m_SubCubeSize = 0x07;
+
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.h
new file mode 100644
index 000000000..992de082c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NDInterpUtils.h
@@ -0,0 +1,60 @@
+
+#ifndef _NDINTERP_H_
+#define _NDINTERP_H_
+
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef nSeparationsIn
+#define nSeparationsIn 4
+#endif
+
+#ifndef nSeparationsOut
+#define nSeparationsOut 4
+#endif
+
+
+#ifndef Sh4MSB
+#define Sh4MSB 4 // for 17 gridpoints table
+#endif
+
+//Assumption: Table used for interpolation is saved in 16 bits accuracy. Number of nodes per channel can vary
+//Interpolation suports 3 or 4 input channels and 3 or 4 output channels
+class NDInterpUtils {
+public:
+ NDInterpUtils();
+ /*__declspec(dllexport) */void InitData(unsigned short *DataBuffer, int SeparationsIn, int SeparationsOut, int nGridPoints, int MSBShift);
+ void InitData(unsigned char *DataBuffer, int SeparationsIn, int SeparationsOut, int nGridPoints, int MSBShift);
+ ~NDInterpUtils();
+ void ColorMap4(const unsigned short * ValIn, double * ValOut);
+ void ColorMap3(const unsigned short * ValIn, double * ValOut);
+private:
+ unsigned char m_MSBShift;
+ unsigned char m_SubCubeSize;
+ unsigned char m_LastCubeComp;
+ int m_nSeparationsIn;
+ int m_nSeparationsOut;
+ int m_nGridPoints;
+ unsigned short *m_DataBuffer;
+ unsigned short *m_Point;
+ int *m_tmpResult;
+ void SetSubCubeSize();
+ void SetMSBShift(unsigned char ShMSB) { m_MSBShift = ShMSB; };
+ void SetLastCubeComp() { m_LastCubeComp = 0xFF - m_SubCubeSize / 2; };
+ void SetdataBuffer(unsigned short *DataBuffer) { m_DataBuffer = DataBuffer; };
+ void getMax4(int a, int b, int c, int d, int &max, int &pos);
+ void getOrdering4(int a, int b, int c, int d,
+ int &max, int &mid1, int &mid2, int &min, int &maxPos,
+ int &midPos1, int &midPos2, int &minPos);
+ void getMax3(int a, int b, int c, int &max, int &pos);
+ void getOrdering3(int a, int b, int c,
+ int &max, int &mid1, int &min, int &maxPos,
+ int &midPos1, int &minPos);
+ void SetMSBShift(int MSBShift) { m_MSBShift = MSBShift; };
+ void SetNDData(unsigned short *DataBuffer) { m_DataBuffer = DataBuffer; };
+ void SetSeparationsIn(int SeparationsIn) { m_nSeparationsIn = SeparationsIn; };
+ void SetSeparationsOut(int SeparationsOut) { m_nSeparationsOut = SeparationsOut; };
+ void SetNGridpoints(int nGridPoints) { m_nGridPoints = nGridPoints; };
+};
+
+#endif \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.cpp
new file mode 100644
index 000000000..f541b370c
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.cpp
@@ -0,0 +1,85 @@
+#include "NumConversions.h"
+#include <cmath>
+#include <cstdlib>
+#include <cstdint>
+#include <iostream>
+#include <stdio.h>
+
+/*#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <cstdlib>
+
+#ifdef _DEBUG
+#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+// allocations to be of _CLIENT_BLOCK type
+#else
+#define DBG_NEW new
+#endif */
+
+NumConversions::NumConversions(void)
+{
+}
+
+NumConversions::NumConversions(const NumConversions &rhs)
+{
+}
+
+NumConversions::~NumConversions()
+{
+
+}
+int NumConversions::ByteToInt(uint8_t *byteN, int start)
+{
+ int res;
+ res = (int)((unsigned int)byteN[start] << 24 |
+ (unsigned int)byteN[start + 1] << 16 |
+ (unsigned int)byteN[start + 2] << 8 |
+ (unsigned int)byteN[start + 3]);
+ return(res);
+}
+
+uint16_t NumConversions::ByteToShort(uint8_t *byteN, int start)
+{
+ uint16_t res;
+ res = (uint16_t)((unsigned short)byteN[start] << 8 |
+ (unsigned short)byteN[start + 1]);
+ return(res);
+}
+
+void NumConversions::getchar(uint32_t num, char &tmpC)
+{
+ char getChar[sizeof(uint32_t)];
+ getChar[0] = num >> 24;
+ getChar[1] = num >> 16;
+ getChar[2] = num >> 8;
+ getChar[3] = num;
+ strncpy_s(&tmpC, sizeof(uint32_t)+1, getChar, sizeof(uint32_t) );
+
+ //reverse order
+ //char *tmp = new char[nlen];
+ //char *tmp = DBG_NEW char[nlen];
+ /*for (int i = 0; i < nlen; ++i)
+ {
+ tmpC[i] = getChar[nlen - 1 - i];
+ }*/
+}
+
+void NumConversions::DecToBinary(int DecNumber, int *&BinOut, int nsize)
+{
+ //Store in reverse order, meaning the way it comes out of the calculation
+ // array to store binary number
+
+ // counter for binary array
+ int i = 0;
+ for (int i = 0; i < nsize; ++i)
+ BinOut[i] = 0;
+ while (DecNumber > 0 && i<nsize)
+ {
+ // store remainder in binary array
+ BinOut[i] = DecNumber % 2;
+ DecNumber = DecNumber / 2;
+ i++;
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.h
new file mode 100644
index 000000000..a2ac26306
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/NumConversions.h
@@ -0,0 +1,18 @@
+#ifndef __NUMCONVER_H__
+#define __NUMCONVER_H__
+#include <stdlib.h>
+#include <stdint.h>
+
+class NumConversions
+{
+ public:
+ NumConversions(void);
+ NumConversions(const NumConversions &rhs);
+ ~NumConversions();
+ int ByteToInt(uint8_t *byteN, int Start);
+ uint16_t ByteToShort(uint8_t *byteN, int Start);
+ void getchar(uint32_t num, char &tmpC);
+ void DecToBinary(int DecNumber,int *&BinOut, int nsize);
+ private:
+};
+#endif //__NUMCONVERSIONS_H__ \ No newline at end of file
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.cpp
new file mode 100644
index 000000000..2e746f09b
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.cpp
@@ -0,0 +1,142 @@
+
+#include <cmath> // for fabs()
+
+#include "ObjectiveFunction.h"
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorTable.h"
+#include "Dense"
+
+using Eigen::MatrixXd;
+using Eigen::VectorXd;
+using Eigen::VectorXi;
+
+ObjectiveFunction::ObjectiveFunction(void) : m_FreeParamIndex(NULL),
+m_FixedParamIndex(NULL),
+m_ZeroValues(NULL),
+m_ValsIn(NULL),
+m_LabOut(NULL),
+m_dLabOut(NULL),
+m_nFreeParams(0),
+m_nFixedParams(0),
+m_nParams(0),
+m_forwardmodel(NULL),
+m_LabGoal(NULL)
+{
+}
+
+ObjectiveFunction::~ObjectiveFunction(void)
+{
+ if (m_FreeParamIndex != NULL)
+ {
+ delete[] m_FreeParamIndex;
+ m_FreeParamIndex = NULL;
+ }
+ if (m_FixedParamIndex != NULL)
+ {
+ delete[] m_FixedParamIndex;
+ m_FixedParamIndex = NULL;
+ }
+
+ if (m_ZeroValues != NULL)
+ {
+ delete[] m_ZeroValues;
+ m_ZeroValues = NULL;
+ }
+ if (m_ValsIn != NULL)
+ {
+ delete[] m_ValsIn;
+ m_ValsIn = NULL;
+ }
+
+ if (m_UpperBound != NULL)
+ {
+ delete[] m_UpperBound;
+ m_UpperBound = NULL;
+ }
+ if (m_LowerBound != NULL)
+ {
+ delete[] m_LowerBound;
+ m_LowerBound = NULL;
+ }
+}
+
+ObjectiveFunction::ObjectiveFunction(ForwardModel *forwardmodel): m_FreeParamIndex(NULL),
+m_FixedParamIndex(NULL),
+m_ZeroValues(NULL),
+m_ValsIn(NULL),
+m_LabOut(NULL),
+m_nFreeParams(0),
+m_nFixedParams(0),
+m_nParams(0)
+{
+ m_forwardmodel = forwardmodel;
+}
+
+
+int ObjectiveFunction::EvaluateObjectiveFunction(double *params, double *retVector)
+{
+ for (int i = 0; i<(int)m_nFreeParams; ++i)
+ m_ValsIn[m_FreeParamIndex[i]] = params[m_FreeParamIndex[i]];
+ for (int i = 0; i < (int)m_nFixedParams; ++i)
+ m_ValsIn[m_FixedParamIndex[i]]= params[m_FixedParamIndex[i]]; //Units of [0-100]
+ m_dLabOut[0] = m_LabOut.Get_x();
+ m_dLabOut[1] = m_LabOut.Get_y();
+ m_dLabOut[2] = m_LabOut.Get_z();
+ int GamutRegion = 0;
+ m_forwardmodel->CalcFM(m_ValsIn, m_dLabOut);
+
+ m_LabOut.Set(m_dLabOut[0], m_dLabOut[1], m_dLabOut[2]);
+ retVector[0] = m_LabOut.Get_x() - m_LabGoal.Get_x();
+ retVector[1] = m_LabOut.Get_y() - m_LabGoal.Get_y();
+ retVector[2] = m_LabOut.Get_z()- m_LabGoal.Get_z();
+
+ return(0);
+
+}
+
+void ObjectiveFunction::SetLabGoal(double *LabIn)
+{
+ m_LabGoal.Set(LabIn[0], LabIn[1], LabIn[2]);
+}
+
+void ObjectiveFunction::SetParameters(unsigned int nFreeParams, unsigned int nFixedParams, unsigned int *FreeParamIndex,
+ unsigned int *FixedParamIndex, double*UpperBound, double *LowerBound)
+{
+ m_nFreeParams =nFreeParams;
+ m_nFixedParams = nFixedParams;
+ m_nParams = m_nFreeParams + m_nFixedParams;
+ m_nOut = (unsigned int)3;
+ m_FreeParamIndex = FreeParamIndex;
+ m_FixedParamIndex = FixedParamIndex;
+ m_UpperBound = UpperBound;
+ m_LowerBound = LowerBound;
+ if (m_ValsIn == NULL)
+ m_ValsIn = new double[(int)m_nParams];
+
+ for (int i = 0; i < (int)m_nParams; ++i)
+ m_ValsIn[i] = 0.0;
+
+ m_LabOut.Set(0.0, 0.0, 0.0);
+ m_LabGoal.Set(0.0, 0.0, 0.0);
+
+ for (int i = 0; i < (int)m_nFreeParams; ++i)
+ {
+ m_FreeParamIndex[i] = FreeParamIndex[i];
+ m_UpperBound[i] = UpperBound[i];
+ m_LowerBound[i] = LowerBound[i];
+ }
+
+ for (int i = 0; i < (int)m_nFixedParams; ++i)
+ m_FixedParamIndex[i] = FixedParamIndex[i];
+
+ m_ZeroValues = new double[m_nParams];
+ for (int i = 0; i < (int)m_nParams; ++i)
+ m_ZeroValues[i] = 0.0;
+
+ if (m_dLabOut != NULL)
+ m_dLabOut = new double[m_nOut];
+ for (int i = 0; i < (int)m_nOut; ++i)
+ m_dLabOut[i] = 0.0;
+
+}
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.h
new file mode 100644
index 000000000..2e2da1f64
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/Utils/ObjectiveFunction.h
@@ -0,0 +1,49 @@
+
+#ifndef _OBJECTIVEFUNCTION_H_
+#define _OBJECTIVEFUNCTION_H_
+
+#include "C_RGB_XYZ_Lab.h"
+#include "ColorTable.h"
+
+class ObjectiveFunction
+{
+public:
+ ObjectiveFunction(void);
+ ~ObjectiveFunction(void);
+ ObjectiveFunction(ForwardModel *forwardmodel);
+
+ int EvaluateObjectiveFunction(double *params, double*retVector);
+ void SetLabGoal(double *LabIn);
+ void ObjectiveFunction::SetParameters(unsigned int nFreeParams, unsigned int nFixedParams, unsigned int *FreeParamIndex,
+ unsigned int *FixedParamIndex, double *UpperBound, double *LowerBound);
+ unsigned int GetNumFreeParams() {return(m_nFreeParams);};
+ unsigned int GetNumFixedParams() {return(m_nFixedParams);};
+ unsigned int GetNumOutResult() {return(m_nOut);};
+ unsigned int *GetFreeParamsIndex() {return (m_FreeParamIndex);};
+ unsigned int *GetFixedParamsIndex() {return (m_FixedParamIndex);};
+ double *GetLowerBound() {return(m_LowerBound);};
+ double *GetUpperBound() {return(m_UpperBound);};
+
+protected:
+
+private:
+
+ ForwardModel *m_forwardmodel;
+ double *m_ValsIn;
+ C_RGB_XYZ_Lab m_LabOut;
+ C_RGB_XYZ_Lab m_LabGoal;
+
+ unsigned int *m_FreeParamIndex;
+ unsigned int *m_FixedParamIndex;
+ double *m_ZeroValues;
+ unsigned int m_nFreeParams;
+ unsigned int m_nFixedParams;
+ unsigned int m_nParams;
+ unsigned int m_nOut;
+ double *m_UpperBound;
+ double *m_LowerBound;
+ double *m_dLabOut;
+};
+
+#endif // _OBJECTIVEFUNCTION_H_
+
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.c b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.c
new file mode 100644
index 000000000..5debac820
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.c
@@ -0,0 +1,3642 @@
+/*
+ * Copyright (c) 2008-2015, Dave Benson and the protobuf-c authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*! \file
+ * Support library for `protoc-c` generated code.
+ *
+ * This file implements the public API used by the code generated
+ * by `protoc-c`.
+ *
+ * \authors Dave Benson and the protobuf-c authors
+ *
+ * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license.
+ */
+
+/**
+ * \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math
+ * even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64).
+ *
+ * \todo Use size_t consistently.
+ */
+
+#include <stdlib.h> /* for malloc, free */
+#include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */
+
+#include "protobuf-c.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0)
+
+/* Workaround for Microsoft compilers. */
+#ifdef _MSC_VER
+# define inline __inline
+#endif
+
+/**
+ * \defgroup internal Internal functions and macros
+ *
+ * These are not exported by the library but are useful to developers working
+ * on `libprotobuf-c` itself.
+ */
+
+/**
+ * \defgroup macros Utility macros for manipulating structures
+ *
+ * Macros and constants used to manipulate the base "classes" generated by
+ * `protobuf-c`. They also define limits and check correctness.
+ *
+ * \ingroup internal
+ * @{
+ */
+
+/** The maximum length of a 64-bit integer in varint encoding. */
+#define MAX_UINT64_ENCODED_SIZE 10
+
+#ifndef PROTOBUF_C_UNPACK_ERROR
+# define PROTOBUF_C_UNPACK_ERROR(...)
+#endif
+
+const char protobuf_c_empty_string[] = "";
+
+/**
+ * Internal `ProtobufCMessage` manipulation macro.
+ *
+ * Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and
+ * STRUCT_MEMBER_PTR().
+ */
+#define STRUCT_MEMBER_P(struct_p, struct_offset) \
+ ((void *) ((uint8_t *) (struct_p) + (struct_offset)))
+
+/**
+ * Return field in a `ProtobufCMessage` based on offset.
+ *
+ * Take a pointer to a `ProtobufCMessage` and find the field at the offset.
+ * Cast it to the passed type.
+ */
+#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \
+ (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset)))
+
+/**
+ * Return field in a `ProtobufCMessage` based on offset.
+ *
+ * Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast
+ * it to a pointer to the passed type.
+ */
+#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \
+ ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset)))
+
+/* Assertions for magic numbers. */
+
+#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \
+ assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC)
+
+#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \
+ assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC)
+
+#define ASSERT_IS_MESSAGE(message) \
+ ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor)
+
+#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \
+ assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC)
+
+/**@}*/
+
+/* --- version --- */
+
+const char *
+protobuf_c_version(void)
+{
+ return PROTOBUF_C_VERSION;
+}
+
+uint32_t
+protobuf_c_version_number(void)
+{
+ return PROTOBUF_C_VERSION_NUMBER;
+}
+
+/* --- allocator --- */
+
+static void *
+system_alloc(void *allocator_data, size_t size)
+{
+ return malloc(size);
+}
+
+static void
+system_free(void *allocator_data, void *data)
+{
+ free(data);
+}
+
+static inline void *
+do_alloc(ProtobufCAllocator *allocator, size_t size)
+{
+ return allocator->alloc(allocator->allocator_data, size);
+}
+
+static inline void
+do_free(ProtobufCAllocator *allocator, void *data)
+{
+ if (data != NULL)
+ allocator->free(allocator->allocator_data, data);
+}
+
+/*
+ * This allocator uses the system's malloc() and free(). It is the default
+ * allocator used if NULL is passed as the ProtobufCAllocator to an exported
+ * function.
+ */
+static ProtobufCAllocator protobuf_c__allocator = {
+ .alloc = &system_alloc,
+ .free = &system_free,
+ .allocator_data = NULL,
+};
+
+/* === buffer-simple === */
+
+void
+protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer,
+ size_t len, const uint8_t *data)
+{
+ ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer;
+ size_t new_len = simp->len + len;
+
+ if (new_len > simp->alloced) {
+ ProtobufCAllocator *allocator = simp->allocator;
+ size_t new_alloced = simp->alloced * 2;
+ uint8_t *new_data;
+
+ if (allocator == NULL)
+ allocator = &protobuf_c__allocator;
+ while (new_alloced < new_len)
+ new_alloced += new_alloced;
+ new_data = do_alloc(allocator, new_alloced);
+ if (!new_data)
+ return;
+ memcpy(new_data, simp->data, simp->len);
+ if (simp->must_free_data)
+ do_free(allocator, simp->data);
+ else
+ simp->must_free_data = TRUE;
+ simp->data = new_data;
+ simp->alloced = new_alloced;
+ }
+ memcpy(simp->data + simp->len, data, len);
+ simp->len = new_len;
+}
+
+/**
+ * \defgroup packedsz protobuf_c_message_get_packed_size() implementation
+ *
+ * Routines mainly used by protobuf_c_message_get_packed_size().
+ *
+ * \ingroup internal
+ * @{
+ */
+
+/**
+ * Return the number of bytes required to store the tag for the field. Includes
+ * 3 bits for the wire-type, and a single bit that denotes the end-of-tag.
+ *
+ * \param number
+ * Field tag to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+get_tag_size(uint32_t number)
+{
+ if (number < (1UL << 4)) {
+ return 1;
+ } else if (number < (1UL << 11)) {
+ return 2;
+ } else if (number < (1UL << 18)) {
+ return 3;
+ } else if (number < (1UL << 25)) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+/**
+ * Return the number of bytes required to store a variable-length unsigned
+ * 32-bit integer in base-128 varint encoding.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+uint32_size(uint32_t v)
+{
+ if (v < (1UL << 7)) {
+ return 1;
+ } else if (v < (1UL << 14)) {
+ return 2;
+ } else if (v < (1UL << 21)) {
+ return 3;
+ } else if (v < (1UL << 28)) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+/**
+ * Return the number of bytes required to store a variable-length signed 32-bit
+ * integer in base-128 varint encoding.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+int32_size(int32_t v)
+{
+ if (v < 0) {
+ return 10;
+ } else if (v < (1L << 7)) {
+ return 1;
+ } else if (v < (1L << 14)) {
+ return 2;
+ } else if (v < (1L << 21)) {
+ return 3;
+ } else if (v < (1L << 28)) {
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+/**
+ * Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed
+ * integer.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * ZigZag encoded integer.
+ */
+static inline uint32_t
+zigzag32(int32_t v)
+{
+ if (v < 0)
+ return (-(uint32_t)v) * 2 - 1;
+ else
+ return (uint32_t)(v) * 2;
+}
+
+/**
+ * Return the number of bytes required to store a signed 32-bit integer,
+ * converted to an unsigned 32-bit integer with ZigZag encoding, using base-128
+ * varint encoding.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+sint32_size(int32_t v)
+{
+ return uint32_size(zigzag32(v));
+}
+
+/**
+ * Return the number of bytes required to store a 64-bit unsigned integer in
+ * base-128 varint encoding.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+uint64_size(uint64_t v)
+{
+ uint32_t upper_v = (uint32_t) (v >> 32);
+
+ if (upper_v == 0) {
+ return uint32_size((uint32_t) v);
+ } else if (upper_v < (1UL << 3)) {
+ return 5;
+ } else if (upper_v < (1UL << 10)) {
+ return 6;
+ } else if (upper_v < (1UL << 17)) {
+ return 7;
+ } else if (upper_v < (1UL << 24)) {
+ return 8;
+ } else if (upper_v < (1UL << 31)) {
+ return 9;
+ } else {
+ return 10;
+ }
+}
+
+/**
+ * Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed
+ * integer.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * ZigZag encoded integer.
+ */
+static inline uint64_t
+zigzag64(int64_t v)
+{
+ if (v < 0)
+ return (-(uint64_t)v) * 2 - 1;
+ else
+ return (uint64_t)(v) * 2;
+}
+
+/**
+ * Return the number of bytes required to store a signed 64-bit integer,
+ * converted to an unsigned 64-bit integer with ZigZag encoding, using base-128
+ * varint encoding.
+ *
+ * \param v
+ * Value to encode.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+sint64_size(int64_t v)
+{
+ return uint64_size(zigzag64(v));
+}
+
+/**
+ * Calculate the serialized size of a single required message field, including
+ * the space needed by the preceding tag.
+ *
+ * \param field
+ * Field descriptor for member.
+ * \param member
+ * Field to encode.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+required_field_get_packed_size(const ProtobufCFieldDescriptor *field,
+ const void *member)
+{
+ size_t rv = get_tag_size(field->id);
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SINT32:
+ return rv + sint32_size(*(const int32_t *) member);
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ return rv + int32_size(*(const int32_t *) member);
+ case PROTOBUF_C_TYPE_UINT32:
+ return rv + uint32_size(*(const uint32_t *) member);
+ case PROTOBUF_C_TYPE_SINT64:
+ return rv + sint64_size(*(const int64_t *) member);
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ return rv + uint64_size(*(const uint64_t *) member);
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ return rv + 4;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ return rv + 8;
+ case PROTOBUF_C_TYPE_BOOL:
+ return rv + 1;
+ case PROTOBUF_C_TYPE_FLOAT:
+ return rv + 4;
+ case PROTOBUF_C_TYPE_DOUBLE:
+ return rv + 8;
+ case PROTOBUF_C_TYPE_STRING: {
+ const char *str = *(char * const *) member;
+ size_t len = str ? strlen(str) : 0;
+ return rv + uint32_size(len) + len;
+ }
+ case PROTOBUF_C_TYPE_BYTES: {
+ size_t len = ((const ProtobufCBinaryData *) member)->len;
+ return rv + uint32_size(len) + len;
+ }
+ case PROTOBUF_C_TYPE_MESSAGE: {
+ const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member;
+ size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0;
+ return rv + uint32_size(subrv) + subrv;
+ }
+ }
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ return 0;
+}
+
+/**
+ * Calculate the serialized size of a single oneof message field, including
+ * the space needed by the preceding tag. Returns 0 if the oneof field isn't
+ * selected or is not set.
+ *
+ * \param field
+ * Field descriptor for member.
+ * \param oneof_case
+ * Enum value that selects the field in the oneof.
+ * \param member
+ * Field to encode.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field,
+ uint32_t oneof_case,
+ const void *member)
+{
+ if (oneof_case != field->id) {
+ return 0;
+ }
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void * const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ }
+ return required_field_get_packed_size(field, member);
+}
+
+/**
+ * Calculate the serialized size of a single optional message field, including
+ * the space needed by the preceding tag. Returns 0 if the optional field isn't
+ * set.
+ *
+ * \param field
+ * Field descriptor for member.
+ * \param has
+ * True if the field exists, false if not.
+ * \param member
+ * Field to encode.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+optional_field_get_packed_size(const ProtobufCFieldDescriptor *field,
+ const protobuf_c_boolean has,
+ const void *member)
+{
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void * const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ } else {
+ if (!has)
+ return 0;
+ }
+ return required_field_get_packed_size(field, member);
+}
+
+static protobuf_c_boolean
+field_is_zeroish(const ProtobufCFieldDescriptor *field,
+ const void *member)
+{
+ protobuf_c_boolean ret = FALSE;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_BOOL:
+ ret = (0 == *(const protobuf_c_boolean *) member);
+ break;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_SINT32:
+ case PROTOBUF_C_TYPE_INT32:
+ case PROTOBUF_C_TYPE_UINT32:
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ ret = (0 == *(const uint32_t *) member);
+ break;
+ case PROTOBUF_C_TYPE_SINT64:
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ ret = (0 == *(const uint64_t *) member);
+ break;
+ case PROTOBUF_C_TYPE_FLOAT:
+ ret = (0 == *(const float *) member);
+ break;
+ case PROTOBUF_C_TYPE_DOUBLE:
+ ret = (0 == *(const double *) member);
+ break;
+ case PROTOBUF_C_TYPE_STRING:
+ ret = (NULL == *(const char * const *) member) ||
+ ('\0' == **(const char * const *) member);
+ break;
+ case PROTOBUF_C_TYPE_BYTES:
+ case PROTOBUF_C_TYPE_MESSAGE:
+ ret = (NULL == *(const void * const *) member);
+ break;
+ default:
+ ret = TRUE;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * Calculate the serialized size of a single unlabeled message field, including
+ * the space needed by the preceding tag. Returns 0 if the field isn't set or
+ * if it is set to a "zeroish" value (null pointer or 0 for numerical values).
+ * Unlabeled fields are supported only in proto3.
+ *
+ * \param field
+ * Field descriptor for member.
+ * \param member
+ * Field to encode.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field,
+ const void *member)
+{
+ if (field_is_zeroish(field, member))
+ return 0;
+ return required_field_get_packed_size(field, member);
+}
+
+/**
+ * Calculate the serialized size of repeated message fields, which may consist
+ * of any number of values (including 0). Includes the space needed by the
+ * preceding tags (as needed).
+ *
+ * \param field
+ * Field descriptor for member.
+ * \param count
+ * Number of repeated field members.
+ * \param member
+ * Field to encode.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field,
+ size_t count, const void *member)
+{
+ size_t header_size;
+ size_t rv = 0;
+ unsigned i;
+ void *array = *(void * const *) member;
+
+ if (count == 0)
+ return 0;
+ header_size = get_tag_size(field->id);
+ if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED))
+ header_size *= count;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SINT32:
+ for (i = 0; i < count; i++)
+ rv += sint32_size(((int32_t *) array)[i]);
+ break;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ for (i = 0; i < count; i++)
+ rv += int32_size(((int32_t *) array)[i]);
+ break;
+ case PROTOBUF_C_TYPE_UINT32:
+ for (i = 0; i < count; i++)
+ rv += uint32_size(((uint32_t *) array)[i]);
+ break;
+ case PROTOBUF_C_TYPE_SINT64:
+ for (i = 0; i < count; i++)
+ rv += sint64_size(((int64_t *) array)[i]);
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ for (i = 0; i < count; i++)
+ rv += uint64_size(((uint64_t *) array)[i]);
+ break;
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ rv += 4 * count;
+ break;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ rv += 8 * count;
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ rv += count;
+ break;
+ case PROTOBUF_C_TYPE_STRING:
+ for (i = 0; i < count; i++) {
+ size_t len = strlen(((char **) array)[i]);
+ rv += uint32_size(len) + len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_BYTES:
+ for (i = 0; i < count; i++) {
+ size_t len = ((ProtobufCBinaryData *) array)[i].len;
+ rv += uint32_size(len) + len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_MESSAGE:
+ for (i = 0; i < count; i++) {
+ size_t len = protobuf_c_message_get_packed_size(
+ ((ProtobufCMessage **) array)[i]);
+ rv += uint32_size(len) + len;
+ }
+ break;
+ }
+
+ if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED))
+ header_size += uint32_size(rv);
+ return header_size + rv;
+}
+
+/**
+ * Calculate the serialized size of an unknown field, i.e. one that is passed
+ * through mostly uninterpreted. This is required for forward compatibility if
+ * new fields are added to the message descriptor.
+ *
+ * \param field
+ * Unknown field type.
+ * \return
+ * Number of bytes required.
+ */
+static inline size_t
+unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field)
+{
+ return get_tag_size(field->tag) + field->len;
+}
+
+/**@}*/
+
+/*
+ * Calculate the serialized size of the message.
+ */
+size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message)
+{
+ unsigned i;
+ size_t rv = 0;
+
+ ASSERT_IS_MESSAGE(message);
+ for (i = 0; i < message->descriptor->n_fields; i++) {
+ const ProtobufCFieldDescriptor *field =
+ message->descriptor->fields + i;
+ const void *member =
+ ((const char *) message) + field->offset;
+ const void *qmember =
+ ((const char *) message) + field->quantifier_offset;
+
+ if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
+ rv += required_field_get_packed_size(field, member);
+ } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
+ field->label == PROTOBUF_C_LABEL_NONE) &&
+ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
+ rv += oneof_field_get_packed_size(
+ field,
+ *(const uint32_t *) qmember,
+ member
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
+ rv += optional_field_get_packed_size(
+ field,
+ *(protobuf_c_boolean *) qmember,
+ member
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_NONE) {
+ rv += unlabeled_field_get_packed_size(
+ field,
+ member
+ );
+ } else {
+ rv += repeated_field_get_packed_size(
+ field,
+ *(const size_t *) qmember,
+ member
+ );
+ }
+ }
+ for (i = 0; i < message->n_unknown_fields; i++)
+ rv += unknown_field_get_packed_size(&message->unknown_fields[i]);
+ return rv;
+}
+
+/**
+ * \defgroup pack protobuf_c_message_pack() implementation
+ *
+ * Routines mainly used by protobuf_c_message_pack().
+ *
+ * \ingroup internal
+ * @{
+ */
+
+/**
+ * Pack an unsigned 32-bit integer in base-128 varint encoding and return the
+ * number of bytes written, which must be 5 or less.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+uint32_pack(uint32_t value, uint8_t *out)
+{
+ unsigned rv = 0;
+
+ if (value >= 0x80) {
+ out[rv++] = value | 0x80;
+ value >>= 7;
+ if (value >= 0x80) {
+ out[rv++] = value | 0x80;
+ value >>= 7;
+ if (value >= 0x80) {
+ out[rv++] = value | 0x80;
+ value >>= 7;
+ if (value >= 0x80) {
+ out[rv++] = value | 0x80;
+ value >>= 7;
+ }
+ }
+ }
+ }
+ /* assert: value<128 */
+ out[rv++] = value;
+ return rv;
+}
+
+/**
+ * Pack a signed 32-bit integer and return the number of bytes written.
+ * Negative numbers are encoded as two's complement 64-bit integers.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+int32_pack(int32_t value, uint8_t *out)
+{
+ if (value < 0) {
+ out[0] = value | 0x80;
+ out[1] = (value >> 7) | 0x80;
+ out[2] = (value >> 14) | 0x80;
+ out[3] = (value >> 21) | 0x80;
+ out[4] = (value >> 28) | 0x80;
+ out[5] = out[6] = out[7] = out[8] = 0xff;
+ out[9] = 0x01;
+ return 10;
+ } else {
+ return uint32_pack(value, out);
+ }
+}
+
+/**
+ * Pack a signed 32-bit integer using ZigZag encoding and return the number of
+ * bytes written.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+sint32_pack(int32_t value, uint8_t *out)
+{
+ return uint32_pack(zigzag32(value), out);
+}
+
+/**
+ * Pack a 64-bit unsigned integer using base-128 varint encoding and return the
+ * number of bytes written.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+uint64_pack(uint64_t value, uint8_t *out)
+{
+ uint32_t hi = (uint32_t) (value >> 32);
+ uint32_t lo = (uint32_t) value;
+ unsigned rv;
+
+ if (hi == 0)
+ return uint32_pack((uint32_t) lo, out);
+ out[0] = (lo) | 0x80;
+ out[1] = (lo >> 7) | 0x80;
+ out[2] = (lo >> 14) | 0x80;
+ out[3] = (lo >> 21) | 0x80;
+ if (hi < 8) {
+ out[4] = (hi << 4) | (lo >> 28);
+ return 5;
+ } else {
+ out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80;
+ hi >>= 3;
+ }
+ rv = 5;
+ while (hi >= 128) {
+ out[rv++] = hi | 0x80;
+ hi >>= 7;
+ }
+ out[rv++] = hi;
+ return rv;
+}
+
+/**
+ * Pack a 64-bit signed integer in ZigZag encoding and return the number of
+ * bytes written.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+sint64_pack(int64_t value, uint8_t *out)
+{
+ return uint64_pack(zigzag64(value), out);
+}
+
+/**
+ * Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire
+ * types fixed32, sfixed32, float. Similar to "htole32".
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+fixed32_pack(uint32_t value, void *out)
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(out, &value, 4);
+#else
+ uint8_t *buf = out;
+
+ buf[0] = value;
+ buf[1] = value >> 8;
+ buf[2] = value >> 16;
+ buf[3] = value >> 24;
+#endif
+ return 4;
+}
+
+/**
+ * Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire
+ * types fixed64, sfixed64, double. Similar to "htole64".
+ *
+ * \todo The big-endian impl is really only good for 32-bit machines, a 64-bit
+ * version would be appreciated, plus a way to decide to use 64-bit math where
+ * convenient.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+fixed64_pack(uint64_t value, void *out)
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(out, &value, 8);
+#else
+ fixed32_pack(value, out);
+ fixed32_pack(value >> 32, ((char *) out) + 4);
+#endif
+ return 8;
+}
+
+/**
+ * Pack a boolean value as an integer and return the number of bytes written.
+ *
+ * \todo Perhaps on some platforms *out = !!value would be a better impl, b/c
+ * that is idiomatic C++ in some STL implementations.
+ *
+ * \param value
+ * Value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+boolean_pack(protobuf_c_boolean value, uint8_t *out)
+{
+ *out = value ? TRUE : FALSE;
+ return 1;
+}
+
+/**
+ * Pack a NUL-terminated C string and return the number of bytes written. The
+ * output includes a length delimiter.
+ *
+ * The NULL pointer is treated as an empty string. This isn't really necessary,
+ * but it allows people to leave required strings blank. (See Issue #13 in the
+ * bug tracker for a little more explanation).
+ *
+ * \param str
+ * String to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+string_pack(const char *str, uint8_t *out)
+{
+ if (str == NULL) {
+ out[0] = 0;
+ return 1;
+ } else {
+ size_t len = strlen(str);
+ size_t rv = uint32_pack(len, out);
+ memcpy(out + rv, str, len);
+ return rv + len;
+ }
+}
+
+/**
+ * Pack a ProtobufCBinaryData and return the number of bytes written. The output
+ * includes a length delimiter.
+ *
+ * \param bd
+ * ProtobufCBinaryData to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out)
+{
+ size_t len = bd->len;
+ size_t rv = uint32_pack(len, out);
+ memcpy(out + rv, bd->data, len);
+ return rv + len;
+}
+
+/**
+ * Pack a ProtobufCMessage and return the number of bytes written. The output
+ * includes a length delimiter.
+ *
+ * \param message
+ * ProtobufCMessage object to pack.
+ * \param[out] out
+ * Packed message.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static inline size_t
+prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out)
+{
+ if (message == NULL) {
+ out[0] = 0;
+ return 1;
+ } else {
+ size_t rv = protobuf_c_message_pack(message, out + 1);
+ uint32_t rv_packed_size = uint32_size(rv);
+ if (rv_packed_size != 1)
+ memmove(out + rv_packed_size, out + 1, rv);
+ return uint32_pack(rv, out) + rv;
+ }
+}
+
+/**
+ * Pack a field tag.
+ *
+ * Wire-type will be added in required_field_pack().
+ *
+ * \todo Just call uint64_pack on 64-bit platforms.
+ *
+ * \param id
+ * Tag value to encode.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+tag_pack(uint32_t id, uint8_t *out)
+{
+ if (id < (1UL << (32 - 3)))
+ return uint32_pack(id << 3, out);
+ else
+ return uint64_pack(((uint64_t) id) << 3, out);
+}
+
+/**
+ * Pack a required field and return the number of bytes written.
+ *
+ * \param field
+ * Field descriptor.
+ * \param member
+ * The field member.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+required_field_pack(const ProtobufCFieldDescriptor *field,
+ const void *member, uint8_t *out)
+{
+ size_t rv = tag_pack(field->id, out);
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SINT32:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + sint32_pack(*(const int32_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + int32_pack(*(const int32_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_UINT32:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + uint32_pack(*(const uint32_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_SINT64:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + sint64_pack(*(const int64_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + uint64_pack(*(const uint64_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT;
+ return rv + fixed32_pack(*(const uint32_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT;
+ return rv + fixed64_pack(*(const uint64_t *) member, out + rv);
+ case PROTOBUF_C_TYPE_BOOL:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv);
+ case PROTOBUF_C_TYPE_STRING:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ return rv + string_pack(*(char *const *) member, out + rv);
+ case PROTOBUF_C_TYPE_BYTES:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv);
+ case PROTOBUF_C_TYPE_MESSAGE:
+ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv);
+ }
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ return 0;
+}
+
+/**
+ * Pack a oneof field and return the number of bytes written. Only packs the
+ * field that is selected by the case enum.
+ *
+ * \param field
+ * Field descriptor.
+ * \param oneof_case
+ * Enum value that selects the field in the oneof.
+ * \param member
+ * The field member.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+oneof_field_pack(const ProtobufCFieldDescriptor *field,
+ uint32_t oneof_case,
+ const void *member, uint8_t *out)
+{
+ if (oneof_case != field->id) {
+ return 0;
+ }
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void * const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ }
+ return required_field_pack(field, member, out);
+}
+
+/**
+ * Pack an optional field and return the number of bytes written.
+ *
+ * \param field
+ * Field descriptor.
+ * \param has
+ * Whether the field is set.
+ * \param member
+ * The field member.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+optional_field_pack(const ProtobufCFieldDescriptor *field,
+ const protobuf_c_boolean has,
+ const void *member, uint8_t *out)
+{
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void * const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ } else {
+ if (!has)
+ return 0;
+ }
+ return required_field_pack(field, member, out);
+}
+
+/**
+ * Pack an unlabeled field and return the number of bytes written.
+ *
+ * \param field
+ * Field descriptor.
+ * \param member
+ * The field member.
+ * \param[out] out
+ * Packed value.
+ * \return
+ * Number of bytes written to `out`.
+ */
+static size_t
+unlabeled_field_pack(const ProtobufCFieldDescriptor *field,
+ const void *member, uint8_t *out)
+{
+ if (field_is_zeroish(field, member))
+ return 0;
+ return required_field_pack(field, member, out);
+}
+
+/**
+ * Given a field type, return the in-memory size.
+ *
+ * \todo Implement as a table lookup.
+ *
+ * \param type
+ * Field type.
+ * \return
+ * Size of the field.
+ */
+static inline size_t
+sizeof_elt_in_repeated_array(ProtobufCType type)
+{
+ switch (type) {
+ case PROTOBUF_C_TYPE_SINT32:
+ case PROTOBUF_C_TYPE_INT32:
+ case PROTOBUF_C_TYPE_UINT32:
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ case PROTOBUF_C_TYPE_ENUM:
+ return 4;
+ case PROTOBUF_C_TYPE_SINT64:
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ return 8;
+ case PROTOBUF_C_TYPE_BOOL:
+ return sizeof(protobuf_c_boolean);
+ case PROTOBUF_C_TYPE_STRING:
+ case PROTOBUF_C_TYPE_MESSAGE:
+ return sizeof(void *);
+ case PROTOBUF_C_TYPE_BYTES:
+ return sizeof(ProtobufCBinaryData);
+ }
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ return 0;
+}
+
+/**
+ * Pack an array of 32-bit quantities.
+ *
+ * \param[out] out
+ * Destination.
+ * \param[in] in
+ * Source.
+ * \param[in] n
+ * Number of elements in the source array.
+ */
+static void
+copy_to_little_endian_32(void *out, const void *in, const unsigned n)
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(out, in, n * 4);
+#else
+ unsigned i;
+ const uint32_t *ini = in;
+ for (i = 0; i < n; i++)
+ fixed32_pack(ini[i], (uint32_t *) out + i);
+#endif
+}
+
+/**
+ * Pack an array of 64-bit quantities.
+ *
+ * \param[out] out
+ * Destination.
+ * \param[in] in
+ * Source.
+ * \param[in] n
+ * Number of elements in the source array.
+ */
+static void
+copy_to_little_endian_64(void *out, const void *in, const unsigned n)
+{
+#if !defined(WORDS_BIGENDIAN)
+ memcpy(out, in, n * 8);
+#else
+ unsigned i;
+ const uint64_t *ini = in;
+ for (i = 0; i < n; i++)
+ fixed64_pack(ini[i], (uint64_t *) out + i);
+#endif
+}
+
+/**
+ * Get the minimum number of bytes required to pack a field value of a
+ * particular type.
+ *
+ * \param type
+ * Field type.
+ * \return
+ * Number of bytes.
+ */
+static unsigned
+get_type_min_size(ProtobufCType type)
+{
+ if (type == PROTOBUF_C_TYPE_SFIXED32 ||
+ type == PROTOBUF_C_TYPE_FIXED32 ||
+ type == PROTOBUF_C_TYPE_FLOAT)
+ {
+ return 4;
+ }
+ if (type == PROTOBUF_C_TYPE_SFIXED64 ||
+ type == PROTOBUF_C_TYPE_FIXED64 ||
+ type == PROTOBUF_C_TYPE_DOUBLE)
+ {
+ return 8;
+ }
+ return 1;
+}
+
+/**
+ * Packs the elements of a repeated field and returns the serialised field and
+ * its length.
+ *
+ * \param field
+ * Field descriptor.
+ * \param count
+ * Number of elements in the repeated field array.
+ * \param member
+ * Pointer to the elements for this repeated field.
+ * \param[out] out
+ * Serialised representation of the repeated field.
+ * \return
+ * Number of bytes serialised to `out`.
+ */
+static size_t
+repeated_field_pack(const ProtobufCFieldDescriptor *field,
+ size_t count, const void *member, uint8_t *out)
+{
+ void *array = *(void * const *) member;
+ unsigned i;
+
+ if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) {
+ unsigned header_len;
+ unsigned len_start;
+ unsigned min_length;
+ unsigned payload_len;
+ unsigned length_size_min;
+ unsigned actual_length_size;
+ uint8_t *payload_at;
+
+ if (count == 0)
+ return 0;
+ header_len = tag_pack(field->id, out);
+ out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ len_start = header_len;
+ min_length = get_type_min_size(field->type) * count;
+ length_size_min = uint32_size(min_length);
+ header_len += length_size_min;
+ payload_at = out + header_len;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ copy_to_little_endian_32(payload_at, array, count);
+ payload_at += count * 4;
+ break;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ copy_to_little_endian_64(payload_at, array, count);
+ payload_at += count * 8;
+ break;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32: {
+ const int32_t *arr = (const int32_t *) array;
+ for (i = 0; i < count; i++)
+ payload_at += int32_pack(arr[i], payload_at);
+ break;
+ }
+ case PROTOBUF_C_TYPE_SINT32: {
+ const int32_t *arr = (const int32_t *) array;
+ for (i = 0; i < count; i++)
+ payload_at += sint32_pack(arr[i], payload_at);
+ break;
+ }
+ case PROTOBUF_C_TYPE_SINT64: {
+ const int64_t *arr = (const int64_t *) array;
+ for (i = 0; i < count; i++)
+ payload_at += sint64_pack(arr[i], payload_at);
+ break;
+ }
+ case PROTOBUF_C_TYPE_UINT32: {
+ const uint32_t *arr = (const uint32_t *) array;
+ for (i = 0; i < count; i++)
+ payload_at += uint32_pack(arr[i], payload_at);
+ break;
+ }
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64: {
+ const uint64_t *arr = (const uint64_t *) array;
+ for (i = 0; i < count; i++)
+ payload_at += uint64_pack(arr[i], payload_at);
+ break;
+ }
+ case PROTOBUF_C_TYPE_BOOL: {
+ const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array;
+ for (i = 0; i < count; i++)
+ payload_at += boolean_pack(arr[i], payload_at);
+ break;
+ }
+ default:
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ }
+
+ payload_len = payload_at - (out + header_len);
+ actual_length_size = uint32_size(payload_len);
+ if (length_size_min != actual_length_size) {
+ assert(actual_length_size == length_size_min + 1);
+ memmove(out + header_len + 1, out + header_len,
+ payload_len);
+ header_len++;
+ }
+ uint32_pack(payload_len, out + len_start);
+ return header_len + payload_len;
+ } else {
+ /* not "packed" cased */
+ /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */
+ size_t rv = 0;
+ unsigned siz = sizeof_elt_in_repeated_array(field->type);
+
+ for (i = 0; i < count; i++) {
+ rv += required_field_pack(field, array, out + rv);
+ array = (char *)array + siz;
+ }
+ return rv;
+ }
+}
+
+static size_t
+unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out)
+{
+ size_t rv = tag_pack(field->tag, out);
+ out[0] |= field->wire_type;
+ memcpy(out + rv, field->data, field->len);
+ return rv + field->len;
+}
+
+/**@}*/
+
+size_t
+protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out)
+{
+ unsigned i;
+ size_t rv = 0;
+
+ ASSERT_IS_MESSAGE(message);
+ for (i = 0; i < message->descriptor->n_fields; i++) {
+ const ProtobufCFieldDescriptor *field =
+ message->descriptor->fields + i;
+ const void *member = ((const char *) message) + field->offset;
+
+ /*
+ * It doesn't hurt to compute qmember (a pointer to the
+ * quantifier field of the structure), but the pointer is only
+ * valid if the field is:
+ * - a repeated field, or
+ * - a field that is part of a oneof
+ * - an optional field that isn't a pointer type
+ * (Meaning: not a message or a string).
+ */
+ const void *qmember =
+ ((const char *) message) + field->quantifier_offset;
+
+ if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
+ rv += required_field_pack(field, member, out + rv);
+ } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
+ field->label == PROTOBUF_C_LABEL_NONE) &&
+ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
+ rv += oneof_field_pack(
+ field,
+ *(const uint32_t *) qmember,
+ member,
+ out + rv
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
+ rv += optional_field_pack(
+ field,
+ *(const protobuf_c_boolean *) qmember,
+ member,
+ out + rv
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_NONE) {
+ rv += unlabeled_field_pack(field, member, out + rv);
+ } else {
+ rv += repeated_field_pack(field, *(const size_t *) qmember,
+ member, out + rv);
+ }
+ }
+ for (i = 0; i < message->n_unknown_fields; i++)
+ rv += unknown_field_pack(&message->unknown_fields[i], out + rv);
+ return rv;
+}
+
+/**
+ * \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation
+ *
+ * Routines mainly used by protobuf_c_message_pack_to_buffer().
+ *
+ * \ingroup internal
+ * @{
+ */
+
+/**
+ * Pack a required field to a virtual buffer.
+ *
+ * \param field
+ * Field descriptor.
+ * \param member
+ * The element to be packed.
+ * \param[out] buffer
+ * Virtual buffer to append data to.
+ * \return
+ * Number of bytes packed.
+ */
+static size_t
+required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
+ const void *member, ProtobufCBuffer *buffer)
+{
+ size_t rv;
+ uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2];
+
+ rv = tag_pack(field->id, scratch);
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SINT32:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += sint32_pack(*(const int32_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += int32_pack(*(const int32_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_UINT32:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += uint32_pack(*(const uint32_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_SINT64:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += sint64_pack(*(const int64_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += uint64_pack(*(const uint64_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT;
+ rv += fixed32_pack(*(const uint32_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT;
+ rv += fixed64_pack(*(const uint64_t *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
+ rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ break;
+ case PROTOBUF_C_TYPE_STRING: {
+ const char *str = *(char *const *) member;
+ size_t sublen = str ? strlen(str) : 0;
+
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ rv += uint32_pack(sublen, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ buffer->append(buffer, sublen, (const uint8_t *) str);
+ rv += sublen;
+ break;
+ }
+ case PROTOBUF_C_TYPE_BYTES: {
+ const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member);
+ size_t sublen = bd->len;
+
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ rv += uint32_pack(sublen, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ buffer->append(buffer, sublen, bd->data);
+ rv += sublen;
+ break;
+ }
+ case PROTOBUF_C_TYPE_MESSAGE: {
+ uint8_t simple_buffer_scratch[256];
+ size_t sublen;
+ const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member;
+ ProtobufCBufferSimple simple_buffer =
+ PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch);
+
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ if (msg == NULL)
+ sublen = 0;
+ else
+ sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base);
+ rv += uint32_pack(sublen, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ buffer->append(buffer, sublen, simple_buffer.data);
+ rv += sublen;
+ PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer);
+ break;
+ }
+ default:
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ }
+ return rv;
+}
+
+/**
+ * Pack a oneof field to a buffer. Only packs the field that is selected by the case enum.
+ *
+ * \param field
+ * Field descriptor.
+ * \param oneof_case
+ * Enum value that selects the field in the oneof.
+ * \param member
+ * The element to be packed.
+ * \param[out] buffer
+ * Virtual buffer to append data to.
+ * \return
+ * Number of bytes serialised to `buffer`.
+ */
+static size_t
+oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
+ uint32_t oneof_case,
+ const void *member, ProtobufCBuffer *buffer)
+{
+ if (oneof_case != field->id) {
+ return 0;
+ }
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void *const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ }
+ return required_field_pack_to_buffer(field, member, buffer);
+}
+
+/**
+ * Pack an optional field to a buffer.
+ *
+ * \param field
+ * Field descriptor.
+ * \param has
+ * Whether the field is set.
+ * \param member
+ * The element to be packed.
+ * \param[out] buffer
+ * Virtual buffer to append data to.
+ * \return
+ * Number of bytes serialised to `buffer`.
+ */
+static size_t
+optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
+ const protobuf_c_boolean has,
+ const void *member, ProtobufCBuffer *buffer)
+{
+ if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
+ field->type == PROTOBUF_C_TYPE_STRING)
+ {
+ const void *ptr = *(const void *const *) member;
+ if (ptr == NULL || ptr == field->default_value)
+ return 0;
+ } else {
+ if (!has)
+ return 0;
+ }
+ return required_field_pack_to_buffer(field, member, buffer);
+}
+
+/**
+ * Pack an unlabeled field to a buffer.
+ *
+ * \param field
+ * Field descriptor.
+ * \param member
+ * The element to be packed.
+ * \param[out] buffer
+ * Virtual buffer to append data to.
+ * \return
+ * Number of bytes serialised to `buffer`.
+ */
+static size_t
+unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
+ const void *member, ProtobufCBuffer *buffer)
+{
+ if (field_is_zeroish(field, member))
+ return 0;
+ return required_field_pack_to_buffer(field, member, buffer);
+}
+
+/**
+ * Get the packed size of an array of same field type.
+ *
+ * \param field
+ * Field descriptor.
+ * \param count
+ * Number of elements of this type.
+ * \param array
+ * The elements to get the size of.
+ * \return
+ * Number of bytes required.
+ */
+static size_t
+get_packed_payload_length(const ProtobufCFieldDescriptor *field,
+ unsigned count, const void *array)
+{
+ unsigned rv = 0;
+ unsigned i;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ return count * 4;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ return count * 8;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32: {
+ const int32_t *arr = (const int32_t *) array;
+ for (i = 0; i < count; i++)
+ rv += int32_size(arr[i]);
+ break;
+ }
+ case PROTOBUF_C_TYPE_SINT32: {
+ const int32_t *arr = (const int32_t *) array;
+ for (i = 0; i < count; i++)
+ rv += sint32_size(arr[i]);
+ break;
+ }
+ case PROTOBUF_C_TYPE_UINT32: {
+ const uint32_t *arr = (const uint32_t *) array;
+ for (i = 0; i < count; i++)
+ rv += uint32_size(arr[i]);
+ break;
+ }
+ case PROTOBUF_C_TYPE_SINT64: {
+ const int64_t *arr = (const int64_t *) array;
+ for (i = 0; i < count; i++)
+ rv += sint64_size(arr[i]);
+ break;
+ }
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64: {
+ const uint64_t *arr = (const uint64_t *) array;
+ for (i = 0; i < count; i++)
+ rv += uint64_size(arr[i]);
+ break;
+ }
+ case PROTOBUF_C_TYPE_BOOL:
+ return count;
+ default:
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ }
+ return rv;
+}
+
+/**
+ * Pack an array of same field type to a virtual buffer.
+ *
+ * \param field
+ * Field descriptor.
+ * \param count
+ * Number of elements of this type.
+ * \param array
+ * The elements to get the size of.
+ * \param[out] buffer
+ * Virtual buffer to append data to.
+ * \return
+ * Number of bytes packed.
+ */
+static size_t
+pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field,
+ unsigned count, const void *array,
+ ProtobufCBuffer *buffer)
+{
+ uint8_t scratch[16];
+ size_t rv = 0;
+ unsigned i;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+#if !defined(WORDS_BIGENDIAN)
+ rv = count * 4;
+ goto no_packing_needed;
+#else
+ for (i = 0; i < count; i++) {
+ unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+#endif
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+#if !defined(WORDS_BIGENDIAN)
+ rv = count * 8;
+ goto no_packing_needed;
+#else
+ for (i = 0; i < count; i++) {
+ unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+#endif
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ for (i = 0; i < count; i++) {
+ unsigned len = int32_pack(((int32_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_SINT32:
+ for (i = 0; i < count; i++) {
+ unsigned len = sint32_pack(((int32_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_UINT32:
+ for (i = 0; i < count; i++) {
+ unsigned len = uint32_pack(((uint32_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_SINT64:
+ for (i = 0; i < count; i++) {
+ unsigned len = sint64_pack(((int64_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ for (i = 0; i < count; i++) {
+ unsigned len = uint64_pack(((uint64_t *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ for (i = 0; i < count; i++) {
+ unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch);
+ buffer->append(buffer, len, scratch);
+ rv += len;
+ }
+ return count;
+ default:
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ }
+ return rv;
+
+#if !defined(WORDS_BIGENDIAN)
+no_packing_needed:
+ buffer->append(buffer, rv, array);
+ return rv;
+#endif
+}
+
+static size_t
+repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
+ unsigned count, const void *member,
+ ProtobufCBuffer *buffer)
+{
+ char *array = *(char * const *) member;
+
+ if (count == 0)
+ return 0;
+ if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) {
+ uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2];
+ size_t rv = tag_pack(field->id, scratch);
+ size_t payload_len = get_packed_payload_length(field, count, array);
+ size_t tmp;
+
+ scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
+ rv += uint32_pack(payload_len, scratch + rv);
+ buffer->append(buffer, rv, scratch);
+ tmp = pack_buffer_packed_payload(field, count, array, buffer);
+ assert(tmp == payload_len);
+ return rv + payload_len;
+ } else {
+ size_t siz;
+ unsigned i;
+ /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */
+ unsigned rv = 0;
+
+ siz = sizeof_elt_in_repeated_array(field->type);
+ for (i = 0; i < count; i++) {
+ rv += required_field_pack_to_buffer(field, array, buffer);
+ array += siz;
+ }
+ return rv;
+ }
+}
+
+static size_t
+unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field,
+ ProtobufCBuffer *buffer)
+{
+ uint8_t header[MAX_UINT64_ENCODED_SIZE];
+ size_t rv = tag_pack(field->tag, header);
+
+ header[0] |= field->wire_type;
+ buffer->append(buffer, rv, header);
+ buffer->append(buffer, field->len, field->data);
+ return rv + field->len;
+}
+
+/**@}*/
+
+size_t
+protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message,
+ ProtobufCBuffer *buffer)
+{
+ unsigned i;
+ size_t rv = 0;
+
+ ASSERT_IS_MESSAGE(message);
+ for (i = 0; i < message->descriptor->n_fields; i++) {
+ const ProtobufCFieldDescriptor *field =
+ message->descriptor->fields + i;
+ const void *member =
+ ((const char *) message) + field->offset;
+ const void *qmember =
+ ((const char *) message) + field->quantifier_offset;
+
+ if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
+ rv += required_field_pack_to_buffer(field, member, buffer);
+ } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
+ field->label == PROTOBUF_C_LABEL_NONE) &&
+ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
+ rv += oneof_field_pack_to_buffer(
+ field,
+ *(const uint32_t *) qmember,
+ member,
+ buffer
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
+ rv += optional_field_pack_to_buffer(
+ field,
+ *(const protobuf_c_boolean *) qmember,
+ member,
+ buffer
+ );
+ } else if (field->label == PROTOBUF_C_LABEL_NONE) {
+ rv += unlabeled_field_pack_to_buffer(
+ field,
+ member,
+ buffer
+ );
+ } else {
+ rv += repeated_field_pack_to_buffer(
+ field,
+ *(const size_t *) qmember,
+ member,
+ buffer
+ );
+ }
+ }
+ for (i = 0; i < message->n_unknown_fields; i++)
+ rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer);
+
+ return rv;
+}
+
+/**
+ * \defgroup unpack unpacking implementation
+ *
+ * Routines mainly used by the unpacking functions.
+ *
+ * \ingroup internal
+ * @{
+ */
+
+static inline int
+int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value)
+{
+ unsigned n;
+ unsigned start;
+
+ if (n_ranges == 0)
+ return -1;
+ start = 0;
+ n = n_ranges;
+ while (n > 1) {
+ unsigned mid = start + n / 2;
+
+ if (value < ranges[mid].start_value) {
+ n = mid - start;
+ } else if (value >= ranges[mid].start_value +
+ (int) (ranges[mid + 1].orig_index -
+ ranges[mid].orig_index))
+ {
+ unsigned new_start = mid + 1;
+ n = start + n - new_start;
+ start = new_start;
+ } else
+ return (value - ranges[mid].start_value) +
+ ranges[mid].orig_index;
+ }
+ if (n > 0) {
+ unsigned start_orig_index = ranges[start].orig_index;
+ unsigned range_size =
+ ranges[start + 1].orig_index - start_orig_index;
+
+ if (ranges[start].start_value <= value &&
+ value < (int) (ranges[start].start_value + range_size))
+ {
+ return (value - ranges[start].start_value) +
+ start_orig_index;
+ }
+ }
+ return -1;
+}
+
+static size_t
+parse_tag_and_wiretype(size_t len,
+ const uint8_t *data,
+ uint32_t *tag_out,
+ ProtobufCWireType *wiretype_out)
+{
+ unsigned max_rv = len > 5 ? 5 : len;
+ uint32_t tag = (data[0] & 0x7f) >> 3;
+ unsigned shift = 4;
+ unsigned rv;
+
+ *wiretype_out = data[0] & 7;
+ if ((data[0] & 0x80) == 0) {
+ *tag_out = tag;
+ return 1;
+ }
+ for (rv = 1; rv < max_rv; rv++) {
+ if (data[rv] & 0x80) {
+ tag |= (data[rv] & 0x7f) << shift;
+ shift += 7;
+ } else {
+ tag |= data[rv] << shift;
+ *tag_out = tag;
+ return rv + 1;
+ }
+ }
+ return 0; /* error: bad header */
+}
+
+/* sizeof(ScannedMember) must be <= (1UL<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */
+#define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5
+typedef struct _ScannedMember ScannedMember;
+/** Field as it's being read. */
+struct _ScannedMember {
+ uint32_t tag; /**< Field tag. */
+ uint8_t wire_type; /**< Field type. */
+ uint8_t length_prefix_len; /**< Prefix length. */
+ const ProtobufCFieldDescriptor *field; /**< Field descriptor. */
+ size_t len; /**< Field length. */
+ const uint8_t *data; /**< Pointer to field data. */
+};
+
+static inline uint32_t
+scan_length_prefixed_data(size_t len, const uint8_t *data,
+ size_t *prefix_len_out)
+{
+ unsigned hdr_max = len < 5 ? len : 5;
+ unsigned hdr_len;
+ uint32_t val = 0;
+ unsigned i;
+ unsigned shift = 0;
+
+ for (i = 0; i < hdr_max; i++) {
+ val |= (data[i] & 0x7f) << shift;
+ shift += 7;
+ if ((data[i] & 0x80) == 0)
+ break;
+ }
+ if (i == hdr_max) {
+ PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data");
+ return 0;
+ }
+ hdr_len = i + 1;
+ *prefix_len_out = hdr_len;
+ if (hdr_len + val > len) {
+ PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val);
+ return 0;
+ }
+ return hdr_len + val;
+}
+
+static size_t
+max_b128_numbers(size_t len, const uint8_t *data)
+{
+ size_t rv = 0;
+ while (len--)
+ if ((*data++ & 0x80) == 0)
+ ++rv;
+ return rv;
+}
+
+/**@}*/
+
+/**
+ * Merge earlier message into a latter message.
+ *
+ * For numeric types and strings, if the same value appears multiple
+ * times, the parser accepts the last value it sees. For embedded
+ * message fields, the parser merges multiple instances of the same
+ * field. That is, all singular scalar fields in the latter instance
+ * replace those in the former, singular embedded messages are merged,
+ * and repeated fields are concatenated.
+ *
+ * The earlier message should be freed after calling this function, as
+ * some of its fields may have been reused and changed to their default
+ * values during the merge.
+ */
+static protobuf_c_boolean
+merge_messages(ProtobufCMessage *earlier_msg,
+ ProtobufCMessage *latter_msg,
+ ProtobufCAllocator *allocator)
+{
+ unsigned i;
+ const ProtobufCFieldDescriptor *fields =
+ latter_msg->descriptor->fields;
+ for (i = 0; i < latter_msg->descriptor->n_fields; i++) {
+ if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ size_t *n_earlier =
+ STRUCT_MEMBER_PTR(size_t, earlier_msg,
+ fields[i].quantifier_offset);
+ uint8_t **p_earlier =
+ STRUCT_MEMBER_PTR(uint8_t *, earlier_msg,
+ fields[i].offset);
+ size_t *n_latter =
+ STRUCT_MEMBER_PTR(size_t, latter_msg,
+ fields[i].quantifier_offset);
+ uint8_t **p_latter =
+ STRUCT_MEMBER_PTR(uint8_t *, latter_msg,
+ fields[i].offset);
+
+ if (*n_earlier > 0) {
+ if (*n_latter > 0) {
+ /* Concatenate the repeated field */
+ size_t el_size =
+ sizeof_elt_in_repeated_array(fields[i].type);
+ uint8_t *new_field;
+
+ new_field = do_alloc(allocator,
+ (*n_earlier + *n_latter) * el_size);
+ if (!new_field)
+ return FALSE;
+
+ memcpy(new_field, *p_earlier,
+ *n_earlier * el_size);
+ memcpy(new_field +
+ *n_earlier * el_size,
+ *p_latter,
+ *n_latter * el_size);
+
+ do_free(allocator, *p_latter);
+ do_free(allocator, *p_earlier);
+ *p_latter = new_field;
+ *n_latter = *n_earlier + *n_latter;
+ } else {
+ /* Zero copy the repeated field from the earlier message */
+ *n_latter = *n_earlier;
+ *p_latter = *p_earlier;
+ }
+ /* Make sure the field does not get double freed */
+ *n_earlier = 0;
+ *p_earlier = 0;
+ }
+ } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL ||
+ fields[i].label == PROTOBUF_C_LABEL_NONE) {
+ const ProtobufCFieldDescriptor *field;
+ uint32_t *earlier_case_p = STRUCT_MEMBER_PTR(uint32_t,
+ earlier_msg,
+ fields[i].
+ quantifier_offset);
+ uint32_t *latter_case_p = STRUCT_MEMBER_PTR(uint32_t,
+ latter_msg,
+ fields[i].
+ quantifier_offset);
+ protobuf_c_boolean need_to_merge = FALSE;
+ void *earlier_elem;
+ void *latter_elem;
+ const void *def_val;
+
+ if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) {
+ if (*latter_case_p == 0) {
+ /* lookup correct oneof field */
+ int field_index =
+ int_range_lookup(
+ latter_msg->descriptor
+ ->n_field_ranges,
+ latter_msg->descriptor
+ ->field_ranges,
+ *earlier_case_p);
+ field = latter_msg->descriptor->fields +
+ field_index;
+ } else {
+ /* Oneof is present in the latter message, move on */
+ continue;
+ }
+ } else {
+ field = &fields[i];
+ }
+
+ earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset);
+ latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset);
+ def_val = field->default_value;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_MESSAGE: {
+ ProtobufCMessage *em = *(ProtobufCMessage **) earlier_elem;
+ ProtobufCMessage *lm = *(ProtobufCMessage **) latter_elem;
+ if (em != NULL) {
+ if (lm != NULL) {
+ if (!merge_messages(em, lm, allocator))
+ return FALSE;
+ /* Already merged */
+ need_to_merge = FALSE;
+ } else {
+ /* Zero copy the message */
+ need_to_merge = TRUE;
+ }
+ }
+ break;
+ }
+ case PROTOBUF_C_TYPE_BYTES: {
+ uint8_t *e_data =
+ ((ProtobufCBinaryData *) earlier_elem)->data;
+ uint8_t *l_data =
+ ((ProtobufCBinaryData *) latter_elem)->data;
+ const ProtobufCBinaryData *d_bd =
+ (ProtobufCBinaryData *) def_val;
+
+ need_to_merge =
+ (e_data != NULL &&
+ (d_bd == NULL ||
+ e_data != d_bd->data)) &&
+ (l_data == NULL ||
+ (d_bd != NULL &&
+ l_data == d_bd->data));
+ break;
+ }
+ case PROTOBUF_C_TYPE_STRING: {
+ char *e_str = *(char **) earlier_elem;
+ char *l_str = *(char **) latter_elem;
+ const char *d_str = def_val;
+
+ need_to_merge = e_str != d_str && l_str == d_str;
+ break;
+ }
+ default: {
+ /* Could be has field or case enum, the logic is
+ * equivalent, since 0 (FALSE) means not set for
+ * oneof */
+ need_to_merge = (*earlier_case_p != 0) &&
+ (*latter_case_p == 0);
+ break;
+ }
+ }
+
+ if (need_to_merge) {
+ size_t el_size =
+ sizeof_elt_in_repeated_array(field->type);
+ memcpy(latter_elem, earlier_elem, el_size);
+ /*
+ * Reset the element from the old message to 0
+ * to make sure earlier message deallocation
+ * doesn't corrupt zero-copied data in the new
+ * message, earlier message will be freed after
+ * this function is called anyway
+ */
+ memset(earlier_elem, 0, el_size);
+
+ if (field->quantifier_offset != 0) {
+ /* Set the has field or the case enum,
+ * if applicable */
+ *latter_case_p = *earlier_case_p;
+ *earlier_case_p = 0;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Count packed elements.
+ *
+ * Given a raw slab of packed-repeated values, determine the number of
+ * elements. This function detects certain kinds of errors but not
+ * others; the remaining error checking is done by
+ * parse_packed_repeated_member().
+ */
+static protobuf_c_boolean
+count_packed_elements(ProtobufCType type,
+ size_t len, const uint8_t *data, size_t *count_out)
+{
+ switch (type) {
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ if (len % 4 != 0) {
+ PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types");
+ return FALSE;
+ }
+ *count_out = len / 4;
+ return TRUE;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ if (len % 8 != 0) {
+ PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types");
+ return FALSE;
+ }
+ *count_out = len / 8;
+ return TRUE;
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ case PROTOBUF_C_TYPE_SINT32:
+ case PROTOBUF_C_TYPE_UINT32:
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_SINT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ *count_out = max_b128_numbers(len, data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_BOOL:
+ *count_out = len;
+ return TRUE;
+ case PROTOBUF_C_TYPE_STRING:
+ case PROTOBUF_C_TYPE_BYTES:
+ case PROTOBUF_C_TYPE_MESSAGE:
+ default:
+ PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type);
+ return FALSE;
+ }
+}
+
+static inline uint32_t
+parse_uint32(unsigned len, const uint8_t *data)
+{
+ uint32_t rv = data[0] & 0x7f;
+ if (len > 1) {
+ rv |= ((uint32_t) (data[1] & 0x7f) << 7);
+ if (len > 2) {
+ rv |= ((uint32_t) (data[2] & 0x7f) << 14);
+ if (len > 3) {
+ rv |= ((uint32_t) (data[3] & 0x7f) << 21);
+ if (len > 4)
+ rv |= ((uint32_t) (data[4]) << 28);
+ }
+ }
+ }
+ return rv;
+}
+
+static inline uint32_t
+parse_int32(unsigned len, const uint8_t *data)
+{
+ return parse_uint32(len, data);
+}
+
+static inline int32_t
+unzigzag32(uint32_t v)
+{
+ if (v & 1)
+ return -(v >> 1) - 1;
+ else
+ return v >> 1;
+}
+
+static inline uint32_t
+parse_fixed_uint32(const uint8_t *data)
+{
+#if !defined(WORDS_BIGENDIAN)
+ uint32_t t;
+ memcpy(&t, data, 4);
+ return t;
+#else
+ return data[0] |
+ ((uint32_t) (data[1]) << 8) |
+ ((uint32_t) (data[2]) << 16) |
+ ((uint32_t) (data[3]) << 24);
+#endif
+}
+
+static uint64_t
+parse_uint64(unsigned len, const uint8_t *data)
+{
+ unsigned shift, i;
+ uint64_t rv;
+
+ if (len < 5)
+ return parse_uint32(len, data);
+ rv = ((uint64_t) (data[0] & 0x7f)) |
+ ((uint64_t) (data[1] & 0x7f) << 7) |
+ ((uint64_t) (data[2] & 0x7f) << 14) |
+ ((uint64_t) (data[3] & 0x7f) << 21);
+ shift = 28;
+ for (i = 4; i < len; i++) {
+ rv |= (((uint64_t) (data[i] & 0x7f)) << shift);
+ shift += 7;
+ }
+ return rv;
+}
+
+static inline int64_t
+unzigzag64(uint64_t v)
+{
+ if (v & 1)
+ return -(v >> 1) - 1;
+ else
+ return v >> 1;
+}
+
+static inline uint64_t
+parse_fixed_uint64(const uint8_t *data)
+{
+#if !defined(WORDS_BIGENDIAN)
+ uint64_t t;
+ memcpy(&t, data, 8);
+ return t;
+#else
+ return (uint64_t) parse_fixed_uint32(data) |
+ (((uint64_t) parse_fixed_uint32(data + 4)) << 32);
+#endif
+}
+
+static protobuf_c_boolean
+parse_boolean(unsigned len, const uint8_t *data)
+{
+ unsigned i;
+ for (i = 0; i < len; i++)
+ if (data[i] & 0x7f)
+ return TRUE;
+ return FALSE;
+}
+
+static protobuf_c_boolean
+parse_required_member(ScannedMember *scanned_member,
+ void *member,
+ ProtobufCAllocator *allocator,
+ protobuf_c_boolean maybe_clear)
+{
+ unsigned len = scanned_member->len;
+ const uint8_t *data = scanned_member->data;
+ ProtobufCWireType wire_type = scanned_member->wire_type;
+
+ switch (scanned_member->field->type) {
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT)
+ return FALSE;
+ *(int32_t *) member = parse_int32(len, data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_UINT32:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT)
+ return FALSE;
+ *(uint32_t *) member = parse_uint32(len, data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_SINT32:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT)
+ return FALSE;
+ *(int32_t *) member = unzigzag32(parse_uint32(len, data));
+ return TRUE;
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT)
+ return FALSE;
+ *(uint32_t *) member = parse_fixed_uint32(data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT)
+ return FALSE;
+ *(uint64_t *) member = parse_uint64(len, data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_SINT64:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT)
+ return FALSE;
+ *(int64_t *) member = unzigzag64(parse_uint64(len, data));
+ return TRUE;
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT)
+ return FALSE;
+ *(uint64_t *) member = parse_fixed_uint64(data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_BOOL:
+ *(protobuf_c_boolean *) member = parse_boolean(len, data);
+ return TRUE;
+ case PROTOBUF_C_TYPE_STRING: {
+ char **pstr = member;
+ unsigned pref_len = scanned_member->length_prefix_len;
+
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)
+ return FALSE;
+
+ if (maybe_clear && *pstr != NULL) {
+ const char *def = scanned_member->field->default_value;
+ if (*pstr != NULL && *pstr != def)
+ do_free(allocator, *pstr);
+ }
+ *pstr = do_alloc(allocator, len - pref_len + 1);
+ if (*pstr == NULL)
+ return FALSE;
+ memcpy(*pstr, data + pref_len, len - pref_len);
+ (*pstr)[len - pref_len] = 0;
+ return TRUE;
+ }
+ case PROTOBUF_C_TYPE_BYTES: {
+ ProtobufCBinaryData *bd = member;
+ const ProtobufCBinaryData *def_bd;
+ unsigned pref_len = scanned_member->length_prefix_len;
+
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)
+ return FALSE;
+
+ def_bd = scanned_member->field->default_value;
+ if (maybe_clear &&
+ bd->data != NULL &&
+ (def_bd == NULL || bd->data != def_bd->data))
+ {
+ do_free(allocator, bd->data);
+ }
+ if (len - pref_len > 0) {
+ bd->data = do_alloc(allocator, len - pref_len);
+ if (bd->data == NULL)
+ return FALSE;
+ memcpy(bd->data, data + pref_len, len - pref_len);
+ } else {
+ bd->data = NULL;
+ }
+ bd->len = len - pref_len;
+ return TRUE;
+ }
+ case PROTOBUF_C_TYPE_MESSAGE: {
+ ProtobufCMessage **pmessage = member;
+ ProtobufCMessage *subm;
+ const ProtobufCMessage *def_mess;
+ protobuf_c_boolean merge_successful = TRUE;
+ unsigned pref_len = scanned_member->length_prefix_len;
+
+ if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)
+ return FALSE;
+
+ def_mess = scanned_member->field->default_value;
+ subm = protobuf_c_message_unpack(scanned_member->field->descriptor,
+ allocator,
+ len - pref_len,
+ data + pref_len);
+
+ if (maybe_clear &&
+ *pmessage != NULL &&
+ *pmessage != def_mess)
+ {
+ if (subm != NULL)
+ merge_successful = merge_messages(*pmessage, subm, allocator);
+ /* Delete the previous message */
+ protobuf_c_message_free_unpacked(*pmessage, allocator);
+ }
+ *pmessage = subm;
+ if (subm == NULL || !merge_successful)
+ return FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static protobuf_c_boolean
+parse_oneof_member (ScannedMember *scanned_member,
+ void *member,
+ ProtobufCMessage *message,
+ ProtobufCAllocator *allocator)
+{
+ uint32_t *oneof_case = STRUCT_MEMBER_PTR(uint32_t, message,
+ scanned_member->field->quantifier_offset);
+
+ /* If we have already parsed a member of this oneof, free it. */
+ if (*oneof_case != 0) {
+ /* lookup field */
+ int field_index =
+ int_range_lookup(message->descriptor->n_field_ranges,
+ message->descriptor->field_ranges,
+ *oneof_case);
+ const ProtobufCFieldDescriptor *old_field =
+ message->descriptor->fields + field_index;
+ size_t el_size = sizeof_elt_in_repeated_array(old_field->type);
+
+ switch (old_field->type) {
+ case PROTOBUF_C_TYPE_STRING: {
+ char **pstr = member;
+ const char *def = old_field->default_value;
+ if (*pstr != NULL && *pstr != def)
+ do_free(allocator, *pstr);
+ break;
+ }
+ case PROTOBUF_C_TYPE_BYTES: {
+ ProtobufCBinaryData *bd = member;
+ const ProtobufCBinaryData *def_bd = old_field->default_value;
+ if (bd->data != NULL &&
+ (def_bd == NULL || bd->data != def_bd->data))
+ {
+ do_free(allocator, bd->data);
+ }
+ break;
+ }
+ case PROTOBUF_C_TYPE_MESSAGE: {
+ ProtobufCMessage **pmessage = member;
+ const ProtobufCMessage *def_mess = old_field->default_value;
+ if (*pmessage != NULL && *pmessage != def_mess)
+ protobuf_c_message_free_unpacked(*pmessage, allocator);
+ break;
+ }
+ default:
+ break;
+ }
+
+ memset (member, 0, el_size);
+ }
+ if (!parse_required_member (scanned_member, member, allocator, TRUE))
+ return FALSE;
+
+ *oneof_case = scanned_member->tag;
+ return TRUE;
+}
+
+
+static protobuf_c_boolean
+parse_optional_member(ScannedMember *scanned_member,
+ void *member,
+ ProtobufCMessage *message,
+ ProtobufCAllocator *allocator)
+{
+ if (!parse_required_member(scanned_member, member, allocator, TRUE))
+ return FALSE;
+ if (scanned_member->field->quantifier_offset != 0)
+ STRUCT_MEMBER(protobuf_c_boolean,
+ message,
+ scanned_member->field->quantifier_offset) = TRUE;
+ return TRUE;
+}
+
+static protobuf_c_boolean
+parse_repeated_member(ScannedMember *scanned_member,
+ void *member,
+ ProtobufCMessage *message,
+ ProtobufCAllocator *allocator)
+{
+ const ProtobufCFieldDescriptor *field = scanned_member->field;
+ size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
+ size_t siz = sizeof_elt_in_repeated_array(field->type);
+ char *array = *(char **) member;
+
+ if (!parse_required_member(scanned_member, array + siz * (*p_n),
+ allocator, FALSE))
+ {
+ return FALSE;
+ }
+ *p_n += 1;
+ return TRUE;
+}
+
+static unsigned
+scan_varint(unsigned len, const uint8_t *data)
+{
+ unsigned i;
+ if (len > 10)
+ len = 10;
+ for (i = 0; i < len; i++)
+ if ((data[i] & 0x80) == 0)
+ break;
+ if (i == len)
+ return 0;
+ return i + 1;
+}
+
+static protobuf_c_boolean
+parse_packed_repeated_member(ScannedMember *scanned_member,
+ void *member,
+ ProtobufCMessage *message)
+{
+ const ProtobufCFieldDescriptor *field = scanned_member->field;
+ size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
+ size_t siz = sizeof_elt_in_repeated_array(field->type);
+ void *array = *(char **) member + siz * (*p_n);
+ const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len;
+ size_t rem = scanned_member->len - scanned_member->length_prefix_len;
+ size_t count = 0;
+ unsigned i;
+
+ switch (field->type) {
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ count = (scanned_member->len - scanned_member->length_prefix_len) / 4;
+#if !defined(WORDS_BIGENDIAN)
+ goto no_unpacking_needed;
+#else
+ for (i = 0; i < count; i++) {
+ ((uint32_t *) array)[i] = parse_fixed_uint32(at);
+ at += 4;
+ }
+ break;
+#endif
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ count = (scanned_member->len - scanned_member->length_prefix_len) / 8;
+#if !defined(WORDS_BIGENDIAN)
+ goto no_unpacking_needed;
+#else
+ for (i = 0; i < count; i++) {
+ ((uint64_t *) array)[i] = parse_fixed_uint64(at);
+ at += 8;
+ }
+ break;
+#endif
+ case PROTOBUF_C_TYPE_ENUM:
+ case PROTOBUF_C_TYPE_INT32:
+ while (rem > 0) {
+ unsigned s = scan_varint(rem, at);
+ if (s == 0) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value");
+ return FALSE;
+ }
+ ((int32_t *) array)[count++] = parse_int32(s, at);
+ at += s;
+ rem -= s;
+ }
+ break;
+ case PROTOBUF_C_TYPE_SINT32:
+ while (rem > 0) {
+ unsigned s = scan_varint(rem, at);
+ if (s == 0) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value");
+ return FALSE;
+ }
+ ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at));
+ at += s;
+ rem -= s;
+ }
+ break;
+ case PROTOBUF_C_TYPE_UINT32:
+ while (rem > 0) {
+ unsigned s = scan_varint(rem, at);
+ if (s == 0) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value");
+ return FALSE;
+ }
+ ((uint32_t *) array)[count++] = parse_uint32(s, at);
+ at += s;
+ rem -= s;
+ }
+ break;
+
+ case PROTOBUF_C_TYPE_SINT64:
+ while (rem > 0) {
+ unsigned s = scan_varint(rem, at);
+ if (s == 0) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value");
+ return FALSE;
+ }
+ ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at));
+ at += s;
+ rem -= s;
+ }
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ while (rem > 0) {
+ unsigned s = scan_varint(rem, at);
+ if (s == 0) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value");
+ return FALSE;
+ }
+ ((int64_t *) array)[count++] = parse_uint64(s, at);
+ at += s;
+ rem -= s;
+ }
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ count = rem;
+ for (i = 0; i < count; i++) {
+ if (at[i] > 1) {
+ PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value");
+ return FALSE;
+ }
+ ((protobuf_c_boolean *) array)[i] = at[i];
+ }
+ break;
+ default:
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ }
+ *p_n += count;
+ return TRUE;
+
+#if !defined(WORDS_BIGENDIAN)
+no_unpacking_needed:
+ memcpy(array, at, count * siz);
+ *p_n += count;
+ return TRUE;
+#endif
+}
+
+static protobuf_c_boolean
+is_packable_type(ProtobufCType type)
+{
+ return
+ type != PROTOBUF_C_TYPE_STRING &&
+ type != PROTOBUF_C_TYPE_BYTES &&
+ type != PROTOBUF_C_TYPE_MESSAGE;
+}
+
+static protobuf_c_boolean
+parse_member(ScannedMember *scanned_member,
+ ProtobufCMessage *message,
+ ProtobufCAllocator *allocator)
+{
+ const ProtobufCFieldDescriptor *field = scanned_member->field;
+ void *member;
+
+ if (field == NULL) {
+ ProtobufCMessageUnknownField *ufield =
+ message->unknown_fields +
+ (message->n_unknown_fields++);
+ ufield->tag = scanned_member->tag;
+ ufield->wire_type = scanned_member->wire_type;
+ ufield->len = scanned_member->len;
+ ufield->data = do_alloc(allocator, scanned_member->len);
+ if (ufield->data == NULL)
+ return FALSE;
+ memcpy(ufield->data, scanned_member->data, ufield->len);
+ return TRUE;
+ }
+ member = (char *) message + field->offset;
+ switch (field->label) {
+ case PROTOBUF_C_LABEL_REQUIRED:
+ return parse_required_member(scanned_member, member,
+ allocator, TRUE);
+ case PROTOBUF_C_LABEL_OPTIONAL:
+ case PROTOBUF_C_LABEL_NONE:
+ if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) {
+ return parse_oneof_member(scanned_member, member,
+ message, allocator);
+ } else {
+ return parse_optional_member(scanned_member, member,
+ message, allocator);
+ }
+ case PROTOBUF_C_LABEL_REPEATED:
+ if (scanned_member->wire_type ==
+ PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED &&
+ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) ||
+ is_packable_type(field->type)))
+ {
+ return parse_packed_repeated_member(scanned_member,
+ member, message);
+ } else {
+ return parse_repeated_member(scanned_member,
+ member, message,
+ allocator);
+ }
+ }
+ PROTOBUF_C__ASSERT_NOT_REACHED();
+ return 0;
+}
+
+/**
+ * Initialise messages generated by old code.
+ *
+ * This function is used if desc->message_init == NULL (which occurs
+ * for old code, and which would be useful to support allocating
+ * descriptors dynamically).
+ */
+static void
+message_init_generic(const ProtobufCMessageDescriptor *desc,
+ ProtobufCMessage *message)
+{
+ unsigned i;
+
+ memset(message, 0, desc->sizeof_message);
+ message->descriptor = desc;
+ for (i = 0; i < desc->n_fields; i++) {
+ if (desc->fields[i].default_value != NULL &&
+ desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED)
+ {
+ void *field =
+ STRUCT_MEMBER_P(message, desc->fields[i].offset);
+ const void *dv = desc->fields[i].default_value;
+
+ switch (desc->fields[i].type) {
+ case PROTOBUF_C_TYPE_INT32:
+ case PROTOBUF_C_TYPE_SINT32:
+ case PROTOBUF_C_TYPE_SFIXED32:
+ case PROTOBUF_C_TYPE_UINT32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ case PROTOBUF_C_TYPE_FLOAT:
+ case PROTOBUF_C_TYPE_ENUM:
+ memcpy(field, dv, 4);
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_SINT64:
+ case PROTOBUF_C_TYPE_SFIXED64:
+ case PROTOBUF_C_TYPE_UINT64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ case PROTOBUF_C_TYPE_DOUBLE:
+ memcpy(field, dv, 8);
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ memcpy(field, dv, sizeof(protobuf_c_boolean));
+ break;
+ case PROTOBUF_C_TYPE_BYTES:
+ memcpy(field, dv, sizeof(ProtobufCBinaryData));
+ break;
+
+ case PROTOBUF_C_TYPE_STRING:
+ case PROTOBUF_C_TYPE_MESSAGE:
+ /*
+ * The next line essentially implements a cast
+ * from const, which is totally unavoidable.
+ */
+ *(const void **) field = dv;
+ break;
+ }
+ }
+ }
+}
+
+/**@}*/
+
+/*
+ * ScannedMember slabs (an unpacking implementation detail). Before doing real
+ * unpacking, we first scan through the elements to see how many there are (for
+ * repeated fields), and which field to use (for non-repeated fields given
+ * twice).
+ *
+ * In order to avoid allocations for small messages, we keep a stack-allocated
+ * slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we
+ * fill that up, we allocate each slab twice as large as the previous one.
+ */
+#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4
+
+/*
+ * The number of slabs, including the stack-allocated ones; choose the number so
+ * that we would overflow if we needed a slab larger than provided.
+ */
+#define MAX_SCANNED_MEMBER_SLAB \
+ (sizeof(unsigned int)*8 - 1 \
+ - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \
+ - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)
+
+#define REQUIRED_FIELD_BITMAP_SET(index) \
+ (required_fields_bitmap[(index)/8] |= (1UL<<((index)%8)))
+
+#define REQUIRED_FIELD_BITMAP_IS_SET(index) \
+ (required_fields_bitmap[(index)/8] & (1UL<<((index)%8)))
+
+ProtobufCMessage *
+protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc,
+ ProtobufCAllocator *allocator,
+ size_t len, const uint8_t *data)
+{
+ ProtobufCMessage *rv;
+ size_t rem = len;
+ const uint8_t *at = data;
+ const ProtobufCFieldDescriptor *last_field = desc->fields + 0;
+ ScannedMember first_member_slab[1UL <<
+ FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2];
+
+ /*
+ * scanned_member_slabs[i] is an array of arrays of ScannedMember.
+ * The first slab (scanned_member_slabs[0] is just a pointer to
+ * first_member_slab), above. All subsequent slabs will be allocated
+ * using the allocator.
+ */
+ ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1];
+ unsigned which_slab = 0; /* the slab we are currently populating */
+ unsigned in_slab_index = 0; /* number of members in the slab */
+ size_t n_unknown = 0;
+ unsigned f;
+ unsigned j;
+ unsigned i_slab;
+ unsigned last_field_index = 0;
+ unsigned required_fields_bitmap_len;
+ unsigned char required_fields_bitmap_stack[16];
+ unsigned char *required_fields_bitmap = required_fields_bitmap_stack;
+ protobuf_c_boolean required_fields_bitmap_alloced = FALSE;
+
+ ASSERT_IS_MESSAGE_DESCRIPTOR(desc);
+
+ if (allocator == NULL)
+ allocator = &protobuf_c__allocator;
+
+ rv = do_alloc(allocator, desc->sizeof_message);
+ if (!rv)
+ return (NULL);
+ scanned_member_slabs[0] = first_member_slab;
+
+ required_fields_bitmap_len = (desc->n_fields + 7) / 8;
+ if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) {
+ required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len);
+ if (!required_fields_bitmap) {
+ do_free(allocator, rv);
+ return (NULL);
+ }
+ required_fields_bitmap_alloced = TRUE;
+ }
+ memset(required_fields_bitmap, 0, required_fields_bitmap_len);
+
+ /*
+ * Generated code always defines "message_init". However, we provide a
+ * fallback for (1) users of old protobuf-c generated-code that do not
+ * provide the function, and (2) descriptors constructed from some other
+ * source (most likely, direct construction from the .proto file).
+ */
+ if (desc->message_init != NULL)
+ protobuf_c_message_init(desc, rv);
+ else
+ message_init_generic(desc, rv);
+
+ while (rem > 0) {
+ uint32_t tag;
+ ProtobufCWireType wire_type;
+ size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type);
+ const ProtobufCFieldDescriptor *field;
+ ScannedMember tmp;
+
+ if (used == 0) {
+ PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u",
+ (unsigned) (at - data));
+ goto error_cleanup_during_scan;
+ }
+ /*
+ * \todo Consider optimizing for field[1].id == tag, if field[1]
+ * exists!
+ */
+ if (last_field == NULL || last_field->id != tag) {
+ /* lookup field */
+ int field_index =
+ int_range_lookup(desc->n_field_ranges,
+ desc->field_ranges,
+ tag);
+ if (field_index < 0) {
+ field = NULL;
+ n_unknown++;
+ } else {
+ field = desc->fields + field_index;
+ last_field = field;
+ last_field_index = field_index;
+ }
+ } else {
+ field = last_field;
+ }
+
+ if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED)
+ REQUIRED_FIELD_BITMAP_SET(last_field_index);
+
+ at += used;
+ rem -= used;
+ tmp.tag = tag;
+ tmp.wire_type = wire_type;
+ tmp.field = field;
+ tmp.data = at;
+ tmp.length_prefix_len = 0;
+
+ switch (wire_type) {
+ case PROTOBUF_C_WIRE_TYPE_VARINT: {
+ unsigned max_len = rem < 10 ? rem : 10;
+ unsigned i;
+
+ for (i = 0; i < max_len; i++)
+ if ((at[i] & 0x80) == 0)
+ break;
+ if (i == max_len) {
+ PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u",
+ (unsigned) (at - data));
+ goto error_cleanup_during_scan;
+ }
+ tmp.len = i + 1;
+ break;
+ }
+ case PROTOBUF_C_WIRE_TYPE_64BIT:
+ if (rem < 8) {
+ PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u",
+ (unsigned) (at - data));
+ goto error_cleanup_during_scan;
+ }
+ tmp.len = 8;
+ break;
+ case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: {
+ size_t pref_len;
+
+ tmp.len = scan_length_prefixed_data(rem, at, &pref_len);
+ if (tmp.len == 0) {
+ /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */
+ goto error_cleanup_during_scan;
+ }
+ tmp.length_prefix_len = pref_len;
+ break;
+ }
+ case PROTOBUF_C_WIRE_TYPE_32BIT:
+ if (rem < 4) {
+ PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u",
+ (unsigned) (at - data));
+ goto error_cleanup_during_scan;
+ }
+ tmp.len = 4;
+ break;
+ default:
+ PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u",
+ wire_type, (unsigned) (at - data));
+ goto error_cleanup_during_scan;
+ }
+
+ if (in_slab_index == (1UL <<
+ (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)))
+ {
+ size_t size;
+
+ in_slab_index = 0;
+ if (which_slab == MAX_SCANNED_MEMBER_SLAB) {
+ PROTOBUF_C_UNPACK_ERROR("too many fields");
+ goto error_cleanup_during_scan;
+ }
+ which_slab++;
+ size = sizeof(ScannedMember)
+ << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2);
+ scanned_member_slabs[which_slab] = do_alloc(allocator, size);
+ if (scanned_member_slabs[which_slab] == NULL)
+ goto error_cleanup_during_scan;
+ }
+ scanned_member_slabs[which_slab][in_slab_index++] = tmp;
+
+ if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) {
+ size_t *n = STRUCT_MEMBER_PTR(size_t, rv,
+ field->quantifier_offset);
+ if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED &&
+ (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) ||
+ is_packable_type(field->type)))
+ {
+ size_t count;
+ if (!count_packed_elements(field->type,
+ tmp.len -
+ tmp.length_prefix_len,
+ tmp.data +
+ tmp.length_prefix_len,
+ &count))
+ {
+ PROTOBUF_C_UNPACK_ERROR("counting packed elements");
+ goto error_cleanup_during_scan;
+ }
+ *n += count;
+ } else {
+ *n += 1;
+ }
+ }
+
+ at += tmp.len;
+ rem -= tmp.len;
+ }
+
+ /* allocate space for repeated fields, also check that all required fields have been set */
+ for (f = 0; f < desc->n_fields; f++) {
+ const ProtobufCFieldDescriptor *field = desc->fields + f;
+ if (field->label == PROTOBUF_C_LABEL_REPEATED) {
+ size_t siz =
+ sizeof_elt_in_repeated_array(field->type);
+ size_t *n_ptr =
+ STRUCT_MEMBER_PTR(size_t, rv,
+ field->quantifier_offset);
+ if (*n_ptr != 0) {
+ unsigned n = *n_ptr;
+ void *a;
+ *n_ptr = 0;
+ assert(rv->descriptor != NULL);
+#define CLEAR_REMAINING_N_PTRS() \
+ for(f++;f < desc->n_fields; f++) \
+ { \
+ field = desc->fields + f; \
+ if (field->label == PROTOBUF_C_LABEL_REPEATED) \
+ STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \
+ }
+ a = do_alloc(allocator, siz * n);
+ if (!a) {
+ CLEAR_REMAINING_N_PTRS();
+ goto error_cleanup;
+ }
+ STRUCT_MEMBER(void *, rv, field->offset) = a;
+ }
+ } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
+ if (field->default_value == NULL &&
+ !REQUIRED_FIELD_BITMAP_IS_SET(f))
+ {
+ CLEAR_REMAINING_N_PTRS();
+ PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'",
+ desc->name, field->name);
+ goto error_cleanup;
+ }
+ }
+ }
+#undef CLEAR_REMAINING_N_PTRS
+
+ /* allocate space for unknown fields */
+ if (n_unknown) {
+ rv->unknown_fields = do_alloc(allocator,
+ n_unknown * sizeof(ProtobufCMessageUnknownField));
+ if (rv->unknown_fields == NULL)
+ goto error_cleanup;
+ }
+
+ /* do real parsing */
+ for (i_slab = 0; i_slab <= which_slab; i_slab++) {
+ unsigned max = (i_slab == which_slab) ?
+ in_slab_index : (1UL << (i_slab + 4));
+ ScannedMember *slab = scanned_member_slabs[i_slab];
+
+ for (j = 0; j < max; j++) {
+ if (!parse_member(slab + j, rv, allocator)) {
+ PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s",
+ slab->field ? slab->field->name : "*unknown-field*",
+ desc->name);
+ goto error_cleanup;
+ }
+ }
+ }
+
+ /* cleanup */
+ for (j = 1; j <= which_slab; j++)
+ do_free(allocator, scanned_member_slabs[j]);
+ if (required_fields_bitmap_alloced)
+ do_free(allocator, required_fields_bitmap);
+ return rv;
+
+error_cleanup:
+ protobuf_c_message_free_unpacked(rv, allocator);
+ for (j = 1; j <= which_slab; j++)
+ do_free(allocator, scanned_member_slabs[j]);
+ if (required_fields_bitmap_alloced)
+ do_free(allocator, required_fields_bitmap);
+ return NULL;
+
+error_cleanup_during_scan:
+ do_free(allocator, rv);
+ for (j = 1; j <= which_slab; j++)
+ do_free(allocator, scanned_member_slabs[j]);
+ if (required_fields_bitmap_alloced)
+ do_free(allocator, required_fields_bitmap);
+ return NULL;
+}
+
+void
+protobuf_c_message_free_unpacked(ProtobufCMessage *message,
+ ProtobufCAllocator *allocator)
+{
+ const ProtobufCMessageDescriptor *desc;
+ unsigned f;
+
+ if (message == NULL)
+ return;
+
+ desc = message->descriptor;
+
+ ASSERT_IS_MESSAGE(message);
+
+ if (allocator == NULL)
+ allocator = &protobuf_c__allocator;
+ message->descriptor = NULL;
+ for (f = 0; f < desc->n_fields; f++) {
+ if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) &&
+ desc->fields[f].id !=
+ STRUCT_MEMBER(uint32_t, message, desc->fields[f].quantifier_offset))
+ {
+ /* This is not the selected oneof, skip it */
+ continue;
+ }
+
+ if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) {
+ size_t n = STRUCT_MEMBER(size_t,
+ message,
+ desc->fields[f].quantifier_offset);
+ void *arr = STRUCT_MEMBER(void *,
+ message,
+ desc->fields[f].offset);
+
+ if (arr != NULL) {
+ if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) {
+ unsigned i;
+ for (i = 0; i < n; i++)
+ do_free(allocator, ((char **) arr)[i]);
+ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) {
+ unsigned i;
+ for (i = 0; i < n; i++)
+ do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data);
+ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) {
+ unsigned i;
+ for (i = 0; i < n; i++)
+ protobuf_c_message_free_unpacked(
+ ((ProtobufCMessage **) arr)[i],
+ allocator
+ );
+ }
+ do_free(allocator, arr);
+ }
+ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) {
+ char *str = STRUCT_MEMBER(char *, message,
+ desc->fields[f].offset);
+
+ if (str && str != desc->fields[f].default_value)
+ do_free(allocator, str);
+ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) {
+ void *data = STRUCT_MEMBER(ProtobufCBinaryData, message,
+ desc->fields[f].offset).data;
+ const ProtobufCBinaryData *default_bd;
+
+ default_bd = desc->fields[f].default_value;
+ if (data != NULL &&
+ (default_bd == NULL ||
+ default_bd->data != data))
+ {
+ do_free(allocator, data);
+ }
+ } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) {
+ ProtobufCMessage *sm;
+
+ sm = STRUCT_MEMBER(ProtobufCMessage *, message,
+ desc->fields[f].offset);
+ if (sm && sm != desc->fields[f].default_value)
+ protobuf_c_message_free_unpacked(sm, allocator);
+ }
+ }
+
+ for (f = 0; f < message->n_unknown_fields; f++)
+ do_free(allocator, message->unknown_fields[f].data);
+ if (message->unknown_fields != NULL)
+ do_free(allocator, message->unknown_fields);
+
+ do_free(allocator, message);
+}
+
+void
+protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor,
+ void *message)
+{
+ descriptor->message_init((ProtobufCMessage *) (message));
+}
+
+protobuf_c_boolean
+protobuf_c_message_check(const ProtobufCMessage *message)
+{
+ unsigned i;
+
+ if (!message ||
+ !message->descriptor ||
+ message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC)
+ {
+ return FALSE;
+ }
+
+ for (i = 0; i < message->descriptor->n_fields; i++) {
+ const ProtobufCFieldDescriptor *f = message->descriptor->fields + i;
+ ProtobufCType type = f->type;
+ ProtobufCLabel label = f->label;
+ void *field = STRUCT_MEMBER_P (message, f->offset);
+
+ if (label == PROTOBUF_C_LABEL_REPEATED) {
+ size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset);
+
+ if (*quantity > 0 && *(void **) field == NULL) {
+ return FALSE;
+ }
+
+ if (type == PROTOBUF_C_TYPE_MESSAGE) {
+ ProtobufCMessage **submessage = *(ProtobufCMessage ***) field;
+ unsigned j;
+ for (j = 0; j < *quantity; j++) {
+ if (!protobuf_c_message_check(submessage[j]))
+ return FALSE;
+ }
+ } else if (type == PROTOBUF_C_TYPE_STRING) {
+ char **string = *(char ***) field;
+ unsigned j;
+ for (j = 0; j < *quantity; j++) {
+ if (!string[j])
+ return FALSE;
+ }
+ } else if (type == PROTOBUF_C_TYPE_BYTES) {
+ ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field;
+ unsigned j;
+ for (j = 0; j < *quantity; j++) {
+ if (bd[j].len > 0 && bd[j].data == NULL)
+ return FALSE;
+ }
+ }
+
+ } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */
+
+ if (type == PROTOBUF_C_TYPE_MESSAGE) {
+ ProtobufCMessage *submessage = *(ProtobufCMessage **) field;
+ if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) {
+ if (!protobuf_c_message_check(submessage))
+ return FALSE;
+ }
+ } else if (type == PROTOBUF_C_TYPE_STRING) {
+ char *string = *(char **) field;
+ if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL)
+ return FALSE;
+ } else if (type == PROTOBUF_C_TYPE_BYTES) {
+ protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset);
+ ProtobufCBinaryData *bd = field;
+ if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) {
+ if (bd->len > 0 && bd->data == NULL)
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* === services === */
+
+typedef void (*GenericHandler) (void *service,
+ const ProtobufCMessage *input,
+ ProtobufCClosure closure,
+ void *closure_data);
+void
+protobuf_c_service_invoke_internal(ProtobufCService *service,
+ unsigned method_index,
+ const ProtobufCMessage *input,
+ ProtobufCClosure closure,
+ void *closure_data)
+{
+ GenericHandler *handlers;
+ GenericHandler handler;
+
+ /*
+ * Verify that method_index is within range. If this fails, you are
+ * likely invoking a newly added method on an old service. (Although
+ * other memory corruption bugs can cause this assertion too.)
+ */
+ assert(method_index < service->descriptor->n_methods);
+
+ /*
+ * Get the array of virtual methods (which are enumerated by the
+ * generated code).
+ */
+ handlers = (GenericHandler *) (service + 1);
+
+ /*
+ * Get our method and invoke it.
+ * \todo Seems like handler == NULL is a situation that needs handling.
+ */
+ handler = handlers[method_index];
+ (*handler)(service, input, closure, closure_data);
+}
+
+void
+protobuf_c_service_generated_init(ProtobufCService *service,
+ const ProtobufCServiceDescriptor *descriptor,
+ ProtobufCServiceDestroy destroy)
+{
+ ASSERT_IS_SERVICE_DESCRIPTOR(descriptor);
+ service->descriptor = descriptor;
+ service->destroy = destroy;
+ service->invoke = protobuf_c_service_invoke_internal;
+ memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler));
+}
+
+void protobuf_c_service_destroy(ProtobufCService *service)
+{
+ service->destroy(service);
+}
+
+/* --- querying the descriptors --- */
+
+const ProtobufCEnumValue *
+protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc,
+ const char *name)
+{
+ unsigned start = 0;
+ unsigned count;
+
+ if (desc == NULL || desc->values_by_name == NULL)
+ return NULL;
+
+ count = desc->n_value_names;
+
+ while (count > 1) {
+ unsigned mid = start + count / 2;
+ int rv = strcmp(desc->values_by_name[mid].name, name);
+ if (rv == 0)
+ return desc->values + desc->values_by_name[mid].index;
+ else if (rv < 0) {
+ count = start + count - (mid + 1);
+ start = mid + 1;
+ } else
+ count = mid - start;
+ }
+ if (count == 0)
+ return NULL;
+ if (strcmp(desc->values_by_name[start].name, name) == 0)
+ return desc->values + desc->values_by_name[start].index;
+ return NULL;
+}
+
+const ProtobufCEnumValue *
+protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc,
+ int value)
+{
+ int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value);
+ if (rv < 0)
+ return NULL;
+ return desc->values + rv;
+}
+
+const ProtobufCFieldDescriptor *
+protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc,
+ const char *name)
+{
+ unsigned start = 0;
+ unsigned count;
+ const ProtobufCFieldDescriptor *field;
+
+ if (desc == NULL || desc->fields_sorted_by_name == NULL)
+ return NULL;
+
+ count = desc->n_fields;
+
+ while (count > 1) {
+ unsigned mid = start + count / 2;
+ int rv;
+ field = desc->fields + desc->fields_sorted_by_name[mid];
+ rv = strcmp(field->name, name);
+ if (rv == 0)
+ return field;
+ else if (rv < 0) {
+ count = start + count - (mid + 1);
+ start = mid + 1;
+ } else
+ count = mid - start;
+ }
+ if (count == 0)
+ return NULL;
+ field = desc->fields + desc->fields_sorted_by_name[start];
+ if (strcmp(field->name, name) == 0)
+ return field;
+ return NULL;
+}
+
+const ProtobufCFieldDescriptor *
+protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc,
+ unsigned value)
+{
+ int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value);
+ if (rv < 0)
+ return NULL;
+ return desc->fields + rv;
+}
+
+const ProtobufCMethodDescriptor *
+protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc,
+ const char *name)
+{
+ unsigned start = 0;
+ unsigned count;
+
+ if (desc == NULL || desc->method_indices_by_name == NULL)
+ return NULL;
+
+ count = desc->n_methods;
+
+ while (count > 1) {
+ unsigned mid = start + count / 2;
+ unsigned mid_index = desc->method_indices_by_name[mid];
+ const char *mid_name = desc->methods[mid_index].name;
+ int rv = strcmp(mid_name, name);
+
+ if (rv == 0)
+ return desc->methods + desc->method_indices_by_name[mid];
+ if (rv < 0) {
+ count = start + count - (mid + 1);
+ start = mid + 1;
+ } else {
+ count = mid - start;
+ }
+ }
+ if (count == 0)
+ return NULL;
+ if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0)
+ return desc->methods + desc->method_indices_by_name[start];
+ return NULL;
+}
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.h
new file mode 100644
index 000000000..c8fa4fc2a
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/protobuf-c/protobuf-c.h
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (c) 2008-2017, Dave Benson and the protobuf-c authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*! \file
+ * \mainpage Introduction
+ *
+ * This is [protobuf-c], a C implementation of [Protocol Buffers].
+ *
+ * This file defines the public API for the `libprotobuf-c` support library.
+ * This API includes interfaces that can be used directly by client code as well
+ * as the interfaces used by the code generated by the `protoc-c` compiler.
+ *
+ * The `libprotobuf-c` support library performs the actual serialization and
+ * deserialization of Protocol Buffers messages. It interacts with structures,
+ * definitions, and metadata generated by the `protoc-c` compiler from .proto
+ * files.
+ *
+ * \authors Dave Benson and the `protobuf-c` authors.
+ *
+ * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license.
+ *
+ * [protobuf-c]: https://github.com/protobuf-c/protobuf-c
+ * [Protocol Buffers]: https://developers.google.com/protocol-buffers/
+ * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause
+ *
+ * \page gencode Generated Code
+ *
+ * For each enum, we generate a C enum. For each message, we generate a C
+ * structure which can be cast to a `ProtobufCMessage`.
+ *
+ * For each enum and message, we generate a descriptor object that allows us to
+ * implement a kind of reflection on the structures.
+ *
+ * First, some naming conventions:
+ *
+ * - The name of the type for enums and messages and services is camel case
+ * (meaning WordsAreCrammedTogether) except that double underscores are used
+ * to delimit scopes. For example, the following `.proto` file:
+ *
+~~~{.proto}
+ package foo.bar;
+ message BazBah {
+ optional int32 val = 1;
+ }
+~~~
+ *
+ * would generate a C type `Foo__Bar__BazBah`.
+ *
+ * - Identifiers for functions and globals are all lowercase, with camel case
+ * words separated by single underscores. For example, one of the function
+ * prototypes generated by `protoc-c` for the above example:
+ *
+~~~{.c}
+Foo__Bar__BazBah *
+ foo__bar__baz_bah__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+~~~
+ *
+ * - Identifiers for enum values contain an uppercase prefix which embeds the
+ * package name and the enum type name.
+ *
+ * - A double underscore is used to separate further components of identifier
+ * names.
+ *
+ * For example, in the name of the unpack function above, the package name
+ * `foo.bar` has become `foo__bar`, the message name BazBah has become
+ * `baz_bah`, and the method name is `unpack`. These are all joined with double
+ * underscores to form the C identifier `foo__bar__baz_bah__unpack`.
+ *
+ * We also generate descriptor objects for messages and enums. These are
+ * declared in the `.pb-c.h` files:
+ *
+~~~{.c}
+extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor;
+~~~
+ *
+ * The message structures all begin with `ProtobufCMessageDescriptor *` which is
+ * sufficient to allow them to be cast to `ProtobufCMessage`.
+ *
+ * For each message defined in a `.proto` file, we generate a number of
+ * functions and macros. Each function name contains a prefix based on the
+ * package name and message name in order to make it a unique C identifier.
+ *
+ * - `INIT`. Statically initializes a message object, initializing its
+ * descriptor and setting its fields to default values. Uninitialized
+ * messages cannot be processed by the protobuf-c library.
+ *
+~~~{.c}
+#define FOO__BAR__BAZ_BAH__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&foo__bar__baz_bah__descriptor), 0 }
+~~~
+ * - `init()`. Initializes a message object, initializing its descriptor and
+ * setting its fields to default values. Uninitialized messages cannot be
+ * processed by the protobuf-c library.
+ *
+~~~{.c}
+void foo__bar__baz_bah__init
+ (Foo__Bar__BazBah *message);
+~~~
+ * - `unpack()`. Unpacks data for a particular message format. Note that the
+ * `allocator` parameter is usually `NULL` to indicate that the system's
+ * `malloc()` and `free()` functions should be used for dynamically allocating
+ * memory.
+ *
+~~~{.c}
+Foo__Bar__BazBah *
+ foo__bar__baz_bah__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+~~~
+ *
+ * - `free_unpacked()`. Frees a message object obtained with the `unpack()`
+ * method. Freeing `NULL` is allowed (the same as with `free()`).
+ *
+~~~{.c}
+void foo__bar__baz_bah__free_unpacked
+ (Foo__Bar__BazBah *message,
+ ProtobufCAllocator *allocator);
+~~~
+ *
+ * - `get_packed_size()`. Calculates the length in bytes of the serialized
+ * representation of the message object.
+ *
+~~~{.c}
+size_t foo__bar__baz_bah__get_packed_size
+ (const Foo__Bar__BazBah *message);
+~~~
+ *
+ * - `pack()`. Pack a message object into a preallocated buffer. Assumes that
+ * the buffer is large enough. (Use `get_packed_size()` first.)
+ *
+~~~{.c}
+size_t foo__bar__baz_bah__pack
+ (const Foo__Bar__BazBah *message,
+ uint8_t *out);
+~~~
+ *
+ * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an
+ * object which defines an "append bytes" callback to consume data as it is
+ * serialized.
+ *
+~~~{.c}
+size_t foo__bar__baz_bah__pack_to_buffer
+ (const Foo__Bar__BazBah *message,
+ ProtobufCBuffer *buffer);
+~~~
+ *
+ * \page pack Packing and unpacking messages
+ *
+ * To pack a message, first compute the packed size of the message with
+ * protobuf_c_message_get_packed_size(), then allocate a buffer of at least
+ * that size, then call protobuf_c_message_pack().
+ *
+ * Alternatively, a message can be serialized without calculating the final size
+ * first. Use the protobuf_c_message_pack_to_buffer() function and provide a
+ * ProtobufCBuffer object which implements an "append" method that consumes
+ * data.
+ *
+ * To unpack a message, call the protobuf_c_message_unpack() function. The
+ * result can be cast to an object of the type that matches the descriptor for
+ * the message.
+ *
+ * The result of unpacking a message should be freed with
+ * protobuf_c_message_free_unpacked().
+ */
+
+#ifndef PROTOBUF_C_H
+#define PROTOBUF_C_H
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+# define PROTOBUF_C__BEGIN_DECLS extern "C" {
+# define PROTOBUF_C__END_DECLS }
+#else
+# define PROTOBUF_C__BEGIN_DECLS
+# define PROTOBUF_C__END_DECLS
+#endif
+
+PROTOBUF_C__BEGIN_DECLS
+
+#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB)
+# ifdef PROTOBUF_C_EXPORT
+# define PROTOBUF_C__API __declspec(dllexport)
+# else
+# define PROTOBUF_C__API __declspec(dllimport)
+# endif
+#else
+# define PROTOBUF_C__API
+#endif
+
+#if !defined(PROTOBUF_C__NO_DEPRECATED) && \
+ ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__))
+#else
+# define PROTOBUF_C__DEPRECATED
+#endif
+
+#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE
+ #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \
+ , _##enum_name##_IS_INT_SIZE = INT_MAX
+#endif
+
+#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3
+#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9
+#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af
+
+/* Empty string used for initializers */
+extern const char protobuf_c_empty_string[];
+
+/**
+ * \defgroup api Public API
+ *
+ * This is the public API for `libprotobuf-c`. These interfaces are stable and
+ * subject to Semantic Versioning guarantees.
+ *
+ * @{
+ */
+
+/**
+ * Values for the `flags` word in `ProtobufCFieldDescriptor`.
+ */
+typedef enum {
+ /** Set if the field is repeated and marked with the `packed` option. */
+ PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0),
+
+ /** Set if the field is marked with the `deprecated` option. */
+ PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1),
+
+ /** Set if the field is a member of a oneof (union). */
+ PROTOBUF_C_FIELD_FLAG_ONEOF = (1 << 2),
+} ProtobufCFieldFlag;
+
+/**
+ * Message field rules.
+ *
+ * \see [Defining A Message Type] in the Protocol Buffers documentation.
+ *
+ * [Defining A Message Type]:
+ * https://developers.google.com/protocol-buffers/docs/proto#simple
+ */
+typedef enum {
+ /** A well-formed message must have exactly one of this field. */
+ PROTOBUF_C_LABEL_REQUIRED,
+
+ /**
+ * A well-formed message can have zero or one of this field (but not
+ * more than one).
+ */
+ PROTOBUF_C_LABEL_OPTIONAL,
+
+ /**
+ * This field can be repeated any number of times (including zero) in a
+ * well-formed message. The order of the repeated values will be
+ * preserved.
+ */
+ PROTOBUF_C_LABEL_REPEATED,
+
+ /**
+ * This field has no label. This is valid only in proto3 and is
+ * equivalent to OPTIONAL but no "has" quantifier will be consulted.
+ */
+ PROTOBUF_C_LABEL_NONE,
+} ProtobufCLabel;
+
+/**
+ * Field value types.
+ *
+ * \see [Scalar Value Types] in the Protocol Buffers documentation.
+ *
+ * [Scalar Value Types]:
+ * https://developers.google.com/protocol-buffers/docs/proto#scalar
+ */
+typedef enum {
+ PROTOBUF_C_TYPE_INT32, /**< int32 */
+ PROTOBUF_C_TYPE_SINT32, /**< signed int32 */
+ PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */
+ PROTOBUF_C_TYPE_INT64, /**< int64 */
+ PROTOBUF_C_TYPE_SINT64, /**< signed int64 */
+ PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */
+ PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */
+ PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */
+ PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */
+ PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */
+ PROTOBUF_C_TYPE_FLOAT, /**< float */
+ PROTOBUF_C_TYPE_DOUBLE, /**< double */
+ PROTOBUF_C_TYPE_BOOL, /**< boolean */
+ PROTOBUF_C_TYPE_ENUM, /**< enumerated type */
+ PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */
+ PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */
+ PROTOBUF_C_TYPE_MESSAGE, /**< nested message */
+} ProtobufCType;
+
+/**
+ * Field wire types.
+ *
+ * \see [Message Structure] in the Protocol Buffers documentation.
+ *
+ * [Message Structure]:
+ * https://developers.google.com/protocol-buffers/docs/encoding#structure
+ */
+typedef enum {
+ PROTOBUF_C_WIRE_TYPE_VARINT = 0,
+ PROTOBUF_C_WIRE_TYPE_64BIT = 1,
+ PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2,
+ /* "Start group" and "end group" wire types are unsupported. */
+ PROTOBUF_C_WIRE_TYPE_32BIT = 5,
+} ProtobufCWireType;
+
+struct ProtobufCAllocator;
+struct ProtobufCBinaryData;
+struct ProtobufCBuffer;
+struct ProtobufCBufferSimple;
+struct ProtobufCEnumDescriptor;
+struct ProtobufCEnumValue;
+struct ProtobufCEnumValueIndex;
+struct ProtobufCFieldDescriptor;
+struct ProtobufCIntRange;
+struct ProtobufCMessage;
+struct ProtobufCMessageDescriptor;
+struct ProtobufCMessageUnknownField;
+struct ProtobufCMethodDescriptor;
+struct ProtobufCService;
+struct ProtobufCServiceDescriptor;
+
+typedef struct ProtobufCAllocator ProtobufCAllocator;
+typedef struct ProtobufCBinaryData ProtobufCBinaryData;
+typedef struct ProtobufCBuffer ProtobufCBuffer;
+typedef struct ProtobufCBufferSimple ProtobufCBufferSimple;
+typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor;
+typedef struct ProtobufCEnumValue ProtobufCEnumValue;
+typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex;
+typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor;
+typedef struct ProtobufCIntRange ProtobufCIntRange;
+typedef struct ProtobufCMessage ProtobufCMessage;
+typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor;
+typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField;
+typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor;
+typedef struct ProtobufCService ProtobufCService;
+typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor;
+
+/** Boolean type. */
+typedef int protobuf_c_boolean;
+
+typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data);
+typedef void (*ProtobufCMessageInit)(ProtobufCMessage *);
+typedef void (*ProtobufCServiceDestroy)(ProtobufCService *);
+
+/**
+ * Structure for defining a custom memory allocator.
+ */
+struct ProtobufCAllocator {
+ /** Function to allocate memory. */
+ void *(*alloc)(void *allocator_data, size_t size);
+
+ /** Function to free memory. */
+ void (*free)(void *allocator_data, void *pointer);
+
+ /** Opaque pointer passed to `alloc` and `free` functions. */
+ void *allocator_data;
+};
+
+/**
+ * Structure for the protobuf `bytes` scalar type.
+ *
+ * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of
+ * bytes. It may contain embedded `NUL` characters and is not required to be
+ * `NUL`-terminated.
+ */
+struct ProtobufCBinaryData {
+ size_t len; /**< Number of bytes in the `data` field. */
+ uint8_t *data; /**< Data bytes. */
+};
+
+/**
+ * Structure for defining a virtual append-only buffer. Used by
+ * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized
+ * bytes.
+ *
+ * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to
+ * write to a `FILE` object:
+ *
+~~~{.c}
+typedef struct {
+ ProtobufCBuffer base;
+ FILE *fp;
+} BufferAppendToFile;
+
+static void
+my_buffer_file_append(ProtobufCBuffer *buffer,
+ size_t len,
+ const uint8_t *data)
+{
+ BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer;
+ fwrite(data, len, 1, file_buf->fp); // XXX: No error handling!
+}
+~~~
+ *
+ * To use this new type of ProtobufCBuffer, it could be called as follows:
+ *
+~~~{.c}
+...
+BufferAppendToFile tmp = {0};
+tmp.base.append = my_buffer_file_append;
+tmp.fp = fp;
+protobuf_c_message_pack_to_buffer(&message, &tmp);
+...
+~~~
+ */
+struct ProtobufCBuffer {
+ /** Append function. Consumes the `len` bytes stored at `data`. */
+ void (*append)(ProtobufCBuffer *buffer,
+ size_t len,
+ const uint8_t *data);
+};
+
+/**
+ * Simple buffer "subclass" of `ProtobufCBuffer`.
+ *
+ * A `ProtobufCBufferSimple` object is declared on the stack and uses a
+ * scratch buffer provided by the user for the initial allocation. It performs
+ * exponential resizing, using dynamically allocated memory. A
+ * `ProtobufCBufferSimple` object can be created and used as follows:
+ *
+~~~{.c}
+uint8_t pad[128];
+ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad);
+ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple;
+~~~
+ *
+ * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a
+ * message has been serialized to a `ProtobufCBufferSimple` object, the
+ * serialized data bytes can be accessed from the `.data` field.
+ *
+ * To free the memory allocated by a `ProtobufCBufferSimple` object, if any,
+ * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example:
+ *
+~~~{.c}
+PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple);
+~~~
+ *
+ * \see PROTOBUF_C_BUFFER_SIMPLE_INIT
+ * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR
+ */
+struct ProtobufCBufferSimple {
+ /** "Base class". */
+ ProtobufCBuffer base;
+ /** Number of bytes allocated in `data`. */
+ size_t alloced;
+ /** Number of bytes currently stored in `data`. */
+ size_t len;
+ /** Data bytes. */
+ uint8_t *data;
+ /** Whether `data` must be freed. */
+ protobuf_c_boolean must_free_data;
+ /** Allocator to use. May be NULL to indicate the system allocator. */
+ ProtobufCAllocator *allocator;
+};
+
+/**
+ * Describes an enumeration as a whole, with all of its values.
+ */
+struct ProtobufCEnumDescriptor {
+ /** Magic value checked to ensure that the API is used correctly. */
+ uint32_t magic;
+
+ /** The qualified name (e.g., "namespace.Type"). */
+ const char *name;
+ /** The unqualified name as given in the .proto file (e.g., "Type"). */
+ const char *short_name;
+ /** Identifier used in generated C code. */
+ const char *c_name;
+ /** The dot-separated namespace. */
+ const char *package_name;
+
+ /** Number elements in `values`. */
+ unsigned n_values;
+ /** Array of distinct values, sorted by numeric value. */
+ const ProtobufCEnumValue *values;
+
+ /** Number of elements in `values_by_name`. */
+ unsigned n_value_names;
+ /** Array of named values, including aliases, sorted by name. */
+ const ProtobufCEnumValueIndex *values_by_name;
+
+ /** Number of elements in `value_ranges`. */
+ unsigned n_value_ranges;
+ /** Value ranges, for faster lookups by numeric value. */
+ const ProtobufCIntRange *value_ranges;
+
+ /** Reserved for future use. */
+ void *reserved1;
+ /** Reserved for future use. */
+ void *reserved2;
+ /** Reserved for future use. */
+ void *reserved3;
+ /** Reserved for future use. */
+ void *reserved4;
+};
+
+/**
+ * Represents a single value of an enumeration.
+ */
+struct ProtobufCEnumValue {
+ /** The string identifying this value in the .proto file. */
+ const char *name;
+
+ /** The string identifying this value in generated C code. */
+ const char *c_name;
+
+ /** The numeric value assigned in the .proto file. */
+ int value;
+};
+
+/**
+ * Used by `ProtobufCEnumDescriptor` to look up enum values.
+ */
+struct ProtobufCEnumValueIndex {
+ /** Name of the enum value. */
+ const char *name;
+ /** Index into values[] array. */
+ unsigned index;
+};
+
+/**
+ * Describes a single field in a message.
+ */
+struct ProtobufCFieldDescriptor {
+ /** Name of the field as given in the .proto file. */
+ const char *name;
+
+ /** Tag value of the field as given in the .proto file. */
+ uint32_t id;
+
+ /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */
+ ProtobufCLabel label;
+
+ /** The type of the field. */
+ ProtobufCType type;
+
+ /**
+ * The offset in bytes of the message's C structure's quantifier field
+ * (the `has_MEMBER` field for optional members or the `n_MEMBER` field
+ * for repeated members or the case enum for oneofs).
+ */
+ unsigned quantifier_offset;
+
+ /**
+ * The offset in bytes into the message's C structure for the member
+ * itself.
+ */
+ unsigned offset;
+
+ /**
+ * A type-specific descriptor.
+ *
+ * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the
+ * corresponding `ProtobufCEnumDescriptor`.
+ *
+ * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to
+ * the corresponding `ProtobufCMessageDescriptor`.
+ *
+ * Otherwise this field is NULL.
+ */
+ const void *descriptor; /* for MESSAGE and ENUM types */
+
+ /** The default value for this field, if defined. May be NULL. */
+ const void *default_value;
+
+ /**
+ * A flag word. Zero or more of the bits defined in the
+ * `ProtobufCFieldFlag` enum may be set.
+ */
+ uint32_t flags;
+
+ /** Reserved for future use. */
+ unsigned reserved_flags;
+ /** Reserved for future use. */
+ void *reserved2;
+ /** Reserved for future use. */
+ void *reserved3;
+};
+
+/**
+ * Helper structure for optimizing int => index lookups in the case
+ * where the keys are mostly consecutive values, as they presumably are for
+ * enums and fields.
+ *
+ * The data structures requires that the values in the original array are
+ * sorted.
+ */
+struct ProtobufCIntRange {
+ int start_value;
+ unsigned orig_index;
+ /*
+ * NOTE: the number of values in the range can be inferred by looking
+ * at the next element's orig_index. A dummy element is added to make
+ * this simple.
+ */
+};
+
+/**
+ * An instance of a message.
+ *
+ * `ProtobufCMessage` is a light-weight "base class" for all messages.
+ *
+ * In particular, `ProtobufCMessage` doesn't have any allocation policy
+ * associated with it. That's because it's common to create `ProtobufCMessage`
+ * objects on the stack. In fact, that's what we recommend for sending messages.
+ * If the object is allocated from the stack, you can't really have a memory
+ * leak.
+ *
+ * This means that calls to functions like protobuf_c_message_unpack() which
+ * return a `ProtobufCMessage` must be paired with a call to a free function,
+ * like protobuf_c_message_free_unpacked().
+ */
+struct ProtobufCMessage {
+ /** The descriptor for this message type. */
+ const ProtobufCMessageDescriptor *descriptor;
+ /** The number of elements in `unknown_fields`. */
+ unsigned n_unknown_fields;
+ /** The fields that weren't recognized by the parser. */
+ ProtobufCMessageUnknownField *unknown_fields;
+};
+
+/**
+ * Describes a message.
+ */
+struct ProtobufCMessageDescriptor {
+ /** Magic value checked to ensure that the API is used correctly. */
+ uint32_t magic;
+
+ /** The qualified name (e.g., "namespace.Type"). */
+ const char *name;
+ /** The unqualified name as given in the .proto file (e.g., "Type"). */
+ const char *short_name;
+ /** Identifier used in generated C code. */
+ const char *c_name;
+ /** The dot-separated namespace. */
+ const char *package_name;
+
+ /**
+ * Size in bytes of the C structure representing an instance of this
+ * type of message.
+ */
+ size_t sizeof_message;
+
+ /** Number of elements in `fields`. */
+ unsigned n_fields;
+ /** Field descriptors, sorted by tag number. */
+ const ProtobufCFieldDescriptor *fields;
+ /** Used for looking up fields by name. */
+ const unsigned *fields_sorted_by_name;
+
+ /** Number of elements in `field_ranges`. */
+ unsigned n_field_ranges;
+ /** Used for looking up fields by id. */
+ const ProtobufCIntRange *field_ranges;
+
+ /** Message initialisation function. */
+ ProtobufCMessageInit message_init;
+
+ /** Reserved for future use. */
+ void *reserved1;
+ /** Reserved for future use. */
+ void *reserved2;
+ /** Reserved for future use. */
+ void *reserved3;
+};
+
+/**
+ * An unknown message field.
+ */
+struct ProtobufCMessageUnknownField {
+ /** The tag number. */
+ uint32_t tag;
+ /** The wire type of the field. */
+ ProtobufCWireType wire_type;
+ /** Number of bytes in `data`. */
+ size_t len;
+ /** Field data. */
+ uint8_t *data;
+};
+
+/**
+ * Method descriptor.
+ */
+struct ProtobufCMethodDescriptor {
+ /** Method name. */
+ const char *name;
+ /** Input message descriptor. */
+ const ProtobufCMessageDescriptor *input;
+ /** Output message descriptor. */
+ const ProtobufCMessageDescriptor *output;
+};
+
+/**
+ * Service.
+ */
+struct ProtobufCService {
+ /** Service descriptor. */
+ const ProtobufCServiceDescriptor *descriptor;
+ /** Function to invoke the service. */
+ void (*invoke)(ProtobufCService *service,
+ unsigned method_index,
+ const ProtobufCMessage *input,
+ ProtobufCClosure closure,
+ void *closure_data);
+ /** Function to destroy the service. */
+ void (*destroy)(ProtobufCService *service);
+};
+
+/**
+ * Service descriptor.
+ */
+struct ProtobufCServiceDescriptor {
+ /** Magic value checked to ensure that the API is used correctly. */
+ uint32_t magic;
+
+ /** Service name. */
+ const char *name;
+ /** Short version of service name. */
+ const char *short_name;
+ /** C identifier for the service name. */
+ const char *c_name;
+ /** Package name. */
+ const char *package;
+ /** Number of elements in `methods`. */
+ unsigned n_methods;
+ /** Method descriptors, in the order defined in the .proto file. */
+ const ProtobufCMethodDescriptor *methods;
+ /** Sort index of methods. */
+ const unsigned *method_indices_by_name;
+};
+
+/**
+ * Get the version of the protobuf-c library. Note that this is the version of
+ * the library linked against, not the version of the headers compiled against.
+ *
+ * \return A string containing the version number of protobuf-c.
+ */
+PROTOBUF_C__API
+const char *
+protobuf_c_version(void);
+
+/**
+ * Get the version of the protobuf-c library. Note that this is the version of
+ * the library linked against, not the version of the headers compiled against.
+ *
+ * \return A 32 bit unsigned integer containing the version number of
+ * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH.
+ */
+PROTOBUF_C__API
+uint32_t
+protobuf_c_version_number(void);
+
+/**
+ * The version of the protobuf-c headers, represented as a string using the same
+ * format as protobuf_c_version().
+ */
+#define PROTOBUF_C_VERSION "1.3.0"
+
+/**
+ * The version of the protobuf-c headers, represented as an integer using the
+ * same format as protobuf_c_version_number().
+ */
+#define PROTOBUF_C_VERSION_NUMBER 1003000
+
+/**
+ * The minimum protoc-c version which works with the current version of the
+ * protobuf-c headers.
+ */
+#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000
+
+/**
+ * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name.
+ *
+ * \param desc
+ * The `ProtobufCEnumDescriptor` object.
+ * \param name
+ * The `name` field from the corresponding `ProtobufCEnumValue` object to
+ * match.
+ * \return
+ * A `ProtobufCEnumValue` object.
+ * \retval NULL
+ * If not found or if the optimize_for = CODE_SIZE option was set.
+ */
+PROTOBUF_C__API
+const ProtobufCEnumValue *
+protobuf_c_enum_descriptor_get_value_by_name(
+ const ProtobufCEnumDescriptor *desc,
+ const char *name);
+
+/**
+ * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric
+ * value.
+ *
+ * \param desc
+ * The `ProtobufCEnumDescriptor` object.
+ * \param value
+ * The `value` field from the corresponding `ProtobufCEnumValue` object to
+ * match.
+ *
+ * \return
+ * A `ProtobufCEnumValue` object.
+ * \retval NULL
+ * If not found.
+ */
+PROTOBUF_C__API
+const ProtobufCEnumValue *
+protobuf_c_enum_descriptor_get_value(
+ const ProtobufCEnumDescriptor *desc,
+ int value);
+
+/**
+ * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by
+ * the name of the field.
+ *
+ * \param desc
+ * The `ProtobufCMessageDescriptor` object.
+ * \param name
+ * The name of the field.
+ * \return
+ * A `ProtobufCFieldDescriptor` object.
+ * \retval NULL
+ * If not found or if the optimize_for = CODE_SIZE option was set.
+ */
+PROTOBUF_C__API
+const ProtobufCFieldDescriptor *
+protobuf_c_message_descriptor_get_field_by_name(
+ const ProtobufCMessageDescriptor *desc,
+ const char *name);
+
+/**
+ * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by
+ * the tag value of the field.
+ *
+ * \param desc
+ * The `ProtobufCMessageDescriptor` object.
+ * \param value
+ * The tag value of the field.
+ * \return
+ * A `ProtobufCFieldDescriptor` object.
+ * \retval NULL
+ * If not found.
+ */
+PROTOBUF_C__API
+const ProtobufCFieldDescriptor *
+protobuf_c_message_descriptor_get_field(
+ const ProtobufCMessageDescriptor *desc,
+ unsigned value);
+
+/**
+ * Determine the number of bytes required to store the serialised message.
+ *
+ * \param message
+ * The message object to serialise.
+ * \return
+ * Number of bytes.
+ */
+PROTOBUF_C__API
+size_t
+protobuf_c_message_get_packed_size(const ProtobufCMessage *message);
+
+/**
+ * Serialise a message from its in-memory representation.
+ *
+ * This function stores the serialised bytes of the message in a pre-allocated
+ * buffer.
+ *
+ * \param message
+ * The message object to serialise.
+ * \param[out] out
+ * Buffer to store the bytes of the serialised message. This buffer must
+ * have enough space to store the packed message. Use
+ * protobuf_c_message_get_packed_size() to determine the number of bytes
+ * required.
+ * \return
+ * Number of bytes stored in `out`.
+ */
+PROTOBUF_C__API
+size_t
+protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out);
+
+/**
+ * Serialise a message from its in-memory representation to a virtual buffer.
+ *
+ * This function calls the `append` method of a `ProtobufCBuffer` object to
+ * consume the bytes generated by the serialiser.
+ *
+ * \param message
+ * The message object to serialise.
+ * \param buffer
+ * The virtual buffer object.
+ * \return
+ * Number of bytes passed to the virtual buffer.
+ */
+PROTOBUF_C__API
+size_t
+protobuf_c_message_pack_to_buffer(
+ const ProtobufCMessage *message,
+ ProtobufCBuffer *buffer);
+
+/**
+ * Unpack a serialised message into an in-memory representation.
+ *
+ * \param descriptor
+ * The message descriptor.
+ * \param allocator
+ * `ProtobufCAllocator` to use for memory allocation. May be NULL to
+ * specify the default allocator.
+ * \param len
+ * Length in bytes of the serialised message.
+ * \param data
+ * Pointer to the serialised message.
+ * \return
+ * An unpacked message object.
+ * \retval NULL
+ * If an error occurred during unpacking.
+ */
+PROTOBUF_C__API
+ProtobufCMessage *
+protobuf_c_message_unpack(
+ const ProtobufCMessageDescriptor *descriptor,
+ ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+
+/**
+ * Free an unpacked message object.
+ *
+ * This function should be used to deallocate the memory used by a call to
+ * protobuf_c_message_unpack().
+ *
+ * \param message
+ * The message object to free. May be NULL.
+ * \param allocator
+ * `ProtobufCAllocator` to use for memory deallocation. May be NULL to
+ * specify the default allocator.
+ */
+PROTOBUF_C__API
+void
+protobuf_c_message_free_unpacked(
+ ProtobufCMessage *message,
+ ProtobufCAllocator *allocator);
+
+/**
+ * Check the validity of a message object.
+ *
+ * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present.
+ * Recursively checks nested messages.
+ *
+ * \retval TRUE
+ * Message is valid.
+ * \retval FALSE
+ * Message is invalid.
+ */
+PROTOBUF_C__API
+protobuf_c_boolean
+protobuf_c_message_check(const ProtobufCMessage *);
+
+/** Message initialiser. */
+#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL }
+
+/**
+ * Initialise a message object from a message descriptor.
+ *
+ * \param descriptor
+ * Message descriptor.
+ * \param message
+ * Allocated block of memory of size `descriptor->sizeof_message`.
+ */
+PROTOBUF_C__API
+void
+protobuf_c_message_init(
+ const ProtobufCMessageDescriptor *descriptor,
+ void *message);
+
+/**
+ * Free a service.
+ *
+ * \param service
+ * The service object to free.
+ */
+PROTOBUF_C__API
+void
+protobuf_c_service_destroy(ProtobufCService *service);
+
+/**
+ * Look up a `ProtobufCMethodDescriptor` by name.
+ *
+ * \param desc
+ * Service descriptor.
+ * \param name
+ * Name of the method.
+ *
+ * \return
+ * A `ProtobufCMethodDescriptor` object.
+ * \retval NULL
+ * If not found or if the optimize_for = CODE_SIZE option was set.
+ */
+PROTOBUF_C__API
+const ProtobufCMethodDescriptor *
+protobuf_c_service_descriptor_get_method_by_name(
+ const ProtobufCServiceDescriptor *desc,
+ const char *name);
+
+/**
+ * Initialise a `ProtobufCBufferSimple` object.
+ */
+#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \
+{ \
+ { protobuf_c_buffer_simple_append }, \
+ sizeof(array_of_bytes), \
+ 0, \
+ (array_of_bytes), \
+ 0, \
+ NULL \
+}
+
+/**
+ * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory.
+ */
+#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \
+do { \
+ if ((simp_buf)->must_free_data) { \
+ if ((simp_buf)->allocator != NULL) \
+ (simp_buf)->allocator->free( \
+ (simp_buf)->allocator, \
+ (simp_buf)->data); \
+ else \
+ free((simp_buf)->data); \
+ } \
+} while (0)
+
+/**
+ * The `append` method for `ProtobufCBufferSimple`.
+ *
+ * \param buffer
+ * The buffer object to append to. Must actually be a
+ * `ProtobufCBufferSimple` object.
+ * \param len
+ * Number of bytes in `data`.
+ * \param data
+ * Data to append.
+ */
+PROTOBUF_C__API
+void
+protobuf_c_buffer_simple_append(
+ ProtobufCBuffer *buffer,
+ size_t len,
+ const unsigned char *data);
+
+PROTOBUF_C__API
+void
+protobuf_c_service_generated_init(
+ ProtobufCService *service,
+ const ProtobufCServiceDescriptor *descriptor,
+ ProtobufCServiceDestroy destroy);
+
+PROTOBUF_C__API
+void
+protobuf_c_service_invoke_internal(
+ ProtobufCService *service,
+ unsigned method_index,
+ const ProtobufCMessage *input,
+ ProtobufCClosure closure,
+ void *closure_data);
+
+/**@}*/
+
+PROTOBUF_C__END_DECLS
+
+#endif /* PROTOBUF_C_H */
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/targetver.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/targetver.h
new file mode 100644
index 000000000..87c0086de
--- /dev/null
+++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v5/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>
diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj
index 4455ec720..ac52d55c5 100644
--- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj
+++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj
@@ -544,6 +544,13 @@
<Name>Tango.MachineStudio.Common</Name>
</ProjectReference>
<!--ColorLib-->
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v5\Tango.ColorLib_v5.vcxproj">
+ <Project>{0F87D32E-B65F-4AE8-862C-29F4CCC38240}</Project>
+ <Name>Tango.ColorLib_v5</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
<ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v4\Tango.ColorLib_v4.vcxproj">
<Project>{E9528353-7D41-4AA8-BBAC-D65B7FE3A0D6}</Project>
<Name>Tango.ColorLib_v4</Name>
@@ -712,7 +719,7 @@ if $(ConfigurationName) == Release RD /S /Q "$(TargetDir)lib\"</PostBuildEvent>
</Target>
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="True" BuildVersion_UpdateFileVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.DeltaBaseYearDayOfYear" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_StartDate="2000/1/1" />
+ <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_BuildVersioningStyle="None.None.Increment.DeltaBaseYearDayOfYear" BuildVersion_UpdateFileVersion="True" BuildVersion_DetectChanges="True" BuildVersion_UseGlobalSettings="False" />
</VisualStudio>
</ProjectExtensions>
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj
index 8ff836354..bb37dbea2 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj
@@ -630,6 +630,13 @@
<Name>Tango.PPC.Shared</Name>
</ProjectReference>
<!--ColorLib-->
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v5\Tango.ColorLib_v5.vcxproj">
+ <Project>{0F87D32E-B65F-4AE8-862C-29F4CCC38240}</Project>
+ <Name>Tango.ColorLib_v5</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
<ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v4\Tango.ColorLib_v4.vcxproj">
<Project>{E9528353-7D41-4AA8-BBAC-D65B7FE3A0D6}</Project>
<Name>Tango.ColorLib_v4</Name>
diff --git a/Software/Visual_Studio/Tango.sln b/Software/Visual_Studio/Tango.sln
index 0dc0334fa..8415287b5 100644
--- a/Software/Visual_Studio/Tango.sln
+++ b/Software/Visual_Studio/Tango.sln
@@ -475,6 +475,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.MachineStudio.ThreadE
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.PPC.JobsV2", "PPC\Modules\Tango.PPC.JobsV2\Tango.PPC.JobsV2.csproj", "{DBBD90F4-4135-475D-A8F8-6795D3A8F697}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tango.ColorLib_v5", "ColorLib\Tango.ColorLib_v5\Tango.ColorLib_v5.vcxproj", "{0F87D32E-B65F-4AE8-862C-29F4CCC38240}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -4530,6 +4532,22 @@ Global
{DBBD90F4-4135-475D-A8F8-6795D3A8F697}.Release|x64.Build.0 = Release|Any CPU
{DBBD90F4-4135-475D-A8F8-6795D3A8F697}.Release|x86.ActiveCfg = Release|Any CPU
{DBBD90F4-4135-475D-A8F8-6795D3A8F697}.Release|x86.Build.0 = Release|Any CPU
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|Any CPU.Build.0 = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|ARM.ActiveCfg = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|ARM64.ActiveCfg = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|x64.ActiveCfg = Debug|x64
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|x64.Build.0 = Debug|x64
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|x86.ActiveCfg = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Debug|x86.Build.0 = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|Any CPU.ActiveCfg = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|Any CPU.Build.0 = Debug|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|ARM.ActiveCfg = Release|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|ARM64.ActiveCfg = Release|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|x64.ActiveCfg = Release|x64
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|x64.Build.0 = Release|x64
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|x86.ActiveCfg = Release|Win32
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -4699,14 +4717,15 @@ Global
{C89C1866-C76B-401F-A232-40FC58065CBF} = {EC62BC9C-F2FE-4333-B7E4-110E38D43958}
{859A766B-78AD-484E-9BF2-2CE0FE288894} = {B2AF4F3F-2828-47C3-8F3E-A0EA0BD66FF8}
{DBBD90F4-4135-475D-A8F8-6795D3A8F697} = {0048447D-1D94-4E60-9DAD-7349C777CB4E}
+ {0F87D32E-B65F-4AE8-862C-29F4CCC38240} = {7181F9DE-0760-46B7-AD8F-BDBCAEDEF1B7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- BuildVersion_UseGlobalSettings = False
- BuildVersion_AssemblyInfoFilename = Properties\AssemblyInfo.cs
- BuildVersion_StartDate = 2000/1/1
- BuildVersion_UpdateFileVersion = False
- BuildVersion_UpdateAssemblyVersion = True
- BuildVersion_BuildVersioningStyle = None.None.Increment.DeltaBaseYearDayOfYear
SolutionGuid = {7986F7F4-A86A-4994-B1B6-0988D7F057B6}
+ BuildVersion_BuildVersioningStyle = None.None.Increment.DeltaBaseYearDayOfYear
+ BuildVersion_UpdateAssemblyVersion = True
+ BuildVersion_UpdateFileVersion = False
+ BuildVersion_StartDate = 2000/1/1
+ BuildVersion_AssemblyInfoFilename = Properties\AssemblyInfo.cs
+ BuildVersion_UseGlobalSettings = False
EndGlobalSection
EndGlobal