Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 2453 → Rev 2454

/trunk/lprof/src/cmspcoll.c
0,0 → 1,1045
//
// Little cms - profiler construction set
// Copyright (C) 1998-2001 Marti Maria
//
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// This file is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception to the GNU General Public License, if you
// distribute this file as part of a program that contains a
// configuration script generated by Autoconf, you may include it under
// the same distribution terms that you use for the rest of that program.
//
// Version 1.08a
 
 
#include "lcmsprf.h"
 
 
// ----------------------------------------------------------------- Patch collections
 
BOOL cdecl cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet);
 
BOOL cdecl cmsxPCollBuildMeasurement(LPMEASUREMENT m,
const char *ReferenceSheet,
const char *MeasurementSheet,
DWORD dwNeededSamplesType);
 
LPPATCH cdecl cmsxPCollGetPatch(LPMEASUREMENT m, int n);
 
LPPATCH cdecl cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* Name, int* lpPos);
LPPATCH cdecl cmsxPCollGetPatchByPos(LPMEASUREMENT m, int row, int col);
LPPATCH cdecl cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name,
double r, double g, double b,
LPcmsCIEXYZ XYZ, LPcmsCIELab Lab);
 
// Sets of patches
 
SETOFPATCHES cdecl cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault);
int cdecl cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set);
BOOL cdecl cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags);
 
 
// Collect "need" patches of the specific kind, return the number of collected (that
// could be less if set of patches is exhausted)
 
 
void cdecl cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result);
 
int cdecl cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
double r, double g, double b, int need, SETOFPATCHES Result);
 
int cdecl cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids,
int need, SETOFPATCHES Result);
 
int cdecl cmsxPCollPatchesNearPrimary(LPMEASUREMENT m, SETOFPATCHES Valids,
int nChannel, int need, SETOFPATCHES Result);
 
int cdecl cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
double Lmin, double LMax, double a, double b, SETOFPATCHES Result);
 
int cdecl cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids,
LPLUT Gamut, SETOFPATCHES Result);
 
LPPATCH cdecl cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance);
LPPATCH cdecl cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance);
LPPATCH cdecl cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* Distance);
 
 
// ------------------------------------------------------------- Implementation
 
#define IS(x) EqualsTo(c, x)
 
// A wrapper on stricmp()
 
static
BOOL EqualsTo(const char* a, const char *b)
{
return (stricmp(a, b) == 0);
}
 
 
// Does return a bitwise mask holding the measurements contained in a Sheet
 
static
DWORD MaskOfDataSet(LCMSHANDLE hSheet)
{
char** Names;
int i, n;
DWORD dwMask = 0;
 
n = cmsxIT8EnumDataFormat(hSheet, &Names);
 
for (i=0; i < n; i++) {
 
char *c = Names[i];
 
if (IS("RGB_R") || IS("RGB_G") || IS("RGB_B"))
dwMask |= PATCH_HAS_RGB;
else
if (IS("XYZ_X") || IS("XYZ_Y") || IS("XYZ_Z"))
dwMask |= PATCH_HAS_XYZ;
else
if (IS("LAB_L") || IS("LAB_A") ||IS("LAB_B"))
dwMask |= PATCH_HAS_Lab;
else
if (IS("STDEV_DE"))
dwMask |= PATCH_HAS_STD_DE;
}
 
return dwMask;
}
 
 
// Addition of a patch programatically
 
LPPATCH cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name,
double r, double g, double b,
LPcmsCIEXYZ XYZ, LPcmsCIELab Lab)
{
LPPATCH p;
 
p = m->Patches + m->nPatches++;
 
strcpy(p -> Name, Name);
 
p -> Colorant.RGB[0] = r;
p -> Colorant.RGB[1] = g;
p -> Colorant.RGB[2] = b;
p -> dwFlags = PATCH_HAS_RGB;
 
if (XYZ) {
 
p -> XYZ = *XYZ;
p -> dwFlags |= PATCH_HAS_XYZ;
}
 
if (Lab) {
p -> Lab = *Lab;
p -> dwFlags |= PATCH_HAS_Lab;
}
 
return p;
}
 
