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 static void
 493 awt_getBIColorOrder(int type, int *colorOrder) {
 494     switch(type) {
 495         case java_awt_image_BufferedImage_TYPE_INT_ARGB:
 496         case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
 497 #ifdef _LITTLE_ENDIAN
 498             colorOrder[0] = 2;
 499             colorOrder[1] = 1;
 500             colorOrder[2] = 0;
 501             colorOrder[3] = 3;
 502 #else
 503             colorOrder[0] = 1;
 504             colorOrder[1] = 2;
 505             colorOrder[2] = 3;
 506             colorOrder[3] = 0;
 507 #endif
 508             break;
 509         case java_awt_image_BufferedImage_TYPE_INT_BGR:
 510 #ifdef _LITTLE_ENDIAN
 511             colorOrder[0] = 0;
 512             colorOrder[1] = 1;
 513             colorOrder[2] = 2;
 514 #else
 515             colorOrder[0] = 3;
 516             colorOrder[1] = 2;
 517             colorOrder[2] = 1;
 518 #endif
 519             break;
 520         case java_awt_image_BufferedImage_TYPE_INT_RGB:
 521 #ifdef _LITTLE_ENDIAN
 522             colorOrder[0] = 2;
 523             colorOrder[1] = 1;
 524             colorOrder[2] = 0;
 525 #else
 526             colorOrder[0] = 1;
 527             colorOrder[1] = 2;
 528             colorOrder[2] = 3;
 529 #endif
 530             break;
 531         case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
 532         case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
 533             colorOrder[0] = 3;
 534             colorOrder[1] = 2;
 535             colorOrder[2] = 1;
 536             colorOrder[3] = 0;
 537             break;
 538         case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
 539             colorOrder[0] = 2;
 540             colorOrder[1] = 1;
 541             colorOrder[2] = 0;
 542             break;
 543         case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
 544         case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB:
 545             colorOrder[0] = 0;
 546             colorOrder[1] = 1;
 547             colorOrder[2] = 2;
 548             break;
 549         case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
 550         case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
 551         case java_awt_image_BufferedImage_TYPE_BYTE_BINARY:
 552         case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
 553             colorOrder[0] = 0;
 554             break;
 555     }
 556 }
 557 
 558 static int
 559 setHints(JNIEnv *env, BufImageS_t *imageP) {
 560     HintS_t *hintP = &imageP->hints;
 561     RasterS_t *rasterP = &imageP->raster;
 562     ColorModelS_t *cmodelP = &imageP->cmodel;
 563     int imageType = imageP->imageType;
 564 
 565     hintP->numChans = imageP->cmodel.numComponents;
 566     hintP->colorOrder = NULL;
 567     if (SAFE_TO_ALLOC_2(hintP->numChans, sizeof(int))) {
 568         hintP->colorOrder = (int *)malloc(hintP->numChans * sizeof(int));
 569     }
 570     if (hintP->colorOrder == NULL) {
 571         JNU_ThrowOutOfMemoryError(env, "Out of memory");
 572         return -1;
 573     }
 574     if (imageType != java_awt_image_BufferedImage_TYPE_CUSTOM) {
 575         awt_getBIColorOrder(imageType, hintP->colorOrder);
 576     }
 577     if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
 578         imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
 579         imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
 580     {
 581         hintP->channelOffset = rasterP->chanOffsets[0];
 582         /* These hints are #bytes  */
 583         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 584         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 585         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 586         hintP->packing = BYTE_INTERLEAVED;
 587     } else if (imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR ||
 588                imageType==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE||
 589                imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR ||
 590                imageType == java_awt_image_BufferedImage_TYPE_INT_BGR)
 591     {
 592         if (imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) {
 593             hintP->channelOffset = rasterP->chanOffsets[0];
 594         }
 595         else {
 596             hintP->channelOffset = rasterP->chanOffsets[hintP->numChans-1];
 597         }
 598         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 599         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 600         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 601         hintP->packing = BYTE_INTERLEAVED;
 602     } else if (imageType==java_awt_image_BufferedImage_TYPE_USHORT_565_RGB ||
 603                imageType==java_awt_image_BufferedImage_TYPE_USHORT_555_RGB) {
 604         hintP->needToExpand  = TRUE;
 605         hintP->expandToNbits = 8;
 606         hintP->packing = PACKED_SHORT_INTER;
 607     } else if (cmodelP->cmType == INDEX_CM_TYPE) {
 608         int i;
 609         hintP->numChans = 1;
 610         hintP->channelOffset = rasterP->chanOffsets[0];
 611         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 612         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 613         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 614         switch(rasterP->dataType ) {
 615         case BYTE_DATA_TYPE:
 616             if (rasterP->rasterType == PACKED_RASTER_TYPE) {
 617                 hintP->needToExpand = TRUE;
 618                 hintP->expandToNbits = 8;
 619                 hintP->packing = BYTE_PACKED_BAND;
 620             }
 621             else {
 622                 hintP->packing = BYTE_SINGLE_BAND;
 623             }
 624             break;
 625         case SHORT_DATA_TYPE:
 626             hintP->packing = SHORT_SINGLE_BAND;
 627             break;
 628         case INT_DATA_TYPE:
 629         default:
 630             hintP->packing = UNKNOWN_PACKING;
 631             break;
 632         }
 633         for (i=0; i < hintP->numChans; i++) {
 634             hintP->colorOrder[i] = i;
 635         }
 636     }
 637     else if (cmodelP->cmType == COMPONENT_CM_TYPE) {
 638         /* Figure out if it is interleaved */
 639         int bits=1;
 640         int i;
 641         int low = rasterP->chanOffsets[0];
 642         int diff;
 643         int banded = 0;
 644         for (i=1; i < hintP->numChans; i++) {
 645             if (rasterP->chanOffsets[i] < low) {
 646                 low = rasterP->chanOffsets[i];
 647             }
 648         }
 649         for (i=1; i < hintP->numChans; i++) {
 650             diff = rasterP->chanOffsets[i]-low;
 651             if (diff < hintP->numChans) {
 652                 if (bits & (1<<diff)) {
 653                     /* Overlapping samples */
 654                     /* Could just copy */
 655                     return -1;
 656                 }
 657                 bits |= (1<<diff);
 658             }
 659             else if (diff >= rasterP->width) {
 660                 banded = 1;
 661             }
 662             /* Ignore the case if bands are overlapping */
 663         }
 664         hintP->channelOffset = low;
 665         hintP->dataOffset    = low*rasterP->dataSize;
 666         hintP->sStride       = rasterP->scanlineStride*rasterP->dataSize;
 667         hintP->pStride       = rasterP->pixelStride*rasterP->dataSize;
 668         switch(rasterP->dataType) {
 669         case BYTE_DATA_TYPE:
 670             hintP->packing = BYTE_COMPONENTS;
 671             break;
 672         case SHORT_DATA_TYPE:
 673             hintP->packing = SHORT_COMPONENTS;
 674             break;
 675         default:
 676             /* Don't handle any other case */
 677             return -1;
 678         }
 679         if (bits == ((1<<hintP->numChans)-1)) {
 680             hintP->packing |= INTERLEAVED;
 681             for (i=0; i < hintP->numChans; i++) {
 682                 hintP->colorOrder[rasterP->chanOffsets[i]-low] = i;
 683             }
 684         }
 685         else if (banded == 1) {
 686             int bandSize = rasterP->width*rasterP->height;
 687             hintP->packing |= BANDED;
 688             for (i=0; i < hintP->numChans; i++) {
 689                 /* REMIND: Not necessarily correct */
 690                 hintP->colorOrder[(rasterP->chanOffsets[i]-low)%bandSize] = i;
 691             }
 692         }
 693         else {
 694             return -1;
 695         }
 696     }
 697     else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) {
 698         int i;
 699         if (cmodelP->maxNbits > 8) {
 700             hintP->needToExpand = TRUE;
 701             hintP->expandToNbits = cmodelP->maxNbits;
 702         }
 703         else if (rasterP->sppsm.offsets != NULL) {
 704             for (i=0; i < rasterP->numBands; i++) {
 705                 if (!(rasterP->sppsm.offsets[i] % 8)) {
 706                     hintP->needToExpand  = TRUE;
 707                     hintP->expandToNbits = 8;
 708                     break;
 709                 }
 710                 else {
 711                     hintP->colorOrder[i] = rasterP->sppsm.offsets[i]>>3;
 712                 }
 713             }
 714         }
 715 
 716         hintP->channelOffset = rasterP->chanOffsets[0];
 717         hintP->dataOffset    = hintP->channelOffset*rasterP->dataSize;
 718         hintP->sStride = rasterP->scanlineStride*rasterP->dataSize;
 719         hintP->pStride = rasterP->pixelStride*rasterP->dataSize;
 720         if (hintP->needToExpand) {
 721             switch(rasterP->dataType) {
 722             case BYTE_DATA_TYPE:
 723                 hintP->packing = PACKED_BYTE_INTER;
 724                 break;
 725             case SHORT_DATA_TYPE:
 726                 hintP->packing = PACKED_SHORT_INTER;
 727                 break;
 728             case INT_DATA_TYPE:
 729                 hintP->packing = PACKED_INT_INTER;
 730                 break;
 731             default:
 732                 /* Don't know what it is */
 733                 return -1;
 734             }
 735         }
 736         else {
 737             hintP->packing = BYTE_INTERLEAVED;
 738 
 739         }
 740     }
 741     else {
 742         /* REMIND: Need to handle more cases */
 743         return -1;
 744     }
 745 
 746     return 1;
 747 }
 748 
 749 /*
 750  * This routine will fill in a buffer of data for either 1 band or all
 751  * bands (if band == -1).
 752  */
 753 #define MAX_TO_GRAB (10240)
 754 
 755 int awt_getPixelByte(JNIEnv *env, int band, RasterS_t *rasterP,
 756                      unsigned char *bufferP) {
 757     int w = rasterP->width;
 758     int h = rasterP->height;
 759     int numBands = rasterP->numBands;
 760     int y;
 761     int i;
 762     int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w);
 763     jobject jsm;
 764     int off;
 765     jarray jdata = NULL;
 766     jobject jdatabuffer;
 767     int *dataP;
 768     int maxBytes = w;
 769 
 770     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
 771     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
 772                                          g_RasterDataBufferID);
 773     jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines);
 774     if (JNU_IsNull(env, jdata)) {
 775         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
 776         return -1;
 777     }
 778 
 779     /* Here is the generic code */
 780     if (band >= 0) {
 781         int dOff;
 782         if (band >= numBands) {
 783             (*env)->DeleteLocalRef(env, jdata);
 784             JNU_ThrowInternalError(env, "Band out of range.");
 785             return -1;
 786         }
 787         off = 0;
 788         for (y=0; y < h; ) {
 789             (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
 790                                      0, y, w,
 791                                      maxLines, jdata, jdatabuffer);
 792             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 793                                                               NULL);
 794             if (dataP == NULL) {
 795                 (*env)->DeleteLocalRef(env, jdata);
 796                 return -1;
 797             }
 798             dOff = band;
 799             for (i=0; i < maxBytes; i++, dOff += numBands) {
 800                 bufferP[off++] = (unsigned char) dataP[dOff];
 801             }
 802 
 803             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
 804                                                   JNI_ABORT);
 805 
 806             if (y+maxLines < h) {
 807                 y += maxLines;
 808             }
 809             else {
 810                 y++;
 811                 maxBytes = w;
 812             }
 813         }
 814     }
 815     else {
 816         off = 0;
 817         maxBytes *= numBands;
 818         for (y=0; y < h; ) {
 819             (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
 820                                      0, y, w,
 821                                      maxLines, jdata, jdatabuffer);
 822             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 823                                                               NULL);
 824             if (dataP == NULL) {
 825                 (*env)->DeleteLocalRef(env, jdata);
 826                 return -1;
 827             }
 828             for (i=0; i < maxBytes; i++) {
 829                 bufferP[off++] = (unsigned char) dataP[i];
 830             }
 831 
 832             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
 833                                                   JNI_ABORT);
 834 
 835             if (y+maxLines < h) {
 836                 y += maxLines;
 837             }
 838             else {
 839                 y++;
 840                 maxBytes = w*numBands;
 841             }
 842         }
 843 
 844     }
 845     (*env)->DeleteLocalRef(env, jdata);
 846 
 847     return 0;
 848 }
 849 int awt_setPixelByte(JNIEnv *env, int band, RasterS_t *rasterP,
 850                      unsigned char *bufferP) {
 851     int w = rasterP->width;
 852     int h = rasterP->height;
 853     int numBands = rasterP->numBands;
 854     int y;
 855     int i;
 856     int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w);
 857     jobject jsm;
 858     int off;
 859     jarray jdata = NULL;
 860     jobject jdatabuffer;
 861     int *dataP;
 862     int maxBytes = w;
 863 
 864     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
 865     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
 866                                          g_RasterDataBufferID);
 867     /* Here is the generic code */
 868     jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines);
 869     if (JNU_IsNull(env, jdata)) {
 870         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
 871         return -1;
 872     }
 873     if (band >= 0) {
 874         int dOff;
 875         if (band >= numBands) {
 876             (*env)->DeleteLocalRef(env, jdata);
 877             JNU_ThrowInternalError(env, "Band out of range.");
 878             return -1;
 879         }
 880         off = 0;
 881         for (y=0; y < h; y+=maxLines) {
 882             if (y+maxLines > h) {
 883                 maxBytes = w*numBands;
 884                 maxLines = h - y;
 885             }
 886             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 887                                                               NULL);
 888             if (dataP == NULL) {
 889                 (*env)->DeleteLocalRef(env, jdata);
 890                 return -1;
 891             }
 892             dOff = band;
 893             for (i=0; i < maxBytes; i++, dOff += numBands) {
 894                 dataP[dOff] = bufferP[off++];
 895             }
 896 
 897             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
 898                                                   JNI_ABORT);
 899 
 900             (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
 901                                    0, y, w,
 902                                    maxLines, jdata, jdatabuffer);
 903         }
 904     }
 905     else {
 906         off = 0;
 907         maxBytes *= numBands;
 908         for (y=0; y < h; y+=maxLines) {
 909             if (y+maxLines > h) {
 910                 maxBytes = w*numBands;
 911                 maxLines = h - y;
 912             }
 913             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 914                                                               NULL);
 915             if (dataP == NULL) {
 916                 (*env)->DeleteLocalRef(env, jdata);
 917                 return -1;
 918             }
 919             for (i=0; i < maxBytes; i++) {
 920                 dataP[i] = bufferP[off++];
 921             }
 922 
 923             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
 924                                                   JNI_ABORT);
 925 
 926             (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
 927                                      0, y, w,
 928                                      maxLines, jdata, jdatabuffer);
 929         }
 930 
 931     }
 932 
 933     (*env)->DeleteLocalRef(env, jdata);
 934 
 935     return 0;
 936 }
 937 int awt_getPixelShort(JNIEnv *env, int band, RasterS_t *rasterP,
 938                      unsigned short *bufferP) {
 939     int w = rasterP->width;
 940     int h = rasterP->height;
 941     int numBands = rasterP->numBands;
 942     int y;
 943     int i;
 944     int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w);
 945     jobject jsm;
 946     int off;
 947     jarray jdata = NULL;
 948     jobject jdatabuffer;
 949     int *dataP;
 950     int maxBytes = w*maxLines;
 951 
 952     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
 953     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
 954                                          g_RasterDataBufferID);
 955     jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines);
 956     if (JNU_IsNull(env, jdata)) {
 957         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
 958         return -1;
 959     }
 960     /* Here is the generic code */
 961     if (band >= 0) {
 962         int dOff;
 963         if (band >= numBands) {
 964             (*env)->DeleteLocalRef(env, jdata);
 965             JNU_ThrowInternalError(env, "Band out of range.");
 966             return -1;
 967         }
 968         off = 0;
 969         for (y=0; y < h; y += maxLines) {
 970             if (y+maxLines > h) {
 971                 maxBytes = w*numBands;
 972                 maxLines = h - y;
 973             }
 974             (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
 975                                      0, y, w,
 976                                      maxLines, jdata, jdatabuffer);
 977             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
 978                                                               NULL);
 979             if (dataP == NULL) {
 980                 (*env)->DeleteLocalRef(env, jdata);
 981                 return -1;
 982             }
 983 
 984             dOff = band;
 985             for (i=0; i < maxBytes; i++, dOff += numBands) {
 986                 bufferP[off++] = (unsigned short) dataP[dOff];
 987             }
 988 
 989             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
 990                                                   JNI_ABORT);
 991         }
 992     }
 993     else {
 994         off = 0;
 995         maxBytes *= numBands;
 996         for (y=0; y < h; y+=maxLines) {
 997             if (y+maxLines > h) {
 998                 maxBytes = w*numBands;
 999                 maxLines = h - y;
1000             }
1001             (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID,
1002                                      0, y, w,
1003                                      maxLines, jdata, jdatabuffer);
1004             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
1005                                                               NULL);
1006             if (dataP == NULL) {
1007                 (*env)->DeleteLocalRef(env, jdata);
1008                 return -1;
1009             }
1010             for (i=0; i < maxBytes; i++) {
1011                 bufferP[off++] = (unsigned short) dataP[i];
1012             }
1013 
1014             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1015                                                   JNI_ABORT);
1016         }
1017 
1018     }
1019 
1020     (*env)->DeleteLocalRef(env, jdata);
1021     return 0;
1022 }
1023 int awt_setPixelShort(JNIEnv *env, int band, RasterS_t *rasterP,
1024                       unsigned short *bufferP) {
1025     int w = rasterP->width;
1026     int h = rasterP->height;
1027     int numBands = rasterP->numBands;
1028     int y;
1029     int i;
1030     int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w);
1031     jobject jsm;
1032     int off;
1033     jarray jdata = NULL;
1034     jobject jdatabuffer;
1035     int *dataP;
1036     int maxBytes = w;
1037 
1038     jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID);
1039     jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster,
1040                                          g_RasterDataBufferID);
1041     /* Here is the generic code */
1042     jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines);
1043     if (JNU_IsNull(env, jdata)) {
1044         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
1045         return -1;
1046     }
1047     if (band >= 0) {
1048         int dOff;
1049         if (band >= numBands) {
1050             (*env)->DeleteLocalRef(env, jdata);
1051             JNU_ThrowInternalError(env, "Band out of range.");
1052             return -1;
1053         }
1054         off = 0;
1055         for (y=0; y < h; y+=maxLines) {
1056             if (y+maxLines > h) {
1057                 maxBytes = w*numBands;
1058                 maxLines = h - y;
1059             }
1060             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
1061                                                               NULL);
1062             if (dataP == NULL) {
1063                 (*env)->DeleteLocalRef(env, jdata);
1064                 return -1;
1065             }
1066             dOff = band;
1067             for (i=0; i < maxBytes; i++, dOff += numBands) {
1068                 dataP[dOff] = bufferP[off++];
1069             }
1070 
1071             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1072                                                   JNI_ABORT);
1073 
1074             (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
1075                                    0, y, w,
1076                                    maxLines, jdata, jdatabuffer);
1077         }
1078     }
1079     else {
1080         off = 0;
1081         maxBytes *= numBands;
1082         for (y=0; y < h; y+=maxLines) {
1083             if (y+maxLines > h) {
1084                 maxBytes = w*numBands;
1085                 maxLines = h - y;
1086             }
1087             dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata,
1088                                                               NULL);
1089             if (dataP == NULL) {
1090                 (*env)->DeleteLocalRef(env, jdata);
1091                 return -1;
1092             }
1093             for (i=0; i < maxBytes; i++) {
1094                 dataP[i] = bufferP[off++];
1095             }
1096 
1097             (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP,
1098                                                   JNI_ABORT);
1099 
1100             (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID,
1101                                    0, y, w,
1102                                    maxLines, jdata, jdatabuffer);
1103         }
1104 
1105     }
1106 
1107     (*env)->DeleteLocalRef(env, jdata);
1108     return 0;
1109 }