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 39 static 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 */ 56 int 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 */ 125 static 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 */ 182 int 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 411 static 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 449 int 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 595 void 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 605 void 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 622 static void 623 awt_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 688 static int 689 setHints(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 if (rasterP->sppsm.offsets != NULL) { 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 903 typedef union { 904 void *pv; 905 unsigned char *pb; 906 unsigned short *ps; 907 } PixelData_t; 908 909 910 int 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 1007 int 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 }