2693N/A/*
2693N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2693N/A *
2693N/A * This code is free software; you can redistribute it and/or modify it
2693N/A * under the terms of the GNU General Public License version 2 only, as
2693N/A * published by the Free Software Foundation. Oracle designates this
2693N/A * particular file as subject to the "Classpath" exception as provided
2693N/A * by Oracle in the LICENSE file that accompanied this code.
2693N/A *
2693N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2693N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2693N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2693N/A * version 2 for more details (a copy is included in the LICENSE file that
2693N/A * accompanied this code).
2693N/A *
2693N/A * You should have received a copy of the GNU General Public License version
2693N/A * 2 along with this work; if not, write to the Free Software Foundation,
2693N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2693N/A *
2693N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2693N/A * or visit www.oracle.com if you need additional information or have any
2693N/A * questions.
2693N/A */
2693N/A
2693N/A// This file is available under and governed by the GNU General Public
2693N/A// License version 2 only, as published by the Free Software Foundation.
2693N/A// However, the following notice accompanied the original version of this
2693N/A// file:
2693N/A//
2693N/A//---------------------------------------------------------------------------------
2693N/A//
2693N/A// Little Color Management System
6271N/A// Copyright (c) 1998-2011 Marti Maria Saguer
2693N/A//
2693N/A// Permission is hereby granted, free of charge, to any person obtaining
2693N/A// a copy of this software and associated documentation files (the "Software"),
2693N/A// to deal in the Software without restriction, including without limitation
2693N/A// the rights to use, copy, modify, merge, publish, distribute, sublicense,
2693N/A// and/or sell copies of the Software, and to permit persons to whom the Software
2693N/A// is furnished to do so, subject to the following conditions:
2693N/A//
2693N/A// The above copyright notice and this permission notice shall be included in
2693N/A// all copies or substantial portions of the Software.
2693N/A//
2693N/A// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2693N/A// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
2693N/A// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2693N/A// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2693N/A// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2693N/A// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2693N/A// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2693N/A//
2693N/A//---------------------------------------------------------------------------------
2693N/A//
2693N/A
2693N/A#include "lcms2_internal.h"
2693N/A
2693N/A
2693N/A// ------------------------------------------------------------------------
2693N/A
2693N/A// Gamut boundary description by using Jan Morovic's Segment maxima method
2693N/A// Many thanks to Jan for allowing me to use his algorithm.
2693N/A
2693N/A// r = C*
2693N/A// alpha = Hab
2693N/A// theta = L*
2693N/A
2693N/A#define SECTORS 16 // number of divisions in alpha and theta
2693N/A
2693N/A// Spherical coordinates
2693N/Atypedef struct {
2693N/A
2693N/A cmsFloat64Number r;
2693N/A cmsFloat64Number alpha;
2693N/A cmsFloat64Number theta;
2693N/A
2693N/A} cmsSpherical;
2693N/A
2693N/Atypedef enum {
2693N/A GP_EMPTY,
2693N/A GP_SPECIFIED,
2693N/A GP_MODELED
2693N/A
2693N/A } GDBPointType;
2693N/A
2693N/A
2693N/Atypedef struct {
2693N/A
2693N/A GDBPointType Type;
2693N/A cmsSpherical p; // Keep also alpha & theta of maximum
2693N/A
2693N/A} cmsGDBPoint;
2693N/A
2693N/A
2693N/Atypedef struct {
2693N/A
2693N/A cmsContext ContextID;
2693N/A cmsGDBPoint Gamut[SECTORS][SECTORS];
2693N/A
2693N/A} cmsGDB;
2693N/A
2693N/A
2693N/A// A line using the parametric form
2693N/A// P = a + t*u
2693N/Atypedef struct {
2693N/A
2693N/A cmsVEC3 a;
2693N/A cmsVEC3 u;
2693N/A
2693N/A} cmsLine;
2693N/A
2693N/A
2693N/A// A plane using the parametric form
2693N/A// Q = b + r*v + s*w
2693N/Atypedef struct {
2693N/A
2693N/A cmsVEC3 b;
2693N/A cmsVEC3 v;
2693N/A cmsVEC3 w;
2693N/A
2693N/A} cmsPlane;
2693N/A
2693N/A
2693N/A
2693N/A// --------------------------------------------------------------------------------------------
2693N/A
2693N/A// ATAN2() which always returns degree positive numbers
2693N/A
2693N/Astatic
2693N/AcmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x)
2693N/A{
2693N/A cmsFloat64Number a;
2693N/A
2693N/A // Deal with undefined case
2693N/A if (x == 0.0 && y == 0.0) return 0;
2693N/A
2693N/A a = (atan2(y, x) * 180.0) / M_PI;
2693N/A
2693N/A while (a < 0) {
2693N/A a += 360;
2693N/A }
2693N/A
2693N/A return a;
2693N/A}
2693N/A
2693N/A// Convert to spherical coordinates
2693N/Astatic
2693N/Avoid ToSpherical(cmsSpherical* sp, const cmsVEC3* v)
2693N/A{
2693N/A
2693N/A cmsFloat64Number L, a, b;
2693N/A
2693N/A L = v ->n[VX];
2693N/A a = v ->n[VY];
2693N/A b = v ->n[VZ];
2693N/A
2693N/A sp ->r = sqrt( L*L + a*a + b*b );
2693N/A
2693N/A if (sp ->r == 0) {
2693N/A sp ->alpha = sp ->theta = 0;
2693N/A return;
2693N/A }
2693N/A
2693N/A sp ->alpha = _cmsAtan2(a, b);
2693N/A sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L);
2693N/A}
2693N/A
2693N/A
2693N/A// Convert to cartesian from spherical
2693N/Astatic
2693N/Avoid ToCartesian(cmsVEC3* v, const cmsSpherical* sp)
2693N/A{
2693N/A cmsFloat64Number sin_alpha;
2693N/A cmsFloat64Number cos_alpha;
2693N/A cmsFloat64Number sin_theta;
2693N/A cmsFloat64Number cos_theta;
2693N/A cmsFloat64Number L, a, b;
2693N/A
2693N/A sin_alpha = sin((M_PI * sp ->alpha) / 180.0);
2693N/A cos_alpha = cos((M_PI * sp ->alpha) / 180.0);
2693N/A sin_theta = sin((M_PI * sp ->theta) / 180.0);
2693N/A cos_theta = cos((M_PI * sp ->theta) / 180.0);
2693N/A
2693N/A a = sp ->r * sin_theta * sin_alpha;
2693N/A b = sp ->r * sin_theta * cos_alpha;
2693N/A L = sp ->r * cos_theta;
2693N/A
2693N/A v ->n[VX] = L;
2693N/A v ->n[VY] = a;
2693N/A v ->n[VZ] = b;
2693N/A}
2693N/A
2693N/A
2693N/A// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector
2693N/A// The limits are the centers of each sector, so
2693N/Astatic
2693N/Avoid QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta)
2693N/A{
2693N/A *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) );
2693N/A *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) );
2693N/A
2693N/A if (*alpha >= SECTORS)
2693N/A *alpha = SECTORS-1;
2693N/A if (*theta >= SECTORS)
2693N/A *theta = SECTORS-1;
2693N/A}
2693N/A
2693N/A
2693N/A// Line determined by 2 points
2693N/Astatic
2693N/Avoid LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b)
2693N/A{
2693N/A
2693N/A _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]);
2693N/A _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX],
2693N/A b ->n[VY] - a ->n[VY],
2693N/A b ->n[VZ] - a ->n[VZ]);
2693N/A}
2693N/A
2693N/A
2693N/A// Evaluate parametric line
2693N/Astatic
2693N/Avoid GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t)
2693N/A{
2693N/A p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX];
2693N/A p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY];
2693N/A p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ];
2693N/A}
2693N/A
2693N/A
2693N/A
2693N/A/*
2693N/A Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1)
2693N/A http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
2693N/A
2693N/A Copyright 2001, softSurfer (www.softsurfer.com)
2693N/A This code may be freely used and modified for any purpose
2693N/A providing that this copyright notice is included with it.
2693N/A SoftSurfer makes no warranty for this code, and cannot be held
2693N/A liable for any real or imagined damage resulting from its use.
2693N/A Users of this code must verify correctness for their application.
2693N/A
2693N/A*/
2693N/A
2693N/Astatic
2693N/AcmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2)
2693N/A{
2693N/A cmsFloat64Number a, b, c, d, e, D;
2693N/A cmsFloat64Number sc, sN, sD;
2693N/A cmsFloat64Number tc, tN, tD;
2693N/A cmsVEC3 w0;
2693N/A
2693N/A _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a);
2693N/A
2693N/A a = _cmsVEC3dot(&line1 ->u, &line1 ->u);
2693N/A b = _cmsVEC3dot(&line1 ->u, &line2 ->u);
2693N/A c = _cmsVEC3dot(&line2 ->u, &line2 ->u);
2693N/A d = _cmsVEC3dot(&line1 ->u, &w0);
2693N/A e = _cmsVEC3dot(&line2 ->u, &w0);
2693N/A
2693N/A D = a*c - b * b; // Denominator
2693N/A sD = tD = D; // default sD = D >= 0
2693N/A
2693N/A if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel
2693N/A
2693N/A sN = 0.0; // force using point P0 on segment S1
2693N/A sD = 1.0; // to prevent possible division by 0.0 later
2693N/A tN = e;
2693N/A tD = c;
2693N/A }
2693N/A else { // get the closest points on the infinite lines
2693N/A
2693N/A sN = (b*e - c*d);
2693N/A tN = (a*e - b*d);
2693N/A
2693N/A if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
2693N/A
2693N/A sN = 0.0;
2693N/A tN = e;
2693N/A tD = c;
2693N/A }
2693N/A else if (sN > sD) { // sc > 1 => the s=1 edge is visible
2693N/A sN = sD;
2693N/A tN = e + b;
2693N/A tD = c;
2693N/A }
2693N/A }
2693N/A
2693N/A if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
2693N/A
2693N/A tN = 0.0;
2693N/A // recompute sc for this edge
2693N/A if (-d < 0.0)
2693N/A sN = 0.0;
2693N/A else if (-d > a)
2693N/A sN = sD;
2693N/A else {
2693N/A sN = -d;
2693N/A sD = a;
2693N/A }
2693N/A }
2693N/A else if (tN > tD) { // tc > 1 => the t=1 edge is visible
2693N/A
2693N/A tN = tD;
2693N/A
2693N/A // recompute sc for this edge
2693N/A if ((-d + b) < 0.0)
2693N/A sN = 0;
2693N/A else if ((-d + b) > a)
2693N/A sN = sD;
2693N/A else {
2693N/A sN = (-d + b);
2693N/A sD = a;
2693N/A }
2693N/A }
2693N/A // finally do the division to get sc and tc
2693N/A sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD);
2693N/A tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD);
2693N/A
2693N/A GetPointOfLine(r, line1, sc);
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A
2693N/A
2693N/A// ------------------------------------------------------------------ Wrapper
2693N/A
2693N/A
2693N/A// Allocate & free structure
2693N/AcmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID)
2693N/A{
2693N/A cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB));
2693N/A if (gbd == NULL) return NULL;
2693N/A
2693N/A gbd -> ContextID = ContextID;
2693N/A
2693N/A return (cmsHANDLE) gbd;
2693N/A}
2693N/A
2693N/A
2693N/Avoid CMSEXPORT cmsGBDFree(cmsHANDLE hGBD)
2693N/A{
2693N/A cmsGDB* gbd = (cmsGDB*) hGBD;
2693N/A if (hGBD != NULL)
2693N/A _cmsFree(gbd->ContextID, (void*) gbd);
2693N/A}
2693N/A
2693N/A
2693N/A// Auxiliar to retrieve a pointer to the segmentr containing the Lab value
2693N/Astatic
2693N/AcmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp)
2693N/A{
2693N/A cmsVEC3 v;
2693N/A int alpha, theta;
2693N/A
2693N/A // Housekeeping
2693N/A _cmsAssert(gbd != NULL);
2693N/A _cmsAssert(Lab != NULL);
2693N/A _cmsAssert(sp != NULL);
2693N/A
2693N/A // Center L* by substracting half of its domain, that's 50
2693N/A _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b);
2693N/A
2693N/A // Convert to spherical coordinates
2693N/A ToSpherical(sp, &v);
2693N/A
2693N/A if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) {
2693N/A cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range");
2693N/A return NULL;
2693N/A }
2693N/A
2693N/A // On which sector it falls?
2693N/A QuantizeToSector(sp, &alpha, &theta);
2693N/A
2693N/A if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) {
2693N/A cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range");
2693N/A return NULL;
2693N/A }
2693N/A
2693N/A // Get pointer to the sector
2693N/A return &gbd ->Gamut[theta][alpha];
2693N/A}
2693N/A
2693N/A// Add a point to gamut descriptor. Point to add is in Lab color space.
2693N/A// GBD is centered on a=b=0 and L*=50
2693N/AcmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
2693N/A{
2693N/A cmsGDB* gbd = (cmsGDB*) hGBD;
2693N/A cmsGDBPoint* ptr;
2693N/A cmsSpherical sp;
2693N/A
2693N/A
2693N/A // Get pointer to the sector
2693N/A ptr = GetPoint(gbd, Lab, &sp);
2693N/A if (ptr == NULL) return FALSE;
2693N/A
2693N/A // If no samples at this sector, add it
2693N/A if (ptr ->Type == GP_EMPTY) {
2693N/A
2693N/A ptr -> Type = GP_SPECIFIED;
2693N/A ptr -> p = sp;
2693N/A }
2693N/A else {
2693N/A
2693N/A
2693N/A // Substitute only if radius is greater
2693N/A if (sp.r > ptr -> p.r) {
2693N/A
2693N/A ptr -> Type = GP_SPECIFIED;
2693N/A ptr -> p = sp;
2693N/A }
2693N/A }
2693N/A
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A// Check if a given point falls inside gamut
2693N/AcmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
2693N/A{
2693N/A cmsGDB* gbd = (cmsGDB*) hGBD;
2693N/A cmsGDBPoint* ptr;
2693N/A cmsSpherical sp;
2693N/A
2693N/A // Get pointer to the sector
2693N/A ptr = GetPoint(gbd, Lab, &sp);
2693N/A if (ptr == NULL) return FALSE;
2693N/A
2693N/A // If no samples at this sector, return no data
2693N/A if (ptr ->Type == GP_EMPTY) return FALSE;
2693N/A
2693N/A // In gamut only if radius is greater
2693N/A
2693N/A return (sp.r <= ptr -> p.r);
2693N/A}
2693N/A
2693N/A// -----------------------------------------------------------------------------------------------------------------------
2693N/A
2693N/A// Find near sectors. The list of sectors found is returned on Close[].
2693N/A// The function returns the number of sectors as well.
2693N/A
2693N/A// 24 9 10 11 12
2693N/A// 23 8 1 2 13
2693N/A// 22 7 * 3 14
2693N/A// 21 6 5 4 15
2693N/A// 20 19 18 17 16
2693N/A//
2693N/A// Those are the relative movements
2693N/A// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
2693N/A// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1},
2693N/A// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0},
2693N/A// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1},
2693N/A// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}};
2693N/A
2693N/A
2693N/Astatic
2693N/Aconst struct _spiral {
2693N/A
2693N/A int AdvX, AdvY;
2693N/A
2693N/A } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1},
2693N/A {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
2693N/A {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2},
2693N/A {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} };
2693N/A
2693N/A#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral))
2693N/A
2693N/Astatic
2693N/Aint FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[])
2693N/A{
2693N/A int nSectors = 0;
6271N/A int a, t;
6271N/A cmsUInt32Number i;
2693N/A cmsGDBPoint* pt;
2693N/A
2693N/A for (i=0; i < NSTEPS; i++) {
2693N/A
2693N/A a = alpha + Spiral[i].AdvX;
2693N/A t = theta + Spiral[i].AdvY;
2693N/A
2693N/A // Cycle at the end
2693N/A a %= SECTORS;
2693N/A t %= SECTORS;
2693N/A
2693N/A // Cycle at the begin
2693N/A if (a < 0) a = SECTORS + a;
2693N/A if (t < 0) t = SECTORS + t;
2693N/A
2693N/A pt = &gbd ->Gamut[t][a];
2693N/A
2693N/A if (pt -> Type != GP_EMPTY) {
2693N/A
2693N/A Close[nSectors++] = pt;
2693N/A }
2693N/A }
2693N/A
2693N/A return nSectors;
2693N/A}
2693N/A
2693N/A
2693N/A// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid
2693N/Astatic
2693N/AcmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta)
2693N/A{
2693N/A cmsSpherical sp;
2693N/A cmsVEC3 Lab;
2693N/A cmsVEC3 Centre;
2693N/A cmsLine ray;
2693N/A int nCloseSectors;
6271N/A cmsGDBPoint* Close[NSTEPS + 1];
2693N/A cmsSpherical closel, templ;
2693N/A cmsLine edge;
2693N/A int k, m;
2693N/A
2693N/A // Is that point already specified?
2693N/A if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE;
2693N/A
2693N/A // Fill close points
2693N/A nCloseSectors = FindNearSectors(gbd, alpha, theta, Close);
2693N/A
2693N/A
2693N/A // Find a central point on the sector
2693N/A sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS);
2693N/A sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS);
2693N/A sp.r = 50.0;
2693N/A
2693N/A // Convert to Cartesian
2693N/A ToCartesian(&Lab, &sp);
2693N/A
2693N/A // Create a ray line from centre to this point
2693N/A _cmsVEC3init(&Centre, 50.0, 0, 0);
2693N/A LineOf2Points(&ray, &Lab, &Centre);
2693N/A
2693N/A // For all close sectors
2693N/A closel.r = 0.0;
2693N/A closel.alpha = 0;
2693N/A closel.theta = 0;
2693N/A
2693N/A for (k=0; k < nCloseSectors; k++) {
2693N/A
2693N/A for(m = k+1; m < nCloseSectors; m++) {
2693N/A
2693N/A cmsVEC3 temp, a1, a2;
2693N/A
2693N/A // A line from sector to sector
2693N/A ToCartesian(&a1, &Close[k]->p);
2693N/A ToCartesian(&a2, &Close[m]->p);
2693N/A
2693N/A LineOf2Points(&edge, &a1, &a2);
2693N/A
2693N/A // Find a line
2693N/A ClosestLineToLine(&temp, &ray, &edge);
2693N/A
2693N/A // Convert to spherical
2693N/A ToSpherical(&templ, &temp);
2693N/A
2693N/A
2693N/A if ( templ.r > closel.r &&
2693N/A templ.theta >= (theta*180.0/SECTORS) &&
2693N/A templ.theta <= ((theta+1)*180.0/SECTORS) &&
2693N/A templ.alpha >= (alpha*360.0/SECTORS) &&
2693N/A templ.alpha <= ((alpha+1)*360.0/SECTORS)) {
2693N/A
2693N/A closel = templ;
2693N/A }
2693N/A }
2693N/A }
2693N/A
2693N/A gbd ->Gamut[theta][alpha].p = closel;
2693N/A gbd ->Gamut[theta][alpha].Type = GP_MODELED;
2693N/A
2693N/A return TRUE;
2693N/A
2693N/A}
2693N/A
2693N/A
2693N/A// Interpolate missing parts. The algorithm fist computes slices at
2693N/A// theta=0 and theta=Max.
2693N/AcmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags)
2693N/A{
2693N/A int alpha, theta;
2693N/A cmsGDB* gbd = (cmsGDB*) hGBD;
2693N/A
2693N/A _cmsAssert(hGBD != NULL);
2693N/A
2693N/A // Interpolate black
6271N/A for (alpha = 0; alpha < SECTORS; alpha++) {
2693N/A
2693N/A if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE;
2693N/A }
2693N/A
2693N/A // Interpolate white
6271N/A for (alpha = 0; alpha < SECTORS; alpha++) {
2693N/A
2693N/A if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE;
2693N/A }
2693N/A
2693N/A
2693N/A // Interpolate Mid
2693N/A for (theta = 1; theta < SECTORS; theta++) {
6271N/A for (alpha = 0; alpha < SECTORS; alpha++) {
2693N/A
2693N/A if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE;
2693N/A }
2693N/A }
2693N/A
2693N/A // Done
2693N/A return TRUE;
2693N/A
2693N/A cmsUNUSED_PARAMETER(dwFlags);
2693N/A}
2693N/A
2693N/A
2693N/A
2693N/A
2693N/A// --------------------------------------------------------------------------------------------------------
2693N/A
2693N/A// Great for debug, but not suitable for real use
2693N/A
2693N/A#if 0
2693N/AcmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname)
2693N/A{
2693N/A FILE* fp;
2693N/A int i, j;
2693N/A cmsGDB* gbd = (cmsGDB*) hGBD;
2693N/A cmsGDBPoint* pt;
2693N/A
2693N/A fp = fopen (fname, "wt");
2693N/A if (fp == NULL)
2693N/A return FALSE;
2693N/A
2693N/A fprintf (fp, "#VRML V2.0 utf8\n");
2693N/A
2693N/A // set the viewing orientation and distance
2693N/A fprintf (fp, "DEF CamTest Group {\n");
2693N/A fprintf (fp, "\tchildren [\n");
2693N/A fprintf (fp, "\t\tDEF Cameras Group {\n");
2693N/A fprintf (fp, "\t\t\tchildren [\n");
2693N/A fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n");
2693N/A fprintf (fp, "\t\t\t\t\tposition 0 0 340\n");
2693N/A fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n");
2693N/A fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n");
2693N/A fprintf (fp, "\t\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\t]\n");
2693N/A fprintf (fp, "\t\t},\n");
2693N/A fprintf (fp, "\t]\n");
2693N/A fprintf (fp, "}\n");
2693N/A
2693N/A // Output the background stuff
2693N/A fprintf (fp, "Background {\n");
2693N/A fprintf (fp, "\tskyColor [\n");
2693N/A fprintf (fp, "\t\t.5 .5 .5\n");
2693N/A fprintf (fp, "\t]\n");
2693N/A fprintf (fp, "}\n");
2693N/A
2693N/A // Output the shape stuff
2693N/A fprintf (fp, "Transform {\n");
2693N/A fprintf (fp, "\tscale .3 .3 .3\n");
2693N/A fprintf (fp, "\tchildren [\n");
2693N/A
2693N/A // Draw the axes as a shape:
2693N/A fprintf (fp, "\t\tShape {\n");
2693N/A fprintf (fp, "\t\t\tappearance Appearance {\n");
2693N/A fprintf (fp, "\t\t\t\tmaterial Material {\n");
2693N/A fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
2693N/A fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n");
2693N/A fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
2693N/A fprintf (fp, "\t\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n");
2693N/A fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
2693N/A fprintf (fp, "\t\t\t\t\tpoint [\n");
2693N/A fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n");
2693N/A fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0);
2693N/A fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0);
2693N/A fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0);
2693N/A fprintf (fp, "\t\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\t\tcoordIndex [\n");
2693N/A fprintf (fp, "\t\t\t\t\t0, 1, -1\n");
2693N/A fprintf (fp, "\t\t\t\t\t0, 2, -1\n");
2693N/A fprintf (fp, "\t\t\t\t\t0, 3, -1]\n");
2693N/A fprintf (fp, "\t\t\t}\n");
2693N/A fprintf (fp, "\t\t}\n");
2693N/A
2693N/A
2693N/A fprintf (fp, "\t\tShape {\n");
2693N/A fprintf (fp, "\t\t\tappearance Appearance {\n");
2693N/A fprintf (fp, "\t\t\t\tmaterial Material {\n");
2693N/A fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
2693N/A fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n");
2693N/A fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
2693N/A fprintf (fp, "\t\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\t}\n");
2693N/A fprintf (fp, "\t\t\tgeometry PointSet {\n");
2693N/A
2693N/A // fill in the points here
2693N/A fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
2693N/A fprintf (fp, "\t\t\t\t\tpoint [\n");
2693N/A
2693N/A // We need to transverse all gamut hull.
2693N/A for (i=0; i < SECTORS; i++)
2693N/A for (j=0; j < SECTORS; j++) {
2693N/A
2693N/A cmsVEC3 v;
2693N/A
2693N/A pt = &gbd ->Gamut[i][j];
2693N/A ToCartesian(&v, &pt ->p);
2693N/A
2693N/A fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]);
2693N/A
2693N/A if ((j == SECTORS - 1) && (i == SECTORS - 1))
2693N/A fprintf (fp, "]\n");
2693N/A else
2693N/A fprintf (fp, ",\n");
2693N/A
2693N/A }
2693N/A
2693N/A fprintf (fp, "\t\t\t\t}\n");
2693N/A
2693N/A
2693N/A
2693N/A // fill in the face colors
2693N/A fprintf (fp, "\t\t\t\tcolor Color {\n");
2693N/A fprintf (fp, "\t\t\t\t\tcolor [\n");
2693N/A
2693N/A for (i=0; i < SECTORS; i++)
2693N/A for (j=0; j < SECTORS; j++) {
2693N/A
2693N/A cmsVEC3 v;
2693N/A
2693N/A pt = &gbd ->Gamut[i][j];
2693N/A
2693N/A
2693N/A ToCartesian(&v, &pt ->p);
2693N/A
2693N/A
2693N/A if (pt ->Type == GP_EMPTY)
2693N/A fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0);
2693N/A else
2693N/A if (pt ->Type == GP_MODELED)
2693N/A fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5);
2693N/A else {
2693N/A fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0);
2693N/A
2693N/A }
2693N/A
2693N/A if ((j == SECTORS - 1) && (i == SECTORS - 1))
2693N/A fprintf (fp, "]\n");
2693N/A else
2693N/A fprintf (fp, ",\n");
2693N/A }
2693N/A fprintf (fp, "\t\t\t}\n");
2693N/A
2693N/A
2693N/A fprintf (fp, "\t\t\t}\n");
2693N/A fprintf (fp, "\t\t}\n");
2693N/A fprintf (fp, "\t]\n");
2693N/A fprintf (fp, "}\n");
2693N/A
2693N/A fclose (fp);
2693N/A
2693N/A return TRUE;
2693N/A}
2693N/A#endif
6271N/A