0N/A/*
2362N/A * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include "dither.h"
0N/A
0N/Asgn_ordered_dither_array std_img_oda_red;
0N/Asgn_ordered_dither_array std_img_oda_green;
0N/Asgn_ordered_dither_array std_img_oda_blue;
0N/Aint std_odas_computed = 0;
0N/A
0N/Avoid initInverseGrayLut(int* prgb, int rgbsize, ColorData *cData) {
0N/A int *inverse;
0N/A int lastindex, lastgray, missing, i;
0N/A
0N/A if (!cData) {
0N/A return;
0N/A }
0N/A
0N/A inverse = calloc(256, sizeof(int));
0N/A if (!inverse) {
0N/A return;
0N/A }
0N/A cData->pGrayInverseLutData = inverse;
0N/A
0N/A for (i = 0; i < 256; i++) {
0N/A inverse[i] = -1;
0N/A }
0N/A
0N/A /* First, fill the gray values */
0N/A for (i = 0; i < rgbsize; i++) {
0N/A int r, g, b, rgb = prgb[i];
0N/A if (rgb == 0x0) {
0N/A /* ignore transparent black */
0N/A continue;
0N/A }
0N/A r = (rgb >> 16) & 0xff;
0N/A g = (rgb >> 8 ) & 0xff;
0N/A b = rgb & 0xff;
0N/A if (b == r && b == g) {
0N/A inverse[b] = i;
0N/A }
0N/A }
0N/A
0N/A /* fill the missing gaps by taking the valid values
0N/A * on either side and filling them halfway into the gap
0N/A */
0N/A lastindex = -1;
0N/A lastgray = -1;
0N/A missing = 0;
0N/A for (i = 0; i < 256; i++) {
0N/A if (inverse[i] < 0) {
0N/A inverse[i] = lastgray;
0N/A missing = 1;
0N/A } else {
0N/A lastgray = inverse[i];
0N/A if (missing) {
0N/A lastindex = lastindex < 0 ? 0 : (i+lastindex)/2;
0N/A while (lastindex < i) {
0N/A inverse[lastindex++] = lastgray;
0N/A }
0N/A }
0N/A lastindex = i;
0N/A missing = 0;
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid freeICMColorData(ColorData *pData) {
0N/A if (CANFREE(pData)) {
0N/A if (pData->img_clr_tbl) {
0N/A free(pData->img_clr_tbl);
0N/A }
0N/A if (pData->pGrayInverseLutData) {
0N/A free(pData->pGrayInverseLutData);
0N/A }
0N/A free(pData);
0N/A }
0N/A}
0N/A
0N/A/* REMIND: does not deal well with bifurcation which happens when two
0N/A * palette entries map to the same cube vertex
0N/A */
0N/A
0N/Astatic int
0N/ArecurseLevel(CubeStateInfo *priorState) {
0N/A int i;
0N/A CubeStateInfo currentState;
0N/A memcpy(&currentState, priorState, sizeof(CubeStateInfo));
0N/A
0N/A
0N/A currentState.rgb = (unsigned short *)malloc(6
0N/A * sizeof(unsigned short)
0N/A * priorState->activeEntries);
0N/A if (currentState.rgb == NULL) {
0N/A return 0;
0N/A }
0N/A
0N/A currentState.indices = (unsigned char *)malloc(6
0N/A * sizeof(unsigned char)
0N/A * priorState->activeEntries);
0N/A
0N/A if (currentState.indices == NULL) {
0N/A free(currentState.rgb);
0N/A return 0;
0N/A }
0N/A
0N/A currentState.depth++;
0N/A if (currentState.depth > priorState->maxDepth) {
0N/A priorState->maxDepth = currentState.depth;
0N/A }
0N/A currentState.activeEntries = 0;
0N/A for (i=priorState->activeEntries - 1; i >= 0; i--) {
0N/A unsigned short rgb = priorState->rgb[i];
0N/A unsigned char index = priorState->indices[i];
0N/A ACTIVATE(rgb, 0x7c00, 0x0400, currentState, index);
0N/A ACTIVATE(rgb, 0x03e0, 0x0020, currentState, index);
0N/A ACTIVATE(rgb, 0x001f, 0x0001, currentState, index);
0N/A }
0N/A if (currentState.activeEntries) {
0N/A if (!recurseLevel(&currentState)) {
0N/A free(currentState.rgb);
0N/A free(currentState.indices);
0N/A return 0;
0N/A }
0N/A }
0N/A if (currentState.maxDepth > priorState->maxDepth) {
0N/A priorState->maxDepth = currentState.maxDepth;
0N/A }
0N/A
0N/A free(currentState.rgb);
0N/A free(currentState.indices);
0N/A return 1;
0N/A}
0N/A
0N/A/*
0N/A * REMIND: take core inversedLUT calculation to the shared tree and
0N/A * recode the functions (Win32)awt_Image:initCubemap(),
0N/A * (Win32)awt_Image:make_cubemap(), (Win32)AwtToolkit::GenerateInverseLUT(),
0N/A * (Solaris)color:initCubemap() to call the shared codes.
0N/A */
0N/Aunsigned char*
0N/AinitCubemap(int* cmap,
0N/A int cmap_len,
0N/A int cube_dim) {
0N/A int i;
0N/A CubeStateInfo currentState;
0N/A int cubesize = cube_dim * cube_dim * cube_dim;
0N/A unsigned char *useFlags;
0N/A unsigned char *newILut = (unsigned char*)malloc(cubesize);
993N/A int cmap_mid = (cmap_len >> 1) + (cmap_len & 0x1);
0N/A if (newILut) {
0N/A
0N/A useFlags = (unsigned char *)calloc(cubesize, 1);
0N/A
0N/A if (useFlags == 0) {
0N/A free(newILut);
0N/A#ifdef DEBUG
0N/A fprintf(stderr, "Out of memory in color:initCubemap()1\n");
0N/A#endif
0N/A return NULL;
0N/A }
0N/A
0N/A currentState.depth = 0;
0N/A currentState.maxDepth = 0;
0N/A currentState.usedFlags = useFlags;
0N/A currentState.activeEntries = 0;
0N/A currentState.iLUT = newILut;
0N/A
0N/A currentState.rgb = (unsigned short *)
993N/A malloc(cmap_len * sizeof(unsigned short));
0N/A if (currentState.rgb == NULL) {
0N/A free(newILut);
0N/A free(useFlags);
0N/A#ifdef DEBUG
0N/A fprintf(stderr, "Out of memory in color:initCubemap()2\n");
0N/A#endif
0N/A return NULL;
0N/A }
0N/A
0N/A currentState.indices = (unsigned char *)
993N/A malloc(cmap_len * sizeof(unsigned char));
0N/A if (currentState.indices == NULL) {
0N/A free(currentState.rgb);
0N/A free(newILut);
0N/A free(useFlags);
0N/A#ifdef DEBUG
0N/A fprintf(stderr, "Out of memory in color:initCubemap()3\n");
0N/A#endif
0N/A return NULL;
0N/A }
0N/A
993N/A for (i = 0; i < cmap_mid; i++) {
0N/A unsigned short rgb;
0N/A int pixel = cmap[i];
0N/A rgb = (pixel & 0x00f80000) >> 9;
0N/A rgb |= (pixel & 0x0000f800) >> 6;
0N/A rgb |= (pixel & 0xf8) >> 3;
0N/A INSERTNEW(currentState, rgb, i);
993N/A pixel = cmap[cmap_len - i - 1];
0N/A rgb = (pixel & 0x00f80000) >> 9;
0N/A rgb |= (pixel & 0x0000f800) >> 6;
0N/A rgb |= (pixel & 0xf8) >> 3;
993N/A INSERTNEW(currentState, rgb, cmap_len - i - 1);
0N/A }
0N/A
0N/A if (!recurseLevel(&currentState)) {
0N/A free(newILut);
0N/A free(useFlags);
0N/A free(currentState.rgb);
0N/A free(currentState.indices);
0N/A#ifdef DEBUG
0N/A fprintf(stderr, "Out of memory in color:initCubemap()4\n");
0N/A#endif
0N/A return NULL;
0N/A }
0N/A
0N/A free(useFlags);
0N/A free(currentState.rgb);
0N/A free(currentState.indices);
0N/A
0N/A return newILut;
0N/A }
0N/A
0N/A#ifdef DEBUG
0N/A fprintf(stderr, "Out of memory in color:initCubemap()5\n");
0N/A#endif
0N/A return NULL;
0N/A}
0N/A
0N/Avoid
0N/AinitDitherTables(ColorData* cData) {
0N/A
0N/A
0N/A if(std_odas_computed) {
0N/A cData->img_oda_red = &(std_img_oda_red[0][0]);
0N/A cData->img_oda_green = &(std_img_oda_green[0][0]);
0N/A cData->img_oda_blue = &(std_img_oda_blue[0][0]);
0N/A } else {
0N/A cData->img_oda_red = &(std_img_oda_red[0][0]);
0N/A cData->img_oda_green = &(std_img_oda_green[0][0]);
0N/A cData->img_oda_blue = &(std_img_oda_blue[0][0]);
0N/A make_dither_arrays(256, cData);
0N/A std_odas_computed = 1;
0N/A }
0N/A
0N/A}
0N/A
0N/Avoid make_dither_arrays(int cmapsize, ColorData *cData) {
0N/A int i, j, k;
0N/A
0N/A /*
0N/A * Initialize the per-component ordered dithering arrays
0N/A * Choose a size based on how far between elements in the
0N/A * virtual cube. Assume the cube has cuberoot(cmapsize)
0N/A * elements per axis and those elements are distributed
0N/A * over 256 colors.
0N/A * The calculation should really divide by (#comp/axis - 1)
0N/A * since the first and last elements are at the extremes of
0N/A * the 256 levels, but in a practical sense this formula
0N/A * produces a smaller error array which results in smoother
0N/A * images that have slightly less color fidelity but much
0N/A * less dithering noise, especially for grayscale images.
0N/A */
0N/A i = (int) (256 / pow(cmapsize, 1.0/3.0));
0N/A make_sgn_ordered_dither_array(cData->img_oda_red, -i / 2, i / 2);
0N/A make_sgn_ordered_dither_array(cData->img_oda_green, -i / 2, i / 2);
0N/A make_sgn_ordered_dither_array(cData->img_oda_blue, -i / 2, i / 2);
0N/A
0N/A /*
0N/A * Flip green horizontally and blue vertically so that
0N/A * the errors don't line up in the 3 primary components.
0N/A */
0N/A for (i = 0; i < 8; i++) {
0N/A for (j = 0; j < 4; j++) {
0N/A k = cData->img_oda_green[(i<<3)+j];
0N/A cData->img_oda_green[(i<<3)+j] = cData->img_oda_green[(i<<3)+7 - j];
0N/A cData->img_oda_green[(i<<3) + 7 - j] = k;
0N/A k = cData->img_oda_blue[(j<<3)+i];
0N/A cData->img_oda_blue[(j<<3)+i] = cData->img_oda_blue[((7 - j)<<3)+i];
0N/A cData->img_oda_blue[((7 - j)<<3) + i] = k;
0N/A }
0N/A }
0N/A}