1/*
2 * Copyright (c) 1997, 2014, 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 <stdio.h>
27#include <stdlib.h>
28#include "awt_parseImage.h"
29#include "imageInitIDs.h"
30#include "java_awt_Transparency.h"
31#include "java_awt_image_BufferedImage.h"
32#include "sun_awt_image_IntegerComponentRaster.h"
33#include "sun_awt_image_ImagingLib.h"
34#include "java_awt_color_ColorSpace.h"
35#include "awt_Mlib.h"
36#include "safe_alloc.h"
37#include "safe_math.h"
38
39static int setHints(JNIEnv *env, BufImageS_t *imageP);
40
41
42
43/* Parse the buffered image. All of the raster information is returned in the
44 * imagePP structure.
45 *
46 * The handleCustom parameter specifies whether or not the caller
47 * can use custom channels. If it is false and a custom channel
48 * is encountered, the returned value will be 0 and all structures
49 * will be deallocated.
50 *
51 * Return value:
52 * -1: Exception
53 * 0: Can't do it.
54 * 1: Success
55 */
56int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP,
57 int handleCustom) {
58 BufImageS_t *imageP;
59 int status;
60 jobject jraster;
61 jobject jcmodel;
62
63 /* Make sure the image exists */
64 if (JNU_IsNull(env, jimage)) {
65 JNU_ThrowNullPointerException(env, "null BufferedImage object");
66 return -1;
67 }
68
69 if ((imageP = (BufImageS_t *) calloc(1, sizeof(BufImageS_t))) == NULL) {
70 JNU_ThrowOutOfMemoryError(env, "Out of memory");
71 return -1;
72 }
73 imageP->jimage = jimage;
74
75 /* Retrieve the raster */
76 if ((jraster = (*env)->GetObjectField(env, jimage,
77 g_BImgRasterID)) == NULL) {
78 free((void *) imageP);
79 JNU_ThrowNullPointerException(env, "null Raster object");
80 return 0;
81 }
82
83 /* Retrieve the image type */
84 imageP->imageType = (*env)->GetIntField(env, jimage, g_BImgTypeID);
85
86 /* Parse the raster */
87 if ((status = awt_parseRaster(env, jraster, &imageP->raster)) <= 0) {
88 free((void *)imageP);
89 return status;
90 }
91
92 /* Retrieve the color model */
93 if ((jcmodel = (*env)->GetObjectField(env, jimage, g_BImgCMID)) == NULL) {
94 free((void *) imageP);
95 JNU_ThrowNullPointerException(env, "null Raster object");
96 return 0;
97 }
98
99 /* Parse the color model */
100 if ((status = awt_parseColorModel(env, jcmodel, imageP->imageType,
101 &imageP->cmodel)) <= 0) {
102 awt_freeParsedRaster(&imageP->raster, FALSE);
103 free((void *)imageP);
104 return 0;
105 }
106
107 /* Set hints */
108 if ((status = setHints(env, imageP)) <= 0) {
109 awt_freeParsedImage(imageP, TRUE);
110 return 0;
111 }
112
113 *imagePP = imageP;
114
115 return status;
116}
117
118/* Verifies whether the channel offsets are sane and correspond to the type of
119 * the raster.
120 *
121 * Return value:
122 * 0: Failure: channel offsets are invalid
123 * 1: Success
124 */
125static int checkChannelOffsets(RasterS_t *rasterP, int dataArrayLength) {
126 int i, lastPixelOffset, lastScanOffset;
127 switch (rasterP->rasterType) {
128 case COMPONENT_RASTER_TYPE:
129 if (!SAFE_TO_MULT(rasterP->height, rasterP->scanlineStride)) {
130 return 0;
131 }
132 if (!SAFE_TO_MULT(rasterP->width, rasterP->pixelStride)) {
133 return 0;
134 }
135
136 lastScanOffset = (rasterP->height - 1) * rasterP->scanlineStride;
137 lastPixelOffset = (rasterP->width - 1) * rasterP->pixelStride;
138
139
140 if (!SAFE_TO_ADD(lastPixelOffset, lastScanOffset)) {
141 return 0;
142 }
143
144 lastPixelOffset += lastScanOffset;
145
146 for (i = 0; i < rasterP->numDataElements; i++) {
147 int off = rasterP->chanOffsets[i];
148 int size = lastPixelOffset + off;
149
150 if (off < 0 || !SAFE_TO_ADD(lastPixelOffset, off)) {
151 return 0;
152 }
153
154 if (size < lastPixelOffset || size >= dataArrayLength) {
155 // an overflow, or insufficient buffer capacity
156 return 0;
157 }
158 }
159 return 1;
160 case BANDED_RASTER_TYPE:
161 // NB:caller does not support the banded rasters yet,
162 // so this branch of the code must be re-defined in
163 // order to provide valid criteria for the data offsets
164 // verification, when/if banded rasters will be supported.
165 // At the moment, we prohibit banded rasters as well.
166 return 0;
167 default:
168 // PACKED_RASTER_TYPE: does not support channel offsets
169 // UNKNOWN_RASTER_TYPE: should not be used, likely indicates an error
170 return 0;
171 }
172}
173
174/* Parse the raster. All of the raster information is returned in the
175 * rasterP structure.
176 *
177 * Return value:
178 * -1: Exception
179 * 0: Can't do it (Custom channel)
180 * 1: Success
181 */
182int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) {
183 jobject joffs = NULL;
184 /* int status;*/
185 jclass singlePixelPackedSampleModelClass = NULL;
186 jclass integerComponentRasterClass = NULL;
187 jclass byteComponentRasterClass = NULL;
188 jclass shortComponentRasterClass = NULL;
189 jclass bytePackedRasterClass = NULL;
190
191 if (JNU_IsNull(env, jraster)) {
192 JNU_ThrowNullPointerException(env, "null Raster object");
193 return -1;
194 }
195
196 rasterP->jraster = jraster;
197 rasterP->width = (*env)->GetIntField(env, jraster, g_RasterWidthID);
198 rasterP->height = (*env)->GetIntField(env, jraster, g_RasterHeightID);
199 rasterP->numDataElements = (*env)->GetIntField(env, jraster,
200 g_RasterNumDataElementsID);
201 rasterP->numBands = (*env)->GetIntField(env, jraster,
202 g_RasterNumBandsID);
203
204 rasterP->baseOriginX = (*env)->GetIntField(env, jraster,
205 g_RasterBaseOriginXID);
206 rasterP->baseOriginY = (*env)->GetIntField(env, jraster,
207 g_RasterBaseOriginYID);
208 rasterP->minX = (*env)->GetIntField(env, jraster, g_RasterMinXID);
209 rasterP->minY = (*env)->GetIntField(env, jraster, g_RasterMinYID);
210
211 rasterP->jsampleModel = (*env)->GetObjectField(env, jraster,
212 g_RasterSampleModelID);
213
214 if (JNU_IsNull(env, rasterP->jsampleModel)) {
215 JNU_ThrowNullPointerException(env, "null Raster object");
216 return -1;
217 }
218
219 // make sure that the raster type is initialized
220 rasterP->rasterType = UNKNOWN_RASTER_TYPE;
221
222 if (rasterP->numBands <= 0 ||
223 rasterP->numBands > MAX_NUMBANDS)
224 {
225 /*
226 * we can't handle such kind of rasters due to limitations
227 * of SPPSampleModelS_t structure and expand/set methods.
228 */
229 return 0;
230 }
231
232 rasterP->sppsm.isUsed = 0;
233
234 singlePixelPackedSampleModelClass = (*env)->FindClass(env,
235 "java/awt/image/SinglePixelPackedSampleModel");
236 CHECK_NULL_RETURN(singlePixelPackedSampleModelClass, -1);
237 if ((*env)->IsInstanceOf(env, rasterP->jsampleModel,
238 singlePixelPackedSampleModelClass)) {
239 jobject jmask, joffs, jnbits;
240
241 rasterP->sppsm.isUsed = 1;
242
243 rasterP->sppsm.maxBitSize = (*env)->GetIntField(env,
244 rasterP->jsampleModel,
245 g_SPPSMmaxBitID);
246 jmask = (*env)->GetObjectField(env, rasterP->jsampleModel,
247 g_SPPSMmaskArrID);
248 joffs = (*env)->GetObjectField(env, rasterP->jsampleModel,
249 g_SPPSMmaskOffID);
250 jnbits = (*env)->GetObjectField(env, rasterP->jsampleModel,
251 g_SPPSMnBitsID);
252 if (jmask == NULL || joffs == NULL || jnbits == NULL ||
253 rasterP->sppsm.maxBitSize < 0)
254 {
255 JNU_ThrowInternalError(env, "Can't grab SPPSM fields");
256 return -1;
257 }
258 (*env)->GetIntArrayRegion(env, jmask, 0,
259 rasterP->numBands, rasterP->sppsm.maskArray);
260 (*env)->GetIntArrayRegion(env, joffs, 0,
261 rasterP->numBands, rasterP->sppsm.offsets);
262 (*env)->GetIntArrayRegion(env, jnbits, 0,
263 rasterP->numBands, rasterP->sppsm.nBits);
264
265 }
266 rasterP->baseRasterWidth = (*env)->GetIntField(env, rasterP->jsampleModel,
267 g_SMWidthID);
268 rasterP->baseRasterHeight = (*env)->GetIntField(env,
269 rasterP->jsampleModel,
270 g_SMHeightID);
271
272 integerComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/IntegerComponentRaster");
273 CHECK_NULL_RETURN(integerComponentRasterClass, -1);
274 byteComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/ByteComponentRaster");
275 CHECK_NULL_RETURN(byteComponentRasterClass, -1);
276 shortComponentRasterClass = (*env)->FindClass(env,"sun/awt/image/ShortComponentRaster");
277 CHECK_NULL_RETURN(shortComponentRasterClass, -1);
278 bytePackedRasterClass = (*env)->FindClass(env, "sun/awt/image/BytePackedRaster");
279 CHECK_NULL_RETURN(bytePackedRasterClass, -1);
280 if ((*env)->IsInstanceOf(env, jraster, integerComponentRasterClass)){
281 rasterP->jdata = (*env)->GetObjectField(env, jraster, g_ICRdataID);
282 rasterP->dataType = INT_DATA_TYPE;
283 rasterP->dataSize = 4;
284 rasterP->dataIsShared = TRUE;
285 rasterP->rasterType = COMPONENT_RASTER_TYPE;
286 rasterP->type = (*env)->GetIntField(env, jraster, g_ICRtypeID);
287 rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_ICRscanstrID);
288 rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_ICRpixstrID);
289 joffs = (*env)->GetObjectField(env, jraster, g_ICRdataOffsetsID);
290 }
291 else if ((*env)->IsInstanceOf(env, jraster, byteComponentRasterClass)){
292 rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BCRdataID);
293 rasterP->dataType = BYTE_DATA_TYPE;
294 rasterP->dataSize = 1;
295 rasterP->dataIsShared = TRUE;
296 rasterP->rasterType = COMPONENT_RASTER_TYPE;
297 rasterP->type = (*env)->GetIntField(env, jraster, g_BCRtypeID);
298 rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BCRscanstrID);
299 rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BCRpixstrID);
300 joffs = (*env)->GetObjectField(env, jraster, g_BCRdataOffsetsID);
301 }
302 else if ((*env)->IsInstanceOf(env, jraster, shortComponentRasterClass)){
303 rasterP->jdata = (*env)->GetObjectField(env, jraster, g_SCRdataID);
304 rasterP->dataType = SHORT_DATA_TYPE;
305 rasterP->dataSize = 2;
306 rasterP->dataIsShared = TRUE;
307 rasterP->rasterType = COMPONENT_RASTER_TYPE;
308 rasterP->type = (*env)->GetIntField(env, jraster, g_SCRtypeID);
309 rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_SCRscanstrID);
310 rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_SCRpixstrID);
311 joffs = (*env)->GetObjectField(env, jraster, g_SCRdataOffsetsID);
312 }
313 else if ((*env)->IsInstanceOf(env, jraster, bytePackedRasterClass)){
314 rasterP->rasterType = PACKED_RASTER_TYPE;
315 rasterP->dataType = BYTE_DATA_TYPE;
316 rasterP->dataSize = 1;
317 rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BPRscanstrID);
318 rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BPRpixstrID);
319 rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BPRdataID);
320 rasterP->type = (*env)->GetIntField(env, jraster, g_BPRtypeID);
321 rasterP->chanOffsets = NULL;
322 if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) {
323 rasterP->chanOffsets =
324 (jint *)malloc(rasterP->numDataElements * sizeof(jint));
325 }
326 if (rasterP->chanOffsets == NULL) {
327 /* Out of memory */
328 JNU_ThrowOutOfMemoryError(env, "Out of memory");
329 return -1;
330 }
331 rasterP->chanOffsets[0] = (*env)->GetIntField(env, jraster, g_BPRdataBitOffsetID);
332 rasterP->dataType = BYTE_DATA_TYPE;
333 }
334 else {
335 rasterP->type = sun_awt_image_IntegerComponentRaster_TYPE_CUSTOM;
336 rasterP->dataType = UNKNOWN_DATA_TYPE;
337 rasterP->rasterType = UNKNOWN_RASTER_TYPE;
338 rasterP->chanOffsets = NULL;
339 /* Custom raster */
340 return 0;
341 }
342
343 // do basic validation of the raster structure
344 if (rasterP->width <= 0 || rasterP->height <= 0 ||
345 rasterP->pixelStride <= 0 || rasterP->scanlineStride <= 0)
346 {
347 // invalid raster
348 return -1;
349 }
350
351 // channel (data) offsets
352 switch (rasterP->rasterType) {
353 case COMPONENT_RASTER_TYPE:
354 case BANDED_RASTER_TYPE: // note that this routine does not support banded rasters at the moment
355 // get channel (data) offsets
356 rasterP->chanOffsets = NULL;
357 if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) {
358 rasterP->chanOffsets =
359 (jint *)malloc(rasterP->numDataElements * sizeof(jint));
360 }
361 if (rasterP->chanOffsets == NULL) {
362 /* Out of memory */
363 JNU_ThrowOutOfMemoryError(env, "Out of memory");
364 return -1;
365 }
366 (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numDataElements,
367 rasterP->chanOffsets);
368 if (rasterP->jdata == NULL) {
369 // unable to verify the raster
370 return -1;
371 }
372 // verify whether channel offsets look sane
373 if (!checkChannelOffsets(rasterP, (*env)->GetArrayLength(env, rasterP->jdata))) {
374 return -1;
375 }
376 break;
377 default:
378 ; // PACKED_RASTER_TYPE does not use the channel offsets.
379 }
380
381 /* additional check for sppsm fields validity: make sure that
382 * size of raster samples doesn't exceed the data type capacity.
383 */
384 if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */
385 rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */
386 rasterP->sppsm.maxBitSize > (rasterP->dataSize * 8))
387 {
388 JNU_ThrowInternalError(env, "Raster samples are too big");
389 return -1;
390 }
391
392#if 0
393 fprintf(stderr,"---------------------\n");
394 fprintf(stderr,"Width : %d\n",rasterP->width);
395 fprintf(stderr,"Height : %d\n",rasterP->height);
396 fprintf(stderr,"X : %d\n",rasterP->x);
397 fprintf(stderr,"Y : %d\n",rasterP->y);
398 fprintf(stderr,"numC : %d\n",rasterP->numDataElements);
399 fprintf(stderr,"SS : %d\n",rasterP->scanlineStride);
400 fprintf(stderr,"PS : %d\n",rasterP->pixelStride);
401 fprintf(stderr,"CO : %d\n",rasterP->chanOffsets);
402 fprintf(stderr,"shared?: %d\n",rasterP->dataIsShared);
403 fprintf(stderr,"RasterT: %d\n",rasterP->rasterType);
404 fprintf(stderr,"DataT : %d\n",rasterP->dataType);
405 fprintf(stderr,"---------------------\n");
406#endif
407
408 return 1;
409}
410
411static int getColorModelType(JNIEnv *env, jobject jcmodel) {
412 jclass colorModelClass;
413
414 colorModelClass = (*env)->FindClass(env,
415 "java/awt/image/IndexColorModel");
416 CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
417
418 if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
419 {
420 return INDEX_CM_TYPE;
421 }
422
423 colorModelClass = (*env)->FindClass(env,
424 "java/awt/image/PackedColorModel");
425 CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
426 if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
427 {
428 colorModelClass = (*env)->FindClass(env,
429 "java/awt/image/DirectColorModel");
430 CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
431 if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) {
432 return DIRECT_CM_TYPE;
433 }
434 else {
435 return PACKED_CM_TYPE;
436 }
437 }
438 colorModelClass = (*env)->FindClass(env,
439 "java/awt/image/ComponentColorModel");
440 CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE);
441 if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass))
442 {
443 return COMPONENT_CM_TYPE;
444 }
445
446 return UNKNOWN_CM_TYPE;
447}
448
449int awt_parseColorModel (JNIEnv *env, jobject jcmodel, int imageType,
450 ColorModelS_t *cmP) {
451 /*jmethodID jID; */
452 jobject jnBits;
453 jsize nBitsLength;
454
455 int i;
456 static jobject s_jdefCM = NULL;
457
458 if (JNU_IsNull(env, jcmodel)) {
459 JNU_ThrowNullPointerException(env, "null ColorModel object");
460 return -1;
461 }
462
463 cmP->jcmodel = jcmodel;
464
465 cmP->jcspace = (*env)->GetObjectField(env, jcmodel, g_CMcspaceID);
466
467 cmP->numComponents = (*env)->GetIntField(env, jcmodel,
468 g_CMnumComponentsID);
469 cmP->supportsAlpha = (*env)->GetBooleanField(env, jcmodel,
470 g_CMsuppAlphaID);
471 cmP->isAlphaPre = (*env)->GetBooleanField(env,jcmodel,
472 g_CMisAlphaPreID);
473 cmP->transparency = (*env)->GetIntField(env, jcmodel,
474 g_CMtransparencyID);
475
476 jnBits = (*env)->GetObjectField(env, jcmodel, g_CMnBitsID);
477 if (jnBits == NULL) {
478 JNU_ThrowNullPointerException(env, "null nBits structure in CModel");
479 return -1;
480 }
481
482 nBitsLength = (*env)->GetArrayLength(env, jnBits);
483 if (nBitsLength != cmP->numComponents) {
484 // invalid number of components?
485 return -1;
486 }
487
488 cmP->nBits = NULL;
489 if (SAFE_TO_ALLOC_2(cmP->numComponents, sizeof(jint))) {
490 cmP->nBits = (jint *)malloc(cmP->numComponents * sizeof(jint));
491 }
492
493 if (cmP->nBits == NULL){
494 JNU_ThrowOutOfMemoryError(env, "Out of memory");
495 return -1;
496 }
497 (*env)->GetIntArrayRegion(env, jnBits, 0, cmP->numComponents,
498 cmP->nBits);
499 cmP->maxNbits = 0;
500 for (i=0; i < cmP->numComponents; i++) {
501 if (cmP->maxNbits < cmP->nBits[i]) {
502 cmP->maxNbits = cmP->nBits[i];
503 }
504 }
505
506 cmP->is_sRGB = (*env)->GetBooleanField(env, cmP->jcmodel, g_CMis_sRGBID);
507
508 cmP->csType = (*env)->GetIntField(env, cmP->jcmodel, g_CMcsTypeID);
509
510 cmP->cmType = getColorModelType(env, jcmodel);
511 JNU_CHECK_EXCEPTION_RETURN(env, -1);
512
513 cmP->isDefaultCM = FALSE;
514 cmP->isDefaultCompatCM = FALSE;
515
516 /* look for standard cases */
517 if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB) {
518 cmP->isDefaultCM = TRUE;
519 cmP->isDefaultCompatCM = TRUE;
520 } else if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
521 imageType == java_awt_image_BufferedImage_TYPE_INT_RGB ||
522 imageType == java_awt_image_BufferedImage_TYPE_INT_BGR ||
523 imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR ||
524 imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE)
525 {
526 cmP->isDefaultCompatCM = TRUE;
527 }
528 else {
529 /* Figure out if this is the default CM */
530 if (s_jdefCM == NULL) {
531 jobject defCM;
532 jclass jcm = (*env)->FindClass(env, "java/awt/image/ColorModel");
533 CHECK_NULL_RETURN(jcm, -1);
534 defCM = (*env)->CallStaticObjectMethod(env, jcm,
535 g_CMgetRGBdefaultMID, NULL);
536 s_jdefCM = (*env)->NewGlobalRef(env, defCM);
537 if (defCM == NULL || s_jdefCM == NULL) {
538 (*env)->ExceptionClear(env);
539 JNU_ThrowNullPointerException(env, "Unable to find default CM");
540 return -1;
541 }
542 }
543 cmP->isDefaultCM = ((*env)->IsSameObject(env, s_jdefCM, jcmodel));
544 cmP->isDefaultCompatCM = cmP->isDefaultCM;
545 }
546
547 /* check whether image attributes correspond to default cm */
548 if (cmP->isDefaultCompatCM) {
549 if (cmP->csType != java_awt_color_ColorSpace_TYPE_RGB ||
550 !cmP->is_sRGB)
551 {
552 return -1;
553 }
554
555 for (i = 0; i < cmP->numComponents; i++) {
556 if (cmP->nBits[i] != 8) {
557 return -1;
558 }
559 }
560 }
561
562 /* Get index color model attributes */
563 if (imageType == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED ||
564 cmP->cmType == INDEX_CM_TYPE)
565 {
566 cmP->transIdx = (*env)->GetIntField(env, jcmodel, g_ICMtransIdxID);
567 cmP->mapSize = (*env)->GetIntField(env, jcmodel, g_ICMmapSizeID);
568 cmP->jrgb = (*env)->GetObjectField(env, jcmodel, g_ICMrgbID);
569 if (cmP->transIdx == -1) {
570 /* Need to find the transparent index */
571 int *rgb = (int *) (*env)->GetPrimitiveArrayCritical(env,
572 cmP->jrgb,
573 NULL);
574 if (rgb == NULL) {
575 return -1;
576 }
577 for (i=0; i < cmP->mapSize; i++) {
578 if ((rgb[i]&0xff000000) == 0) {
579 cmP->transIdx = i;
580 break;
581 }
582 }
583 (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb,
584 JNI_ABORT);
585 if (cmP->transIdx == -1) {
586 /* Now what? No transparent pixel... */
587 cmP->transIdx = 0;
588 }
589 }
590 }
591
592 return 1;
593}
594
595void awt_freeParsedRaster(RasterS_t *rasterP, int freeRasterP) {
596 if (rasterP->chanOffsets) {
597 free((void *) rasterP->chanOffsets);
598 }
599
600 if (freeRasterP) {
601 free((void *) rasterP);
602 }
603}
604
605void awt_freeParsedImage(BufImageS_t *imageP, int freeImageP) {
606 if (imageP->hints.colorOrder) {
607 free ((void *) imageP->hints.colorOrder);
608 }
609
610 if (imageP->cmodel.nBits) {
611 free ((void *) imageP->cmodel.nBits);
612 }
613
614 /* Free the raster */
615 awt_freeParsedRaster(&imageP->raster, FALSE);
616
617 if (freeImageP) {
618 free((void *) imageP);
619 }
620}
621
622static void
623awt_getBIColorOrder(int type, int *colorOrder) {
624 switch(type) {
625 case java_awt_image_BufferedImage_TYPE_INT_ARGB:
626 case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
627#ifdef _LITTLE_ENDIAN
628 colorOrder[0] = 2;
629 colorOrder[1] = 1;
630 colorOrder[2] = 0;
631 colorOrder[3] = 3;
632#else
633 colorOrder[0] = 1;
634 colorOrder[1] = 2;
635 colorOrder[2] = 3;
636 colorOrder[3] = 0;
637#endif
638 break;
639 case java_awt_image_BufferedImage_TYPE_INT_BGR:
640#ifdef _LITTLE_ENDIAN
641 colorOrder[0] = 0;
642 colorOrder[1] = 1;
643 colorOrder[2] = 2;
644#else
645 colorOrder[0] = 3;
646 colorOrder[1] = 2;
647 colorOrder[2] = 1;
648#endif
649 break;
650 case java_awt_image_BufferedImage_TYPE_INT_RGB:
651#ifdef _LITTLE_ENDIAN
652 colorOrder[0] = 2;
653 colorOrder[1] = 1;
654 colorOrder[2] = 0;
655#else
656 colorOrder[0] = 1;
657 colorOrder[1] = 2;
658 colorOrder[2] = 3;
659#endif
660 break;
661 case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
662 case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
663 colorOrder[0] = 3;
664 colorOrder[1] = 2;
665 colorOrder[2] = 1;
666 colorOrder[3] = 0;
667 break;
668 case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
669 colorOrder[0] = 2;
670 colorOrder[1] = 1;
671 colorOrder[2] = 0;
672 break;
673 case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
674 case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB:
675 colorOrder[0] = 0;
676 colorOrder[1] = 1;
677 colorOrder[2] = 2;
678 break;
679 case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
680 case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
681 case java_awt_image_BufferedImage_TYPE_BYTE_BINARY:
682 case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
683 colorOrder[0] = 0;
684 break;
685 }
686}
687
688static int
689setHints(JNIEnv *env, BufImageS_t *imageP) {
690 HintS_t *hintP = &imageP->hints;
691 RasterS_t *rasterP = &imageP->raster;
692 ColorModelS_t *cmodelP = &imageP->cmodel;
693 int imageType = imageP->imageType;
694
695 // check whether raster and color model are compatible
696 if (cmodelP->numComponents != rasterP->numBands) {
697 if (cmodelP->cmType != INDEX_CM_TYPE) {
698 return -1;
699 }
700 }
701
702 hintP->numChans = imageP->cmodel.numComponents;
703 hintP->colorOrder = NULL;
704 if (SAFE_TO_ALLOC_2(hintP->numChans, sizeof(int))) {
705 hintP->colorOrder = (int *)malloc(hintP->numChans * sizeof(int));
706 }
707 if (hintP->colorOrder == NULL) {
708 JNU_ThrowOutOfMemoryError(env, "Out of memory");
709 return -1;
710 }
711 if (imageType != java_awt_image_BufferedImage_TYPE_CUSTOM) {
712 awt_getBIColorOrder(imageType, hintP->colorOrder);
713 }
714 if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
715 imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
716 imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
717 {
718 hintP->channelOffset = rasterP->chanOffsets[0];
719 /* These hints are #bytes */
720 hintP->dataOffset = hintP->channelOffset*rasterP->dataSize;
721 hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
722 hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
723 hintP->packing = BYTE_INTERLEAVED;
724 } else if (imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR ||
725 imageType==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE||
726 imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR ||
727 imageType == java_awt_image_BufferedImage_TYPE_INT_BGR)
728 {
729 if (imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) {
730 hintP->channelOffset = rasterP->chanOffsets[0];
731 }
732 else {
733 hintP->channelOffset = rasterP->chanOffsets[hintP->numChans-1];
734 }
735 hintP->dataOffset = hintP->channelOffset*rasterP->dataSize;
736 hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
737 hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
738 hintP->packing = BYTE_INTERLEAVED;
739 } else if (imageType==java_awt_image_BufferedImage_TYPE_USHORT_565_RGB ||
740 imageType==java_awt_image_BufferedImage_TYPE_USHORT_555_RGB) {
741 hintP->needToExpand = TRUE;
742 hintP->expandToNbits = 8;
743 hintP->packing = PACKED_SHORT_INTER;
744 } else if (cmodelP->cmType == INDEX_CM_TYPE) {
745 int i;
746 hintP->numChans = 1;
747 hintP->channelOffset = rasterP->chanOffsets[0];
748 hintP->dataOffset = hintP->channelOffset*rasterP->dataSize;
749 hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
750 hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
751 switch(rasterP->dataType ) {
752 case BYTE_DATA_TYPE:
753 if (rasterP->rasterType == PACKED_RASTER_TYPE) {
754 hintP->needToExpand = TRUE;
755 hintP->expandToNbits = 8;
756 hintP->packing = BYTE_PACKED_BAND;
757 }
758 else {
759 hintP->packing = BYTE_SINGLE_BAND;
760 }
761 break;
762 case SHORT_DATA_TYPE:
763 hintP->packing = SHORT_SINGLE_BAND;
764 break;
765 case INT_DATA_TYPE:
766 default:
767 hintP->packing = UNKNOWN_PACKING;
768 break;
769 }
770 for (i=0; i < hintP->numChans; i++) {
771 hintP->colorOrder[i] = i;
772 }
773 }
774 else if (cmodelP->cmType == COMPONENT_CM_TYPE) {
775 /* Figure out if it is interleaved */
776 int bits=1;
777 int i;
778 int low = rasterP->chanOffsets[0];
779 int diff;
780 int banded = 0;
781 for (i=1; i < hintP->numChans; i++) {
782 if (rasterP->chanOffsets[i] < low) {
783 low = rasterP->chanOffsets[i];
784 }
785 }
786 for (i=1; i < hintP->numChans; i++) {
787 diff = rasterP->chanOffsets[i]-low;
788 if (diff < hintP->numChans) {
789 if (bits & (1<<diff)) {
790 /* Overlapping samples */
791 /* Could just copy */
792 return -1;
793 }
794 bits |= (1<<diff);
795 }
796 else if (diff >= rasterP->width) {
797 banded = 1;
798 }
799 /* Ignore the case if bands are overlapping */
800 }
801 hintP->channelOffset = low;
802 hintP->dataOffset = low*rasterP->dataSize;
803 hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
804 hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
805 switch(rasterP->dataType) {
806 case BYTE_DATA_TYPE:
807 hintP->packing = BYTE_COMPONENTS;
808 break;
809 case SHORT_DATA_TYPE:
810 hintP->packing = SHORT_COMPONENTS;
811 break;
812 default:
813 /* Don't handle any other case */
814 return -1;
815 }
816 if (bits == ((1<<hintP->numChans)-1)) {
817 hintP->packing |= INTERLEAVED;
818 for (i=0; i < hintP->numChans; i++) {
819 hintP->colorOrder[rasterP->chanOffsets[i]-low] = i;
820 }
821 }
822 else if (banded == 1) {
823 int bandSize = rasterP->width*rasterP->height;
824 hintP->packing |= BANDED;
825 for (i=0; i < hintP->numChans; i++) {
826 /* REMIND: Not necessarily correct */
827 hintP->colorOrder[(rasterP->chanOffsets[i]-low)%bandSize] = i;
828 }
829 }
830 else {
831 return -1;
832 }
833 }
834 else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) {
835 int i;
836
837 /* do some sanity check first: make sure that
838 * - sample model is SinglePixelPackedSampleModel
839 * - number of bands in the raster corresponds to the number
840 * of color components in the color model
841 */
842 if (!rasterP->sppsm.isUsed ||
843 rasterP->numBands != cmodelP->numComponents)
844 {
845 /* given raster is not compatible with the color model,
846 * so the operation has to be aborted.
847 */
848 return -1;
849 }
850
851 if (cmodelP->maxNbits > 8) {
852 hintP->needToExpand = TRUE;
853 hintP->expandToNbits = cmodelP->maxNbits;
854 }
855 else {
856 for (i=0; i < rasterP->numBands; i++) {
857 if (!(rasterP->sppsm.offsets[i] % 8)) {
858 hintP->needToExpand = TRUE;
859 hintP->expandToNbits = 8;
860 break;
861 }
862 else {
863 hintP->colorOrder[i] = rasterP->sppsm.offsets[i]>>3;
864 }
865 }
866 }
867
868 hintP->channelOffset = rasterP->chanOffsets[0];
869 hintP->dataOffset = hintP->channelOffset*rasterP->dataSize;
870 hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
871 hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
872 if (hintP->needToExpand) {
873 switch(rasterP->dataType) {
874 case BYTE_DATA_TYPE:
875 hintP->packing = PACKED_BYTE_INTER;
876 break;
877 case SHORT_DATA_TYPE:
878 hintP->packing = PACKED_SHORT_INTER;
879 break;
880 case INT_DATA_TYPE:
881 hintP->packing = PACKED_INT_INTER;
882 break;
883 default:
884 /* Don't know what it is */
885 return -1;
886 }
887 }
888 else {
889 hintP->packing = BYTE_INTERLEAVED;
890
891 }
892 }
893 else {
894 /* REMIND: Need to handle more cases */
895 return -1;
896 }
897
898 return 1;
899}
900
901#define MAX_TO_GRAB (10240)
902
903typedef union {
904 void *pv;
905 unsigned char *pb;
906 unsigned short *ps;
907} PixelData_t;
908
909
910int awt_getPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) {
911 const int w = rasterP->width;
912 const int h = rasterP->height;
913 const int numBands = rasterP->numBands;
914 int y;
915 int i;
916 int maxLines;
917 jobject jsm;
918 int off = 0;
919 jarray jdata = NULL;
920 jobject jdatabuffer;
921 int *dataP;
922 int maxSamples;
923 PixelData_t p;
924
925 if (bufferP == NULL) {
926 return -1;
927 }
928
929 if (rasterP->dataType != BYTE_DATA_TYPE &&
930 rasterP->dataType != SHORT_DATA_TYPE)
931 {
932 return -1;
933 }
934
935 p.pv = bufferP;
936
937 if (!SAFE_TO_MULT(w, numBands)) {
938 return -1;
939 }
940 maxSamples = w * numBands;
941
942 maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples);
943 if (maxLines > h) {
944 maxLines = h;
945 }
946
947 if (!SAFE_TO_MULT(maxSamples, maxLines)) {
948 return -1;
949 }
950
951 maxSamples *= maxLines;
952
953 jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
954 jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
955 g_RasterDataBufferID);
956
957 jdata = (*env)->NewIntArray(env, maxSamples);
958 if (JNU_IsNull(env, jdata)) {
959 (*env)->ExceptionClear(env);
960 JNU_ThrowOutOfMemoryError(env, "Out of Memory");
961 return -1;
962 }
963
964 for (y = 0; y < h; y += maxLines) {
965 if (y + maxLines > h) {
966 maxLines = h - y;
967 maxSamples = w * numBands * maxLines;
968 }
969
970 (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
971 0, y, w,
972 maxLines, jdata, jdatabuffer);
973
974 if ((*env)->ExceptionOccurred(env)) {
975 (*env)->DeleteLocalRef(env, jdata);
976 return -1;
977 }
978
979 dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
980 NULL);
981 if (dataP == NULL) {
982 (*env)->DeleteLocalRef(env, jdata);
983 return -1;
984 }
985
986 switch (rasterP->dataType) {
987 case BYTE_DATA_TYPE:
988 for (i = 0; i < maxSamples; i ++) {
989 p.pb[off++] = (unsigned char) dataP[i];
990 }
991 break;
992 case SHORT_DATA_TYPE:
993 for (i = 0; i < maxSamples; i ++) {
994 p.ps[off++] = (unsigned short) dataP[i];
995 }
996 break;
997 }
998
999 (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1000 JNI_ABORT);
1001 }
1002 (*env)->DeleteLocalRef(env, jdata);
1003
1004 return 1;
1005}
1006
1007int awt_setPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) {
1008 const int w = rasterP->width;
1009 const int h = rasterP->height;
1010 const int numBands = rasterP->numBands;
1011
1012 int y;
1013 int i;
1014 int maxLines;
1015 jobject jsm;
1016 int off = 0;
1017 jarray jdata = NULL;
1018 jobject jdatabuffer;
1019 int *dataP;
1020 int maxSamples;
1021 PixelData_t p;
1022
1023 if (bufferP == NULL) {
1024 return -1;
1025 }
1026
1027 if (rasterP->dataType != BYTE_DATA_TYPE &&
1028 rasterP->dataType != SHORT_DATA_TYPE)
1029 {
1030 return -1;
1031 }
1032
1033 p.pv = bufferP;
1034
1035 if (!SAFE_TO_MULT(w, numBands)) {
1036 return -1;
1037 }
1038 maxSamples = w * numBands;
1039
1040 maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples);
1041 if (maxLines > h) {
1042 maxLines = h;
1043 }
1044
1045 if (!SAFE_TO_MULT(maxSamples, maxLines)) {
1046 return -1;
1047 }
1048
1049 maxSamples *= maxLines;
1050
1051 jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
1052 jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
1053 g_RasterDataBufferID);
1054
1055 jdata = (*env)->NewIntArray(env, maxSamples);
1056 if (JNU_IsNull(env, jdata)) {
1057 (*env)->ExceptionClear(env);
1058 JNU_ThrowOutOfMemoryError(env, "Out of Memory");
1059 return -1;
1060 }
1061
1062 for (y = 0; y < h; y += maxLines) {
1063 if (y + maxLines > h) {
1064 maxLines = h - y;
1065 maxSamples = w * numBands * maxLines;
1066 }
1067 dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
1068 NULL);
1069 if (dataP == NULL) {
1070 (*env)->DeleteLocalRef(env, jdata);
1071 return -1;
1072 }
1073
1074 switch (rasterP->dataType) {
1075 case BYTE_DATA_TYPE:
1076 for (i = 0; i < maxSamples; i ++) {
1077 dataP[i] = p.pb[off++];
1078 }
1079 break;
1080 case SHORT_DATA_TYPE:
1081 for (i = 0; i < maxSamples; i ++) {
1082 dataP[i] = p.ps[off++];
1083 }
1084 break;
1085 }
1086
1087 (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1088 JNI_ABORT);
1089
1090 (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
1091 0, y, w,
1092 maxLines, jdata, jdatabuffer);
1093
1094 if ((*env)->ExceptionOccurred(env)) {
1095 (*env)->DeleteLocalRef(env, jdata);
1096 return -1;
1097 }
1098 }
1099
1100 (*env)->DeleteLocalRef(env, jdata);
1101
1102 return 1;
1103}
1104