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