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
29JNIEXPORT sgn_ordered_dither_array std_img_oda_red;
30JNIEXPORT sgn_ordered_dither_array std_img_oda_green;
31JNIEXPORT sgn_ordered_dither_array std_img_oda_blue;
32JNIEXPORT int std_odas_computed = 0;
33
34JNIEXPORT void JNICALL
35initInverseGrayLut(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
92void 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
108static int
109recurseLevel(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 */
165unsigned char*
166initCubemap(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
254void
255initDitherTables(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
272JNIEXPORT void JNICALL
273make_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}
309