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(¤tState, 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(¤tState)) { |
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(¤tState)) { |
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 | } |
309 | |