1 /*
   2  * Copyright (c) 2001, 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 #include "dither.h"
  27 
  28 sgn_ordered_dither_array std_img_oda_red;
  29 sgn_ordered_dither_array std_img_oda_green;
  30 sgn_ordered_dither_array std_img_oda_blue;
  31 int std_odas_computed = 0;
  32 
  33 void initInverseGrayLut(int* prgb, int rgbsize, ColorData *cData) {
  34     int *inverse;
  35     int lastindex, lastgray, missing, i;
  36 
  37     if (!cData) {
  38         return;
  39     }
  40 
  41     inverse = calloc(256, sizeof(int));
  42     if (!inverse) {
  43         return;
  44     }
  45     cData->pGrayInverseLutData = inverse;
  46 
  47     for (i = 0; i < 256; i++) {
  48         inverse[i] = -1;
  49     }
  50 
  51     /* First, fill the gray values */
  52     for (i = 0; i < rgbsize; i++) {
  53         int r, g, b, rgb = prgb[i];
  54         if (rgb == 0x0) {
  55             /* ignore transparent black */
  56             continue;
  57         }
  58         r = (rgb >> 16) & 0xff;
  59         g = (rgb >> 8 ) & 0xff;
  60         b = rgb & 0xff;
  61         if (b == r && b == g) {
  62             inverse[b] = i;
  63         }
  64     }
  65 
  66     /* fill the missing gaps by taking the valid values
  67      * on either side and filling them halfway into the gap
  68      */
  69     lastindex = -1;
  70     lastgray = -1;
  71     missing = 0;
  72     for (i = 0; i < 256; i++) {
  73         if (inverse[i] < 0) {
  74             inverse[i] = lastgray;
  75             missing = 1;
  76         } else {
  77             lastgray = inverse[i];
  78             if (missing) {
  79                 lastindex = lastindex < 0 ? 0 : (i+lastindex)/2;
  80                 while (lastindex < i) {
  81                     inverse[lastindex++] = lastgray;
  82                 }
  83             }
  84             lastindex = i;
  85             missing = 0;
  86         }
  87     }
  88 }
  89 
  90 void freeICMColorData(ColorData *pData) {
  91     if (CANFREE(pData)) {
  92         if (pData->img_clr_tbl) {
  93             free(pData->img_clr_tbl);
  94         }
  95         if (pData->pGrayInverseLutData) {
  96             free(pData->pGrayInverseLutData);
  97         }
  98         free(pData);
  99     }
 100 }
 101 
 102 /* REMIND: does not deal well with bifurcation which happens when two
 103  * palette entries map to the same cube vertex
 104  */
 105 
 106 static int
 107 recurseLevel(CubeStateInfo *priorState) {
 108     int i;
 109     CubeStateInfo currentState;
 110     memcpy(&currentState, priorState, sizeof(CubeStateInfo));
 111 
 112 
 113     currentState.rgb = (unsigned short *)malloc(6
 114                                                 * sizeof(unsigned short)
 115                                                 * priorState->activeEntries);
 116     if (currentState.rgb == NULL) {
 117         return 0;
 118     }
 119 
 120     currentState.indices = (unsigned char *)malloc(6
 121                                                 * sizeof(unsigned char)
 122                                                 * priorState->activeEntries);
 123 
 124     if (currentState.indices == NULL) {
 125         free(currentState.rgb);
 126         return 0;
 127     }
 128 
 129     currentState.depth++;
 130     if (currentState.depth > priorState->maxDepth) {
 131         priorState->maxDepth = currentState.depth;
 132     }
 133     currentState.activeEntries = 0;
 134     for (i=priorState->activeEntries - 1; i >= 0; i--) {
 135         unsigned short rgb = priorState->rgb[i];
 136         unsigned char  index = priorState->indices[i];
 137         ACTIVATE(rgb, 0x7c00, 0x0400, currentState, index);
 138         ACTIVATE(rgb, 0x03e0, 0x0020, currentState, index);
 139         ACTIVATE(rgb, 0x001f, 0x0001, currentState, index);
 140     }
 141     if (currentState.activeEntries) {
 142         if (!recurseLevel(&currentState)) {
 143             free(currentState.rgb);
 144             free(currentState.indices);
 145             return 0;
 146         }
 147     }
 148     if (currentState.maxDepth > priorState->maxDepth) {
 149         priorState->maxDepth = currentState.maxDepth;
 150     }
 151 
 152     free(currentState.rgb);
 153     free(currentState.indices);
 154     return  1;
 155 }
 156 
 157 /*
 158  * REMIND: take core inversedLUT calculation to the shared tree and
 159  * recode the functions (Win32)awt_Image:initCubemap(),
 160  * (Win32)awt_Image:make_cubemap(), (Win32)AwtToolkit::GenerateInverseLUT(),
 161  * (Solaris)color:initCubemap() to call the shared codes.
 162  */
 163 unsigned char*
 164 initCubemap(int* cmap,
 165             int  cmap_len,
 166             int  cube_dim) {
 167     int i;
 168     CubeStateInfo currentState;
 169     int cubesize = cube_dim * cube_dim * cube_dim;
 170     unsigned char *useFlags;
 171     unsigned char *newILut = (unsigned char*)malloc(cubesize);
 172     int cmap_mid = (cmap_len >> 1) + (cmap_len & 0x1);
 173     if (newILut) {
 174 
 175       useFlags = (unsigned char *)calloc(cubesize, 1);
 176 
 177       if (useFlags == 0) {
 178           free(newILut);
 179 #ifdef DEBUG
 180         fprintf(stderr, "Out of memory in color:initCubemap()1\n");
 181 #endif
 182           return NULL;
 183       }
 184 
 185         currentState.depth          = 0;
 186         currentState.maxDepth       = 0;
 187         currentState.usedFlags      = useFlags;
 188         currentState.activeEntries  = 0;
 189         currentState.iLUT           = newILut;
 190 
 191         currentState.rgb = (unsigned short *)
 192                                 malloc(cmap_len * sizeof(unsigned short));
 193         if (currentState.rgb == NULL) {
 194             free(newILut);
 195             free(useFlags);
 196 #ifdef DEBUG
 197         fprintf(stderr, "Out of memory in color:initCubemap()2\n");
 198 #endif
 199             return NULL;
 200         }
 201 
 202         currentState.indices = (unsigned char *)
 203                                 malloc(cmap_len * sizeof(unsigned char));
 204         if (currentState.indices == NULL) {
 205             free(currentState.rgb);
 206             free(newILut);
 207             free(useFlags);
 208 #ifdef DEBUG
 209         fprintf(stderr, "Out of memory in color:initCubemap()3\n");
 210 #endif
 211             return NULL;
 212         }
 213 
 214         for (i = 0; i < cmap_mid; i++) {
 215             unsigned short rgb;
 216             int pixel = cmap[i];
 217             rgb = (pixel & 0x00f80000) >> 9;
 218             rgb |= (pixel & 0x0000f800) >> 6;
 219             rgb |=  (pixel & 0xf8) >> 3;
 220             INSERTNEW(currentState, rgb, i);
 221             pixel = cmap[cmap_len - i - 1];
 222             rgb = (pixel & 0x00f80000) >> 9;
 223             rgb |= (pixel & 0x0000f800) >> 6;
 224             rgb |=  (pixel & 0xf8) >> 3;
 225             INSERTNEW(currentState, rgb, cmap_len - i - 1);
 226         }
 227 
 228         if (!recurseLevel(&currentState)) {
 229             free(newILut);
 230             free(useFlags);
 231             free(currentState.rgb);
 232             free(currentState.indices);
 233 #ifdef DEBUG
 234         fprintf(stderr, "Out of memory in color:initCubemap()4\n");
 235 #endif
 236             return NULL;
 237         }
 238 
 239         free(useFlags);
 240         free(currentState.rgb);
 241         free(currentState.indices);
 242 
 243         return newILut;
 244     }
 245 
 246 #ifdef DEBUG
 247         fprintf(stderr, "Out of memory in color:initCubemap()5\n");
 248 #endif
 249     return NULL;
 250 }
 251 
 252 void
 253 initDitherTables(ColorData* cData) {
 254 
 255 
 256     if(std_odas_computed) {
 257         cData->img_oda_red   = &(std_img_oda_red[0][0]);
 258         cData->img_oda_green = &(std_img_oda_green[0][0]);
 259         cData->img_oda_blue  = &(std_img_oda_blue[0][0]);
 260     } else {
 261         cData->img_oda_red   = &(std_img_oda_red[0][0]);
 262         cData->img_oda_green = &(std_img_oda_green[0][0]);
 263         cData->img_oda_blue  = &(std_img_oda_blue[0][0]);
 264         make_dither_arrays(256, cData);
 265         std_odas_computed = 1;
 266     }
 267 
 268 }
 269 
 270 void make_dither_arrays(int cmapsize, ColorData *cData) {
 271     int i, j, k;
 272 
 273     /*
 274      * Initialize the per-component ordered dithering arrays
 275      * Choose a size based on how far between elements in the
 276      * virtual cube.  Assume the cube has cuberoot(cmapsize)
 277      * elements per axis and those elements are distributed
 278      * over 256 colors.
 279      * The calculation should really divide by (#comp/axis - 1)
 280      * since the first and last elements are at the extremes of
 281      * the 256 levels, but in a practical sense this formula
 282      * produces a smaller error array which results in smoother
 283      * images that have slightly less color fidelity but much
 284      * less dithering noise, especially for grayscale images.
 285      */
 286     i = (int) (256 / pow(cmapsize, 1.0/3.0));
 287     make_sgn_ordered_dither_array(cData->img_oda_red, -i / 2, i / 2);
 288     make_sgn_ordered_dither_array(cData->img_oda_green, -i / 2, i / 2);
 289     make_sgn_ordered_dither_array(cData->img_oda_blue, -i / 2, i / 2);
 290 
 291     /*
 292      * Flip green horizontally and blue vertically so that
 293      * the errors don't line up in the 3 primary components.
 294      */
 295     for (i = 0; i < 8; i++) {
 296         for (j = 0; j < 4; j++) {
 297             k = cData->img_oda_green[(i<<3)+j];
 298             cData->img_oda_green[(i<<3)+j] = cData->img_oda_green[(i<<3)+7 - j];
 299             cData->img_oda_green[(i<<3) + 7 - j] = k;
 300             k = cData->img_oda_blue[(j<<3)+i];
 301             cData->img_oda_blue[(j<<3)+i] = cData->img_oda_blue[((7 - j)<<3)+i];
 302             cData->img_oda_blue[((7 - j)<<3) + i] = k;
 303         }
 304     }
 305 }