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