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