// Some vendors does store colorant data in a non-standard way,
// i.e, from 0.0..1.0 or from 0.0..100.0 This routine tries to
// detect such situations
 
static
void NormalizeColorant(LPMEASUREMENT m)
{
int i, j;
double MaxColorant=0;
double Normalize;
 
for (i=0; i < m -> nPatches; i++) {
 
 
LPPATCH p = m -> Patches + i;
for (j=0; j < MAXCHANNELS; j++) {
if (p ->Colorant.Hexa[j] > MaxColorant)
MaxColorant = p ->Colorant.Hexa[j];
}
}
 
// Ok, some heuristics
 
if (MaxColorant < 2)
Normalize = 255.0; // goes 0..1
else
if (MaxColorant < 102)
Normalize = 2.55; // goes 0..100
else
if (MaxColorant > 300)
Normalize = (255.0 / 65535.0); // Goes 0..65535.0
else
return; // Is ok
 
 
// Rearrange patches
for (i=0; i < m -> nPatches; i++) {
 
 
LPPATCH p = m -> Patches + i;
for (j=0; j < MAXCHANNELS; j++)
p ->Colorant.Hexa[j] *= Normalize;
}
 
}
 
 
// Load a collection from a Sheet
 
BOOL cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet)
{
int i;
DWORD dwMask;
 
 
if (m -> nPatches == 0) {
 
m -> nPatches = (int) cmsxIT8GetPropertyDbl(hSheet, "NUMBER_OF_SETS");
m -> Patches = calloc(m -> nPatches, sizeof(PATCH));
 
if (m -> Patches == NULL) {
cmsxIT8Free(hSheet);
return FALSE;
}
 
for (i=0; i < m -> nPatches; i++) {
 
LPPATCH p = m -> Patches + i;
p -> dwFlags = 0;
cmsxIT8GetPatchName(hSheet, i, p ->Name);
}
 
}
 
 
// Build mask according to data format
 
dwMask = MaskOfDataSet(hSheet);
 
 
// Read items. Set flags accordly.
for (i = 0; i < m->nPatches; i++) {
 
LPPATCH Patch = m -> Patches + i;
// Fill in data according to mask
 
if (dwMask & PATCH_HAS_Lab) {
 
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_L", &Patch -> Lab.L) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_A", &Patch -> Lab.a) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_B", &Patch -> Lab.b))
 
Patch -> dwFlags |= PATCH_HAS_Lab;
}
 
if (dwMask & PATCH_HAS_XYZ) {
 
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_X", &Patch -> XYZ.X) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Y", &Patch -> XYZ.Y) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Z", &Patch -> XYZ.Z))
 
Patch -> dwFlags |= PATCH_HAS_XYZ;
 
}
 
if (dwMask & PATCH_HAS_RGB) {
 
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_R", &Patch -> Colorant.RGB[0]) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_G", &Patch -> Colorant.RGB[1]) &&
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_B", &Patch -> Colorant.RGB[2]))
 
Patch -> dwFlags |= PATCH_HAS_RGB;
}
 
if (dwMask & PATCH_HAS_STD_DE) {
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "STDEV_DE", &Patch -> dEStd))
 
Patch -> dwFlags |= PATCH_HAS_STD_DE;
 
}
}
 
NormalizeColorant(m);
return TRUE;
}
 
 
// Does save parameters to a empty sheet
 
BOOL cmsxPCollSaveToSheet(LPMEASUREMENT m, LCMSHANDLE it8)
{
int nNumberOfSets = cmsxPCollCountSet(m, m->Allowed);
int nNumberOfFields = 0;
DWORD dwMask = 0;
int i;
 
// Find mask of fields
for (i=0; i < m ->nPatches; i++) {
if (m ->Allowed[i]) {
 
LPPATCH p = m ->Patches + i;
dwMask |= p ->dwFlags;
}
}
 
nNumberOfFields = 1; // SampleID
 
if (dwMask & PATCH_HAS_RGB)
nNumberOfFields += 3;
 
if (dwMask & PATCH_HAS_XYZ)
nNumberOfFields += 3;
 
if (dwMask & PATCH_HAS_Lab)
nNumberOfFields += 3;
 
cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", nNumberOfSets);
cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", nNumberOfFields);
 
nNumberOfFields = 0;
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "SAMPLE_ID");
 
