1 /*
   2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /* Iterative color palette generation */
  27 #include <stdio.h>
  28 #include <stdlib.h>
  29 #include <string.h>
  30 #include <math.h>
  31 #ifdef TIMES
  32 #include <time.h>
  33 #endif /* TIMES */
  34 
  35 #ifndef MAKECUBE_EXE
  36 #include "jvm.h"
  37 #include "jni_util.h"
  38 
  39 extern JavaVM *jvm;
  40 #endif
  41 #include "img_colors.h"
  42 
  43 #define jio_fprintf fprintf
  44 
  45 #define TRUE 1
  46 #define FALSE 0
  47 static float monitor_gamma[3] = {2.6f, 2.6f, 2.4f}; /* r,g,b */
  48 static float mat[3][3] = {
  49     {0.3811f, 0.2073f, 0.0213f},
  50     {0.3203f, 0.6805f, 0.1430f},
  51     {0.2483f, 0.1122f, 1.2417f}
  52 };
  53 static float whiteXYZ[3] = { 0.9497f, 1.0000f, 1.4060f };
  54 #define whitex (0.9497f / (0.9497f + 1.0000f + 1.4060f))
  55 #define whitey (1.0000f / (0.9497f + 1.0000f + 1.4060f))
  56 static float uwht = 4*whitex/(-2*whitex + 12*whitey + 3);
  57 static float vwht = 9*whitey/(-2*whitex + 12*whitey + 3);
  58 
  59 static float Rmat[3][256];
  60 static float Gmat[3][256];
  61 static float Bmat[3][256];
  62 static float Ltab[256], Utab[256], Vtab[256];
  63 
  64 typedef struct {
  65     unsigned char red;
  66     unsigned char green;
  67     unsigned char blue;
  68     unsigned char bestidx;
  69     int nextidx;
  70     float L, U, V;
  71     float dist;
  72     float dE;
  73     float dL;
  74 } CmapEntry;
  75 
  76 static int num_virt_cmap_entries;
  77 static CmapEntry *virt_cmap;
  78 static int prevtest[256];
  79 static int nexttest[256];
  80 
  81 static float Lscale = 10.0f;
  82 /* this is a multiplier--it should not be zero */
  83 static float Weight = 250.0f;
  84 
  85 #define WEIGHT_DIST(d,l)   (Weight*(d)/(Weight+(l)))
  86 #define UNWEIGHT_DIST(d,l) ((Weight+(l))*(d)/Weight)
  87 
  88 #if 0
  89 #define WEIGHT_DIST(d,l) (d)
  90 #define UNWEIGHT_DIST(d,l) (d)
  91 #endif
  92 
  93 static void
  94 init_matrices()
  95 {
  96     static int done = 0;
  97     int i;
  98 
  99     if (done) {
 100         return;
 101     }
 102     for (i = 0; i < 256; ++i)
 103     {
 104         float iG = (float) pow(i/255.0, monitor_gamma[0]);
 105         Rmat[0][i] = mat[0][0] * iG;
 106         Rmat[1][i] = mat[0][1] * iG;
 107         Rmat[2][i] = mat[0][2] * iG;
 108 
 109         iG = (float) pow(i/255.0, monitor_gamma[1]);
 110         Gmat[0][i] = mat[1][0] * iG;
 111         Gmat[1][i] = mat[1][1] * iG;
 112         Gmat[2][i] = mat[1][2] * iG;
 113 
 114         iG = (float) pow(i/255.0, monitor_gamma[2]);
 115         Bmat[0][i] = mat[2][0] * iG;
 116         Bmat[1][i] = mat[2][1] * iG;
 117         Bmat[2][i] = mat[2][2] * iG;
 118     }
 119     done = 1;
 120 }
 121 
 122 static void
 123 LUV_convert(int red, int grn, int blu, float *L, float *u, float *v)
 124 {
 125     float X = Rmat[0][red] + Gmat[0][grn] + Bmat[0][blu];
 126     float Y = Rmat[1][red] + Gmat[1][grn] + Bmat[1][blu];
 127     float Z = Rmat[2][red] + Gmat[2][grn] + Bmat[2][blu];
 128     float sum = X+Y+Z;
 129 
 130     if (sum != 0.0f) {
 131         float x    = X/sum;
 132         float y    = Y/sum;
 133         float dnm  = -2*x + 12*y + 3;
 134         float ytmp = (float) pow(Y/whiteXYZ[1], 1.0/3.0);
 135 
 136         if (ytmp < .206893f) {
 137             *L = 903.3f*Y/whiteXYZ[1];
 138         } else {
 139             *L = 116*(ytmp) - 16;
 140         }
 141         if (dnm != 0.0f) {
 142             float uprm = 4*x/dnm;
 143             float vprm = 9*y/dnm;
 144 
 145             *u = 13*(*L)*(uprm-uwht);
 146             *v = 13*(*L)*(vprm-vwht);
 147         } else {
 148             *u = 0.0f;
 149             *v = 0.0f;
 150         }
 151     } else {
 152         *L = 0.0f;
 153         *u = 0.0f;
 154         *v = 0.0f;
 155     }
 156 }
 157 
 158 static int cmapmax;
 159 static int total;
 160 static unsigned char cmap_r[256], cmap_g[256], cmap_b[256];
 161 
 162 #define DIST_THRESHOLD 7
 163 static int
 164 no_close_color(float l, float u, float v, int c_tot, int exact) {
 165     int i;
 166     for (i = 0; i < c_tot; ++i) {
 167         float t, dist = 0.0f;
 168         t = Ltab[i] - l; dist += t*t*Lscale;
 169         t = Utab[i] - u; dist += t*t;
 170         t = Vtab[i] - v; dist += t*t;
 171 
 172         if (dist < (exact ? 0.1 : DIST_THRESHOLD))
 173             return 0;
 174     }
 175 
 176     return 1;
 177 }
 178 
 179 static int
 180 add_color(int r, int g, int b, int f) {
 181     if (total >= cmapmax)
 182         return 0;
 183     cmap_r[total] = r;
 184     cmap_g[total] = g;
 185     cmap_b[total] = b;
 186     LUV_convert(cmap_r[total],cmap_g[total],cmap_b[total],
 187                 Ltab + total, Utab + total, Vtab + total);
 188     if (no_close_color(Ltab[total], Utab[total], Vtab[total], total-1, f)) {
 189         ++total;
 190         return 1;
 191     } else {
 192         return 0;
 193     }
 194 }
 195 
 196 static void
 197 init_primaries() {
 198     int r, g, b;
 199 
 200     for (r = 0; r < 256; r += (r?128:127)) {
 201         for (g = 0; g < 256; g += (g?128:127)) {
 202             for (b = 0; b < 256; b += (b?128:127)) {
 203                 if ((r == g) && (g == b)) continue; /* black or white */
 204                 add_color(r, g, b, TRUE);
 205             }
 206         }
 207     }
 208 }
 209 
 210 static void
 211 init_pastels() {
 212     int i;
 213     /* very light colors */
 214     for (i = 6; i >= 0; --i)
 215         add_color((i&4) ? 0xff : 0xf0,
 216                   (i&2) ? 0xff : 0xf0,
 217                   (i&1) ? 0xff : 0xf0, TRUE);
 218 }
 219 
 220 static void
 221 init_grays() {
 222     int i;
 223     for (i = 15; i < 255; i += 16)
 224         add_color(i, i, i, TRUE);
 225 }
 226 
 227 static void
 228 init_mac_palette() {
 229     add_color(255, 255, 204, TRUE);
 230     add_color(255, 255, 0,   TRUE);
 231     add_color(255, 204, 153, TRUE);
 232     add_color(255, 102, 204, TRUE);
 233     add_color(255, 102, 51,  TRUE);
 234     add_color(221, 0, 0,     TRUE);
 235     add_color(204, 204, 255, TRUE);
 236     add_color(204, 153, 102, TRUE);
 237     add_color(153, 255, 255, TRUE);
 238     add_color(153, 153, 255, TRUE);
 239     add_color(153, 102, 153, TRUE);
 240     add_color(153, 0, 102,   TRUE);
 241     add_color(102, 102, 204, TRUE);
 242     add_color(51, 255, 153,  TRUE);
 243     add_color(51, 153, 102,  TRUE);
 244     add_color(51, 102, 102,  TRUE);
 245     add_color(51, 51, 102,   TRUE);
 246     add_color(51, 0, 153,    TRUE);
 247     add_color(0, 187, 0,     TRUE);
 248     add_color(0, 153, 255,   TRUE);
 249     add_color(0, 0, 221,     TRUE);
 250 }
 251 
 252 static void
 253 init_virt_cmap(int tablesize, int testsize)
 254 {
 255     int r, g, b;
 256     int gray = -1;
 257     CmapEntry *pCmap;
 258     unsigned int dotest[256];
 259 
 260     if (virt_cmap) {
 261         free(virt_cmap);
 262         virt_cmap = 0;
 263     }
 264 
 265     num_virt_cmap_entries = tablesize * tablesize * tablesize;
 266     virt_cmap = malloc(sizeof(CmapEntry) * num_virt_cmap_entries);
 267     /*
 268      * Fix for bug 4070647 malloc return value not check in img_colors.c
 269      * We have to handle the malloc failure differently under
 270      * Win32 and Solaris since under Solaris this file is linked with
 271      * libawt.so and under Win32 it's a separate awt_makecube.exe
 272      * application.
 273      */
 274     if (virt_cmap == NULL) {
 275 #ifndef MAKECUBE_EXE
 276         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 277         JNU_ThrowOutOfMemoryError(env, "init_virt_cmap: OutOfMemoryError");
 278         return;
 279 #else
 280         fprintf(stderr,"init_virt_cmap: OutOfMemoryError\n");
 281         exit(-1);
 282 #endif
 283     }
 284     pCmap = virt_cmap;
 285     for (r = 0; r < total; r++) {
 286         if (cmap_r[r] == cmap_g[r] && cmap_g[r] == cmap_b[r]) {
 287             if (gray < 0 || cmap_r[gray] < cmap_r[r]) {
 288                 gray = r;
 289             }
 290         }
 291     }
 292     if (gray < 0) {
 293 #ifdef DEBUG
 294         jio_fprintf(stderr, "Didn't find any grays in color table!\n");
 295 #endif /* DEBUG */
 296         gray = 0;
 297     }
 298     g = 0;
 299     b = 0;
 300     for (r = 0; r < tablesize - 1; ++r) {
 301         if (g >= 0) {
 302             b = r;
 303             dotest[r] = 1;
 304             g -= tablesize;
 305         } else {
 306             dotest[r] = 0;
 307         }
 308         prevtest[r] = b;
 309         g += testsize;
 310     }
 311     b = r;
 312     prevtest[r] = b;
 313     dotest[r] = 1;
 314     for (r = tablesize - 1; r >= 0; --r) {
 315         if (prevtest[r] == r) {
 316             b = r;
 317         }
 318         nexttest[r] = b;
 319     }
 320 #ifdef DEBUG
 321     for (r = 0; r < tablesize; ++r) {
 322         if (dotest[r]) {
 323             if (prevtest[r] != r || nexttest[r] != r) {
 324                 jio_fprintf(stderr, "prev/next != r!\n");
 325             }
 326         }
 327     }
 328 #endif /* DEBUG */
 329     for (r = 0; r < tablesize; ++r)
 330     {
 331         int red = (int)(floor(r*255.0/(tablesize - 1)));
 332         for (g = 0; g < tablesize; ++g)
 333         {
 334             int green = (int)(floor(g*255.0/(tablesize - 1)));
 335             for (b = 0; b < tablesize; ++b)
 336             {
 337                 int blue = (int)(floor(b*255.0/(tablesize - 1)));
 338                 float t, d;
 339                 if (pCmap >= virt_cmap + num_virt_cmap_entries) {
 340 #ifdef DEBUG
 341                     jio_fprintf(stderr, "OUT OF pCmap CONVERSION SPACE!\n");
 342 #endif /* DEBUG */
 343                     continue;           /* Shouldn't happen */
 344                 }
 345                 pCmap->red = red;
 346                 pCmap->green = green;
 347                 pCmap->blue = blue;
 348                 LUV_convert(red, green, blue, &pCmap->L, &pCmap->U, &pCmap->V);
 349                 if ((red != green || green != blue) &&
 350                     (!dotest[r] || !dotest[g] || !dotest[b]))
 351                 {
 352                     pCmap->nextidx = -1;
 353                     pCmap++;
 354                     continue;
 355                 }
 356                 pCmap->bestidx = gray;
 357                 pCmap->nextidx = 0;
 358                 t = Ltab[gray] - pCmap->L;
 359                 d = t * t;
 360                 if (red == green && green == blue) {
 361                     pCmap->dist = d;
 362                     d *= Lscale;
 363                 } else {
 364                     d *= Lscale;
 365                     t = Utab[gray] - pCmap->U;
 366                     d += t * t;
 367                     t = Vtab[gray] - pCmap->V;
 368                     d += t * t;
 369                     pCmap->dist = d;
 370                 }
 371                 pCmap->dE = WEIGHT_DIST(d, pCmap->L);
 372                 pCmap++;
 373             }
 374         }
 375     }
 376 #ifdef DEBUG
 377     if (pCmap < virt_cmap + num_virt_cmap_entries) {
 378         jio_fprintf(stderr, "Didn't fill pCmap conversion table!\n");
 379     }
 380 #endif /* DEBUG */
 381 }
 382 
 383 static int
 384 find_nearest(CmapEntry *pCmap) {
 385     int red = pCmap->red;
 386     int grn = pCmap->green;
 387     int blu = pCmap->blue;
 388     float L = pCmap->L;
 389     float dist;
 390     int i;
 391 
 392     if ((red == grn) && (grn == blu)) {
 393         dist = pCmap->dist;
 394 
 395         for (i = pCmap->nextidx; i < total; ++i) {
 396             float dL;
 397 
 398             if (cmap_r[i] != cmap_g[i] || cmap_g[i] != cmap_b[i]) {
 399                 continue;
 400             }
 401 
 402             dL = Ltab[i] - L; dL *= dL;
 403 
 404             if (dL < dist) {
 405                 dist = dL;
 406                 pCmap->dist = dist;
 407                 pCmap->dL = dist;
 408                 pCmap->dE = WEIGHT_DIST(dist*Lscale,L);
 409                 pCmap->bestidx = i;
 410             }
 411         }
 412         pCmap->nextidx = total;
 413     } else {
 414         float U = pCmap->U;
 415         float V = pCmap->V;
 416         dist = pCmap->dist;
 417 
 418         for (i = pCmap->nextidx; i < total; ++i) {
 419             float dL, dU, dV, dE;
 420             dL = Ltab[i] - L; dL *= (dL*Lscale);
 421             dU = Utab[i] - U; dU *= dU;
 422             dV = Vtab[i] - V; dV *= dV;
 423 
 424             dE = dL + dU + dV;
 425             if (dE < dist)
 426             {
 427                 dist = dE;
 428                 /* *delta = (dL/4) + dU + dV; */
 429                 /* *delta = dist */
 430                 /* *delta = dL + 100*(dU+dV)/(100+L); */
 431                 pCmap->dist = dist;
 432                 pCmap->dE = WEIGHT_DIST(dE, L);
 433                 pCmap->dL = dL/Lscale;
 434                 pCmap->bestidx = i;
 435             }
 436         }
 437         pCmap->nextidx = total;
 438     }
 439 
 440     return pCmap->bestidx;
 441 }
 442 
 443 #define MAX_OFFENDERS 32
 444 static CmapEntry *offenders[MAX_OFFENDERS + 1];
 445 static int num_offenders;
 446 
 447 static void
 448 insert_in_list(CmapEntry *pCmap)
 449 {
 450     int i;
 451     float dE = pCmap->dE;
 452 
 453     for (i = num_offenders; i > 0; --i) {
 454         if (dE < offenders[i-1]->dE) break;
 455         offenders[i] = offenders[i-1];
 456     }
 457 
 458     offenders[i] = pCmap;
 459     if (num_offenders < MAX_OFFENDERS) ++num_offenders;
 460 }
 461 
 462 static void
 463 handle_biggest_offenders(int testtblsize, int maxcolors) {
 464     int i, j;
 465     float dEthresh = 0;
 466     CmapEntry *pCmap;
 467 
 468     num_offenders = 0;
 469 
 470     for (pCmap = virt_cmap, i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
 471         if (pCmap->nextidx < 0) {
 472             continue;
 473         }
 474         if (num_offenders == MAX_OFFENDERS
 475             && pCmap->dE < offenders[MAX_OFFENDERS-1]->dE)
 476         {
 477             continue;
 478         }
 479         find_nearest(pCmap);
 480         insert_in_list(pCmap);
 481     }
 482 
 483     if (num_offenders > 0) {
 484         dEthresh = offenders[num_offenders-1]->dE;
 485     }
 486 
 487     for (i = 0; (total < maxcolors) && (i < num_offenders); ++i) {
 488         pCmap = offenders[i];
 489 
 490         if (!pCmap) continue;
 491 
 492         j = add_color(pCmap->red, pCmap->green, pCmap->blue, FALSE);
 493 
 494         if (j) {
 495             for (j = i+1; j < num_offenders; ++j) {
 496                 float dE;
 497 
 498                 pCmap = offenders[j];
 499                 if (!pCmap) {
 500                     continue;
 501                 }
 502 
 503                 find_nearest(pCmap);
 504 
 505                 dE = pCmap->dE;
 506                 if (dE < dEthresh) {
 507                     offenders[j] = 0;
 508                 } else {
 509                     if (offenders[i+1] == 0 || dE > offenders[i+1]->dE) {
 510                         offenders[j] = offenders[i+1];
 511                         offenders[i+1] = pCmap;
 512                     }
 513                 }
 514             }
 515         }
 516     }
 517 }
 518 
 519 JNIEXPORT void JNICALL
 520 img_makePalette(int cmapsize, int tablesize, int lookupsize,
 521                 float lscale, float weight,
 522                 int prevclrs, int doMac,
 523                 unsigned char *reds,
 524                 unsigned char *greens,
 525                 unsigned char *blues,
 526                 unsigned char *lookup)
 527 {
 528     CmapEntry *pCmap;
 529     int i, ix;
 530 #ifdef STATS
 531     double ave_dL, ave_dE;
 532     double max_dL, max_dE;
 533 #endif /* STATS */
 534 #ifdef TIMES
 535     clock_t start, mid, tbl, end;
 536 
 537     start = clock();
 538 #endif /* TIMES */
 539 
 540     init_matrices();
 541     Lscale = lscale;
 542     Weight = weight;
 543 
 544     cmapmax = cmapsize;
 545     total = 0;
 546     for (i = 0; i < prevclrs; i++) {
 547         add_color(reds[i], greens[i], blues[i], TRUE);
 548     }
 549 
 550     add_color(0, 0, 0, TRUE);
 551     add_color(255,255,255, TRUE);
 552 
 553     /* do grays next; otherwise find_nearest may break! */
 554     init_grays();
 555     if (doMac) {
 556         init_mac_palette();
 557     }
 558     init_pastels();
 559 
 560     init_primaries();
 561 
 562     /* special case some blues */
 563     add_color(0,0,192,TRUE);
 564     add_color(0x30,0x20,0x80,TRUE);
 565     add_color(0x20,0x60,0xc0,TRUE);
 566 
 567     init_virt_cmap(lookupsize, tablesize);
 568 
 569     while (total < cmapsize) {
 570         handle_biggest_offenders(tablesize, cmapsize);
 571     }
 572 
 573     memcpy(reds, cmap_r, cmapsize);
 574     memcpy(greens, cmap_g, cmapsize);
 575     memcpy(blues, cmap_b, cmapsize);
 576 
 577 #ifdef TIMES
 578     mid = clock();
 579 #endif /* TIMES */
 580 
 581     pCmap = virt_cmap;
 582     for (i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
 583         if (pCmap->nextidx < 0) {
 584             continue;
 585         }
 586         if (pCmap->nextidx < total) {
 587             ix = find_nearest(pCmap);
 588         }
 589     }
 590 
 591 #ifdef TIMES
 592     tbl = clock();
 593 #endif /* TIMES */
 594 
 595     pCmap = virt_cmap;
 596     if (tablesize != lookupsize) {
 597         int r, g, b;
 598         for (r = 0; r < lookupsize; ++r)
 599         {
 600             for (g = 0; g < lookupsize; ++g)
 601             {
 602                 for (b = 0; b < lookupsize; ++b, pCmap++)
 603                 {
 604                     float L, U, V;
 605                     float bestd = 0;
 606                     CmapEntry *pTest;
 607 
 608                     if (pCmap->nextidx >= 0) {
 609                         continue;
 610                     }
 611 #ifdef DEBUG
 612                     if (r == g && g == b) {
 613                         jio_fprintf(stderr, "GRAY VALUE!?\n");
 614                     }
 615 #endif /* DEBUG */
 616                     L = pCmap->L;
 617                     U = pCmap->U;
 618                     V = pCmap->V;
 619                     for (i = 0; i < 8; i++) {
 620                         int ri, gi, bi;
 621                         float d, t;
 622                         ri = (i & 1) ? prevtest[r] : nexttest[r];
 623                         gi = (i & 2) ? prevtest[g] : nexttest[g];
 624                         bi = (i & 4) ? prevtest[b] : nexttest[b];
 625                         pTest = &virt_cmap[((ri * lookupsize)
 626                                             + gi) * lookupsize
 627                                            + bi];
 628 #ifdef DEBUG
 629                         if (pTest->nextidx < 0) {
 630                             jio_fprintf(stderr, "OOPS!\n");
 631                         }
 632 #endif /* DEBUG */
 633                         ix = pTest->bestidx;
 634                         t = Ltab[ix] - L; d  = t * t * Lscale;
 635                         if (i != 0 && d > bestd) continue;
 636                         t = Utab[ix] - U; d += t * t;
 637                         if (i != 0 && d > bestd) continue;
 638                         t = Vtab[ix] - V; d += t * t;
 639                         if (i != 0 && d > bestd) continue;
 640                         bestd = d;
 641                         pCmap->bestidx = ix;
 642                     }
 643                 }
 644             }
 645         }
 646     }
 647     pCmap = virt_cmap;
 648     for (i = 0; i < num_virt_cmap_entries; i++) {
 649         *lookup++ = (pCmap++)->bestidx;
 650     }
 651 
 652 #ifdef TIMES
 653     end = clock();
 654 #endif /* TIMES */
 655 
 656 #ifdef STATS
 657     max_dL = 0.0;
 658     max_dE = 0.0;
 659     ave_dL = 0.0;
 660     ave_dE = 0.0;
 661 
 662     pCmap = virt_cmap;
 663     for (i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
 664         double t, dL, dU, dV, dE;
 665         if (pCmap->nextidx < 0) {
 666             int ix = pCmap->bestidx;
 667             dL = pCmap->L - Ltab[ix]; dL *= dL;
 668             dU = pCmap->U - Utab[ix]; dU *= dU;
 669             dV = pCmap->V - Vtab[ix]; dV *= dV;
 670             dE = dL * Lscale + dU + dV;
 671             dE = WEIGHT_DIST(dE, pCmap->L);
 672         } else {
 673             dL = pCmap->dL;
 674             dE = pCmap->dE;
 675         }
 676 
 677         if (dL > max_dL) max_dL = dL;
 678         t = UNWEIGHT_DIST(dE,dL) - dL*(Lscale-1);
 679         if (t > max_dE) max_dE = t;
 680 
 681         ave_dL += (dL > 0) ? sqrt(dL) : 0.0;
 682         ave_dE += (t > 0) ? sqrt(t) : 0.0;
 683     }
 684 
 685     jio_fprintf(stderr, "colors=%d, tablesize=%d, cubesize=%d, ",
 686             cmapsize, tablesize, lookupsize);
 687     jio_fprintf(stderr, "Lscale=%5.3f, Weight=%5.3f mac=%s\n",
 688             (double)lscale, (double)weight, doMac ? "true" : "false");
 689     jio_fprintf(stderr, "Worst case error dL = %5.3f, dE = %5.3f\n",
 690             sqrt(max_dL), sqrt(max_dE));
 691     jio_fprintf(stderr, "Average error dL = %5.3f, dE = %5.3f\n",
 692             ave_dL / num_virt_cmap_entries,  ave_dE / num_virt_cmap_entries);
 693 #endif /* STATS */
 694 #ifdef TIMES
 695     jio_fprintf(stderr, "%f seconds to find colors\n",
 696             (double)(mid - start) / CLOCKS_PER_SEC);
 697     jio_fprintf(stderr, "%f seconds to finish nearest colors\n",
 698             (double)(tbl - mid) / CLOCKS_PER_SEC);
 699     jio_fprintf(stderr, "%f seconds to make lookup table\n",
 700             (double)(end - tbl) / CLOCKS_PER_SEC);
 701     jio_fprintf(stderr, "%f seconds total\n",
 702             (double)(end - start) / CLOCKS_PER_SEC);
 703 #endif /* TIMES */
 704 
 705     free(virt_cmap);
 706     virt_cmap = 0;
 707 }