1 /*
   2  * Copyright (c) 1997, 2016, 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 <string.h>
  29 #include "sun_awt_image_ImagingLib.h"
  30 #include "java_awt_Transparency.h"
  31 #include "java_awt_image_AffineTransformOp.h"
  32 #include "java_awt_image_BufferedImage.h"
  33 #include "java_awt_color_ColorSpace.h"
  34 #include "java_awt_image_ConvolveOp.h"
  35 #include "sun_awt_image_IntegerComponentRaster.h"
  36 #include "awt_ImagingLib.h"
  37 #include "awt_parseImage.h"
  38 #include "imageInitIDs.h"
  39 #include <jni.h>
  40 #include <jni_util.h>
  41 #include <assert.h>
  42 #include "awt_Mlib.h"
  43 #include "gdefs.h"
  44 #include "safe_alloc.h"
  45 #include "safe_math.h"
  46 
  47 /***************************************************************************
  48  *                               Definitions                               *
  49  ***************************************************************************/
  50 #define jio_fprintf fprintf
  51 
  52 #ifndef TRUE
  53 #define TRUE 1
  54 #endif /* TRUE */
  55 
  56 #ifndef FALSE
  57 #define FALSE 0
  58 #endif /* FALSE */
  59 
  60 #define TYPE_CUSTOM         java_awt_image_BufferedImage_TYPE_CUSTOM
  61 #define TYPE_INT_RGB        java_awt_image_BufferedImage_TYPE_INT_RGB
  62 #define TYPE_INT_ARGB       java_awt_image_BufferedImage_TYPE_INT_ARGB
  63 #define TYPE_INT_ARGB_PRE   java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE
  64 #define TYPE_INT_BGR        java_awt_image_BufferedImage_TYPE_INT_BGR
  65 #define TYPE_4BYTE_ABGR     java_awt_image_BufferedImage_TYPE_4BYTE_ABGR
  66 #define TYPE_4BYTE_ABGR_PRE java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE
  67 
  68 /* (alpha*color)>>nbits + alpha>>(nbits-1) */
  69 #define BLEND(color, alpha, alphaNbits) \
  70     ((((alpha)*(color))>>(alphaNbits)) + ((alpha) >> ((alphaNbits)-1)))
  71 
  72     /* ((color - (alpha>>(nBits-1)))<<nBits)/alpha */
  73 #define UNBLEND(color, alpha, alphaNbits) \
  74     ((((color)-((alpha)>>((alphaNbits)-1)))<<(alphaNbits))/(alpha))
  75 
  76 /* Enumeration of all of the mlib functions used */
  77 typedef enum {
  78     MLIB_CONVMxN,
  79     MLIB_AFFINE,
  80     MLIB_LOOKUP,
  81     MLIB_CONVKERNCVT
  82 } mlibTypeE_t;
  83 
  84 typedef struct {
  85     int dataType;           /* One of BYTE_DATA_TYPE, SHORT_DATA_TYPE, */
  86     int needToCopy;
  87     int cvtSrcToDefault;    /* If TRUE, convert the src to def CM (pre?) */
  88     int allocDefaultDst;    /* If TRUE, alloc def CM dst buffer */
  89     int cvtToDst;           /* If TRUE, convert dst buffer to Dst CM */
  90     int addAlpha;
  91 } mlibHintS_t;
  92 
  93 /***************************************************************************
  94  *                     Static Variables/Structures                         *
  95  ***************************************************************************/
  96 
  97 static mlibSysFnS_t sMlibSysFns = {
  98     NULL, // placeholder for j2d_mlib_ImageCreate
  99     NULL, // placeholder for j2d_mlib_ImageCreateStruct
 100     NULL, // placeholder for j2d_mlib_ImageDelete
 101 };
 102 
 103 static mlibFnS_t sMlibFns[] = {
 104     {NULL, "j2d_mlib_ImageConvMxN"},
 105     {NULL, "j2d_mlib_ImageAffine"},
 106     {NULL, "j2d_mlib_ImageLookUp"},
 107     {NULL, "j2d_mlib_ImageConvKernelConvert"},
 108     {NULL, NULL},
 109 };
 110 
 111 static int s_timeIt = 0;
 112 static int s_printIt = 0;
 113 static int s_startOff = 0;
 114 static int s_nomlib = 0;
 115 
 116 /***************************************************************************
 117  *                          Static Function Prototypes                     *
 118  ***************************************************************************/
 119 
 120 static int
 121 allocateArray(JNIEnv *env, BufImageS_t *imageP,
 122               mlib_image **mlibImagePP, void **dataPP, int isSrc,
 123               int cvtToDefault, int addAlpha);
 124 static int
 125 allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
 126                     mlib_image **mlibImagePP, void **dataPP, int isSrc);
 127 
 128 static void
 129 freeArray(JNIEnv *env, BufImageS_t *srcimageP, mlib_image *srcmlibImP,
 130           void *srcdataP, BufImageS_t *dstimageP, mlib_image *dstmlibImP,
 131           void *dstdataP);
 132 static void
 133 freeDataArray(JNIEnv *env, jobject srcJdata, mlib_image *srcmlibImP,
 134           void *srcdataP, jobject dstJdata, mlib_image *dstmlibImP,
 135           void *dstdataP);
 136 
 137 static int
 138 storeImageArray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
 139                 mlib_image *mlibImP);
 140 
 141 static int
 142 storeRasterArray(JNIEnv *env, RasterS_t *srcP, RasterS_t *dstP,
 143                 mlib_image *mlibImP);
 144 
 145 static int
 146 storeICMarray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
 147               mlib_image *mlibImP);
 148 
 149 static int
 150 colorMatch(int r, int g, int b, int a, unsigned char *argb, int numColors);
 151 
 152 static int
 153 setImageHints(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
 154               int expandICM, int useAlpha,
 155               int premultiply, mlibHintS_t *hintP);
 156 
 157 
 158 static int expandICM(JNIEnv *env, BufImageS_t *imageP, unsigned int *mDataP);
 159 static int expandPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
 160                            unsigned char *outDataP);
 161 static int expandPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
 162                            unsigned char *outDataP);
 163 static int expandPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
 164                            unsigned char *outDataP);
 165 static int expandPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
 166                                   int component, unsigned char *outDataP,
 167                                   int forceAlpha);
 168 static int expandPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
 169                                   int component, unsigned char *outDataP,
 170                                   int forceAlpha);
 171 static int expandPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
 172                                   int component, unsigned char *outDataP,
 173                                   int forceAlpha);
 174 static int setPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
 175                         unsigned char *outDataP);
 176 static int setPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
 177                         unsigned char *outDataP);
 178 static int setPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
 179                         unsigned char *outDataP);
 180 static int setPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
 181                                int component, unsigned char *outDataP,
 182                                int supportsAlpha);
 183 static int setPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
 184                                int component, unsigned char *outDataP,
 185                                int supportsAlpha);
 186 static int setPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
 187                                int component, unsigned char *outDataP,
 188                                int supportsAlpha);
 189 
 190 mlib_start_timer start_timer = NULL;
 191 mlib_stop_timer stop_timer = NULL;
 192 
 193 /***************************************************************************
 194  *                          Debugging Definitions                          *
 195  ***************************************************************************/
 196 #ifdef DEBUG
 197 
 198 static void
 199 printMedialibError(int status) {
 200     switch(status) {
 201     case MLIB_FAILURE:
 202         jio_fprintf(stderr, "failure\n");
 203         break;
 204     case MLIB_NULLPOINTER:
 205         jio_fprintf(stderr, "null pointer\n");
 206         break;
 207     case MLIB_OUTOFRANGE:
 208         jio_fprintf (stderr, "out of range\n");
 209         break;
 210     default:
 211         jio_fprintf (stderr, "medialib error\n");
 212         break;
 213     }
 214 }
 215 #else /* ! DEBUG */
 216 #  define printMedialibError(x)
 217 
 218 #endif /* ! DEBUG */
 219 
 220 static int
 221 getMlibEdgeHint(jint edgeHint) {
 222     switch (edgeHint) {
 223     case java_awt_image_ConvolveOp_EDGE_NO_OP:
 224         return MLIB_EDGE_DST_COPY_SRC;
 225     case java_awt_image_ConvolveOp_EDGE_ZERO_FILL:
 226     default:
 227         return MLIB_EDGE_DST_FILL_ZERO;
 228     }
 229 }
 230 
 231 /*
 232  * We have to make sure that awt_setPixels can be safely applied to the given pair of
 233  * raster and mlib image.
 234  *
 235  * In particular, make sure that
 236  *  - dimension is the same
 237  *  - number of channels in mlib image corresponds to the number of bands in the raster
 238  *  - sample size in image and raster are the same.
 239  *
 240  * Returns:
 241  *  -1 to indicate failure,
 242  *   1 to indicate success
 243  */
 244 static int setPixelsFormMlibImage(JNIEnv *env, RasterS_t *rasterP, mlib_image* img) {
 245     if (rasterP->width != img->width || rasterP->height != img->height) {
 246         /* dimension does not match */
 247         return -1;
 248     }
 249 
 250     if (rasterP->numBands != img->channels) {
 251         /* number of bands does not match */
 252         return -1;
 253     }
 254 
 255     switch (rasterP->dataType) {
 256     case BYTE_DATA_TYPE:
 257         if (img->type != MLIB_BYTE) {
 258             return -1;
 259         }
 260         break;
 261     case SHORT_DATA_TYPE:
 262         if (img->type != MLIB_SHORT && img->type != MLIB_USHORT) {
 263             return -1;
 264         }
 265         break;
 266     default:
 267         /* awt_setPixels does not support such rasters */
 268         return -1;
 269     }
 270 
 271     return awt_setPixels(env, rasterP, mlib_ImageGetData(img));
 272 }
 273 
 274 /***************************************************************************
 275  *                          External Functions                             *
 276  ***************************************************************************/
 277 JNIEXPORT jint JNICALL
 278 Java_sun_awt_image_ImagingLib_convolveBI(JNIEnv *env, jobject this,
 279                                          jobject jsrc, jobject jdst,
 280                                          jobject jkernel, jint edgeHint)
 281 {
 282     void *sdata, *ddata;
 283     mlib_image *src;
 284     mlib_image *dst;
 285     int i, scale;
 286     mlib_d64 *dkern;
 287     mlib_s32 *kdata;
 288     int klen;
 289     float kmax;
 290     mlib_s32 cmask;
 291     mlib_status status;
 292     int retStatus = 1;
 293     float *kern;
 294     BufImageS_t *srcImageP, *dstImageP;
 295     jobject jdata;
 296     int kwidth;
 297     int kheight;
 298     int w, h;
 299     int x, y;
 300     mlibHintS_t hint;
 301     int nbands;
 302 
 303     /* This function requires a lot of local refs ??? Is 64 enough ??? */
 304     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
 305         return 0;
 306 
 307     if (s_nomlib) return 0;
 308     if (s_timeIt)     (*start_timer)(3600);
 309 
 310     kwidth  = (*env)->GetIntField(env, jkernel, g_KernelWidthID);
 311     kheight = (*env)->GetIntField(env, jkernel, g_KernelHeightID);
 312     jdata = (*env)->GetObjectField(env, jkernel, g_KernelDataID);
 313     klen  = (*env)->GetArrayLength(env, jdata);
 314     kern  = (float *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL);
 315     if (kern == NULL) {
 316         /* out of memory exception already thrown */
 317         return 0;
 318     }
 319 
 320     if ((kwidth&0x1) == 0) {
 321         /* Kernel has even width */
 322         w = kwidth+1;
 323     }
 324     else {
 325         w = kwidth;
 326     }
 327     if ((kheight&0x1) == 0) {
 328         /* Kernel has even height */
 329         h = kheight+1;
 330     }
 331     else {
 332         h = kheight;
 333     }
 334 
 335     dkern = NULL;
 336     if (SAFE_TO_ALLOC_3(w, h, sizeof(mlib_d64))) {
 337         dkern = (mlib_d64 *)calloc(1, w * h * sizeof(mlib_d64));
 338     }
 339     if (dkern == NULL) {
 340         (*env)->ReleasePrimitiveArrayCritical(env, jdata, kern, JNI_ABORT);
 341         return 0;
 342     }
 343 
 344     /* Need to flip and find max value of the kernel.
 345      * Also, save the kernel values as mlib_d64 values.
 346      * The flip is to operate correctly with medialib,
 347      * which doesn't do the mathemetically correct thing,
 348      * i.e. it doesn't rotate the kernel by 180 degrees.
 349      * REMIND: This should perhaps be done at the Java
 350      * level by ConvolveOp.
 351      * REMIND: Should the max test be looking at absolute
 352      * values?
 353      * REMIND: What if klen != kheight * kwidth?
 354      */
 355     kmax = kern[klen-1];
 356     i = klen-1;
 357     for (y=0; y < kheight; y++) {
 358         for (x=0; x < kwidth; x++, i--) {
 359             dkern[y*w+x] = (mlib_d64) kern[i];
 360             if (kern[i] > kmax) {
 361                 kmax = kern[i];
 362             }
 363         }
 364     }
 365 
 366     (*env)->ReleasePrimitiveArrayCritical(env, jdata, kern, JNI_ABORT);
 367 
 368     if (kmax > 1<<16) {
 369         /* We can only handle 16 bit max */
 370         free(dkern);
 371         return 0;
 372     }
 373 
 374 
 375     /* Parse the source image */
 376     if (awt_parseImage(env, jsrc, &srcImageP, FALSE) <= 0) {
 377         /* Can't handle any custom images */
 378         free(dkern);
 379         return 0;
 380     }
 381 
 382     /* Parse the destination image */
 383     if (awt_parseImage(env, jdst, &dstImageP, FALSE) <= 0) {
 384         /* Can't handle any custom images */
 385         awt_freeParsedImage(srcImageP, TRUE);
 386         free(dkern);
 387         return 0;
 388     }
 389 
 390     nbands = setImageHints(env, srcImageP, dstImageP, TRUE, TRUE,
 391                         FALSE, &hint);
 392     if (nbands < 1) {
 393         /* Can't handle any custom images */
 394         awt_freeParsedImage(srcImageP, TRUE);
 395         awt_freeParsedImage(dstImageP, TRUE);
 396         free(dkern);
 397         return 0;
 398     }
 399     /* Allocate the arrays */
 400     if (allocateArray(env, srcImageP, &src, &sdata, TRUE,
 401                       hint.cvtSrcToDefault, hint.addAlpha) < 0) {
 402         /* Must be some problem */
 403         awt_freeParsedImage(srcImageP, TRUE);
 404         awt_freeParsedImage(dstImageP, TRUE);
 405         free(dkern);
 406         return 0;
 407     }
 408     if (allocateArray(env, dstImageP, &dst, &ddata, FALSE,
 409                       hint.cvtToDst, FALSE) < 0) {
 410         /* Must be some problem */
 411         freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
 412         awt_freeParsedImage(srcImageP, TRUE);
 413         awt_freeParsedImage(dstImageP, TRUE);
 414         free(dkern);
 415         return 0;
 416     }
 417 
 418     kdata = NULL;
 419     if (SAFE_TO_ALLOC_3(w, h, sizeof(mlib_s32))) {
 420         kdata = (mlib_s32 *)malloc(w * h * sizeof(mlib_s32));
 421     }
 422     if (kdata == NULL) {
 423         freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
 424         awt_freeParsedImage(srcImageP, TRUE);
 425         awt_freeParsedImage(dstImageP, TRUE);
 426         free(dkern);
 427         return 0;
 428     }
 429 
 430     if ((*sMlibFns[MLIB_CONVKERNCVT].fptr)(kdata, &scale, dkern, w, h,
 431                                     mlib_ImageGetType(src)) != MLIB_SUCCESS) {
 432         freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
 433         awt_freeParsedImage(srcImageP, TRUE);
 434         awt_freeParsedImage(dstImageP, TRUE);
 435         free(dkern);
 436         free(kdata);
 437         return 0;
 438     }
 439 
 440     if (s_printIt) {
 441         fprintf(stderr, "Orig Kernel(len=%d):\n",klen);
 442         for (y=kheight-1; y >= 0; y--) {
 443             for (x=kwidth-1; x >= 0; x--) {
 444                 fprintf(stderr, "%g ", dkern[y*w+x]);
 445             }
 446             fprintf(stderr, "\n");
 447         }
 448         fprintf(stderr, "New Kernel(scale=%d):\n", scale);
 449         for (y=kheight-1; y >= 0; y--) {
 450             for (x=kwidth-1; x >= 0; x--) {
 451                 fprintf(stderr, "%d ", kdata[y*w+x]);
 452             }
 453             fprintf(stderr, "\n");
 454         }
 455     }
 456 
 457     cmask = (1<<src->channels)-1;
 458     status = (*sMlibFns[MLIB_CONVMxN].fptr)(dst, src, kdata, w, h,
 459                                (w-1)/2, (h-1)/2, scale, cmask,
 460                                getMlibEdgeHint(edgeHint));
 461 
 462     if (status != MLIB_SUCCESS) {
 463         printMedialibError(status);
 464         retStatus = 0;
 465     }
 466 
 467     if (s_printIt) {
 468         unsigned int *dP;
 469         if (s_startOff != 0) {
 470             printf("Starting at %d\n", s_startOff);
 471         }
 472         if (sdata == NULL) {
 473             dP = (unsigned int *) mlib_ImageGetData(src);
 474         }
 475         else {
 476             dP = (unsigned int *) sdata;
 477         }
 478         printf("src is\n");
 479         for (i=0; i < 20; i++) {
 480             printf("%x ",dP[s_startOff+i]);
 481         }
 482         printf("\n");
 483         if (ddata == NULL) {
 484             dP = (unsigned int *)mlib_ImageGetData(dst);
 485         }
 486         else {
 487             dP = (unsigned int *) ddata;
 488         }
 489         printf("dst is \n");
 490         for (i=0; i < 20; i++) {
 491             printf("%x ",dP[s_startOff+i]);
 492         }
 493         printf("\n");
 494     }
 495 
 496     /* Means that we couldn't write directly into the destination buffer */
 497     if (ddata == NULL) {
 498 
 499         /* Need to store it back into the array */
 500         if (storeImageArray(env, srcImageP, dstImageP, dst) < 0) {
 501             /* Error */
 502             retStatus = 0;
 503         }
 504     }
 505 
 506     /* Release the pinned memory */
 507     freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
 508     awt_freeParsedImage(srcImageP, TRUE);
 509     awt_freeParsedImage(dstImageP, TRUE);
 510     free(dkern);
 511     free(kdata);
 512 
 513     if (s_timeIt) (*stop_timer)(3600, 1);
 514 
 515     return retStatus;
 516 }
 517 
 518 JNIEXPORT jint JNICALL
 519 Java_sun_awt_image_ImagingLib_convolveRaster(JNIEnv *env, jobject this,
 520                                              jobject jsrc, jobject jdst,
 521                                              jobject jkernel, jint edgeHint)
 522 {
 523     mlib_image *src;
 524     mlib_image *dst;
 525     int i, scale;
 526     mlib_d64 *dkern;
 527     mlib_s32 *kdata;
 528     int klen;
 529     float kmax;
 530     int retStatus = 1;
 531     mlib_status status;
 532     mlib_s32 cmask;
 533     void *sdata;
 534     void *ddata;
 535     RasterS_t *srcRasterP;
 536     RasterS_t *dstRasterP;
 537     int kwidth;
 538     int kheight;
 539     int w, h;
 540     int x, y;
 541     jobject jdata;
 542     float *kern;
 543 
 544     /* This function requires a lot of local refs ??? Is 64 enough ??? */
 545     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
 546         return 0;
 547 
 548     if (s_nomlib) return 0;
 549     if (s_timeIt)     (*start_timer)(3600);
 550 
 551     kwidth  = (*env)->GetIntField(env, jkernel, g_KernelWidthID);
 552     kheight = (*env)->GetIntField(env, jkernel, g_KernelHeightID);
 553     jdata = (*env)->GetObjectField(env, jkernel, g_KernelDataID);
 554     klen  = (*env)->GetArrayLength(env, jdata);
 555     kern  = (float *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL);
 556     if (kern == NULL) {
 557         /* out of memory exception already thrown */
 558         return 0;
 559     }
 560 
 561     if ((kwidth&0x1) == 0) {
 562         /* Kernel has even width */
 563         w = kwidth+1;
 564     }
 565     else {
 566         w = kwidth;
 567     }
 568     if ((kheight&0x1) == 0) {
 569         /* Kernel has even height */
 570         h = kheight+1;
 571     }
 572     else {
 573         h = kheight;
 574     }
 575 
 576     dkern = NULL;
 577     if (SAFE_TO_ALLOC_3(w, h, sizeof(mlib_d64))) {
 578         dkern = (mlib_d64 *)calloc(1, w * h * sizeof(mlib_d64));
 579     }
 580     if (dkern == NULL) {
 581         (*env)->ReleasePrimitiveArrayCritical(env, jdata, kern, JNI_ABORT);
 582         return 0;
 583     }
 584 
 585     /* Need to flip and find max value of the kernel.
 586      * Also, save the kernel values as mlib_d64 values.
 587      * The flip is to operate correctly with medialib,
 588      * which doesn't do the mathemetically correct thing,
 589      * i.e. it doesn't rotate the kernel by 180 degrees.
 590      * REMIND: This should perhaps be done at the Java
 591      * level by ConvolveOp.
 592      * REMIND: Should the max test be looking at absolute
 593      * values?
 594      * REMIND: What if klen != kheight * kwidth?
 595      */
 596     kmax = kern[klen-1];
 597     i = klen-1;
 598     for (y=0; y < kheight; y++) {
 599         for (x=0; x < kwidth; x++, i--) {
 600             dkern[y*w+x] = (mlib_d64) kern[i];
 601             if (kern[i] > kmax) {
 602                 kmax = kern[i];
 603             }
 604         }
 605     }
 606 
 607     (*env)->ReleasePrimitiveArrayCritical(env, jdata, kern, JNI_ABORT);
 608 
 609     if (kmax > 1<<16) {
 610         /* We can only handle 16 bit max */
 611         free(dkern);
 612         return 0;
 613     }
 614 
 615     /* Parse the source image */
 616     if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
 617         JNU_ThrowOutOfMemoryError(env, "Out of memory");
 618         free(dkern);
 619         return -1;
 620     }
 621 
 622     if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
 623         JNU_ThrowOutOfMemoryError(env, "Out of memory");
 624         free(srcRasterP);
 625         free(dkern);
 626         return -1;
 627     }
 628 
 629     /* Parse the source raster */
 630     if (awt_parseRaster(env, jsrc, srcRasterP) <= 0) {
 631         /* Can't handle any custom rasters */
 632         free(srcRasterP);
 633         free(dstRasterP);
 634         free(dkern);
 635         return 0;
 636     }
 637 
 638     /* Parse the destination raster */
 639     if (awt_parseRaster(env, jdst, dstRasterP) <= 0) {
 640         /* Can't handle any custom images */
 641         awt_freeParsedRaster(srcRasterP, TRUE);
 642         free(dstRasterP);
 643         free(dkern);
 644         return 0;
 645     }
 646 
 647     /* Allocate the arrays */
 648     if (allocateRasterArray(env, srcRasterP, &src, &sdata, TRUE) < 0) {
 649         /* Must be some problem */
 650         awt_freeParsedRaster(srcRasterP, TRUE);
 651         awt_freeParsedRaster(dstRasterP, TRUE);
 652         free(dkern);
 653         return 0;
 654     }
 655     if (allocateRasterArray(env, dstRasterP, &dst, &ddata, FALSE) < 0) {
 656         /* Must be some problem */
 657         freeDataArray(env, srcRasterP->jdata, src, sdata, NULL, NULL, NULL);
 658         awt_freeParsedRaster(srcRasterP, TRUE);
 659         awt_freeParsedRaster(dstRasterP, TRUE);
 660         free(dkern);
 661         return 0;
 662     }
 663 
 664     kdata = NULL;
 665     if (SAFE_TO_ALLOC_3(w, h, sizeof(mlib_s32))) {
 666         kdata = (mlib_s32 *)malloc(w * h * sizeof(mlib_s32));
 667     }
 668     if (kdata == NULL) {
 669         freeDataArray(env, srcRasterP->jdata, src, sdata,
 670                       dstRasterP->jdata, dst, ddata);
 671         awt_freeParsedRaster(srcRasterP, TRUE);
 672         awt_freeParsedRaster(dstRasterP, TRUE);
 673         free(dkern);
 674         return 0;
 675     }
 676 
 677     if ((*sMlibFns[MLIB_CONVKERNCVT].fptr)(kdata, &scale, dkern, w, h,
 678                                     mlib_ImageGetType(src)) != MLIB_SUCCESS) {
 679         freeDataArray(env, srcRasterP->jdata, src, sdata,
 680                       dstRasterP->jdata, dst, ddata);
 681         awt_freeParsedRaster(srcRasterP, TRUE);
 682         awt_freeParsedRaster(dstRasterP, TRUE);
 683         free(dkern);
 684         free(kdata);
 685         return 0;
 686     }
 687 
 688     if (s_printIt) {
 689         fprintf(stderr, "Orig Kernel(len=%d):\n",klen);
 690         for (y=kheight-1; y >= 0; y--) {
 691             for (x=kwidth-1; x >= 0; x--) {
 692                 fprintf(stderr, "%g ", dkern[y*w+x]);
 693             }
 694             fprintf(stderr, "\n");
 695         }
 696         fprintf(stderr, "New Kernel(scale=%d):\n", scale);
 697         for (y=kheight-1; y >= 0; y--) {
 698             for (x=kwidth-1; x >= 0; x--) {
 699                 fprintf(stderr, "%d ", kdata[y*w+x]);
 700             }
 701             fprintf(stderr, "\n");
 702         }
 703     }
 704 
 705     cmask = (1<<src->channels)-1;
 706     status = (*sMlibFns[MLIB_CONVMxN].fptr)(dst, src, kdata, w, h,
 707                                (w-1)/2, (h-1)/2, scale, cmask,
 708                                getMlibEdgeHint(edgeHint));
 709 
 710     if (status != MLIB_SUCCESS) {
 711         printMedialibError(status);
 712         retStatus = 0;
 713     }
 714 
 715     if (s_printIt) {
 716         unsigned int *dP;
 717         if (s_startOff != 0) {
 718             printf("Starting at %d\n", s_startOff);
 719         }
 720         if (sdata == NULL) {
 721             dP = (unsigned int *) mlib_ImageGetData(src);
 722         }
 723         else {
 724             dP = (unsigned int *) sdata;
 725         }
 726         printf("src is\n");
 727         for (i=0; i < 20; i++) {
 728             printf("%x ",dP[s_startOff+i]);
 729         }
 730         printf("\n");
 731         if (ddata == NULL) {
 732             dP = (unsigned int *)mlib_ImageGetData(dst);
 733         }
 734         else {
 735             dP = (unsigned int *) ddata;
 736         }
 737         printf("dst is\n");
 738         for (i=0; i < 20; i++) {
 739             printf("%x ",dP[s_startOff+i]);
 740         }
 741         printf("\n");
 742     }
 743 
 744     /* Means that we couldn't write directly into the destination buffer */
 745     if (ddata == NULL) {
 746         if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) {
 747             retStatus = setPixelsFormMlibImage(env, dstRasterP, dst);
 748         }
 749     }
 750 
 751     /* Release the pinned memory */
 752     freeDataArray(env, srcRasterP->jdata, src, sdata,
 753                   dstRasterP->jdata, dst, ddata);
 754     awt_freeParsedRaster(srcRasterP, TRUE);
 755     awt_freeParsedRaster(dstRasterP, TRUE);
 756     free(dkern);
 757     free(kdata);
 758 
 759     if (s_timeIt) (*stop_timer)(3600,1);
 760 
 761     return retStatus;
 762 }
 763 
 764 
 765 JNIEXPORT jint JNICALL
 766 Java_sun_awt_image_ImagingLib_transformBI(JNIEnv *env, jobject this,
 767                                           jobject jsrc,
 768                                           jobject jdst,
 769                                           jdoubleArray jmatrix,
 770                                           jint interpType)
 771 {
 772     mlib_image *src;
 773     mlib_image *dst;
 774     int i;
 775     int j = 0;
 776     int retStatus = 1;
 777     mlib_status status;
 778     double *matrix;
 779     mlib_d64 mtx[6];
 780     void *sdata;
 781     void *ddata;
 782     BufImageS_t *srcImageP;
 783     BufImageS_t *dstImageP;
 784     mlib_filter filter;
 785     mlibHintS_t hint;
 786     unsigned int *dP;
 787     int useIndexed;
 788     int nbands;
 789 
 790     /* This function requires a lot of local refs ??? Is 64 enough ??? */
 791     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
 792         return 0;
 793 
 794     if (s_nomlib) return 0;
 795     if (s_timeIt) {
 796         (*start_timer)(3600);
 797     }
 798 
 799     switch(interpType) {
 800     case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
 801         filter = MLIB_BILINEAR;
 802         break;
 803     case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
 804         filter = MLIB_NEAREST;
 805         break;
 806     case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
 807         filter = MLIB_BICUBIC;
 808         break;
 809     default:
 810         JNU_ThrowInternalError(env, "Unknown interpolation type");
 811         return -1;
 812     }
 813 
 814     if ((*env)->GetArrayLength(env, jmatrix) < 6) {
 815         /*
 816          * Very unlikely, however we should check for this:
 817          * if given matrix array is too short, we can't handle it
 818          */
 819         return 0;
 820     }
 821 
 822     matrix = (*env)->GetPrimitiveArrayCritical(env, jmatrix, NULL);
 823     if (matrix == NULL) {
 824         /* out of memory error already thrown */
 825         return 0;
 826     }
 827 
 828     /* Check for invalid double value in transformation matrix */
 829     for (j = 0; j < 6; j++) {
 830 
 831         if (!(IS_FINITE(matrix[j]))) {
 832             (*env)->ReleasePrimitiveArrayCritical(env, jmatrix, matrix, JNI_ABORT);
 833             return 0;
 834         }
 835     }
 836 
 837     if (s_printIt) {
 838         printf("matrix is %g %g %g %g %g %g\n", matrix[0], matrix[1],
 839                matrix[2], matrix[3], matrix[4], matrix[5]);
 840     }
 841 
 842     mtx[0] = matrix[0];
 843     mtx[1] = matrix[2];
 844     mtx[2] = matrix[4];
 845     mtx[3] = matrix[1];
 846     mtx[4] = matrix[3];
 847     mtx[5] = matrix[5];
 848 
 849     (*env)->ReleasePrimitiveArrayCritical(env, jmatrix, matrix, JNI_ABORT);
 850 
 851     /* Parse the source image */
 852     if (awt_parseImage(env, jsrc, &srcImageP, FALSE) <= 0) {
 853         /* Can't handle any custom images */
 854         return 0;
 855     }
 856 
 857     /* Parse the destination image */
 858     if (awt_parseImage(env, jdst, &dstImageP, FALSE) <= 0) {
 859         /* Can't handle any custom images */
 860         awt_freeParsedImage(srcImageP, TRUE);
 861         return 0;
 862     }
 863 
 864     /* REMIND!!  Can't assume that it is the same LUT!! */
 865     /* Fix 4213160, 4184283 */
 866     useIndexed = (srcImageP->cmodel.cmType == INDEX_CM_TYPE &&
 867                   dstImageP->cmodel.cmType == INDEX_CM_TYPE &&
 868                   srcImageP->raster.rasterType == dstImageP->raster.rasterType &&
 869                   srcImageP->raster.rasterType == COMPONENT_RASTER_TYPE);
 870 
 871     nbands = setImageHints(env, srcImageP, dstImageP, !useIndexed, TRUE,
 872                         FALSE, &hint);
 873     if (nbands < 1) {
 874         /* Can't handle any custom images */
 875         awt_freeParsedImage(srcImageP, TRUE);
 876         awt_freeParsedImage(dstImageP, TRUE);
 877         return 0;
 878     }
 879 
 880     /* Allocate the arrays */
 881     if (allocateArray(env, srcImageP, &src, &sdata, TRUE,
 882                       hint.cvtSrcToDefault, hint.addAlpha) < 0) {
 883         /* Must be some problem */
 884         awt_freeParsedImage(srcImageP, TRUE);
 885         awt_freeParsedImage(dstImageP, TRUE);
 886         return 0;
 887     }
 888     if (allocateArray(env, dstImageP, &dst, &ddata, FALSE,
 889                       hint.cvtToDst, FALSE) < 0) {
 890         /* Must be some problem */
 891         freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
 892         awt_freeParsedImage(srcImageP, TRUE);
 893         awt_freeParsedImage(dstImageP, TRUE);
 894         return 0;
 895     }
 896 #if 0
 897 fprintf(stderr,"Src----------------\n");
 898 fprintf(stderr,"Type : %d\n",src->type);
 899 fprintf(stderr,"Channels: %d\n",src->channels);
 900 fprintf(stderr,"Width   : %d\n",src->width);
 901 fprintf(stderr,"Height  : %d\n",src->height);
 902 fprintf(stderr,"Stride  : %d\n",src->stride);
 903 fprintf(stderr,"Flags   : %d\n",src->flags);
 904 
 905 fprintf(stderr,"Dst----------------\n");
 906 fprintf(stderr,"Type : %d\n",dst->type);
 907 fprintf(stderr,"Channels: %d\n",dst->channels);
 908 fprintf(stderr,"Width   : %d\n",dst->width);
 909 fprintf(stderr,"Height  : %d\n",dst->height);
 910 fprintf(stderr,"Stride  : %d\n",dst->stride);
 911 fprintf(stderr,"Flags   : %d\n",dst->flags);
 912 #endif
 913 
 914     if (dstImageP->cmodel.cmType == INDEX_CM_TYPE) {
 915         /* Need to clear the destination to the transparent pixel */
 916         unsigned char *cP = (unsigned char *)mlib_ImageGetData(dst);
 917 
 918         memset(cP, dstImageP->cmodel.transIdx,
 919                mlib_ImageGetWidth(dst)*mlib_ImageGetHeight(dst));
 920     }
 921     /* Perform the transformation */
 922     if ((status = (*sMlibFns[MLIB_AFFINE].fptr)(dst, src, mtx, filter,
 923                                   MLIB_EDGE_SRC_EXTEND) != MLIB_SUCCESS))
 924     {
 925         printMedialibError(status);
 926         freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
 927         awt_freeParsedImage(srcImageP, TRUE);
 928         awt_freeParsedImage(dstImageP, TRUE);
 929 
 930         return 0;
 931     }
 932 
 933     if (s_printIt) {
 934         if (sdata == NULL) {
 935             dP = (unsigned int *) mlib_ImageGetData(src);
 936         }
 937         else {
 938             dP = (unsigned int *) sdata;
 939         }
 940         printf("src is\n");
 941         for (i=0; i < 20; i++) {
 942             printf("%x ",dP[i]);
 943         }
 944         printf("\n");
 945         if (ddata == NULL) {
 946             dP = (unsigned int *)mlib_ImageGetData(dst);
 947         }
 948         else {
 949             dP = (unsigned int *) ddata;
 950         }
 951         printf("dst is\n");
 952         for (i=0; i < 20; i++) {
 953             printf("%x ",dP[i]);
 954         }
 955         printf("\n");
 956     }
 957 
 958     /* Means that we couldn't write directly into the destination buffer */
 959     if (ddata == NULL) {
 960         freeDataArray(env, srcImageP->raster.jdata, src, sdata,
 961                       NULL, NULL, NULL);
 962         /* Need to store it back into the array */
 963         if (storeImageArray(env, srcImageP, dstImageP, dst) < 0) {
 964             /* Error */
 965             retStatus = 0;
 966         }
 967         freeDataArray(env, NULL, NULL, NULL, dstImageP->raster.jdata,
 968                       dst, ddata);
 969     }
 970     else {
 971         /* Release the pinned memory */
 972         freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
 973     }
 974 
 975     awt_freeParsedImage(srcImageP, TRUE);
 976     awt_freeParsedImage(dstImageP, TRUE);
 977 
 978     if (s_timeIt) (*stop_timer)(3600,1);
 979 
 980     return retStatus;
 981 }
 982 
 983 JNIEXPORT jint JNICALL
 984 Java_sun_awt_image_ImagingLib_transformRaster(JNIEnv *env, jobject this,
 985                                               jobject jsrc,
 986                                               jobject jdst,
 987                                               jdoubleArray jmatrix,
 988                                               jint interpType)
 989 {
 990     mlib_image *src;
 991     mlib_image *dst;
 992     int i;
 993     int j = 0;
 994     int retStatus = 1;
 995     mlib_status status;
 996     double *matrix;
 997     mlib_d64 mtx[6];
 998     void *sdata;
 999     void *ddata;
1000     RasterS_t *srcRasterP;
1001     RasterS_t *dstRasterP;
1002     mlib_filter filter;
1003     unsigned int *dP;
1004 
1005     /* This function requires a lot of local refs ??? Is 64 enough ??? */
1006     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
1007         return 0;
1008 
1009     if (s_nomlib) return 0;
1010     if (s_timeIt) {
1011         (*start_timer)(3600);
1012     }
1013 
1014     switch(interpType) {
1015     case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
1016         filter = MLIB_BILINEAR;
1017         break;
1018     case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
1019         filter = MLIB_NEAREST;
1020         break;
1021     case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
1022         filter = MLIB_BICUBIC;
1023         break;
1024     default:
1025         JNU_ThrowInternalError(env, "Unknown interpolation type");
1026         return -1;
1027     }
1028 
1029     if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
1030         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1031         return -1;
1032     }
1033 
1034     if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
1035         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1036         free(srcRasterP);
1037         return -1;
1038     }
1039 
1040     if ((*env)->GetArrayLength(env, jmatrix) < 6) {
1041         /*
1042          * Very unlikely, however we should check for this:
1043          * if given matrix array is too short, we can't handle it.
1044          */
1045         free(srcRasterP);
1046         free(dstRasterP);
1047         return 0;
1048     }
1049 
1050     matrix = (*env)->GetPrimitiveArrayCritical(env, jmatrix, NULL);
1051     if (matrix == NULL) {
1052         /* out of memory error already thrown */
1053         free(srcRasterP);
1054         free(dstRasterP);
1055         return 0;
1056     }
1057 
1058     /* Check for invalid double value in transformation matrix */
1059     for (j = 0; j < 6; j++) {
1060 
1061         if (!(IS_FINITE(matrix[j]))) {
1062             (*env)->ReleasePrimitiveArrayCritical(env, jmatrix, matrix, JNI_ABORT);
1063             free(srcRasterP);
1064             free(dstRasterP);
1065             return 0;
1066         }
1067     }
1068 
1069     if (s_printIt) {
1070         printf("matrix is %g %g %g %g %g %g\n", matrix[0], matrix[1],
1071                matrix[2], matrix[3], matrix[4], matrix[5]);
1072     }
1073 
1074     mtx[0] = matrix[0];
1075     mtx[1] = matrix[2];
1076     mtx[2] = matrix[4];
1077     mtx[3] = matrix[1];
1078     mtx[4] = matrix[3];
1079     mtx[5] = matrix[5];
1080 
1081     (*env)->ReleasePrimitiveArrayCritical(env, jmatrix, matrix, JNI_ABORT);
1082 
1083     /* Parse the source raster */
1084     if (awt_parseRaster(env, jsrc, srcRasterP) <= 0) {
1085         /* Can't handle any custom rasters */
1086         free(srcRasterP);
1087         free(dstRasterP);
1088         return 0;
1089     }
1090 
1091     /* Parse the destination raster */
1092     if (awt_parseRaster(env, jdst, dstRasterP) <= 0) {
1093         /* Can't handle any custom images */
1094         awt_freeParsedRaster(srcRasterP, TRUE);
1095         free(dstRasterP);
1096         return 0;
1097     }
1098 
1099     /* Allocate the arrays */
1100     if (allocateRasterArray(env, srcRasterP, &src, &sdata, TRUE) < 0) {
1101         /* Must be some problem */
1102         awt_freeParsedRaster(srcRasterP, TRUE);
1103         awt_freeParsedRaster(dstRasterP, TRUE);
1104         return 0;
1105     }
1106     if (allocateRasterArray(env, dstRasterP, &dst, &ddata, FALSE) < 0) {
1107         /* Must be some problem */
1108         freeDataArray(env, srcRasterP->jdata, src, sdata, NULL, NULL, NULL);
1109         awt_freeParsedRaster(srcRasterP, TRUE);
1110         awt_freeParsedRaster(dstRasterP, TRUE);
1111         return 0;
1112     }
1113 
1114 #if 0
1115 fprintf(stderr,"Src----------------\n");
1116 fprintf(stderr,"Type : %d\n",src->type);
1117 fprintf(stderr,"Channels: %d\n",src->channels);
1118 fprintf(stderr,"Width   : %d\n",src->width);
1119 fprintf(stderr,"Height  : %d\n",src->height);
1120 fprintf(stderr,"Stride  : %d\n",src->stride);
1121 fprintf(stderr,"Flags   : %d\n",src->flags);
1122 
1123 fprintf(stderr,"Dst----------------\n");
1124 fprintf(stderr,"Type : %d\n",dst->type);
1125 fprintf(stderr,"Channels: %d\n",dst->channels);
1126 fprintf(stderr,"Width   : %d\n",dst->width);
1127 fprintf(stderr,"Height  : %d\n",dst->height);
1128 fprintf(stderr,"Stride  : %d\n",dst->stride);
1129 fprintf(stderr,"Flags   : %d\n",dst->flags);
1130 #endif
1131 
1132     {
1133         unsigned char *cP = (unsigned char *)mlib_ImageGetData(dst);
1134 
1135         memset(cP, 0, mlib_ImageGetWidth(dst)*mlib_ImageGetHeight(dst));
1136     }
1137 
1138     /* Perform the transformation */
1139     if ((status = (*sMlibFns[MLIB_AFFINE].fptr)(dst, src, mtx, filter,
1140                                   MLIB_EDGE_SRC_EXTEND) != MLIB_SUCCESS))
1141     {
1142         printMedialibError(status);
1143         /* REMIND: Free the regions */
1144         return 0;
1145     }
1146 
1147     if (s_printIt) {
1148         if (sdata == NULL) {
1149             dP = (unsigned int *) mlib_ImageGetData(src);
1150         }
1151         else {
1152             dP = (unsigned int *) sdata;
1153         }
1154         printf("src is\n");
1155         for (i=0; i < 20; i++) {
1156             printf("%x ",dP[i]);
1157         }
1158         printf("\n");
1159         if (ddata == NULL) {
1160             dP = (unsigned int *)mlib_ImageGetData(dst);
1161         }
1162         else {
1163             dP = (unsigned int *) ddata;
1164         }
1165         printf("dst is\n");
1166         for (i=0; i < 20; i++) {
1167             printf("%x ",dP[i]);
1168         }
1169         printf("\n");
1170     }
1171 
1172     /* Means that we couldn't write directly into the destination buffer */
1173     if (ddata == NULL) {
1174         /* Need to store it back into the array */
1175         if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) {
1176             (*env)->ExceptionClear(env); // Could not store the array, try another way
1177             retStatus = setPixelsFormMlibImage(env, dstRasterP, dst);
1178         }
1179     }
1180 
1181     /* Release the pinned memory */
1182     freeDataArray(env, srcRasterP->jdata, src, sdata,
1183                   dstRasterP->jdata, dst, ddata);
1184 
1185     awt_freeParsedRaster(srcRasterP, TRUE);
1186     awt_freeParsedRaster(dstRasterP, TRUE);
1187 
1188     if (s_timeIt) (*stop_timer)(3600,1);
1189 
1190     return retStatus;
1191 }
1192 
1193 typedef struct {
1194     jobject jArray;
1195     jsize length;
1196     unsigned char *table;
1197 } LookupArrayInfo;
1198 
1199 #define NLUT 8
1200 
1201 #ifdef _LITTLE_ENDIAN
1202 #define INDEXES    { 3, 2, 1, 0, 7, 6, 5, 4 }
1203 #else
1204 #define INDEXES    { 0, 1, 2, 3, 4, 5, 6, 7 }
1205 #endif
1206 
1207 static int lookupShortData(mlib_image* src, mlib_image* dst,
1208     LookupArrayInfo* lookup)
1209 {
1210     int x, y;
1211     unsigned int mask = NLUT-1;
1212 
1213     unsigned short* srcLine = (unsigned short*)src->data;
1214     unsigned char* dstLine = (unsigned char*)dst->data;
1215 
1216     static int indexes[NLUT] = INDEXES;
1217 
1218     if (src->width != dst->width || src->height != dst->height) {
1219         return 0;
1220     }
1221 
1222     for (y=0; y < src->height; y++) {
1223         int nloop, nx;
1224         int npix = src->width;
1225 
1226         unsigned short* srcPixel = srcLine;
1227         unsigned char* dstPixel = dstLine;
1228 
1229 #ifdef SIMPLE_LOOKUP_LOOP
1230         for (x=0; status && x < width; x++) {
1231             unsigned short s = *srcPixel++;
1232             if (s >= lookup->length) {
1233                 /* we can not handle source image using
1234                 * byte lookup table. Fall back to processing
1235                 * images in java
1236                 */
1237                 return 0;
1238             }
1239             *dstPixel++ = lookup->table[s];
1240         }
1241 #else
1242         /* Get to 32 bit-aligned point */
1243         while(((uintptr_t)dstPixel & 0x3) != 0 && npix>0) {
1244             unsigned short s = *srcPixel++;
1245             if (s >= lookup->length) {
1246                 return 0;
1247             }
1248             *dstPixel++ = lookup->table[s];
1249             npix--;
1250         }
1251 
1252         /*
1253          * Do NLUT pixels per loop iteration.
1254          * Pack into ints and write out 2 at a time.
1255          */
1256         nloop = npix/NLUT;
1257         nx = npix%NLUT;
1258 
1259         for(x=nloop; x!=0; x--) {
1260             int i = 0;
1261             int* dstP = (int*)dstPixel;
1262 
1263             for (i = 0; i < NLUT; i++) {
1264                 if (srcPixel[i] >= lookup->length) {
1265                     return 0;
1266                 }
1267             }
1268 
1269             dstP[0] = (int)
1270                 ((lookup->table[srcPixel[indexes[0]]] << 24) |
1271                  (lookup->table[srcPixel[indexes[1]]] << 16) |
1272                  (lookup->table[srcPixel[indexes[2]]] << 8)  |
1273                   lookup->table[srcPixel[indexes[3]]]);
1274             dstP[1] = (int)
1275                 ((lookup->table[srcPixel[indexes[4]]] << 24) |
1276                  (lookup->table[srcPixel[indexes[5]]] << 16) |
1277                  (lookup->table[srcPixel[indexes[6]]] << 8)  |
1278                   lookup->table[srcPixel[indexes[7]]]);
1279 
1280 
1281             dstPixel += NLUT;
1282             srcPixel += NLUT;
1283         }
1284 
1285         /*
1286          * Complete any remaining pixels
1287          */
1288         for(x=nx; x!=0; x--) {
1289             unsigned short s = *srcPixel++;
1290             if (s >= lookup->length) {
1291                 return 0;
1292             }
1293             *dstPixel++ = lookup->table[s];
1294         }
1295 #endif
1296 
1297         dstLine += dst->stride;     // array of bytes, scan stride in bytes
1298         srcLine += src->stride / 2; // array of shorts, scan stride in bytes
1299     }
1300     return 1;
1301 }
1302 
1303 JNIEXPORT jint JNICALL
1304 Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject thisLib,
1305                                            jobject jsrc, jobject jdst,
1306                                            jobjectArray jtableArrays)
1307 {
1308     mlib_image *src;
1309     mlib_image *dst;
1310     void *sdata, *ddata;
1311     unsigned char **tbl;
1312     unsigned char lut[256];
1313     int retStatus = 1;
1314     int i;
1315     mlib_status status;
1316     int lut_nbands;
1317     LookupArrayInfo *jtable;
1318     BufImageS_t *srcImageP, *dstImageP;
1319     int nbands;
1320     int ncomponents;
1321     mlibHintS_t hint;
1322 
1323     /* This function requires a lot of local refs ??? Is 64 enough ??? */
1324     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
1325         return 0;
1326 
1327     if (s_nomlib) return 0;
1328     if (s_timeIt) (*start_timer)(3600);
1329 
1330     /* Parse the source image */
1331     if (awt_parseImage(env, jsrc, &srcImageP, FALSE) <= 0) {
1332         /* Can't handle any custom images */
1333         return 0;
1334     }
1335 
1336     /* Parse the destination image */
1337     if (awt_parseImage(env, jdst, &dstImageP, FALSE) <= 0) {
1338         /* Can't handle any custom images */
1339         awt_freeParsedImage(srcImageP, TRUE);
1340         return 0;
1341     }
1342 
1343     nbands = setImageHints(env, srcImageP, dstImageP, FALSE, TRUE,
1344                         FALSE, &hint);
1345 
1346     if (nbands < 1 || nbands > srcImageP->cmodel.numComponents) {
1347         /* Can't handle any custom images */
1348         awt_freeParsedImage(srcImageP, TRUE);
1349         awt_freeParsedImage(dstImageP, TRUE);
1350         return 0;
1351     }
1352 
1353     ncomponents = srcImageP->cmodel.isDefaultCompatCM
1354         ? 4
1355         : srcImageP->cmodel.numComponents;
1356 
1357     /* Make sure that color order can be used for
1358      * re-ordering of lookup arrays.
1359      */
1360     for (i = 0; i < nbands; i++) {
1361         int idx = srcImageP->hints.colorOrder[i];
1362 
1363         if (idx < 0 || idx >= ncomponents) {
1364             awt_freeParsedImage(srcImageP, TRUE);
1365             awt_freeParsedImage(dstImageP, TRUE);
1366             return 0;
1367         }
1368     }
1369 
1370     lut_nbands = (*env)->GetArrayLength(env, jtableArrays);
1371 
1372     if (lut_nbands > ncomponents) {
1373         lut_nbands = ncomponents;
1374     }
1375 
1376     tbl = NULL;
1377     if (SAFE_TO_ALLOC_2(ncomponents, sizeof(unsigned char *))) {
1378         tbl = (unsigned char **)
1379             calloc(1, ncomponents * sizeof(unsigned char *));
1380     }
1381 
1382     jtable = NULL;
1383     if (SAFE_TO_ALLOC_2(lut_nbands, sizeof(LookupArrayInfo))) {
1384         jtable = (LookupArrayInfo *)malloc(lut_nbands * sizeof (LookupArrayInfo));
1385     }
1386 
1387     if (tbl == NULL || jtable == NULL) {
1388         if (tbl != NULL) free(tbl);
1389         if (jtable != NULL) free(jtable);
1390         awt_freeParsedImage(srcImageP, TRUE);
1391         awt_freeParsedImage(dstImageP, TRUE);
1392         JNU_ThrowNullPointerException(env, "NULL LUT");
1393         return 0;
1394     }
1395     /* Need to grab these pointers before we lock down arrays */
1396     for (i=0; i < lut_nbands; i++) {
1397         jtable[i].jArray = (*env)->GetObjectArrayElement(env, jtableArrays, i);
1398 
1399         if (jtable[i].jArray != NULL) {
1400             jtable[i].length = (*env)->GetArrayLength(env, jtable[i].jArray);
1401             jtable[i].table = NULL;
1402 
1403             if (jtable[i].length < 256) {
1404                 /* we may read outside the table during lookup */
1405                 jtable[i].jArray = NULL;
1406                 jtable[i].length = 0;
1407             }
1408         }
1409         if (jtable[i].jArray == NULL) {
1410             free(tbl);
1411             free(jtable);
1412             awt_freeParsedImage(srcImageP, TRUE);
1413             awt_freeParsedImage(dstImageP, TRUE);
1414             return 0;
1415         }
1416     }
1417 
1418     /* Allocate the arrays */
1419     if (allocateArray(env, srcImageP, &src, &sdata, TRUE, FALSE, FALSE) < 0) {
1420         /* Must be some problem */
1421         free(tbl);
1422         free(jtable);
1423         awt_freeParsedImage(srcImageP, TRUE);
1424         awt_freeParsedImage(dstImageP, TRUE);
1425         return 0;
1426     }
1427     if (allocateArray(env, dstImageP, &dst, &ddata, FALSE, FALSE, FALSE) < 0) {
1428         /* Must be some problem */
1429         free(tbl);
1430         free(jtable);
1431         freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
1432         awt_freeParsedImage(srcImageP, TRUE);
1433         awt_freeParsedImage(dstImageP, TRUE);
1434         return 0;
1435     }
1436 
1437     /* Set up a straight lut so we don't mess around with alpha */
1438     /*
1439      * NB: medialib lookup routine expects lookup array for each
1440      * component of source image including alpha.
1441      * If lookup table we got form the java layer does not contain
1442      * sufficient number of lookup arrays we add references to identity
1443      * lookup array to make medialib happier.
1444      */
1445     if (lut_nbands < ncomponents) {
1446         int j;
1447         /* REMIND: This should be the size of the input lut!! */
1448         for (j=0; j < 256; j++) {
1449             lut[j] = j;
1450         }
1451         for (j=0; j < ncomponents; j++) {
1452             tbl[j] = lut;
1453         }
1454     }
1455 
1456     for (i=0; i < lut_nbands; i++) {
1457         jtable[i].table = (unsigned char *)
1458             (*env)->GetPrimitiveArrayCritical(env, jtable[i].jArray, NULL);
1459         if (jtable[i].table == NULL) {
1460             /* Free what we've got so far. */
1461             int j;
1462             for (j = 0; j < i; j++) {
1463                 (*env)->ReleasePrimitiveArrayCritical(env,
1464                                                       jtable[j].jArray,
1465                                                       (jbyte *) jtable[j].table,
1466                                                       JNI_ABORT);
1467             }
1468             free(tbl);
1469             free(jtable);
1470             freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
1471             awt_freeParsedImage(srcImageP, TRUE);
1472             awt_freeParsedImage(dstImageP, TRUE);
1473             return 0;
1474         }
1475         tbl[srcImageP->hints.colorOrder[i]] = jtable[i].table;
1476     }
1477 
1478     if (lut_nbands == 1) {
1479         for (i=1; i < nbands -
1480                  srcImageP->cmodel.supportsAlpha; i++) {
1481                      tbl[srcImageP->hints.colorOrder[i]] = jtable[0].table;
1482         }
1483     }
1484 
1485     /* Mlib needs 16bit lookuptable and must be signed! */
1486     if (src->type == MLIB_SHORT) {
1487         if (dst->type == MLIB_BYTE) {
1488             if (nbands > 1) {
1489                 retStatus = 0;
1490             }
1491             else {
1492                 retStatus = lookupShortData(src, dst, &jtable[0]);
1493             }
1494         }
1495         /* How about ddata == null? */
1496     }
1497     else if ((status = (*sMlibFns[MLIB_LOOKUP].fptr)(dst, src,
1498                                       (void **)tbl) != MLIB_SUCCESS)) {
1499         printMedialibError(status);
1500         retStatus = 0;
1501     }
1502 
1503    /* Release the LUT */
1504     for (i=0; i < lut_nbands; i++) {
1505         (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray,
1506             (jbyte *) jtable[i].table, JNI_ABORT);
1507     }
1508     free ((void *) jtable);
1509     free ((void *) tbl);
1510 
1511     /*
1512      * Means that we couldn't write directly into
1513      * the destination buffer
1514      */
1515     if (ddata == NULL) {
1516 
1517         /* Need to store it back into the array */
1518         if (storeImageArray(env, srcImageP, dstImageP, dst) < 0) {
1519             /* Error */
1520             retStatus = 0;
1521         }
1522     }
1523 
1524 
1525     /* Release the pinned memory */
1526     freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
1527 
1528     awt_freeParsedImage(srcImageP, TRUE);
1529     awt_freeParsedImage(dstImageP, TRUE);
1530 
1531     if (s_timeIt) (*stop_timer)(3600, 1);
1532 
1533     return retStatus;
1534 }
1535 
1536 JNIEXPORT jint JNICALL
1537 Java_sun_awt_image_ImagingLib_lookupByteRaster(JNIEnv *env,
1538                                                jobject this,
1539                                                jobject jsrc,
1540                                                jobject jdst,
1541                                                jobjectArray jtableArrays)
1542 {
1543     RasterS_t*     srcRasterP;
1544     RasterS_t*     dstRasterP;
1545     mlib_image*    src;
1546     mlib_image*    dst;
1547     void*          sdata;
1548     void*          ddata;
1549     LookupArrayInfo jtable[4];
1550     unsigned char* mlib_lookupTable[4];
1551     int            i;
1552     int            retStatus = 1;
1553     mlib_status    status;
1554     int            jlen;
1555     int            lut_nbands;
1556     int            src_nbands;
1557     int            dst_nbands;
1558     unsigned char  ilut[256];
1559 
1560     /* This function requires a lot of local refs ??? Is 64 enough ??? */
1561     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
1562         return 0;
1563 
1564     if (s_nomlib) return 0;
1565     if (s_timeIt) (*start_timer)(3600);
1566 
1567     if ((srcRasterP = (RasterS_t*) calloc(1, sizeof(RasterS_t))) == NULL) {
1568         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1569         return -1;
1570     }
1571 
1572     if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
1573         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1574         free(srcRasterP);
1575         return -1;
1576     }
1577 
1578     /* Parse the source raster - reject custom images */
1579     if (awt_parseRaster(env, jsrc, srcRasterP) <= 0) {
1580         free(srcRasterP);
1581         free(dstRasterP);
1582         return 0;
1583     }
1584 
1585     /* Parse the destination image - reject custom images */
1586     if (awt_parseRaster(env, jdst, dstRasterP) <= 0) {
1587         awt_freeParsedRaster(srcRasterP, TRUE);
1588         free(dstRasterP);
1589         return 0;
1590     }
1591 
1592     jlen = (*env)->GetArrayLength(env, jtableArrays);
1593 
1594     lut_nbands = jlen;
1595     src_nbands = srcRasterP->numBands;
1596     dst_nbands = dstRasterP->numBands;
1597 
1598     /* adjust number of lookup bands */
1599     if (lut_nbands > src_nbands) {
1600         lut_nbands = src_nbands;
1601     }
1602 
1603     /* MediaLib can't do more than 4 bands */
1604     if (src_nbands <= 0 || src_nbands > 4 ||
1605         dst_nbands <= 0 || dst_nbands > 4 ||
1606         lut_nbands <= 0 || lut_nbands > 4 ||
1607         src_nbands != dst_nbands ||
1608         ((lut_nbands != 1) && (lut_nbands != src_nbands)))
1609     {
1610         // we should free parsed rasters here
1611         awt_freeParsedRaster(srcRasterP, TRUE);
1612         awt_freeParsedRaster(dstRasterP, TRUE);
1613         return 0;
1614     }
1615 
1616     /* Allocate the raster arrays */
1617     if (allocateRasterArray(env, srcRasterP, &src, &sdata, TRUE) < 0) {
1618         /* Must be some problem */
1619         awt_freeParsedRaster(srcRasterP, TRUE);
1620         awt_freeParsedRaster(dstRasterP, TRUE);
1621         return 0;
1622     }
1623     if (allocateRasterArray(env, dstRasterP, &dst, &ddata, FALSE) < 0) {
1624         /* Must be some problem */
1625         freeDataArray(env, srcRasterP->jdata, src, sdata, NULL, NULL, NULL);
1626         awt_freeParsedRaster(srcRasterP, TRUE);
1627         awt_freeParsedRaster(dstRasterP, TRUE);
1628         return 0;
1629     }
1630 
1631     /*
1632      * Well, until now we have analyzed number of bands in
1633      * src and dst rasters.
1634      * However, it is not enough because medialib lookup routine uses
1635      * number of channels of medialib image. Note that in certain
1636      * case number of channels may differs form the number of bands.
1637      * Good example is raster that is used in TYPE_INT_RGB buffered
1638      * image: it has 3 bands, but their medialib representation has
1639      * 4 channels.
1640      *
1641      * In order to avoid the lookup routine failure, we need:
1642      *
1643      * 1. verify that src and dst have same number of channels.
1644      * 2. provide lookup array for every channel. If we have "extra"
1645      *    channel (like the raster described above) then we need to
1646      *    provide identical lookup array.
1647      */
1648     if (src->channels != dst->channels) {
1649         freeDataArray(env, srcRasterP->jdata, src, sdata,
1650                       dstRasterP->jdata, dst, ddata);
1651 
1652         awt_freeParsedRaster(srcRasterP, TRUE);
1653         awt_freeParsedRaster(dstRasterP, TRUE);
1654         return 0;
1655     }
1656 
1657     if (src_nbands < src->channels) {
1658         for (i = 0; i < 256; i++) {
1659             ilut[i] = i;
1660         }
1661     }
1662 
1663 
1664     /* Get references to the lookup table arrays */
1665     /* Need to grab these pointers before we lock down arrays */
1666     for (i=0; i < lut_nbands; i++) {
1667         jtable[i].jArray = (*env)->GetObjectArrayElement(env, jtableArrays, i);
1668         jtable[i].table = NULL;
1669         if (jtable[i].jArray != NULL) {
1670             jtable[i].length = (*env)->GetArrayLength(env, jtable[i].jArray);
1671             if (jtable[i].length < 256) {
1672                  /* we may read outside the table during lookup */
1673                 jtable[i].jArray = NULL;
1674             }
1675         }
1676 
1677         if (jtable[i].jArray == NULL)
1678         {
1679             freeDataArray(env, srcRasterP->jdata, src, sdata,
1680                           dstRasterP->jdata, dst, ddata);
1681 
1682             awt_freeParsedRaster(srcRasterP, TRUE);
1683             awt_freeParsedRaster(dstRasterP, TRUE);
1684             return 0;
1685         }
1686     }
1687 
1688     for (i=0; i < lut_nbands; i++) {
1689         jtable[i].table = (unsigned char *)
1690             (*env)->GetPrimitiveArrayCritical(env, jtable[i].jArray, NULL);
1691         if (jtable[i].table == NULL) {
1692             /* Free what we've got so far. */
1693             int j;
1694             for (j = 0; j < i; j++) {
1695                 (*env)->ReleasePrimitiveArrayCritical(env,
1696                                                       jtable[j].jArray,
1697                                                       (jbyte *) jtable[j].table,
1698                                                       JNI_ABORT);
1699             }
1700             freeDataArray(env, srcRasterP->jdata, src, sdata,
1701                           dstRasterP->jdata, dst, ddata);
1702             awt_freeParsedRaster(srcRasterP, TRUE);
1703             awt_freeParsedRaster(dstRasterP, TRUE);
1704             return 0;
1705         }
1706         mlib_lookupTable[i] = jtable[i].table;
1707     }
1708 
1709     /*
1710      * Medialib routine expects lookup array for each band of raster.
1711      * Setup the  rest of lookup arrays if supplied lookup table
1712      * contains single lookup array.
1713      */
1714     for (i = lut_nbands; i < src_nbands; i++) {
1715         mlib_lookupTable[i] = jtable[0].table;
1716     }
1717 
1718     /*
1719      * Setup lookup array for "extra" channels
1720      */
1721     for ( ; i < src->channels; i++) {
1722         mlib_lookupTable[i] = ilut;
1723     }
1724 
1725     /* Mlib needs 16bit lookuptable and must be signed! */
1726     if (src->type == MLIB_SHORT) {
1727         if (dst->type == MLIB_BYTE) {
1728             if (lut_nbands > 1) {
1729                 retStatus = 0;
1730             } else {
1731                 retStatus = lookupShortData(src, dst, &jtable[0]);
1732             }
1733         }
1734         /* How about ddata == null? */
1735     } else if ((status = (*sMlibFns[MLIB_LOOKUP].fptr)(dst, src,
1736                                       (void **)mlib_lookupTable) != MLIB_SUCCESS)) {
1737         printMedialibError(status);
1738         retStatus = 0;
1739     }
1740 
1741     /* Release the LUT */
1742     for (i=0; i < lut_nbands; i++) {
1743         (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray,
1744                                               (jbyte *) jtable[i].table, JNI_ABORT);
1745     }
1746 
1747     /*
1748      * Means that we couldn't write directly into
1749      * the destination buffer
1750      */
1751     if (ddata == NULL) {
1752         if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) {
1753             retStatus = setPixelsFormMlibImage(env, dstRasterP, dst);
1754         }
1755     }
1756 
1757     /* Release the pinned memory */
1758     freeDataArray(env, srcRasterP->jdata, src, sdata,
1759                   dstRasterP->jdata, dst, ddata);
1760 
1761     awt_freeParsedRaster(srcRasterP, TRUE);
1762     awt_freeParsedRaster(dstRasterP, TRUE);
1763 
1764     if (s_timeIt) (*stop_timer)(3600, 1);
1765 
1766     return retStatus;
1767 }
1768 
1769 
1770 JNIEXPORT jboolean JNICALL
1771 Java_sun_awt_image_ImagingLib_init(JNIEnv *env, jclass thisClass) {
1772     char *start;
1773     if (getenv("IMLIB_DEBUG")) {
1774         start_timer = awt_setMlibStartTimer();
1775         stop_timer = awt_setMlibStopTimer();
1776         if (start_timer && stop_timer) {
1777             s_timeIt = 1;
1778         }
1779     }
1780 
1781     if (getenv("IMLIB_PRINT")) {
1782         s_printIt = 1;
1783     }
1784     if ((start = getenv("IMLIB_START")) != NULL) {
1785         sscanf(start, "%d", &s_startOff);
1786     }
1787 
1788     if (getenv ("IMLIB_NOMLIB")) {
1789         s_nomlib = 1;
1790         return JNI_FALSE;
1791     }
1792 
1793     /* This function is platform-dependent and is in awt_mlib.c */
1794     if (awt_getImagingLib(env, (mlibFnS_t *)&sMlibFns, &sMlibSysFns) !=
1795         MLIB_SUCCESS)
1796     {
1797         s_nomlib = 1;
1798         return JNI_FALSE;
1799     }
1800     return JNI_TRUE;
1801 }
1802 
1803 /* REMIND: How to specify border? */
1804 static void extendEdge(JNIEnv *env, BufImageS_t *imageP,
1805                        int *widthP, int *heightP) {
1806     RasterS_t *rasterP = &imageP->raster;
1807     int width;
1808     int height;
1809     /* Useful for convolution? */
1810 
1811     jobject jbaseraster = (*env)->GetObjectField(env, rasterP->jraster,
1812                                                  g_RasterBaseRasterID);
1813     width = rasterP->width;
1814     height = rasterP->height;
1815 #ifdef WORKING
1816     if (! JNU_IsNull(env, jbaseraster) &&
1817         !(*env)->IsSameObject(env, rasterP->jraster, jbaseraster)) {
1818         int xOff;
1819         int yOff;
1820         int baseWidth;
1821         int baseHeight;
1822         int baseXoff;
1823         int baseYoff;
1824         /* Not the same object so get the width and height */
1825         xOff = (*env)->GetIntField(env, rasterP->jraster, g_RasterXOffsetID);
1826         yOff = (*env)->GetIntField(env, rasterP->jraster, g_RasterYOffsetID);
1827         baseWidth  = (*env)->GetIntField(env, jbaseraster, g_RasterWidthID);
1828         baseHeight = (*env)->GetIntField(env, jbaseraster, g_RasterHeightID);
1829         baseXoff   = (*env)->GetIntField(env, jbaseraster, g_RasterXOffsetID);
1830         baseYoff   = (*env)->GetIntField(env, jbaseraster, g_RasterYOffsetID);
1831 
1832         if (xOff + rasterP->width < baseXoff + baseWidth) {
1833             /* Can use edge */
1834             width++;
1835         }
1836         if (yOff + rasterP->height < baseYoff + baseHeight) {
1837             /* Can use edge */
1838             height++;
1839         }
1840 
1841     }
1842 #endif
1843 
1844 }
1845 
1846 static int
1847 setImageHints(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
1848               int expandICM, int useAlpha,
1849               int premultiply, mlibHintS_t *hintP)
1850 {
1851     ColorModelS_t *srcCMP = &srcP->cmodel;
1852     ColorModelS_t *dstCMP = &dstP->cmodel;
1853     int nbands = 0;
1854     int ncomponents;
1855 
1856     hintP->dataType = srcP->raster.dataType;
1857     hintP->addAlpha = FALSE;
1858 
1859     /* Are the color spaces the same? */
1860     if (srcCMP->csType != dstCMP->csType) {
1861         /* If the src is GRAY and dst RGB, we can handle it */
1862         if (!(srcCMP->csType == java_awt_color_ColorSpace_TYPE_GRAY &&
1863               dstCMP->csType == java_awt_color_ColorSpace_TYPE_RGB)) {
1864             /* Nope, need to handle that in java for now */
1865             return -1;
1866         }
1867         else {
1868             hintP->cvtSrcToDefault = TRUE;
1869         }
1870     }
1871     else {
1872         if (srcP->hints.needToExpand) {
1873             hintP->cvtSrcToDefault = TRUE;
1874         }
1875         else {
1876             /* Need to initialize this */
1877             hintP->cvtSrcToDefault = FALSE;
1878         }
1879     }
1880 
1881     ncomponents = srcCMP->numComponents;
1882     if ((useAlpha == 0) && srcCMP->supportsAlpha) {
1883         ncomponents--;  /* ?? */
1884         /* Not really, more like shrink src to get rid of alpha */
1885         hintP->cvtSrcToDefault = TRUE;
1886     }
1887 
1888     hintP->dataType = srcP->raster.dataType;
1889     if (hintP->cvtSrcToDefault == FALSE) {
1890         if (srcCMP->cmType == INDEX_CM_TYPE) {
1891             if (expandICM) {
1892                 nbands = srcCMP->numComponents;
1893                 hintP->cvtSrcToDefault = TRUE;
1894 
1895                 if (dstCMP->isDefaultCompatCM) {
1896                     hintP->allocDefaultDst = FALSE;
1897                     hintP->cvtToDst = FALSE;
1898                 }
1899                 else if (dstCMP->isDefaultCompatCM) {
1900                     hintP->allocDefaultDst = FALSE;
1901                     hintP->cvtToDst = FALSE;
1902                 }
1903             }
1904             else {
1905                 nbands = 1;
1906                 hintP->cvtSrcToDefault = FALSE;
1907             }
1908 
1909         }
1910         else {
1911             if (srcP->hints.packing & INTERLEAVED) {
1912                 nbands = srcCMP->numComponents;
1913             }
1914             else {
1915                 nbands = 1;
1916             }
1917 
1918             /* Look at the packing */
1919             if ((srcP->hints.packing&BYTE_INTERLEAVED)==BYTE_INTERLEAVED ||
1920                 (srcP->hints.packing&SHORT_INTERLEAVED)==SHORT_INTERLEAVED||
1921                 (srcP->hints.packing&BYTE_SINGLE_BAND) == BYTE_SINGLE_BAND||
1922                 (srcP->hints.packing&SHORT_SINGLE_BAND)==SHORT_SINGLE_BAND||
1923                 (srcP->hints.packing&BYTE_BANDED)  == BYTE_BANDED       ||
1924                 (srcP->hints.packing&SHORT_BANDED) == SHORT_BANDED) {
1925                 /* Can use src directly */
1926                 hintP->cvtSrcToDefault = FALSE;
1927             }
1928             else {
1929                 /* Must be packed or custom */
1930                 hintP->cvtSrcToDefault = TRUE;
1931             }
1932         }
1933     }
1934     if (hintP->cvtSrcToDefault) {
1935         /* By definition */
1936         nbands = 4;  /* What about alpha? */
1937         hintP->dataType = BYTE_DATA_TYPE;
1938         hintP->needToCopy = TRUE;
1939 
1940         if (srcP->imageType == dstP->imageType) {
1941             hintP->cvtToDst = TRUE;
1942         }
1943         else if (dstP->cmodel.isDefaultCM) {
1944             /* Not necessarily */
1945             hintP->cvtToDst = FALSE;
1946         }
1947         else {
1948             hintP->cvtToDst = TRUE;
1949         }
1950     }
1951     else {
1952         int srcImageType = srcP->imageType;
1953         int dstImageType = dstP->imageType;
1954         /* Special case where we need to fill in alpha values */
1955         if (srcCMP->isDefaultCompatCM && dstCMP->isDefaultCompatCM) {
1956             int i;
1957             if (!srcCMP->supportsAlpha &&dstCMP->supportsAlpha) {
1958                 hintP->addAlpha = TRUE;
1959             }
1960             for (i=0; i < srcCMP->numComponents; i++) {
1961                 if (srcP->hints.colorOrder[i] != dstP->hints.colorOrder[i]){
1962                     if (!srcCMP->isDefaultCM) {
1963                         hintP->cvtSrcToDefault = TRUE;
1964                         srcImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1965                     }
1966                     if (!dstCMP->isDefaultCM) {
1967                         hintP->cvtToDst = TRUE;
1968                         dstImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1969                     }
1970 
1971                     break;
1972                 }
1973             }
1974         }
1975         else if (srcCMP->cmType != INDEX_CM_TYPE &&
1976                  !srcCMP->supportsAlpha && dstCMP->supportsAlpha)
1977         {
1978             /* We've already handled the index case.  This is for the rest of the cases */
1979             srcImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1980             hintP->cvtSrcToDefault = TRUE;
1981         }
1982 
1983         hintP->allocDefaultDst = FALSE;
1984         if (srcImageType == dstImageType) {
1985             /* Same image type so use it */
1986             hintP->cvtToDst = FALSE;
1987         }
1988         else if (srcImageType == TYPE_INT_RGB &&
1989                  (dstImageType == TYPE_INT_ARGB ||
1990                   dstImageType == TYPE_INT_ARGB_PRE)) {
1991             hintP->cvtToDst = FALSE;
1992         }
1993         else if (srcImageType == TYPE_INT_BGR &&
1994                  (dstImageType == TYPE_4BYTE_ABGR ||
1995                   dstImageType == TYPE_4BYTE_ABGR_PRE)) {
1996             hintP->cvtToDst = FALSE;
1997         }
1998         else if (srcP->hints.packing == dstP->hints.packing) {
1999             /* Now what? */
2000 
2001             /* Check color order */
2002 
2003             /* Check if just need to scale the data */
2004 
2005             hintP->cvtToDst = TRUE;
2006         }
2007         else {
2008             /* Don't know what it is so convert it */
2009             hintP->allocDefaultDst = TRUE;
2010             hintP->cvtToDst = TRUE;
2011         }
2012         hintP->needToCopy = (ncomponents > nbands);
2013     }
2014 
2015     return nbands;
2016 }
2017 
2018 
2019 static int
2020 expandPacked(JNIEnv *env, BufImageS_t *img, ColorModelS_t *cmP,
2021              RasterS_t *rasterP, int component, unsigned char *bdataP) {
2022 
2023     if (rasterP->rasterType == COMPONENT_RASTER_TYPE) {
2024         switch (rasterP->dataType) {
2025         case BYTE_DATA_TYPE:
2026             if (expandPackedBCR(env, rasterP, component, bdataP) < 0) {
2027                 /* Must have been an error */
2028                 return -1;
2029             }
2030             break;
2031 
2032         case SHORT_DATA_TYPE:
2033             if (expandPackedICR(env, rasterP, component, bdataP) < 0) {
2034                 /* Must have been an error */
2035                 return -1;
2036             }
2037             break;
2038 
2039         case INT_DATA_TYPE:
2040             if (expandPackedICR(env, rasterP, component, bdataP) < 0) {
2041                 /* Must have been an error */
2042                 return -1;
2043             }
2044             break;
2045 
2046         default:
2047             /* REMIND: Return some sort of error */
2048             return -1;
2049         }
2050     }
2051     else {
2052         /* REMIND: Return some sort of error */
2053         return -1;
2054     }
2055 
2056     return 0;
2057 }
2058 
2059 #define NUM_LINES    10
2060 
2061 static int
2062 cvtCustomToDefault(JNIEnv *env, BufImageS_t *imageP, int component,
2063                    unsigned char *dataP) {
2064     const RasterS_t *rasterP = &imageP->raster;
2065     const int w = rasterP->width;
2066     const int h = rasterP->height;
2067 
2068     int y;
2069     jintArray jpixels = NULL;
2070     jint *pixels;
2071     unsigned char *dP = dataP;
2072     int numLines = h > NUM_LINES ? NUM_LINES : h;
2073 
2074     /* it is safe to calculate the scan length, because width has been verified
2075      * on creation of the mlib image
2076      */
2077     const int scanLength = w * 4;
2078 
2079     int nbytes = 0;
2080     if (!SAFE_TO_MULT(numLines, scanLength)) {
2081         return -1;
2082     }
2083 
2084     nbytes = numLines * scanLength;
2085 
2086     jpixels = (*env)->NewIntArray(env, nbytes);
2087     if (JNU_IsNull(env, jpixels)) {
2088         (*env)->ExceptionClear(env);
2089         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
2090         return -1;
2091     }
2092 
2093     for (y = 0; y < h; y += numLines) {
2094         if (y + numLines > h) {
2095             numLines = h - y;
2096             nbytes = numLines * scanLength;
2097         }
2098 
2099         (*env)->CallObjectMethod(env, imageP->jimage,
2100                                  g_BImgGetRGBMID, 0, y,
2101                                  w, numLines,
2102                                  jpixels, 0, w);
2103         if ((*env)->ExceptionOccurred(env)) {
2104             (*env)->DeleteLocalRef(env, jpixels);
2105             return -1;
2106         }
2107 
2108         pixels = (*env)->GetPrimitiveArrayCritical(env, jpixels, NULL);
2109         if (pixels == NULL) {
2110             (*env)->DeleteLocalRef(env, jpixels);
2111             return -1;
2112         }
2113 
2114         memcpy(dP, pixels, nbytes);
2115         dP += nbytes;
2116 
2117         (*env)->ReleasePrimitiveArrayCritical(env, jpixels, pixels,
2118                                               JNI_ABORT);
2119     }
2120 
2121     /* Need to release the array */
2122     (*env)->DeleteLocalRef(env, jpixels);
2123 
2124     return 0;
2125 }
2126 
2127 static int
2128 cvtDefaultToCustom(JNIEnv *env, BufImageS_t *imageP, int component,
2129                    unsigned char *dataP) {
2130     const RasterS_t *rasterP = &imageP->raster;
2131     const int w = rasterP->width;
2132     const int h = rasterP->height;
2133 
2134     int y;
2135     jintArray jpixels = NULL;
2136     jint *pixels;
2137     unsigned char *dP = dataP;
2138     int numLines = h > NUM_LINES ? NUM_LINES : h;
2139 
2140     /* it is safe to calculate the scan length, because width has been verified
2141      * on creation of the mlib image
2142      */
2143     const int scanLength = w * 4;
2144 
2145     int nbytes = 0;
2146     if (!SAFE_TO_MULT(numLines, scanLength)) {
2147         return -1;
2148     }
2149 
2150     nbytes = numLines * scanLength;
2151 
2152     jpixels = (*env)->NewIntArray(env, nbytes);
2153     if (JNU_IsNull(env, jpixels)) {
2154         (*env)->ExceptionClear(env);
2155         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
2156         return -1;
2157     }
2158 
2159     for (y = 0; y < h; y += numLines) {
2160         if (y + numLines > h) {
2161             numLines = h - y;
2162             nbytes = numLines * scanLength;
2163         }
2164 
2165         pixels = (*env)->GetPrimitiveArrayCritical(env, jpixels, NULL);
2166         if (pixels == NULL) {
2167             (*env)->DeleteLocalRef(env, jpixels);
2168             return -1;
2169         }
2170 
2171         memcpy(pixels, dP, nbytes);
2172         dP += nbytes;
2173 
2174        (*env)->ReleasePrimitiveArrayCritical(env, jpixels, pixels, 0);
2175 
2176        (*env)->CallVoidMethod(env, imageP->jimage, g_BImgSetRGBMID, 0, y,
2177                                 w, numLines, jpixels,
2178                                 0, w);
2179        if ((*env)->ExceptionOccurred(env)) {
2180            (*env)->DeleteLocalRef(env, jpixels);
2181            return -1;
2182        }
2183     }
2184 
2185     /* Need to release the array */
2186     (*env)->DeleteLocalRef(env, jpixels);
2187 
2188     return 0;
2189 }
2190 
2191 static int
2192 allocateArray(JNIEnv *env, BufImageS_t *imageP,
2193               mlib_image **mlibImagePP, void **dataPP, int isSrc,
2194               int cvtToDefault, int addAlpha) {
2195     void *dataP;
2196     unsigned char *cDataP;
2197     RasterS_t *rasterP = &imageP->raster;
2198     ColorModelS_t *cmP = &imageP->cmodel;
2199     int dataType = BYTE_DATA_TYPE;
2200     int width;
2201     int height;
2202     HintS_t *hintP = &imageP->hints;
2203     *dataPP = NULL;
2204 
2205     width = rasterP->width;
2206     height = rasterP->height;
2207 
2208     /* Useful for convolution? */
2209     /* This code is zero'ed out so that it cannot be called */
2210 
2211     /* To do this correctly, we need to expand src and dst in the     */
2212     /* same direction up/down/left/right only if both can be expanded */
2213     /* in that direction.  Expanding right and down is easy -         */
2214     /* increment width.  Expanding top and left requires bumping      */
2215     /* around pointers and incrementing the width/height              */
2216 
2217 #if 0
2218     if (0 && useEdges) {
2219         baseWidth  = rasterP->baseRasterWidth;
2220         baseHeight = rasterP->baseRasterHeight;
2221         baseXoff = rasterP->baseOriginX;
2222         baseYoff = rasterP->baseOriginY;
2223 
2224         if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
2225             /* Can use edge */
2226             width++;
2227         }
2228         if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
2229             /* Can use edge */
2230             height++;
2231         }
2232 
2233         if (rasterP->minX > baseXoff ) {
2234             /* Can use edge */
2235             width++;
2236             /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
2237         }
2238         if (rasterP->minY  > baseYoff) {
2239             /* Can use edge */
2240             height++;
2241             /* NEED TO BUMP POINTER BACK A SCANLINE */
2242         }
2243 
2244 
2245     }
2246 #endif
2247     if (cvtToDefault) {
2248         int status = 0;
2249         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
2250         if (*mlibImagePP == NULL) {
2251             return -1;
2252         }
2253         cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2254         /* Make sure the image is cleared.
2255          * NB: the image dimension is already verified, so we can
2256          * safely calculate the length of the buffer.
2257          */
2258         memset(cDataP, 0, width*height*4);
2259 
2260         if (!isSrc) {
2261             return 0;
2262         }
2263 
2264         switch(imageP->cmodel.cmType) {
2265         case INDEX_CM_TYPE:
2266             /* REMIND: Need to rearrange according to dst cm */
2267             /* Fix 4213160, 4184283 */
2268             if (rasterP->rasterType == COMPONENT_RASTER_TYPE) {
2269                 return expandICM(env, imageP, (unsigned int *)cDataP);
2270             }
2271             else {
2272                 return cvtCustomToDefault(env, imageP, -1, cDataP);
2273             }
2274 
2275         case DIRECT_CM_TYPE:
2276             switch(imageP->raster.dataType) {
2277             case BYTE_DATA_TYPE:
2278                 return expandPackedBCRdefault(env, rasterP, -1, cDataP,
2279                                               !imageP->cmodel.supportsAlpha);
2280             case SHORT_DATA_TYPE:
2281                 return expandPackedSCRdefault(env, rasterP, -1, cDataP,
2282                                               !imageP->cmodel.supportsAlpha);
2283             case INT_DATA_TYPE:
2284                 return expandPackedICRdefault(env, rasterP, -1, cDataP,
2285                                               !imageP->cmodel.supportsAlpha);
2286             }
2287         } /* switch(imageP->cmodel.cmType) */
2288 
2289         return cvtCustomToDefault(env, imageP, -1, cDataP);
2290     }
2291 
2292     /* Interleaved with shared data */
2293     dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2294                                                        NULL);
2295     if (dataP == NULL) {
2296         return -1;
2297     }
2298 
2299     /* Means we need to fill in alpha */
2300     if (!cvtToDefault && addAlpha) {
2301         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
2302         if (*mlibImagePP != NULL) {
2303             unsigned int *dstP  = (unsigned int *)
2304                 mlib_ImageGetData(*mlibImagePP);
2305             int dstride = (*mlibImagePP)->stride>>2;
2306             int sstride = hintP->sStride>>2;
2307             unsigned int *srcP = (unsigned int *)
2308                 ((unsigned char *)dataP + hintP->dataOffset);
2309             unsigned int *dP, *sP;
2310             int x, y;
2311             for (y=0; y < height; y++, srcP += sstride, dstP += dstride){
2312                 sP = srcP;
2313                 dP = dstP;
2314                 for (x=0; x < width; x++) {
2315                     dP[x] = sP[x] | 0xff000000;
2316                 }
2317             }
2318         }
2319         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2320                                               JNI_ABORT);
2321         return 0;
2322     }
2323     else if ((hintP->packing & BYTE_INTERLEAVED) == BYTE_INTERLEAVED) {
2324         int nChans = (cmP->isDefaultCompatCM ? 4 : hintP->numChans);
2325         /* Easy case.  It is or is similar to the default CM so use
2326      * the array.  Must be byte data.
2327          */
2328             /* Create the medialib image */
2329         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE,
2330                                               nChans,
2331                                               width,
2332                                               height,
2333                                               hintP->sStride,
2334                                               (unsigned char *)dataP
2335                                               + hintP->dataOffset);
2336     }
2337     else if ((hintP->packing & SHORT_INTERLEAVED) == SHORT_INTERLEAVED) {
2338         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
2339                                               hintP->numChans,
2340                                               width,
2341                                               height,
2342                                               imageP->raster.scanlineStride*2,
2343                                               (unsigned short *)dataP
2344                                               + hintP->channelOffset);
2345     }
2346     else {
2347         /* Release the data array */
2348         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2349                                               JNI_ABORT);
2350         return -1;
2351     }
2352 
2353     *dataPP = dataP;
2354     return 0;
2355 }
2356 
2357 static int
2358 allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
2359                     mlib_image **mlibImagePP, void **dataPP, int isSrc) {
2360     void *dataP;
2361     unsigned char *cDataP;
2362     int dataType = BYTE_DATA_TYPE;
2363     int width;
2364     int height;
2365     int dataSize;
2366     int offset;
2367 
2368     *dataPP = NULL;
2369 
2370     width = rasterP->width;
2371     height = rasterP->height;
2372 
2373     if (rasterP->numBands <= 0 || rasterP->numBands > 4) {
2374         /* REMIND: Fix this */
2375         return -1;
2376     }
2377 
2378     /* Useful for convolution? */
2379     /* This code is zero'ed out so that it cannot be called */
2380 
2381     /* To do this correctly, we need to expand src and dst in the     */
2382     /* same direction up/down/left/right only if both can be expanded */
2383     /* in that direction.  Expanding right and down is easy -         */
2384     /* increment width.  Expanding top and left requires bumping      */
2385     /* around pointers and incrementing the width/height              */
2386 
2387 #if 0
2388     if (0 && useEdges) {
2389         baseWidth  = rasterP->baseRasterWidth;
2390         baseHeight = rasterP->baseRasterHeight;
2391         baseXoff = rasterP->baseOriginX;
2392         baseYoff = rasterP->baseOriginY;
2393 
2394         if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
2395             /* Can use edge */
2396             width++;
2397         }
2398         if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
2399             /* Can use edge */
2400             height++;
2401         }
2402 
2403         if (rasterP->minX > baseXoff ) {
2404             /* Can use edge */
2405             width++;
2406             /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
2407         }
2408         if (rasterP->minY  > baseYoff) {
2409             /* Can use edge */
2410             height++;
2411             /* NEED TO BUMP POINTER BACK A SCANLINE */
2412         }
2413 
2414 
2415     }
2416 #endif
2417     switch (rasterP->type) {
2418     case sun_awt_image_IntegerComponentRaster_TYPE_INT_8BIT_SAMPLES:
2419         if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 4)) &&
2420               SAFE_TO_ALLOC_2(width, 4) &&
2421               SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 4)))
2422         {
2423             return -1;
2424         }
2425         offset = 4 * rasterP->chanOffsets[0];
2426         dataSize = 4 * (*env)->GetArrayLength(env, rasterP->jdata);
2427 
2428         if (offset < 0 || offset >= dataSize ||
2429             width > rasterP->scanlineStride ||
2430             height * rasterP->scanlineStride * 4 > dataSize - offset)
2431         {
2432             // raster data buffer is too short
2433             return -1;
2434         }
2435         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2436                                                            NULL);
2437         if (dataP == NULL) {
2438             return -1;
2439         }
2440         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE, 4,
2441                                               width, height,
2442                                               rasterP->scanlineStride*4,
2443                                               (unsigned char *)dataP + offset);
2444         *dataPP = dataP;
2445         return 0;
2446     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_SAMPLES:
2447         if (!(SAFE_TO_ALLOC_2(width, rasterP->numBands) &&
2448               SAFE_TO_ALLOC_2(height, rasterP->scanlineStride)))
2449         {
2450             return -1;
2451         }
2452         offset = rasterP->chanOffsets[0];
2453         dataSize = (*env)->GetArrayLength(env, rasterP->jdata);
2454 
2455         if (offset < 0 || offset >= dataSize ||
2456             width * rasterP->numBands > rasterP->scanlineStride ||
2457             height * rasterP->scanlineStride > dataSize - offset)
2458         {
2459             // raster data buffer is too short
2460             return -1;
2461         }
2462         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2463                                                            NULL);
2464         if (dataP == NULL) {
2465             return -1;
2466         }
2467         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE, rasterP->numBands,
2468                                               width, height,
2469                                               rasterP->scanlineStride,
2470                                               (unsigned char *)dataP + offset);
2471         *dataPP = dataP;
2472         return 0;
2473     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_SAMPLES:
2474         if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 2)) &&
2475               SAFE_TO_ALLOC_3(width, rasterP->numBands, 2) &&
2476               SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 2)))
2477         {
2478               return -1;
2479         }
2480         offset = rasterP->chanOffsets[0] * 2;
2481         dataSize = 2 * (*env)->GetArrayLength(env, rasterP->jdata);
2482 
2483         if (offset < 0 || offset >= dataSize ||
2484             width * rasterP->numBands > rasterP->scanlineStride ||
2485             height * rasterP->scanlineStride * 2 > dataSize - offset)
2486         {
2487             // raster data buffer is too short
2488              return -1;
2489         }
2490         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2491                                                            NULL);
2492         if (dataP == NULL) {
2493             return -1;
2494         }
2495         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
2496                                                      rasterP->numBands,
2497                                                      width, height,
2498                                                      rasterP->scanlineStride*2,
2499                                                      (unsigned char *)dataP + offset);
2500         *dataPP = dataP;
2501         return 0;
2502 
2503     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2504         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2505                                         width, height);
2506         if (*mlibImagePP == NULL) {
2507             return -1;
2508         }
2509         if (!isSrc) return 0;
2510         cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2511         return expandPackedBCR(env, rasterP, -1, cDataP);
2512 
2513     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2514         if (rasterP->sppsm.maxBitSize <= 8) {
2515             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2516                                             width, height);
2517             if (*mlibImagePP == NULL) {
2518                 return -1;
2519             }
2520             if (!isSrc) return 0;
2521             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2522             return expandPackedSCR(env, rasterP, -1, cDataP);
2523         }
2524         break;
2525     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2526         if (rasterP->sppsm.maxBitSize <= 8) {
2527             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2528                                             width, height);
2529             if (*mlibImagePP == NULL) {
2530                 return -1;
2531             }
2532             if (!isSrc) return 0;
2533             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2534             return expandPackedICR(env, rasterP, -1, cDataP);
2535         }
2536         break;
2537     }
2538 
2539     /* Just expand it right now */
2540     switch (rasterP->dataType) {
2541     case BYTE_DATA_TYPE:
2542         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2543                                              width, height)) == NULL) {
2544             return -1;
2545         }
2546         if (isSrc) {
2547             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2548                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2549                 return -1;
2550             }
2551         }
2552         break;
2553 
2554     case SHORT_DATA_TYPE:
2555         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_SHORT,
2556                                                     rasterP->numBands,
2557                                                     width, height)) == NULL) {
2558             return -1;
2559         }
2560         if (isSrc) {
2561             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2562                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2563                 return -1;
2564             }
2565         }
2566         break;
2567 
2568     default:
2569         return -1;
2570     }
2571     return 0;
2572 }
2573 
2574 static void
2575 freeArray(JNIEnv *env, BufImageS_t *srcimageP, mlib_image *srcmlibImP,
2576           void *srcdataP, BufImageS_t *dstimageP, mlib_image *dstmlibImP,
2577           void *dstdataP) {
2578     jobject srcJdata = (srcimageP != NULL ? srcimageP->raster.jdata : NULL);
2579     jobject dstJdata = (dstimageP != NULL ? dstimageP->raster.jdata : NULL);
2580     freeDataArray(env, srcJdata, srcmlibImP, srcdataP,
2581                   dstJdata, dstmlibImP, dstdataP);
2582 }
2583 static void
2584 freeDataArray(JNIEnv *env, jobject srcJdata, mlib_image *srcmlibImP,
2585           void *srcdataP, jobject dstJdata, mlib_image *dstmlibImP,
2586           void *dstdataP)
2587 {
2588     /* Free the medialib image */
2589     if (srcmlibImP) {
2590         (*sMlibSysFns.deleteImageFP)(srcmlibImP);
2591     }
2592 
2593     /* Release the array */
2594     if (srcdataP) {
2595         (*env)->ReleasePrimitiveArrayCritical(env, srcJdata,
2596                                               srcdataP, JNI_ABORT);
2597     }
2598 
2599     /* Free the medialib image */
2600     if (dstmlibImP) {
2601         (*sMlibSysFns.deleteImageFP)(dstmlibImP);
2602     }
2603 
2604     /* Release the array */
2605     if (dstdataP) {
2606         (*env)->ReleasePrimitiveArrayCritical(env, dstJdata,
2607                                               dstdataP, 0);
2608     }
2609 }
2610 
2611 #define ERR_BAD_IMAGE_LAYOUT (-2)
2612 
2613 #define CHECK_DST_ARRAY(start_offset, elements_per_scan, elements_per_pixel) \
2614     do {                                                                     \
2615         int offset = (start_offset);                                         \
2616         int lastScanOffset;                                                  \
2617                                                                              \
2618         if (!SAFE_TO_MULT((elements_per_scan),                               \
2619                           (rasterP->height - 1)))                            \
2620         {                                                                    \
2621             return ERR_BAD_IMAGE_LAYOUT;                                     \
2622         }                                                                    \
2623         lastScanOffset = (elements_per_scan) * (rasterP->height - 1);        \
2624                                                                              \
2625         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2626             return ERR_BAD_IMAGE_LAYOUT;                                     \
2627         }                                                                    \
2628         lastScanOffset += offset;                                            \
2629                                                                              \
2630         if (!SAFE_TO_MULT((elements_per_pixel), rasterP->width)) {           \
2631             return ERR_BAD_IMAGE_LAYOUT;                                     \
2632         }                                                                    \
2633         offset = (elements_per_pixel) * rasterP->width;                      \
2634                                                                              \
2635         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2636             return ERR_BAD_IMAGE_LAYOUT;                                     \
2637         }                                                                    \
2638         lastScanOffset += offset;                                            \
2639                                                                              \
2640         if (dataArrayLength < lastScanOffset) {                              \
2641             return ERR_BAD_IMAGE_LAYOUT;                                     \
2642         }                                                                    \
2643     } while(0);                                                              \
2644 
2645 static int
2646 storeImageArray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2647                 mlib_image *mlibImP) {
2648     int mStride;
2649     unsigned char *cmDataP, *dataP, *cDataP;
2650     HintS_t *hintP = &dstP->hints;
2651     RasterS_t *rasterP = &dstP->raster;
2652     jsize dataArrayLength = (*env)->GetArrayLength(env, rasterP->jdata);
2653     int y;
2654 
2655     /* REMIND: Store mlib data type? */
2656 
2657     /* Check if it is an IndexColorModel */
2658     if (dstP->cmodel.cmType == INDEX_CM_TYPE) {
2659         if (dstP->raster.rasterType == COMPONENT_RASTER_TYPE) {
2660             return storeICMarray(env, srcP, dstP, mlibImP);
2661         }
2662         else {
2663             /* Packed or some other custom raster */
2664             cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2665             return cvtDefaultToCustom(env, dstP, -1, cmDataP);
2666         }
2667     }
2668 
2669     if (hintP->packing == BYTE_INTERLEAVED) {
2670         /* Write it back to the destination */
2671         if (rasterP->dataType != BYTE_DATA_TYPE) {
2672             /* We are working with a raster which was marked
2673                as a byte interleaved due to performance reasons.
2674                So, we have to convert the length of the data
2675                array to bytes as well.
2676             */
2677             if (!SAFE_TO_MULT(rasterP->dataSize, dataArrayLength)) {
2678                 return ERR_BAD_IMAGE_LAYOUT;
2679             }
2680             dataArrayLength *= rasterP->dataSize;
2681         }
2682 
2683         CHECK_DST_ARRAY(hintP->dataOffset, hintP->sStride, hintP->numChans);
2684         cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2685         mStride = mlib_ImageGetStride(mlibImP);
2686         dataP = (unsigned char *)(*env)->GetPrimitiveArrayCritical(env,
2687                                                       rasterP->jdata, NULL);
2688         if (dataP == NULL) return 0;
2689         cDataP = dataP + hintP->dataOffset;
2690         for (y=0; y < rasterP->height;
2691              y++, cmDataP += mStride, cDataP += hintP->sStride)
2692         {
2693             memcpy(cDataP, cmDataP, rasterP->width*hintP->numChans);
2694         }
2695         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2696                                               JNI_ABORT);
2697     }
2698     else if (dstP->cmodel.cmType == DIRECT_CM_TYPE) {
2699         /* Just need to move bits */
2700         if (mlibImP->type == MLIB_BYTE) {
2701             if (dstP->hints.packing == PACKED_BYTE_INTER) {
2702                 return setPackedBCRdefault(env, rasterP, -1,
2703                                            (unsigned char *) mlibImP->data,
2704                                            dstP->cmodel.supportsAlpha);
2705             } else if (dstP->hints.packing == PACKED_SHORT_INTER) {
2706                 return setPackedSCRdefault(env, rasterP, -1,
2707                                            (unsigned char *) mlibImP->data,
2708                                            dstP->cmodel.supportsAlpha);
2709             } else if (dstP->hints.packing == PACKED_INT_INTER) {
2710                 return setPackedICRdefault(env, rasterP, -1,
2711                                            (unsigned char *) mlibImP->data,
2712                                            dstP->cmodel.supportsAlpha);
2713             }
2714         }
2715         else if (mlibImP->type == MLIB_SHORT) {
2716             return setPixelsFormMlibImage(env, rasterP, mlibImP);
2717         }
2718     }
2719     else {
2720         return cvtDefaultToCustom(env, dstP, -1,
2721                                   (unsigned char *)mlibImP->data);
2722     }
2723 
2724     return 0;
2725 }
2726 
2727 static int
2728 storeRasterArray(JNIEnv *env, RasterS_t *srcP, RasterS_t *dstP,
2729                 mlib_image *mlibImP) {
2730     unsigned char *cDataP;
2731 
2732     switch(dstP->type) {
2733     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2734         cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2735         return setPackedBCR(env, dstP, -1, cDataP);
2736 
2737     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2738         if (dstP->sppsm.maxBitSize <= 8) {
2739             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2740             return setPackedSCR(env, dstP, -1, cDataP);
2741         }
2742         break;
2743     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2744         if (dstP->sppsm.maxBitSize <= 8) {
2745             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2746             return setPackedICR(env, dstP, -1, cDataP);
2747         }
2748     }
2749 
2750     return -1;
2751 }
2752 
2753 
2754 static int
2755 storeICMarray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2756               mlib_image *mlibImP)
2757 {
2758     int *argb;
2759     int x, y;
2760     unsigned char *dataP, *cDataP, *cP;
2761     unsigned char *sP;
2762     int aIdx, rIdx, gIdx, bIdx;
2763     ColorModelS_t *cmodelP = &dstP->cmodel;
2764     RasterS_t *rasterP = &dstP->raster;
2765 
2766     /* REMIND: Only works for RGB */
2767     if (cmodelP->csType != java_awt_color_ColorSpace_TYPE_RGB) {
2768         JNU_ThrowInternalError(env, "Writing to non-RGB images not implemented yet");
2769         return -1;
2770     }
2771 
2772     if (srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
2773         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
2774         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
2775     {
2776         aIdx = 0;
2777         rIdx = 1;
2778         gIdx = 2;
2779         bIdx = 3;
2780     }
2781     else if (srcP->imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR||
2782         srcP->imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE)
2783     {
2784         aIdx = 0;
2785         rIdx = 3;
2786         gIdx = 2;
2787         bIdx = 1;
2788     }
2789     else if (srcP->imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR){
2790         rIdx = 2;
2791         gIdx = 1;
2792         bIdx = 0;
2793         aIdx = 0;       /* Ignored */
2794     }
2795     else if (srcP->cmodel.cmType == INDEX_CM_TYPE) {
2796         rIdx = 0;
2797         gIdx = 1;
2798         bIdx = 2;
2799         aIdx = 3;   /* Use supportsAlpha to see if it is really there */
2800     }
2801     else {
2802         return -1;
2803     }
2804 
2805     /* Lock down the destination raster */
2806     dataP = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env,
2807                                                   rasterP->jdata, NULL);
2808     if (dataP == NULL) {
2809         return -1;
2810     }
2811     argb = (*env)->GetPrimitiveArrayCritical(env, cmodelP->jrgb, NULL);
2812     if (argb == NULL) {
2813         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2814                                               JNI_ABORT);
2815         return -1;
2816     }
2817 
2818     cDataP = dataP + dstP->hints.dataOffset;
2819     sP = (unsigned char *) mlib_ImageGetData(mlibImP);
2820 
2821     for (y=0; y < rasterP->height; y++, cDataP += rasterP->scanlineStride) {
2822         cP = cDataP;
2823         for (x=0; x < rasterP->width; x++, cP += rasterP->pixelStride) {
2824             *cP = colorMatch(sP[rIdx], sP[gIdx], sP[bIdx], sP[aIdx],
2825                              (unsigned char *)argb, cmodelP->mapSize);
2826             sP += cmodelP->numComponents;
2827         }
2828     }
2829 
2830     (*env)->ReleasePrimitiveArrayCritical(env, cmodelP->jrgb, argb, JNI_ABORT);
2831     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2832                                           JNI_ABORT);
2833     return -1;
2834 }
2835 
2836 static int expandICM(JNIEnv *env, BufImageS_t *imageP, unsigned int *mDataP)
2837 {
2838     ColorModelS_t *cmP = &imageP->cmodel;
2839     RasterS_t *rasterP = &imageP->raster;
2840     HintS_t *hintP     = &imageP->hints;
2841     int *rgb;
2842     int status = 0;
2843     unsigned char *dataP, *cP;
2844     unsigned int *mP;
2845     int width = rasterP->width;
2846     int height = rasterP->height;
2847     int x, y;
2848 
2849     /* Need to grab the lookup tables.  Right now only bytes */
2850     rgb = (int *) (*env)->GetPrimitiveArrayCritical(env, cmP->jrgb, NULL);
2851     CHECK_NULL_RETURN(rgb, -1);
2852 
2853     /* Interleaved with shared data */
2854     dataP = (void *) (*env)->GetPrimitiveArrayCritical(env,
2855                                                        rasterP->jdata, NULL);
2856     if (dataP == NULL) {
2857         /* Release the lookup tables */
2858         (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb, JNI_ABORT);
2859         return -1;
2860     }
2861 
2862     if (rasterP->dataType == BYTE_DATA_TYPE) {
2863         unsigned char *cDataP = ((unsigned char *)dataP) + hintP->dataOffset;
2864 
2865         for (y=0; y < height; y++) {
2866             mP = mDataP;
2867             cP = cDataP;
2868             for (x=0; x < width; x++, cP += rasterP->pixelStride) {
2869                 *mP++ = rgb[*cP];
2870             }
2871             mDataP += width;
2872             cDataP += rasterP->scanlineStride;
2873         }
2874     }
2875     else if (rasterP->dataType == SHORT_DATA_TYPE) {
2876         unsigned short *sDataP, *sP;
2877         sDataP = ((unsigned short *)dataP) + hintP->channelOffset;
2878 
2879         for (y=0; y < height; y++) {
2880             mP = mDataP;
2881             sP = sDataP;
2882             for (x=0; x < width; x++, sP+=rasterP->pixelStride) {
2883                 *mP++ = rgb[*sP];
2884             }
2885             mDataP += width;
2886             sDataP += rasterP->scanlineStride;
2887         }
2888     }
2889     else {
2890         /* Unknown type */
2891         status = -1;
2892     }
2893     /* Release the lookup table data */
2894     (*env)->ReleasePrimitiveArrayCritical(env, imageP->cmodel.jrgb,
2895                                           rgb, JNI_ABORT);
2896     /* Release the data array */
2897     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata,
2898                                           dataP, JNI_ABORT);
2899     return status;
2900 }
2901 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2902 static int expandPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
2903                            unsigned char *outDataP)
2904 {
2905     int x, y, c;
2906     unsigned char *outP = outDataP;
2907     unsigned char *lineInP, *inP;
2908     jarray jInDataP;
2909     jint   *inDataP;
2910     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
2911 
2912     if (rasterP->numBands > MAX_NUMBANDS) {
2913         return -1;
2914     }
2915 
2916     /* Grab data ptr, strides, offsets from raster */
2917     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
2918     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
2919     if (inDataP == NULL) {
2920         return -1;
2921     }
2922     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
2923 
2924     if (component < 0) {
2925         for (c=0; c < rasterP->numBands; c++) {
2926             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2927             if (roff[c] < 0) {
2928                 loff[c] = -roff[c];
2929                 roff[c] = 0;
2930             }
2931             else loff[c] = 0;
2932         }
2933         /* Convert the all bands */
2934         if (rasterP->numBands < 4) {
2935             /* Need to put in alpha */
2936             for (y=0; y < rasterP->height; y++) {
2937                 inP = lineInP;
2938                 for (x=0; x < rasterP->width; x++) {
2939                     for (c=0; c < rasterP->numBands; c++) {
2940                         *outP++ = (unsigned char)
2941                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2942                              <<loff[c]);
2943                     }
2944                     inP++;
2945                 }
2946                 lineInP += rasterP->scanlineStride;
2947             }
2948         }
2949         else {
2950             for (y=0; y < rasterP->height; y++) {
2951                 inP = lineInP;
2952                 for (x=0; x < rasterP->width; x++) {
2953                     for (c=0; c < rasterP->numBands; c++) {
2954                         *outP++ = (unsigned char)
2955                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2956                              <<loff[c]);
2957                     }
2958                     inP++;
2959                 }
2960                 lineInP += rasterP->scanlineStride;
2961             }
2962         }
2963     }
2964     else {
2965         c = component;
2966         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2967         if (roff[0] < 0) {
2968             loff[0] = -roff[0];
2969             roff[0] = 0;
2970         }
2971         else loff[c] = 0;
2972         for (y=0; y < rasterP->height; y++) {
2973             inP = lineInP;
2974             for (x=0; x < rasterP->width; x++) {
2975                 *outP++ = (unsigned char)
2976                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
2977                 inP++;
2978             }
2979             lineInP += rasterP->scanlineStride;
2980         }
2981     }
2982 
2983     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
2984 
2985     return 0;
2986 }
2987 
2988 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2989 static int expandPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
2990                                   int component, unsigned char *outDataP,
2991                                   int forceAlpha)
2992 {
2993     int x, y, c;
2994     unsigned char *outP = outDataP;
2995     unsigned char *lineInP, *inP;
2996     jarray jInDataP;
2997     jint   *inDataP;
2998     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
2999     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3000     int a = numBands;
3001 
3002     if (rasterP->numBands > MAX_NUMBANDS) {
3003         return -1;
3004     }
3005 
3006     /* Grab data ptr, strides, offsets from raster */
3007     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3008     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3009     if (inDataP == NULL) {
3010         return -1;
3011     }
3012     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
3013 
3014     if (component < 0) {
3015         for (c=0; c < rasterP->numBands; c++) {
3016             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3017             if (roff[c] < 0) {
3018                 loff[c] = -roff[c];
3019                 roff[c] = 0;
3020             }
3021             else loff[c] = 0;
3022         }
3023 
3024         /* Need to put in alpha */
3025         if (forceAlpha) {
3026             for (y=0; y < rasterP->height; y++) {
3027                 inP = lineInP;
3028                 for (x=0; x < rasterP->width; x++) {
3029                     *outP++ = 0xff;
3030                     for (c=0; c < numBands; c++) {
3031                         *outP++ = (unsigned char)
3032                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3033                              <<loff[c]);
3034                     }
3035                     inP++;
3036                 }
3037                 lineInP += rasterP->scanlineStride;
3038             }
3039         }
3040         else {
3041             for (y=0; y < rasterP->height; y++) {
3042                 inP = lineInP;
3043                 for (x=0; x < rasterP->width; x++) {
3044                     *outP++ = (unsigned char)
3045                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3046                          <<loff[a]);
3047                     for (c=0; c < numBands; c++) {
3048                         *outP++ = (unsigned char)
3049                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3050                              <<loff[c]);
3051                     }
3052                     inP++;
3053                 }
3054                 lineInP += rasterP->scanlineStride;
3055             }
3056         }
3057     }
3058     else {
3059         c = component;
3060         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3061         if (roff[0] < 0) {
3062             loff[0] = -roff[0];
3063             roff[0] = 0;
3064         }
3065         else loff[c] = 0;
3066         for (y=0; y < rasterP->height; y++) {
3067             inP = lineInP;
3068             for (x=0; x < rasterP->width; x++) {
3069                 *outP++ = (unsigned char)
3070                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3071                 inP++;
3072             }
3073             lineInP += rasterP->scanlineStride;
3074         }
3075     }
3076 
3077     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3078 
3079     return 0;
3080 }
3081 
3082 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3083 static int expandPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3084                            unsigned char *outDataP)
3085 {
3086     int x, y, c;
3087     unsigned char *outP = outDataP;
3088     unsigned short *lineInP, *inP;
3089     jarray jInDataP;
3090     jint   *inDataP;
3091     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3092 
3093     if (rasterP->numBands > MAX_NUMBANDS) {
3094         return -1;
3095     }
3096 
3097     /* Grab data ptr, strides, offsets from raster */
3098     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3099     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3100     if (inDataP == NULL) {
3101         return -1;
3102     }
3103     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3104 
3105     if (component < 0) {
3106         for (c=0; c < rasterP->numBands; c++) {
3107             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3108             if (roff[c] < 0) {
3109                 loff[c] = -roff[c];
3110                 roff[c] = 0;
3111             }
3112             else loff[c] = 0;
3113         }
3114         /* Convert the all bands */
3115         if (rasterP->numBands < 4) {
3116             /* Need to put in alpha */
3117             for (y=0; y < rasterP->height; y++) {
3118                 inP = lineInP;
3119                 for (x=0; x < rasterP->width; x++) {
3120                     for (c=0; c < rasterP->numBands; c++) {
3121                         /*
3122                          *Not correct.  Might need to unpremult,
3123                          * shift, etc
3124                          */
3125                         *outP++ = (unsigned char)
3126                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3127                              <<loff[c]);
3128                     }
3129                     inP++;
3130                 }
3131                 lineInP += rasterP->scanlineStride;
3132             }
3133         } else {
3134             for (y=0; y < rasterP->height; y++) {
3135                 inP = lineInP;
3136                 for (x=0; x < rasterP->width; x++) {
3137                     for (c=0; c < rasterP->numBands; c++) {
3138                         /*
3139                          *Not correct.  Might need to unpremult,
3140                          * shift, etc
3141                          */
3142                         *outP++ = (unsigned char)
3143                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3144                              <<loff[c]);
3145                     }
3146                     inP++;
3147                 }
3148                 lineInP += rasterP->scanlineStride;
3149             }
3150         }
3151     }
3152     else {
3153         c = component;
3154         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3155         if (roff[0] < 0) {
3156             loff[0] = -roff[0];
3157             roff[0] = 0;
3158         }
3159         else loff[c] = 0;
3160         for (y=0; y < rasterP->height; y++) {
3161             inP = lineInP;
3162             for (x=0; x < rasterP->width; x++) {
3163                 *outP++ = (unsigned char)
3164                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3165                 inP++;
3166             }
3167             lineInP += rasterP->scanlineStride;
3168         }
3169     }
3170 
3171     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3172 
3173     return 0;
3174 }
3175 
3176 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3177 static int expandPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3178                                   int component, unsigned char *outDataP,
3179                                   int forceAlpha)
3180 {
3181     int x, y, c;
3182     unsigned char *outP = outDataP;
3183     unsigned short *lineInP, *inP;
3184     jarray jInDataP;
3185     jint   *inDataP;
3186     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3187     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3188     int a = numBands;
3189 
3190     if (rasterP->numBands > MAX_NUMBANDS) {
3191         return -1;
3192     }
3193 
3194     /* Grab data ptr, strides, offsets from raster */
3195     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3196     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3197     if (inDataP == NULL) {
3198         return -1;
3199     }
3200     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3201 
3202     if (component < 0) {
3203         for (c=0; c < rasterP->numBands; c++) {
3204             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3205             if (roff[c] < 0) {
3206                 loff[c] = -roff[c];
3207                 roff[c] = 0;
3208             }
3209             else loff[c] = 0;
3210         }
3211 
3212         /* Need to put in alpha */
3213         if (forceAlpha) {
3214             for (y=0; y < rasterP->height; y++) {
3215                 inP = lineInP;
3216                 for (x=0; x < rasterP->width; x++) {
3217                     *outP++ = 0xff;
3218                     for (c=0; c < numBands; c++) {
3219                         /*
3220                          * Not correct.  Might need to unpremult,
3221                          * shift, etc
3222                          */
3223                         *outP++ = (unsigned char)
3224                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3225                                    <<loff[c]);
3226                     }
3227                     inP++;
3228                 }
3229                 lineInP += rasterP->scanlineStride;
3230             }
3231         }
3232         else {
3233             for (y=0; y < rasterP->height; y++) {
3234                 inP = lineInP;
3235                 for (x=0; x < rasterP->width; x++) {
3236                     *outP++ = (unsigned char)
3237                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3238                                    <<loff[a]);
3239                     for (c=0; c < numBands; c++) {
3240                         /*
3241                          * Not correct.  Might need to
3242                          * unpremult, shift, etc
3243                          */
3244                         *outP++ = (unsigned char)
3245                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3246                                    <<loff[c]);
3247                     }
3248                     inP++;
3249                 }
3250                 lineInP += rasterP->scanlineStride;
3251             }
3252         }
3253     }
3254     else {
3255         c = component;
3256         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3257         if (roff[0] < 0) {
3258             loff[0] = -roff[0];
3259             roff[0] = 0;
3260         }
3261         else loff[c] = 0;
3262         for (y=0; y < rasterP->height; y++) {
3263             inP = lineInP;
3264             for (x=0; x < rasterP->width; x++) {
3265                 *outP++ = (unsigned char)
3266                         ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3267                 inP++;
3268             }
3269             lineInP += rasterP->scanlineStride;
3270         }
3271     }
3272 
3273     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3274 
3275     return 0;
3276 
3277 }
3278 
3279 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3280 static int expandPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3281                            unsigned char *outDataP)
3282 {
3283     int x, y, c;
3284     unsigned char *outP = outDataP;
3285     unsigned int *lineInP, *inP;
3286     jarray jInDataP;
3287     jint   *inDataP;
3288     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3289 
3290     if (rasterP->numBands > MAX_NUMBANDS) {
3291         return -1;
3292     }
3293 
3294     /* Grab data ptr, strides, offsets from raster */
3295     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3296     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3297     if (inDataP == NULL) {
3298         return -1;
3299     }
3300     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3301 
3302     if (component < 0) {
3303         for (c=0; c < rasterP->numBands; c++) {
3304             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3305             if (roff[c] < 0) {
3306                 loff[c] = -roff[c];
3307                 roff[c] = 0;
3308             }
3309             else loff[c] = 0;
3310         }
3311         /* Convert the all bands */
3312         if (rasterP->numBands < 4) {
3313             for (y=0; y < rasterP->height; y++) {
3314                 inP = lineInP;
3315                 for (x=0; x < rasterP->width; x++) {
3316                     for (c=0; c < rasterP->numBands; c++) {
3317                         /*
3318                          * Not correct.  Might need to unpremult,
3319                          * shift, etc
3320                          */
3321                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3322                                    <<loff[c]);
3323                     }
3324                     inP++;
3325                 }
3326                 lineInP += rasterP->scanlineStride;
3327             }
3328         }
3329         else {
3330             for (y=0; y < rasterP->height; y++) {
3331                 inP = lineInP;
3332                 for (x=0; x < rasterP->width; x++) {
3333                     for (c=0; c < rasterP->numBands; c++) {
3334                         /*
3335                          * Not correct.  Might need to
3336                          * unpremult, shift, etc
3337                          */
3338                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3339                                    <<loff[c]);
3340                     }
3341                     inP++;
3342                 }
3343                 lineInP += rasterP->scanlineStride;
3344             }
3345         }
3346     }
3347     else {
3348         c = component;
3349         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3350         if (roff[0] < 0) {
3351             loff[0] = -roff[0];
3352             roff[0] = 0;
3353         }
3354         else loff[c] = 0;
3355         for (y=0; y < rasterP->height; y++) {
3356             inP = lineInP;
3357             for (x=0; x < rasterP->width; x++) {
3358                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3359                 inP++;
3360             }
3361             lineInP += rasterP->scanlineStride;
3362         }
3363     }
3364 
3365     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3366 
3367     return 0;
3368 }
3369 
3370 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3371 static int expandPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3372                                   int component, unsigned char *outDataP,
3373                                   int forceAlpha)
3374 {
3375     int x, y, c;
3376     unsigned char *outP = outDataP;
3377     unsigned int *lineInP, *inP;
3378     jarray jInDataP;
3379     jint   *inDataP;
3380     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3381     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3382     int a = numBands;
3383 
3384     if (rasterP->numBands > MAX_NUMBANDS) {
3385         return -1;
3386     }
3387 
3388     /* Grab data ptr, strides, offsets from raster */
3389     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3390     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3391     if (inDataP == NULL) {
3392         return -1;
3393     }
3394     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3395 
3396     if (component < 0) {
3397         for (c=0; c < rasterP->numBands; c++) {
3398             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3399             if (roff[c] < 0) {
3400                 loff[c] = -roff[c];
3401                 roff[c] = 0;
3402             }
3403             else loff[c] = 0;
3404         }
3405 
3406         /* Need to put in alpha */
3407         if (forceAlpha) {
3408             for (y=0; y < rasterP->height; y++) {
3409                 inP = lineInP;
3410                 for (x=0; x < rasterP->width; x++) {
3411                     *outP++ = 0xff;
3412                     for (c=0; c < numBands; c++) {
3413                         /*
3414                          * Not correct.  Might need to unpremult,
3415                          * shift, etc
3416                          */
3417                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3418                                    <<loff[c]);
3419                     }
3420                     inP++;
3421                 }
3422                 lineInP += rasterP->scanlineStride;
3423             }
3424         }
3425         else {
3426             for (y=0; y < rasterP->height; y++) {
3427                 inP = lineInP;
3428                 for (x=0; x < rasterP->width; x++) {
3429                     *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3430                                    <<loff[a]);
3431                     for (c=0; c < numBands; c++) {
3432                         /*
3433                          * Not correct.  Might need to
3434                          * unpremult, shift, etc
3435                          */
3436                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3437                                    <<loff[c]);
3438                     }
3439                     inP++;
3440                 }
3441                 lineInP += rasterP->scanlineStride;
3442             }
3443         }
3444     }
3445     else {
3446         c = component;
3447         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3448         if (roff[0] < 0) {
3449             loff[0] = -roff[0];
3450             roff[0] = 0;
3451         }
3452         else loff[c] = 0;
3453         for (y=0; y < rasterP->height; y++) {
3454             inP = lineInP;
3455             for (x=0; x < rasterP->width; x++) {
3456                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3457                 inP++;
3458             }
3459             lineInP += rasterP->scanlineStride;
3460         }
3461     }
3462 
3463     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3464 
3465     return 0;
3466 }
3467 
3468 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3469 static int setPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
3470                         unsigned char *inDataP)
3471 {
3472     int x, y, c;
3473     unsigned char *inP = inDataP;
3474     unsigned char *lineOutP, *outP;
3475     jarray jOutDataP;
3476     jsize dataArrayLength;
3477     unsigned char *outDataP;
3478     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3479 
3480     if (rasterP->numBands > MAX_NUMBANDS) {
3481         return -1;
3482     }
3483 
3484     /* Grab data ptr, strides, offsets from raster */
3485     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3486     if (JNU_IsNull(env, jOutDataP)) {
3487         return -1;
3488     }
3489 
3490     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3491     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3492 
3493     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3494     if (outDataP == NULL) {
3495         return -1;
3496     }
3497     lineOutP = outDataP + rasterP->chanOffsets[0];
3498 
3499     if (component < 0) {
3500         for (c=0; c < rasterP->numBands; c++) {
3501             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3502             if (loff[c] < 0) {
3503                 roff[c] = -loff[c];
3504                 loff[c] = 0;
3505             }
3506             else roff[c] = 0;
3507         }
3508         /* Convert the all bands */
3509         for (y=0; y < rasterP->height; y++) {
3510             outP = lineOutP;
3511             *outP = 0;
3512             for (x=0; x < rasterP->width; x++) {
3513                 for (c=0; c < rasterP->numBands; c++, inP++) {
3514                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3515                 }
3516                 outP++;
3517             }
3518             lineOutP += rasterP->scanlineStride;
3519         }
3520     }
3521     else {
3522         c = component;
3523         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3524         if (loff[0] < 0) {
3525             roff[0] = -loff[0];
3526             loff[0] = 0;
3527         }
3528         else roff[c] = 0;
3529         for (y=0; y < rasterP->height; y++) {
3530             outP = lineOutP;
3531             for (x=0; x < rasterP->width; x++, inP++) {
3532                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3533                 outP++;
3534             }
3535             lineOutP += rasterP->scanlineStride;
3536         }
3537     }
3538 
3539     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3540 
3541     return 0;
3542 }
3543 
3544 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3545 static int setPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3546                            unsigned char *inDataP)
3547 {
3548     int x, y, c;
3549     unsigned char *inP = inDataP;
3550     unsigned short *lineOutP, *outP;
3551     jarray jOutDataP;
3552     jsize dataArrayLength;
3553     unsigned short *outDataP;
3554     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3555 
3556     if (rasterP->numBands > MAX_NUMBANDS) {
3557         return -1;
3558     }
3559 
3560     /* Grab data ptr, strides, offsets from raster */
3561     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3562     if (JNU_IsNull(env, jOutDataP)) {
3563         return -1;
3564     }
3565 
3566     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3567     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3568 
3569     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3570     if (outDataP == NULL) {
3571         return -1;
3572     }
3573     lineOutP = outDataP + rasterP->chanOffsets[0];
3574 
3575     if (component < 0) {
3576         for (c=0; c < rasterP->numBands; c++) {
3577             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3578             if (loff[c] < 0) {
3579                 roff[c] = -loff[c];
3580                 loff[c] = 0;
3581             }
3582             else roff[c] = 0;
3583         }
3584         /* Convert the all bands */
3585         for (y=0; y < rasterP->height; y++) {
3586             outP = lineOutP;
3587             for (x=0; x < rasterP->width; x++) {
3588                 for (c=0; c < rasterP->numBands; c++, inP++) {
3589                     /* Not correct.  Might need to unpremult, shift, etc */
3590                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3591                 }
3592                 outP++;
3593             }
3594             lineOutP += rasterP->scanlineStride;
3595         }
3596     }
3597     else {
3598         c = component;
3599         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3600         if (loff[0] < 0) {
3601             roff[0] = -loff[0];
3602             loff[0] = 0;
3603         }
3604         else roff[c] = 0;
3605         for (y=0; y < rasterP->height; y++) {
3606             outP = lineOutP;
3607             for (x=0; x < rasterP->width; x++, inP++) {
3608                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3609                 outP++;
3610             }
3611             lineOutP += rasterP->scanlineStride;
3612         }
3613     }
3614 
3615     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3616 
3617     return 0;
3618 }
3619 
3620 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3621 static int setPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3622                            unsigned char *inDataP)
3623 {
3624     int x, y, c;
3625     unsigned char *inP = inDataP;
3626     unsigned int *lineOutP, *outP;
3627     jarray jOutDataP;
3628     jsize dataArrayLength;
3629     unsigned int *outDataP;
3630     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3631 
3632     if (rasterP->numBands > MAX_NUMBANDS) {
3633         return -1;
3634     }
3635 
3636     /* Grab data ptr, strides, offsets from raster */
3637     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3638     if (JNU_IsNull(env, jOutDataP)) {
3639         return -1;
3640     }
3641 
3642     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3643     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3644 
3645     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3646     if (outDataP == NULL) {
3647         return -1;
3648     }
3649     lineOutP = outDataP + rasterP->chanOffsets[0];
3650 
3651     if (component < 0) {
3652         for (c=0; c < rasterP->numBands; c++) {
3653             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3654             if (loff[c] < 0) {
3655                 roff[c] = -loff[c];
3656                 loff[c] = 0;
3657             }
3658             else roff[c] = 0;
3659         }
3660         /* Convert the all bands */
3661         for (y=0; y < rasterP->height; y++) {
3662             outP = lineOutP;
3663             for (x=0; x < rasterP->width; x++) {
3664                 for (c=0; c < rasterP->numBands; c++, inP++) {
3665                     /* Not correct.  Might need to unpremult, shift, etc */
3666                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3667                 }
3668                 outP++;
3669             }
3670             lineOutP += rasterP->scanlineStride;
3671         }
3672     }
3673     else {
3674         c = component;
3675         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3676         if (loff[0] < 0) {
3677             roff[0] = -loff[0];
3678             loff[0] = 0;
3679         }
3680         else roff[c] = 0;
3681 
3682         for (y=0; y < rasterP->height; y++) {
3683             outP = lineOutP;
3684             for (x=0; x < rasterP->width; x++, inP++) {
3685                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3686                 outP++;
3687             }
3688             lineOutP += rasterP->scanlineStride;
3689         }
3690     }
3691 
3692     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3693 
3694     return 0;
3695 }
3696 
3697 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3698 static int setPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
3699                                int component, unsigned char *inDataP,
3700                                int supportsAlpha)
3701 {
3702     int x, y, c;
3703     unsigned char *inP = inDataP;
3704     unsigned char *lineOutP, *outP;
3705     jarray jOutDataP;
3706     jsize  dataArrayLength;
3707     unsigned char *outDataP;
3708     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3709     int a = rasterP->numBands - 1;
3710 
3711     if (rasterP->numBands > MAX_NUMBANDS) {
3712         return -1;
3713     }
3714 
3715     /* Grab data ptr, strides, offsets from raster */
3716     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3717     if (JNU_IsNull(env, jOutDataP)) {
3718         return -1;
3719     }
3720 
3721     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3722     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3723 
3724     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3725     if (outDataP == NULL) {
3726         return -1;
3727     }
3728     lineOutP = outDataP + rasterP->chanOffsets[0];
3729 
3730     if (component < 0) {
3731         for (c=0; c < rasterP->numBands; c++) {
3732             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3733             if (loff[c] < 0) {
3734                 roff[c] = -loff[c];
3735                 loff[c] = 0;
3736             }
3737             else roff[c] = 0;
3738         }
3739         /* Convert the all bands */
3740         if (supportsAlpha) {
3741             for (y=0; y < rasterP->height; y++) {
3742                 outP = lineOutP;
3743                 *outP = 0;
3744                 for (x=0; x < rasterP->width; x++) {
3745                     *outP |= (*inP<<loff[a]>>roff[a])&
3746                         rasterP->sppsm.maskArray[a];
3747                     inP++;
3748                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3749                         *outP |= (*inP<<loff[c]>>roff[c])&
3750                             rasterP->sppsm.maskArray[c];
3751                     }
3752                     outP++;
3753                 }
3754                 lineOutP += rasterP->scanlineStride;
3755             }
3756         }
3757         else {
3758             for (y=0; y < rasterP->height; y++) {
3759                 outP = lineOutP;
3760                 *outP = 0;
3761                 for (x=0; x < rasterP->width; x++) {
3762                     inP++;
3763                     for (c=0; c < rasterP->numBands; c++, inP++) {
3764                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3765                     }
3766                     outP++;
3767                 }
3768                 lineOutP += rasterP->scanlineStride;
3769             }
3770         }
3771     }
3772     else {
3773         c = component;
3774         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3775         if (loff[0] < 0) {
3776             roff[0] = -loff[0];
3777             loff[0] = 0;
3778         }
3779         else roff[c] = 0;
3780         for (y=0; y < rasterP->height; y++) {
3781             outP = lineOutP;
3782             for (x=0; x < rasterP->width; x++, inP++) {
3783                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3784                 outP++;
3785             }
3786             lineOutP += rasterP->scanlineStride;
3787         }
3788     }
3789 
3790     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3791 
3792     return 0;
3793 }
3794 
3795 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3796 static int setPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3797                                int component, unsigned char *inDataP,
3798                                int supportsAlpha)
3799 {
3800     int x, y, c;
3801     unsigned char *inP = inDataP;
3802     unsigned short *lineOutP, *outP;
3803     jarray jOutDataP;
3804     jsize dataArrayLength;
3805     unsigned short *outDataP;
3806     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3807     int a = rasterP->numBands - 1;
3808 
3809     if (rasterP->numBands > MAX_NUMBANDS) {
3810         return -1;
3811     }
3812 
3813     /* Grab data ptr, strides, offsets from raster */
3814     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3815     if (JNU_IsNull(env, jOutDataP)) {
3816         return -1;
3817     }
3818     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3819     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3820 
3821     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3822     if (outDataP == NULL) {
3823         return -1;
3824     }
3825     lineOutP = outDataP + rasterP->chanOffsets[0];
3826 
3827     if (component < 0) {
3828         for (c=0; c < rasterP->numBands; c++) {
3829             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3830             if (loff[c] < 0) {
3831                 roff[c] = -loff[c];
3832                 loff[c] = 0;
3833             }
3834             else roff[c] = 0;
3835         }
3836         /* Convert the all bands */
3837         if (supportsAlpha) {
3838             for (y=0; y < rasterP->height; y++) {
3839                 outP = lineOutP;
3840                 for (x=0; x < rasterP->width; x++) {
3841                     *outP |= (*inP<<loff[a]>>roff[a])&
3842                         rasterP->sppsm.maskArray[a];
3843                     inP++;
3844                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3845                         /* Not correct.  Might need to unpremult, shift, etc */
3846                         *outP |= (*inP<<loff[c]>>roff[c])&
3847                             rasterP->sppsm.maskArray[c];
3848                     }
3849                     outP++;
3850                 }
3851                 lineOutP += rasterP->scanlineStride;
3852             }
3853         }
3854         else {
3855             for (y=0; y < rasterP->height; y++) {
3856                 outP = lineOutP;
3857                 for (x=0; x < rasterP->width; x++) {
3858                     inP++;
3859                     for (c=0; c < rasterP->numBands; c++, inP++) {
3860                         /* Not correct.  Might need to unpremult, shift, etc */
3861                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3862                     }
3863                     outP++;
3864                 }
3865                 lineOutP += rasterP->scanlineStride;
3866             }
3867         }
3868     }
3869     else {
3870         c = component;
3871         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3872         if (loff[0] < 0) {
3873             roff[0] = -loff[0];
3874             loff[0] = 0;
3875         }
3876         else roff[c] = 0;
3877         for (y=0; y < rasterP->height; y++) {
3878             outP = lineOutP;
3879             for (x=0; x < rasterP->width; x++, inP++) {
3880                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3881                 outP++;
3882             }
3883             lineOutP += rasterP->scanlineStride;
3884         }
3885     }
3886 
3887     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3888 
3889     return 0;
3890 }
3891 
3892 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3893 static int setPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3894                                int component, unsigned char *inDataP,
3895                                int supportsAlpha)
3896 {
3897     int x, y, c;
3898     unsigned char *inP = inDataP;
3899     unsigned int *lineOutP, *outP;
3900     jarray jOutDataP;
3901     jsize dataArrayLength;
3902     unsigned int *outDataP;
3903     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3904     int a = rasterP->numBands - 1;
3905 
3906     if (rasterP->numBands > MAX_NUMBANDS) {
3907         return -1;
3908     }
3909 
3910     /* Grab data ptr, strides, offsets from raster */
3911     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3912     if (JNU_IsNull(env, jOutDataP)) {
3913         return -1;
3914     }
3915 
3916     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3917     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3918 
3919     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3920     if (outDataP == NULL) {
3921         return -1;
3922     }
3923     lineOutP = outDataP + rasterP->chanOffsets[0];
3924 
3925     if (component < 0) {
3926         for (c=0; c < rasterP->numBands; c++) {
3927             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3928             if (loff[c] < 0) {
3929                 roff[c] = -loff[c];
3930                 loff[c] = 0;
3931             }
3932             else roff[c] = 0;
3933         }
3934         /* Convert the all bands */
3935         if (supportsAlpha) {
3936             for (y=0; y < rasterP->height; y++) {
3937                 outP = lineOutP;
3938                 for (x=0; x < rasterP->width; x++) {
3939                     *outP |= (*inP<<loff[a]>>roff[a])&
3940                         rasterP->sppsm.maskArray[a];
3941                     inP++;
3942                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3943                         /* Not correct.  Might need to unpremult, shift, etc */
3944                         *outP |= (*inP<<loff[c]>>roff[c])&
3945                             rasterP->sppsm.maskArray[c];
3946                     }
3947                     outP++;
3948                 }
3949                 lineOutP += rasterP->scanlineStride;
3950             }
3951         }
3952         else {
3953             for (y=0; y < rasterP->height; y++) {
3954                 outP = lineOutP;
3955                 for (x=0; x < rasterP->width; x++) {
3956                     inP++;
3957                     for (c=0; c < rasterP->numBands; c++, inP++) {
3958                         /* Not correct.  Might need to unpremult, shift, etc */
3959                         *outP |= (*inP<<loff[c]>>roff[c])&
3960                             rasterP->sppsm.maskArray[c];
3961                     }
3962                     outP++;
3963                 }
3964                 lineOutP += rasterP->scanlineStride;
3965             }
3966         }
3967     }
3968     else {
3969         c = component;
3970         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3971         if (loff[0] < 0) {
3972             roff[0] = -loff[0];
3973             loff[0] = 0;
3974         }
3975         else roff[c] = 0;
3976 
3977         for (y=0; y < rasterP->height; y++) {
3978             outP = lineOutP;
3979             for (x=0; x < rasterP->width; x++, inP++) {
3980                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3981                 outP++;
3982             }
3983             lineOutP += rasterP->scanlineStride;
3984         }
3985     }
3986 
3987     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3988 
3989     return 0;
3990 }
3991 
3992 /* This is temporary code.  Should go away when there is better color
3993  * conversion code available.
3994  * REMIND:  Ignoring alpha
3995  */
3996 /* returns the absolute value x */
3997 #define ABS(x) ((x) < 0 ? -(x) : (x))
3998 #define CLIP(val,min,max)       ((val < min) ? min : ((val > max) ? max : val))
3999 
4000 static int
4001 colorMatch(int r, int g, int b, int a, unsigned char *argb, int numColors) {
4002     int besti = 0;
4003     int mindist, i, t, d;
4004     unsigned char red, green, blue;
4005 
4006     r = CLIP(r, 0, 255);
4007     g = CLIP(g, 0, 255);
4008     b = CLIP(b, 0, 255);
4009 
4010     /* look for pure gray match */
4011     if ((r == g) && (g == b)) {
4012         mindist = 256;
4013         for (i = 0 ; i < numColors ; i++, argb+=4) {
4014             red = argb[1];
4015             green = argb[2];
4016             blue = argb[3];
4017             if (! ((red == green) && (green == blue)) ) {
4018                 continue;
4019             }
4020             d = ABS(red - r);
4021             if (d == 0)
4022                 return i;
4023             if (d < mindist) {
4024                 besti = i;
4025                 mindist = d;
4026             }
4027         }
4028         return besti;
4029     }
4030 
4031     /* look for non-pure gray match */
4032     mindist = 256 * 256 * 256;
4033     for (i = 0 ; i < numColors ; i++, argb+=4) {
4034         red = argb[1];
4035         green = argb[2];
4036         blue = argb[3];
4037         t = red - r;
4038         d = t * t;
4039         if (d >= mindist) {
4040             continue;
4041         }
4042         t = green - g;
4043         d += t * t;
4044         if (d >= mindist) {
4045             continue;
4046         }
4047         t = blue - b;
4048         d += t * t;
4049         if (d >= mindist) {
4050             continue;
4051         }
4052         if (d == 0)
4053             return i;
4054         if (d < mindist) {
4055             besti = i;
4056             mindist = d;
4057         }
4058     }
4059 
4060     return besti;
4061 }