if (dwMask & PATCH_HAS_RGB) {
 
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_R");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_G");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_B");
}
if (dwMask & PATCH_HAS_XYZ) {
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_X");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Y");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Z");
}
 
 
if (dwMask & PATCH_HAS_XYZ) {
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_L");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_A");
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_B");
}
 
for (i=0; i < m ->nPatches; i++) {
if (m ->Allowed[i]) {
 
LPPATCH Patch = m ->Patches + i;
 
cmsxIT8SetDataSet(it8, Patch->Name, "SAMPLE_ID", Patch->Name);
if (dwMask & PATCH_HAS_RGB) {
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_R", Patch ->Colorant.RGB[0]);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_G", Patch ->Colorant.RGB[1]);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_B", Patch ->Colorant.RGB[2]);
}
 
if (dwMask & PATCH_HAS_XYZ) {
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_X", Patch ->XYZ.X);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Y", Patch ->XYZ.Y);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Z", Patch ->XYZ.Z);
}
 
if (dwMask & PATCH_HAS_Lab) {
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_L", Patch ->Lab.L);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_A", Patch ->Lab.a);
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_B", Patch ->Lab.b);
}
}
}
 
return TRUE;
}
 
static
void FixLabOnly(LPMEASUREMENT m)
{
int i;
 
for (i=0; i < m ->nPatches; i++) {
LPPATCH p = m ->Patches + i;
if ((p ->dwFlags & PATCH_HAS_Lab) &&
!(p ->dwFlags & PATCH_HAS_XYZ))
{
cmsLab2XYZ(cmsD50_XYZ(), &p->XYZ, &p ->Lab);
 
p ->XYZ.X *= 100.;
p ->XYZ.Y *= 100.;
p ->XYZ.Z *= 100.;
 
p ->dwFlags |= PATCH_HAS_XYZ;
}
}
 
}
 
 
// Higher level function. Does merge reference and measurement sheet into
// a MEASUREMENT struct. Data to keep is described in dwNeededSamplesType
// mask as follows:
//
// PATCH_HAS_Lab 0x00000001
// PATCH_HAS_XYZ 0x00000002
// PATCH_HAS_RGB 0x00000004
// PATCH_HAS_CMY 0x00000008
// PATCH_HAS_CMYK 0x00000010
// PATCH_HAS_HEXACRM 0x00000020
// PATCH_HAS_STD_Lab 0x00010000
// PATCH_HAS_STD_XYZ 0x00020000
// PATCH_HAS_STD_RGB 0x00040000
// PATCH_HAS_STD_CMY 0x00080000
// PATCH_HAS_STD_CMYK 0x00100000
// PATCH_HAS_STD_HEXACRM 0x00100000
// PATCH_HAS_MEAN_DE 0x01000000
// PATCH_HAS_STD_DE 0x02000000
// PATCH_HAS_CHISQ 0x04000000
//
// See lprof.h for further info
 
 
BOOL cmsxPCollBuildMeasurement(LPMEASUREMENT m,
const char *ReferenceSheet,
const char *MeasurementSheet,
DWORD dwNeededSamplesType)
{
LCMSHANDLE hSheet;
BOOL rc = TRUE;
 
ZeroMemory(m, sizeof(MEASUREMENT));
 
 
if (ReferenceSheet != NULL && *ReferenceSheet) {
 
hSheet = cmsxIT8LoadFromFile(ReferenceSheet);
if (hSheet == NULL) return FALSE;
rc = cmsxPCollLoadFromSheet(m, hSheet);
cmsxIT8Free(hSheet);
}
 
if (!rc) return FALSE;
 
if (MeasurementSheet != NULL && *MeasurementSheet) {
 
hSheet = cmsxIT8LoadFromFile(MeasurementSheet);
if (hSheet == NULL) return FALSE;
 
rc = cmsxPCollLoadFromSheet(m, hSheet);
cmsxIT8Free(hSheet);
}
 
if (!rc) return FALSE;
 
 
// Fix up -- If only Lab is present, then compute
// XYZ based on D50
 
FixLabOnly(m);
 
cmsxPCollValidatePatches(m, dwNeededSamplesType);
return TRUE;
}
 
 
 
