Path: blob/master/src/java.desktop/share/native/libawt/awt/image/dither.c
41159 views
/*1* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "jni.h"26#include "dither.h"2728JNIEXPORT sgn_ordered_dither_array std_img_oda_red;29JNIEXPORT sgn_ordered_dither_array std_img_oda_green;30JNIEXPORT sgn_ordered_dither_array std_img_oda_blue;31JNIEXPORT int std_odas_computed = 0;3233JNIEXPORT void JNICALL34initInverseGrayLut(int* prgb, int rgbsize, ColorData *cData) {35int *inverse;36int lastindex, lastgray, missing, i;3738if (!cData) {39return;40}4142inverse = calloc(256, sizeof(int));43if (!inverse) {44return;45}46cData->pGrayInverseLutData = inverse;4748for (i = 0; i < 256; i++) {49inverse[i] = -1;50}5152/* First, fill the gray values */53for (i = 0; i < rgbsize; i++) {54int r, g, b, rgb = prgb[i];55if (rgb == 0x0) {56/* ignore transparent black */57continue;58}59r = (rgb >> 16) & 0xff;60g = (rgb >> 8 ) & 0xff;61b = rgb & 0xff;62if (b == r && b == g) {63inverse[b] = i;64}65}6667/* fill the missing gaps by taking the valid values68* on either side and filling them halfway into the gap69*/70lastindex = -1;71lastgray = -1;72missing = 0;73for (i = 0; i < 256; i++) {74if (inverse[i] < 0) {75inverse[i] = lastgray;76missing = 1;77} else {78lastgray = inverse[i];79if (missing) {80lastindex = lastindex < 0 ? 0 : (i+lastindex)/2;81while (lastindex < i) {82inverse[lastindex++] = lastgray;83}84}85lastindex = i;86missing = 0;87}88}89}9091void freeICMColorData(ColorData *pData) {92if (CANFREE(pData)) {93if (pData->img_clr_tbl) {94free(pData->img_clr_tbl);95}96if (pData->pGrayInverseLutData) {97free(pData->pGrayInverseLutData);98}99free(pData);100}101}102103/* REMIND: does not deal well with bifurcation which happens when two104* palette entries map to the same cube vertex105*/106107static int108recurseLevel(CubeStateInfo *priorState) {109int i;110CubeStateInfo currentState;111memcpy(¤tState, priorState, sizeof(CubeStateInfo));112113114currentState.rgb = (unsigned short *)malloc(6115* sizeof(unsigned short)116* priorState->activeEntries);117if (currentState.rgb == NULL) {118return 0;119}120121currentState.indices = (unsigned char *)malloc(6122* sizeof(unsigned char)123* priorState->activeEntries);124125if (currentState.indices == NULL) {126free(currentState.rgb);127return 0;128}129130currentState.depth++;131if (currentState.depth > priorState->maxDepth) {132priorState->maxDepth = currentState.depth;133}134currentState.activeEntries = 0;135for (i=priorState->activeEntries - 1; i >= 0; i--) {136unsigned short rgb = priorState->rgb[i];137unsigned char index = priorState->indices[i];138ACTIVATE(rgb, 0x7c00, 0x0400, currentState, index);139ACTIVATE(rgb, 0x03e0, 0x0020, currentState, index);140ACTIVATE(rgb, 0x001f, 0x0001, currentState, index);141}142if (currentState.activeEntries) {143if (!recurseLevel(¤tState)) {144free(currentState.rgb);145free(currentState.indices);146return 0;147}148}149if (currentState.maxDepth > priorState->maxDepth) {150priorState->maxDepth = currentState.maxDepth;151}152153free(currentState.rgb);154free(currentState.indices);155return 1;156}157158/*159* REMIND: take core inversedLUT calculation to the shared tree and160* recode the functions (Win32)awt_Image:initCubemap(),161* (Win32)awt_Image:make_cubemap(), (Win32)AwtToolkit::GenerateInverseLUT(),162* (Solaris)color:initCubemap() to call the shared codes.163*/164unsigned char*165initCubemap(int* cmap,166int cmap_len,167int cube_dim) {168int i;169CubeStateInfo currentState;170int cubesize = cube_dim * cube_dim * cube_dim;171unsigned char *useFlags;172unsigned char *newILut = (unsigned char*)malloc(cubesize);173int cmap_mid = (cmap_len >> 1) + (cmap_len & 0x1);174if (newILut) {175176useFlags = (unsigned char *)calloc(cubesize, 1);177178if (useFlags == 0) {179free(newILut);180#ifdef DEBUG181fprintf(stderr, "Out of memory in color:initCubemap()1\n");182#endif183return NULL;184}185186currentState.depth = 0;187currentState.maxDepth = 0;188currentState.usedFlags = useFlags;189currentState.activeEntries = 0;190currentState.iLUT = newILut;191192currentState.rgb = (unsigned short *)193malloc(cmap_len * sizeof(unsigned short));194if (currentState.rgb == NULL) {195free(newILut);196free(useFlags);197#ifdef DEBUG198fprintf(stderr, "Out of memory in color:initCubemap()2\n");199#endif200return NULL;201}202203currentState.indices = (unsigned char *)204malloc(cmap_len * sizeof(unsigned char));205if (currentState.indices == NULL) {206free(currentState.rgb);207free(newILut);208free(useFlags);209#ifdef DEBUG210fprintf(stderr, "Out of memory in color:initCubemap()3\n");211#endif212return NULL;213}214215for (i = 0; i < cmap_mid; i++) {216unsigned short rgb;217int pixel = cmap[i];218rgb = (pixel & 0x00f80000) >> 9;219rgb |= (pixel & 0x0000f800) >> 6;220rgb |= (pixel & 0xf8) >> 3;221INSERTNEW(currentState, rgb, i);222pixel = cmap[cmap_len - i - 1];223rgb = (pixel & 0x00f80000) >> 9;224rgb |= (pixel & 0x0000f800) >> 6;225rgb |= (pixel & 0xf8) >> 3;226INSERTNEW(currentState, rgb, cmap_len - i - 1);227}228229if (!recurseLevel(¤tState)) {230free(newILut);231free(useFlags);232free(currentState.rgb);233free(currentState.indices);234#ifdef DEBUG235fprintf(stderr, "Out of memory in color:initCubemap()4\n");236#endif237return NULL;238}239240free(useFlags);241free(currentState.rgb);242free(currentState.indices);243244return newILut;245}246247#ifdef DEBUG248fprintf(stderr, "Out of memory in color:initCubemap()5\n");249#endif250return NULL;251}252253void254initDitherTables(ColorData* cData) {255256257if(std_odas_computed) {258cData->img_oda_red = &(std_img_oda_red[0][0]);259cData->img_oda_green = &(std_img_oda_green[0][0]);260cData->img_oda_blue = &(std_img_oda_blue[0][0]);261} else {262cData->img_oda_red = &(std_img_oda_red[0][0]);263cData->img_oda_green = &(std_img_oda_green[0][0]);264cData->img_oda_blue = &(std_img_oda_blue[0][0]);265make_dither_arrays(256, cData);266std_odas_computed = 1;267}268269}270271JNIEXPORT void JNICALL272make_dither_arrays(int cmapsize, ColorData *cData) {273int i, j, k;274275/*276* Initialize the per-component ordered dithering arrays277* Choose a size based on how far between elements in the278* virtual cube. Assume the cube has cuberoot(cmapsize)279* elements per axis and those elements are distributed280* over 256 colors.281* The calculation should really divide by (#comp/axis - 1)282* since the first and last elements are at the extremes of283* the 256 levels, but in a practical sense this formula284* produces a smaller error array which results in smoother285* images that have slightly less color fidelity but much286* less dithering noise, especially for grayscale images.287*/288i = (int) (256 / pow(cmapsize, 1.0/3.0));289make_sgn_ordered_dither_array(cData->img_oda_red, -i / 2, i / 2);290make_sgn_ordered_dither_array(cData->img_oda_green, -i / 2, i / 2);291make_sgn_ordered_dither_array(cData->img_oda_blue, -i / 2, i / 2);292293/*294* Flip green horizontally and blue vertically so that295* the errors don't line up in the 3 primary components.296*/297for (i = 0; i < 8; i++) {298for (j = 0; j < 4; j++) {299k = cData->img_oda_green[(i<<3)+j];300cData->img_oda_green[(i<<3)+j] = cData->img_oda_green[(i<<3)+7 - j];301cData->img_oda_green[(i<<3) + 7 - j] = k;302k = cData->img_oda_blue[(j<<3)+i];303cData->img_oda_blue[(j<<3)+i] = cData->img_oda_blue[((7 - j)<<3)+i];304cData->img_oda_blue[((7 - j)<<3) + i] = k;305}306}307}308309310