void cmsxPCollFreeMeasurements(LPMEASUREMENT m)
{
if (m->Patches)
free(m->Patches);
 
m->Patches = NULL;
m->nPatches = 0;
if (m -> Allowed)
free(m -> Allowed);
 
}
 
// Retrieval functions
 
LPPATCH cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* name, int* lpPos)
{
int i;
for (i=0; i < m->nPatches; i++)
{
if (m -> Allowed)
if (!m -> Allowed[i])
continue;
 
if (EqualsTo(m->Patches[i].Name, name)) {
if (lpPos) *lpPos = i;
return m->Patches + i;
}
}
 
return NULL;
}
 
 
 
 
// -------------------------------------------------------------------- Sets
 
 
SETOFPATCHES cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault)
{
SETOFPATCHES Full = (SETOFPATCHES) malloc(m -> nPatches * sizeof(BOOL));
int i;
 
for (i=0; i < m -> nPatches; i++)
Full[i] = lDefault;
 
return Full;
}
 
int cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set)
{
int i, Count = 0;
 
for (i = 0; i < m -> nPatches; i++) {
 
if (Set[i])
Count++;
}
 
return Count;
}
 
 
// Validate patches
 
BOOL cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags)
{
int i, n;
 
if (m->Allowed)
free(m->Allowed);
 
m -> Allowed = cmsxPCollBuildSet(m, TRUE);
// Check for flags
for (i=n=0; i < m -> nPatches; i++) {
 
LPPATCH p = m -> Patches + i;
m -> Allowed[i] = ((p -> dwFlags & dwFlags) == dwFlags);
}
 
return TRUE;
}
 
 
// Several filters
 
 
// This filter does validate patches placed on 'radius' distance of a
// device-color space. Currently only RGB is supported
 
static
void PatchesByRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
double R, double G, double B, double radius, SETOFPATCHES Result)
{
int i;
double ra, rmax = sqrt(radius / 255.);
double dR, dG, dB;
LPPATCH p;
 
for (i=0; i < m->nPatches; i++) {
 
if (Valids[i]) {
 
p = m->Patches + i;
 
dR = fabs(R - p -> Colorant.RGB[0]) / 255.;
dG = fabs(G - p -> Colorant.RGB[1]) / 255.;
dB = fabs(B - p -> Colorant.RGB[2]) / 255.;
 
ra = sqrt(dR*dR + dG*dG + dB*dB);
 
if (ra <= rmax)
Result[i] = TRUE;
else
Result[i] = FALSE;
 
}
}
 
}
 
 
// This filter does validate patches placed at dEmax radius
// in the device-independent side.
 
static
void PatchesByLab(LPMEASUREMENT m, SETOFPATCHES Valids,
double L, double a, double b, double dEmax, SETOFPATCHES Result)
{
int i;
double dE, dEMaxSQR = sqrt(dEmax);
double dL, da, db;
LPPATCH p;
 
 
for (i=0; i < m->nPatches; i++) {
 
if (Valids[i]) {
 
p = m->Patches + i;
 
dL = fabs(L - p -> Lab.L);
da = fabs(a - p -> Lab.a);
db = fabs(b - p -> Lab.b);
 
dE = sqrt(dL*dL + da*da + db*db);
if (dE <= dEMaxSQR)
Result[i] = TRUE;
else
Result[i] = FALSE;
}
}
}
 
 
// Restrict Lab in a cube of variable sides. Quick and dirty out-of-gamut
// stripper used in estimations.
 
static
void PatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
double Lmin, double Lmax, double da, double db, SETOFPATCHES Result)
{
int i;
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
if ((p->Lab.L >= Lmin && p->Lab.L <= Lmax) &&
(fabs(p -> Lab.a) < da) &&
(fabs(p -> Lab.b) < db))
 
Result[i] = TRUE;
else
Result[i] = FALSE;
}
}
 
}
 
// Restrict to low colorfullness
 
static
void PatchesOfLowC(LPMEASUREMENT m, SETOFPATCHES Valids,
double Cmax, SETOFPATCHES Result)
{
int i;
cmsCIELCh LCh;
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
cmsLab2LCh(&LCh, &p->Lab);
 
 
if (LCh.C < Cmax)
Result[i] = TRUE;
else
Result[i] = FALSE;
}
}
 
}
 
 
 
// Primary can be -1 for specifying device gray. Does return patches
// on device-space Colorants. dEMax is the maximum allowed ratio
 
static
void PatchesPrimary(LPMEASUREMENT m, SETOFPATCHES Valids,
int nColorant, double dEMax, SETOFPATCHES Result)
{
int i, j;
double n, dE;
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
 
if (nColorant < 0) // device-grey?
{
// cross.
double drg = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[1]) / 255.;
double drb = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[2]) / 255.;
double dbg = fabs(p -> Colorant.RGB[1] - p -> Colorant.RGB[2]) / 255.;
 
dE = (drg*drg + drb*drb + dbg*dbg);
 
 
}
else {
dE = 0.;
for (j=0; j < 3; j++) {
 
if (j != nColorant) {
 
n = p -> Colorant.RGB[j] / 255.;
dE += (n * n);
 
 
}
}
}
 
 
 
if (sqrt(dE) < dEMax)
Result[i] = TRUE;
else
Result[i] = FALSE;
}
}
 
}
 
 
// The high level extractors -----------------------------------------------------
 
int cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
double r, double g, double b,
int need, SETOFPATCHES Result)
{
double radius;
int nCollected;
 
// Collect points inside of a sphere or radius 'radius' by RGB
 
radius = 1;
do {
PatchesByRGB(m, Valids, r, g, b, radius, Result);
 
nCollected = cmsxPCollCountSet(m, Result);
if (nCollected <= need) {
 
radius += 1.0;
}
 
} while (nCollected <= need && radius < 256.);
 
return nCollected; // Can be less than needed!
}
 
 
int cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids,
int need, SETOFPATCHES Result)
{
int nGrays;
double Cmax;
 
Cmax = 1.;
do {
 
 
PatchesOfLowC(m, Valids, Cmax, Result);
nGrays = cmsxPCollCountSet(m, Result);
if (nGrays <= need) {
 
Cmax += .2;
}
 
} while (nGrays <= need && Cmax < 10.);
 
return nGrays;
}
 
 
int cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
double Lmin, double Lmax, double a, double b,
SETOFPATCHES Result)
 
 
{
PatchesInLabCube(m, Valids, Lmin, Lmax, a, b, Result);
return cmsxPCollCountSet(m, Result);
}
 
 
 
 
int cmsxPCollPatchesNearPrimary(LPMEASUREMENT m,
SETOFPATCHES Valids,
int nChannel,
int need,
SETOFPATCHES Result)
{
double radius;
int nCollected;
 
// Collect points inside of a sphere or radius 'radius' by RGB
 
radius = 0.05;
do {
PatchesPrimary(m, Valids, nChannel, radius, Result);
 
nCollected = cmsxPCollCountSet(m, Result);
if (nCollected <= need) {
 
radius += 0.01;
}
 
} while (nCollected <= need && radius < 256.);
 
return nCollected;
 
}
 
 
static
void AddOneGray(LPMEASUREMENT m, int n, SETOFPATCHES Grays)
{
LPPATCH p;
char Buffer[cmsxIT8_GRAYCOLS];
int pos;
 
if (n == 0) strcpy(Buffer, "DMIN");
else
if (n == cmsxIT8_GRAYCOLS - 1) strcpy(Buffer, "DMAX");
else
sprintf(Buffer, "GS%d", n);
 
p = cmsxPCollGetPatchByName(m, Buffer, &pos);
 
if (p)
Grays[pos] = TRUE;
}
 
 
 
void cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result)
{
 
int i;
 
for (i=0; i < cmsxIT8_GRAYCOLS; i++)
AddOneGray(m, i, Result);
}
 
 
 
// Refresh RGB of all patches after prelinearization
 
void cmsxPCollLinearizePatches(LPMEASUREMENT m, SETOFPATCHES Valids, LPGAMMATABLE Gamma[3])
{
int i;
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
cmsxApplyLinearizationTable(p -> Colorant.RGB, Gamma, p -> Colorant.RGB);
}
}
 
}
 
 
int cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids,
LPLUT Gamut, SETOFPATCHES Result)
{
int i;
int nCollected = 0;
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
WORD EncodedLab[3];
WORD dE;
 
cmsFloat2LabEncoded(EncodedLab, &p->Lab);
cmsEvalLUT(Gamut, EncodedLab, &dE);
Result[i] = (dE < 2) ? TRUE : FALSE;
if (Result[i]) nCollected++;
}
}
 
return nCollected;
}
 
LPPATCH cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
{
int i;
LPPATCH Candidate = NULL;
double Distance, CandidateDistance = 255;
double dR, dG, dB;
 
Candidate = cmsxPCollGetPatchByName(m, "DMIN", NULL);
if (Candidate) {
 
if (TheDistance) *TheDistance = 0.0;
return Candidate;
}
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
dR = fabs(255.0 - p -> Colorant.RGB[0]) / 255.0;
dG = fabs(255.0 - p -> Colorant.RGB[1]) / 255.0;
dB = fabs(255.0 - p -> Colorant.RGB[2]) / 255.0;
 
Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
if (Distance < CandidateDistance) {
Candidate = p;
CandidateDistance = Distance;
}
}
}
 
if (TheDistance)
*TheDistance = floor(CandidateDistance * 255.0 + .5);
 
return Candidate;
}
 
LPPATCH cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
{
int i;
LPPATCH Candidate = NULL;
double Distance, CandidateDistance = 255;
double dR, dG, dB;
 
 
Candidate = cmsxPCollGetPatchByName(m, "DMAX", NULL);
if (Candidate) {
 
if (TheDistance) *TheDistance = 0.0;
return Candidate;
}
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
dR = (p -> Colorant.RGB[0]) / 255.0;
dG = (p -> Colorant.RGB[1]) / 255.0;
dB = (p -> Colorant.RGB[2]) / 255.0;
 
Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
if (Distance < CandidateDistance) {
Candidate = p;
CandidateDistance = Distance;
}
}
}
 
if (TheDistance)
*TheDistance = floor(CandidateDistance * 255.0 + .5);
 
return Candidate;
}
 
 
LPPATCH cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* TheDistance)
{
int i;
LPPATCH Candidate = NULL;
double Distance, CandidateDistance = 255;
double dR, dG, dB;
const struct {
double r, g, b;
 
} RGBPrimaries[3] = {
{ 255.0, 0, 0},
{ 0, 255.0, 0},
{ 0, 0, 255 }};
 
 
for (i=0; i < m -> nPatches; i++) {
 
if (Valids[i]) {
 
LPPATCH p = m -> Patches + i;
 
dR = fabs(RGBPrimaries[Channel].r - p -> Colorant.RGB[0]) / 255.0;
dG = fabs(RGBPrimaries[Channel].g - p -> Colorant.RGB[1]) / 255.0;
dB = fabs(RGBPrimaries[Channel].b - p -> Colorant.RGB[2]) / 255.0;
 
Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
if (Distance < CandidateDistance) {
Candidate = p;
CandidateDistance = Distance;
}
}
}
 
if (TheDistance)
*TheDistance = floor(CandidateDistance * 255.0 + .5);
 
return Candidate;
}
Property changes:
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Revision
\ No newline at end of property