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 
1066             return 0;
1067         }
1068     }
1069 
1070     if (s_printIt) {
1071         printf("matrix is %g %g %g %g %g %g\n", matrix[0], matrix[1],
1072                matrix[2], matrix[3], matrix[4], matrix[5]);
1073     }
1074 
1075     mtx[0] = matrix[0];
1076     mtx[1] = matrix[2];
1077     mtx[2] = matrix[4];
1078     mtx[3] = matrix[1];
1079     mtx[4] = matrix[3];
1080     mtx[5] = matrix[5];
1081 
1082     (*env)->ReleasePrimitiveArrayCritical(env, jmatrix, matrix, JNI_ABORT);
1083 
1084     /* Parse the source raster */
1085     if (awt_parseRaster(env, jsrc, srcRasterP) <= 0) {
1086         /* Can't handle any custom rasters */
1087         free(srcRasterP);
1088         free(dstRasterP);
1089         return 0;
1090     }
1091 
1092     /* Parse the destination raster */
1093     if (awt_parseRaster(env, jdst, dstRasterP) <= 0) {
1094         /* Can't handle any custom images */
1095         awt_freeParsedRaster(srcRasterP, TRUE);
1096         free(dstRasterP);
1097         return 0;
1098     }
1099 
1100     /* Allocate the arrays */
1101     if (allocateRasterArray(env, srcRasterP, &src, &sdata, TRUE) < 0) {
1102         /* Must be some problem */
1103         awt_freeParsedRaster(srcRasterP, TRUE);
1104         awt_freeParsedRaster(dstRasterP, TRUE);
1105         return 0;
1106     }
1107     if (allocateRasterArray(env, dstRasterP, &dst, &ddata, FALSE) < 0) {
1108         /* Must be some problem */
1109         freeDataArray(env, srcRasterP->jdata, src, sdata, NULL, NULL, NULL);
1110         awt_freeParsedRaster(srcRasterP, TRUE);
1111         awt_freeParsedRaster(dstRasterP, TRUE);
1112         return 0;
1113     }
1114 
1115 #if 0
1116 fprintf(stderr,"Src----------------\n");
1117 fprintf(stderr,"Type : %d\n",src->type);
1118 fprintf(stderr,"Channels: %d\n",src->channels);
1119 fprintf(stderr,"Width   : %d\n",src->width);
1120 fprintf(stderr,"Height  : %d\n",src->height);
1121 fprintf(stderr,"Stride  : %d\n",src->stride);
1122 fprintf(stderr,"Flags   : %d\n",src->flags);
1123 
1124 fprintf(stderr,"Dst----------------\n");
1125 fprintf(stderr,"Type : %d\n",dst->type);
1126 fprintf(stderr,"Channels: %d\n",dst->channels);
1127 fprintf(stderr,"Width   : %d\n",dst->width);
1128 fprintf(stderr,"Height  : %d\n",dst->height);
1129 fprintf(stderr,"Stride  : %d\n",dst->stride);
1130 fprintf(stderr,"Flags   : %d\n",dst->flags);
1131 #endif
1132 
1133     {
1134         unsigned char *cP = (unsigned char *)mlib_ImageGetData(dst);
1135 
1136         memset(cP, 0, mlib_ImageGetWidth(dst)*mlib_ImageGetHeight(dst));
1137     }
1138 
1139     /* Perform the transformation */
1140     if ((status = (*sMlibFns[MLIB_AFFINE].fptr)(dst, src, mtx, filter,
1141                                   MLIB_EDGE_SRC_EXTEND) != MLIB_SUCCESS))
1142     {
1143         printMedialibError(status);
1144         /* REMIND: Free the regions */
1145         return 0;
1146     }
1147 
1148     if (s_printIt) {
1149         if (sdata == NULL) {
1150             dP = (unsigned int *) mlib_ImageGetData(src);
1151         }
1152         else {
1153             dP = (unsigned int *) sdata;
1154         }
1155         printf("src is\n");
1156         for (i=0; i < 20; i++) {
1157             printf("%x ",dP[i]);
1158         }
1159         printf("\n");
1160         if (ddata == NULL) {
1161             dP = (unsigned int *)mlib_ImageGetData(dst);
1162         }
1163         else {
1164             dP = (unsigned int *) ddata;
1165         }
1166         printf("dst is\n");
1167         for (i=0; i < 20; i++) {
1168             printf("%x ",dP[i]);
1169         }
1170         printf("\n");
1171     }
1172 
1173     /* Means that we couldn't write directly into the destination buffer */
1174     if (ddata == NULL) {
1175         /* Need to store it back into the array */
1176         if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) {
1177             (*env)->ExceptionClear(env); // Could not store the array, try another way
1178             retStatus = setPixelsFormMlibImage(env, dstRasterP, dst);
1179         }
1180     }
1181 
1182     /* Release the pinned memory */
1183     freeDataArray(env, srcRasterP->jdata, src, sdata,
1184                   dstRasterP->jdata, dst, ddata);
1185 
1186     awt_freeParsedRaster(srcRasterP, TRUE);
1187     awt_freeParsedRaster(dstRasterP, TRUE);
1188 
1189     if (s_timeIt) (*stop_timer)(3600,1);
1190 
1191     return retStatus;
1192 }
1193 
1194 typedef struct {
1195     jobject jArray;
1196     jsize length;
1197     unsigned char *table;
1198 } LookupArrayInfo;
1199 
1200 #define NLUT 8
1201 
1202 #ifdef _LITTLE_ENDIAN
1203 #define INDEXES    { 3, 2, 1, 0, 7, 6, 5, 4 }
1204 #else
1205 #define INDEXES    { 0, 1, 2, 3, 4, 5, 6, 7 }
1206 #endif
1207 
1208 static int lookupShortData(mlib_image* src, mlib_image* dst,
1209     LookupArrayInfo* lookup)
1210 {
1211     int x, y;
1212     unsigned int mask = NLUT-1;
1213 
1214     unsigned short* srcLine = (unsigned short*)src->data;
1215     unsigned char* dstLine = (unsigned char*)dst->data;
1216 
1217     static int indexes[NLUT] = INDEXES;
1218 
1219     if (src->width != dst->width || src->height != dst->height) {
1220         return 0;
1221     }
1222 
1223     for (y=0; y < src->height; y++) {
1224         int nloop, nx;
1225         int npix = src->width;
1226 
1227         unsigned short* srcPixel = srcLine;
1228         unsigned char* dstPixel = dstLine;
1229 
1230 #ifdef SIMPLE_LOOKUP_LOOP
1231         for (x=0; status && x < width; x++) {
1232             unsigned short s = *srcPixel++;
1233             if (s >= lookup->length) {
1234                 /* we can not handle source image using
1235                 * byte lookup table. Fall back to processing
1236                 * images in java
1237                 */
1238                 return 0;
1239             }
1240             *dstPixel++ = lookup->table[s];
1241         }
1242 #else
1243         /* Get to 32 bit-aligned point */
1244         while(((uintptr_t)dstPixel & 0x3) != 0 && npix>0) {
1245             unsigned short s = *srcPixel++;
1246             if (s >= lookup->length) {
1247                 return 0;
1248             }
1249             *dstPixel++ = lookup->table[s];
1250             npix--;
1251         }
1252 
1253         /*
1254          * Do NLUT pixels per loop iteration.
1255          * Pack into ints and write out 2 at a time.
1256          */
1257         nloop = npix/NLUT;
1258         nx = npix%NLUT;
1259 
1260         for(x=nloop; x!=0; x--) {
1261             int i = 0;
1262             int* dstP = (int*)dstPixel;
1263 
1264             for (i = 0; i < NLUT; i++) {
1265                 if (srcPixel[i] >= lookup->length) {
1266                     return 0;
1267                 }
1268             }
1269 
1270             dstP[0] = (int)
1271                 ((lookup->table[srcPixel[indexes[0]]] << 24) |
1272                  (lookup->table[srcPixel[indexes[1]]] << 16) |
1273                  (lookup->table[srcPixel[indexes[2]]] << 8)  |
1274                   lookup->table[srcPixel[indexes[3]]]);
1275             dstP[1] = (int)
1276                 ((lookup->table[srcPixel[indexes[4]]] << 24) |
1277                  (lookup->table[srcPixel[indexes[5]]] << 16) |
1278                  (lookup->table[srcPixel[indexes[6]]] << 8)  |
1279                   lookup->table[srcPixel[indexes[7]]]);
1280 
1281 
1282             dstPixel += NLUT;
1283             srcPixel += NLUT;
1284         }
1285 
1286         /*
1287          * Complete any remaining pixels
1288          */
1289         for(x=nx; x!=0; x--) {
1290             unsigned short s = *srcPixel++;
1291             if (s >= lookup->length) {
1292                 return 0;
1293             }
1294             *dstPixel++ = lookup->table[s];
1295         }
1296 #endif
1297 
1298         dstLine += dst->stride;     // array of bytes, scan stride in bytes
1299         srcLine += src->stride / 2; // array of shorts, scan stride in bytes
1300     }
1301     return 1;
1302 }
1303 
1304 JNIEXPORT jint JNICALL
1305 Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject thisLib,
1306                                            jobject jsrc, jobject jdst,
1307                                            jobjectArray jtableArrays)
1308 {
1309     mlib_image *src;
1310     mlib_image *dst;
1311     void *sdata, *ddata;
1312     unsigned char **tbl;
1313     unsigned char lut[256];
1314     int retStatus = 1;
1315     int i;
1316     mlib_status status;
1317     int lut_nbands;
1318     LookupArrayInfo *jtable;
1319     BufImageS_t *srcImageP, *dstImageP;
1320     int nbands;
1321     int ncomponents;
1322     mlibHintS_t hint;
1323 
1324     /* This function requires a lot of local refs ??? Is 64 enough ??? */
1325     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
1326         return 0;
1327 
1328     if (s_nomlib) return 0;
1329     if (s_timeIt) (*start_timer)(3600);
1330 
1331     /* Parse the source image */
1332     if (awt_parseImage(env, jsrc, &srcImageP, FALSE) <= 0) {
1333         /* Can't handle any custom images */
1334         return 0;
1335     }
1336 
1337     /* Parse the destination image */
1338     if (awt_parseImage(env, jdst, &dstImageP, FALSE) <= 0) {
1339         /* Can't handle any custom images */
1340         awt_freeParsedImage(srcImageP, TRUE);
1341         return 0;
1342     }
1343 
1344     nbands = setImageHints(env, srcImageP, dstImageP, FALSE, TRUE,
1345                         FALSE, &hint);
1346 
1347     if (nbands < 1 || nbands > srcImageP->cmodel.numComponents) {
1348         /* Can't handle any custom images */
1349         awt_freeParsedImage(srcImageP, TRUE);
1350         awt_freeParsedImage(dstImageP, TRUE);
1351         return 0;
1352     }
1353 
1354     ncomponents = srcImageP->cmodel.isDefaultCompatCM
1355         ? 4
1356         : srcImageP->cmodel.numComponents;
1357 
1358     /* Make sure that color order can be used for
1359      * re-ordering of lookup arrays.
1360      */
1361     for (i = 0; i < nbands; i++) {
1362         int idx = srcImageP->hints.colorOrder[i];
1363 
1364         if (idx < 0 || idx >= ncomponents) {
1365             awt_freeParsedImage(srcImageP, TRUE);
1366             awt_freeParsedImage(dstImageP, TRUE);
1367             return 0;
1368         }
1369     }
1370 
1371     lut_nbands = (*env)->GetArrayLength(env, jtableArrays);
1372 
1373     if (lut_nbands > ncomponents) {
1374         lut_nbands = ncomponents;
1375     }
1376 
1377     tbl = NULL;
1378     if (SAFE_TO_ALLOC_2(ncomponents, sizeof(unsigned char *))) {
1379         tbl = (unsigned char **)
1380             calloc(1, ncomponents * sizeof(unsigned char *));
1381     }
1382 
1383     jtable = NULL;
1384     if (SAFE_TO_ALLOC_2(lut_nbands, sizeof(LookupArrayInfo))) {
1385         jtable = (LookupArrayInfo *)malloc(lut_nbands * sizeof (LookupArrayInfo));
1386     }
1387 
1388     if (tbl == NULL || jtable == NULL) {
1389         if (tbl != NULL) free(tbl);
1390         if (jtable != NULL) free(jtable);
1391         awt_freeParsedImage(srcImageP, TRUE);
1392         awt_freeParsedImage(dstImageP, TRUE);
1393         JNU_ThrowNullPointerException(env, "NULL LUT");
1394         return 0;
1395     }
1396     /* Need to grab these pointers before we lock down arrays */
1397     for (i=0; i < lut_nbands; i++) {
1398         jtable[i].jArray = (*env)->GetObjectArrayElement(env, jtableArrays, i);
1399 
1400         if (jtable[i].jArray != NULL) {
1401             jtable[i].length = (*env)->GetArrayLength(env, jtable[i].jArray);
1402             jtable[i].table = NULL;
1403 
1404             if (jtable[i].length < 256) {
1405                 /* we may read outside the table during lookup */
1406                 jtable[i].jArray = NULL;
1407                 jtable[i].length = 0;
1408             }
1409         }
1410         if (jtable[i].jArray == NULL) {
1411             free(tbl);
1412             free(jtable);
1413             awt_freeParsedImage(srcImageP, TRUE);
1414             awt_freeParsedImage(dstImageP, TRUE);
1415             return 0;
1416         }
1417     }
1418 
1419     /* Allocate the arrays */
1420     if (allocateArray(env, srcImageP, &src, &sdata, TRUE, FALSE, FALSE) < 0) {
1421         /* Must be some problem */
1422         free(tbl);
1423         free(jtable);
1424         awt_freeParsedImage(srcImageP, TRUE);
1425         awt_freeParsedImage(dstImageP, TRUE);
1426         return 0;
1427     }
1428     if (allocateArray(env, dstImageP, &dst, &ddata, FALSE, FALSE, FALSE) < 0) {
1429         /* Must be some problem */
1430         free(tbl);
1431         free(jtable);
1432         freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
1433         awt_freeParsedImage(srcImageP, TRUE);
1434         awt_freeParsedImage(dstImageP, TRUE);
1435         return 0;
1436     }
1437 
1438     /* Set up a straight lut so we don't mess around with alpha */
1439     /*
1440      * NB: medialib lookup routine expects lookup array for each
1441      * component of source image including alpha.
1442      * If lookup table we got form the java layer does not contain
1443      * sufficient number of lookup arrays we add references to identity
1444      * lookup array to make medialib happier.
1445      */
1446     if (lut_nbands < ncomponents) {
1447         int j;
1448         /* REMIND: This should be the size of the input lut!! */
1449         for (j=0; j < 256; j++) {
1450             lut[j] = j;
1451         }
1452         for (j=0; j < ncomponents; j++) {
1453             tbl[j] = lut;
1454         }
1455     }
1456 
1457     for (i=0; i < lut_nbands; i++) {
1458         jtable[i].table = (unsigned char *)
1459             (*env)->GetPrimitiveArrayCritical(env, jtable[i].jArray, NULL);
1460         if (jtable[i].table == NULL) {
1461             /* Free what we've got so far. */
1462             int j;
1463             for (j = 0; j < i; j++) {
1464                 (*env)->ReleasePrimitiveArrayCritical(env,
1465                                                       jtable[j].jArray,
1466                                                       (jbyte *) jtable[j].table,
1467                                                       JNI_ABORT);
1468             }
1469             free(tbl);
1470             free(jtable);
1471             freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL);
1472             awt_freeParsedImage(srcImageP, TRUE);
1473             awt_freeParsedImage(dstImageP, TRUE);
1474             return 0;
1475         }
1476         tbl[srcImageP->hints.colorOrder[i]] = jtable[i].table;
1477     }
1478 
1479     if (lut_nbands == 1) {
1480         for (i=1; i < nbands -
1481                  srcImageP->cmodel.supportsAlpha; i++) {
1482                      tbl[srcImageP->hints.colorOrder[i]] = jtable[0].table;
1483         }
1484     }
1485 
1486     /* Mlib needs 16bit lookuptable and must be signed! */
1487     if (src->type == MLIB_SHORT) {
1488         if (dst->type == MLIB_BYTE) {
1489             if (nbands > 1) {
1490                 retStatus = 0;
1491             }
1492             else {
1493                 retStatus = lookupShortData(src, dst, &jtable[0]);
1494             }
1495         }
1496         /* How about ddata == null? */
1497     }
1498     else if ((status = (*sMlibFns[MLIB_LOOKUP].fptr)(dst, src,
1499                                       (void **)tbl) != MLIB_SUCCESS)) {
1500         printMedialibError(status);
1501         retStatus = 0;
1502     }
1503 
1504    /* Release the LUT */
1505     for (i=0; i < lut_nbands; i++) {
1506         (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray,
1507             (jbyte *) jtable[i].table, JNI_ABORT);
1508     }
1509     free ((void *) jtable);
1510     free ((void *) tbl);
1511 
1512     /*
1513      * Means that we couldn't write directly into
1514      * the destination buffer
1515      */
1516     if (ddata == NULL) {
1517 
1518         /* Need to store it back into the array */
1519         if (storeImageArray(env, srcImageP, dstImageP, dst) < 0) {
1520             /* Error */
1521             retStatus = 0;
1522         }
1523     }
1524 
1525 
1526     /* Release the pinned memory */
1527     freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata);
1528 
1529     awt_freeParsedImage(srcImageP, TRUE);
1530     awt_freeParsedImage(dstImageP, TRUE);
1531 
1532     if (s_timeIt) (*stop_timer)(3600, 1);
1533 
1534     return retStatus;
1535 }
1536 
1537 JNIEXPORT jint JNICALL
1538 Java_sun_awt_image_ImagingLib_lookupByteRaster(JNIEnv *env,
1539                                                jobject this,
1540                                                jobject jsrc,
1541                                                jobject jdst,
1542                                                jobjectArray jtableArrays)
1543 {
1544     RasterS_t*     srcRasterP;
1545     RasterS_t*     dstRasterP;
1546     mlib_image*    src;
1547     mlib_image*    dst;
1548     void*          sdata;
1549     void*          ddata;
1550     LookupArrayInfo jtable[4];
1551     unsigned char* mlib_lookupTable[4];
1552     int            i;
1553     int            retStatus = 1;
1554     mlib_status    status;
1555     int            jlen;
1556     int            lut_nbands;
1557     int            src_nbands;
1558     int            dst_nbands;
1559     unsigned char  ilut[256];
1560 
1561     /* This function requires a lot of local refs ??? Is 64 enough ??? */
1562     if ((*env)->EnsureLocalCapacity(env, 64) < 0)
1563         return 0;
1564 
1565     if (s_nomlib) return 0;
1566     if (s_timeIt) (*start_timer)(3600);
1567 
1568     if ((srcRasterP = (RasterS_t*) calloc(1, sizeof(RasterS_t))) == NULL) {
1569         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1570         return -1;
1571     }
1572 
1573     if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) {
1574         JNU_ThrowOutOfMemoryError(env, "Out of memory");
1575         free(srcRasterP);
1576         return -1;
1577     }
1578 
1579     /* Parse the source raster - reject custom images */
1580     if (awt_parseRaster(env, jsrc, srcRasterP) <= 0) {
1581         free(srcRasterP);
1582         free(dstRasterP);
1583         return 0;
1584     }
1585 
1586     /* Parse the destination image - reject custom images */
1587     if (awt_parseRaster(env, jdst, dstRasterP) <= 0) {
1588         awt_freeParsedRaster(srcRasterP, TRUE);
1589         free(dstRasterP);
1590         return 0;
1591     }
1592 
1593     jlen = (*env)->GetArrayLength(env, jtableArrays);
1594 
1595     lut_nbands = jlen;
1596     src_nbands = srcRasterP->numBands;
1597     dst_nbands = dstRasterP->numBands;
1598 
1599     /* adjust number of lookup bands */
1600     if (lut_nbands > src_nbands) {
1601         lut_nbands = src_nbands;
1602     }
1603 
1604     /* MediaLib can't do more than 4 bands */
1605     if (src_nbands <= 0 || src_nbands > 4 ||
1606         dst_nbands <= 0 || dst_nbands > 4 ||
1607         lut_nbands <= 0 || lut_nbands > 4 ||
1608         src_nbands != dst_nbands ||
1609         ((lut_nbands != 1) && (lut_nbands != src_nbands)))
1610     {
1611         // we should free parsed rasters here
1612         awt_freeParsedRaster(srcRasterP, TRUE);
1613         awt_freeParsedRaster(dstRasterP, TRUE);
1614         return 0;
1615     }
1616 
1617     /* Allocate the raster arrays */
1618     if (allocateRasterArray(env, srcRasterP, &src, &sdata, TRUE) < 0) {
1619         /* Must be some problem */
1620         awt_freeParsedRaster(srcRasterP, TRUE);
1621         awt_freeParsedRaster(dstRasterP, TRUE);
1622         return 0;
1623     }
1624     if (allocateRasterArray(env, dstRasterP, &dst, &ddata, FALSE) < 0) {
1625         /* Must be some problem */
1626         freeDataArray(env, srcRasterP->jdata, src, sdata, NULL, NULL, NULL);
1627         awt_freeParsedRaster(srcRasterP, TRUE);
1628         awt_freeParsedRaster(dstRasterP, TRUE);
1629         return 0;
1630     }
1631 
1632     /*
1633      * Well, until now we have analyzed number of bands in
1634      * src and dst rasters.
1635      * However, it is not enough because medialib lookup routine uses
1636      * number of channels of medialib image. Note that in certain
1637      * case number of channels may differs form the number of bands.
1638      * Good example is raster that is used in TYPE_INT_RGB buffered
1639      * image: it has 3 bands, but their medialib representation has
1640      * 4 channels.
1641      *
1642      * In order to avoid the lookup routine failure, we need:
1643      *
1644      * 1. verify that src and dst have same number of channels.
1645      * 2. provide lookup array for every channel. If we have "extra"
1646      *    channel (like the raster described above) then we need to
1647      *    provide identical lookup array.
1648      */
1649     if (src->channels != dst->channels) {
1650         freeDataArray(env, srcRasterP->jdata, src, sdata,
1651                       dstRasterP->jdata, dst, ddata);
1652 
1653         awt_freeParsedRaster(srcRasterP, TRUE);
1654         awt_freeParsedRaster(dstRasterP, TRUE);
1655         return 0;
1656     }
1657 
1658     if (src_nbands < src->channels) {
1659         for (i = 0; i < 256; i++) {
1660             ilut[i] = i;
1661         }
1662     }
1663 
1664 
1665     /* Get references to the lookup table arrays */
1666     /* Need to grab these pointers before we lock down arrays */
1667     for (i=0; i < lut_nbands; i++) {
1668         jtable[i].jArray = (*env)->GetObjectArrayElement(env, jtableArrays, i);
1669         jtable[i].table = NULL;
1670         if (jtable[i].jArray != NULL) {
1671             jtable[i].length = (*env)->GetArrayLength(env, jtable[i].jArray);
1672             if (jtable[i].length < 256) {
1673                  /* we may read outside the table during lookup */
1674                 jtable[i].jArray = NULL;
1675             }
1676         }
1677 
1678         if (jtable[i].jArray == NULL)
1679         {
1680             freeDataArray(env, srcRasterP->jdata, src, sdata,
1681                           dstRasterP->jdata, dst, ddata);
1682 
1683             awt_freeParsedRaster(srcRasterP, TRUE);
1684             awt_freeParsedRaster(dstRasterP, TRUE);
1685             return 0;
1686         }
1687     }
1688 
1689     for (i=0; i < lut_nbands; i++) {
1690         jtable[i].table = (unsigned char *)
1691             (*env)->GetPrimitiveArrayCritical(env, jtable[i].jArray, NULL);
1692         if (jtable[i].table == NULL) {
1693             /* Free what we've got so far. */
1694             int j;
1695             for (j = 0; j < i; j++) {
1696                 (*env)->ReleasePrimitiveArrayCritical(env,
1697                                                       jtable[j].jArray,
1698                                                       (jbyte *) jtable[j].table,
1699                                                       JNI_ABORT);
1700             }
1701             freeDataArray(env, srcRasterP->jdata, src, sdata,
1702                           dstRasterP->jdata, dst, ddata);
1703             awt_freeParsedRaster(srcRasterP, TRUE);
1704             awt_freeParsedRaster(dstRasterP, TRUE);
1705             return 0;
1706         }
1707         mlib_lookupTable[i] = jtable[i].table;
1708     }
1709 
1710     /*
1711      * Medialib routine expects lookup array for each band of raster.
1712      * Setup the  rest of lookup arrays if supplied lookup table
1713      * contains single lookup array.
1714      */
1715     for (i = lut_nbands; i < src_nbands; i++) {
1716         mlib_lookupTable[i] = jtable[0].table;
1717     }
1718 
1719     /*
1720      * Setup lookup array for "extra" channels
1721      */
1722     for ( ; i < src->channels; i++) {
1723         mlib_lookupTable[i] = ilut;
1724     }
1725 
1726     /* Mlib needs 16bit lookuptable and must be signed! */
1727     if (src->type == MLIB_SHORT) {
1728         if (dst->type == MLIB_BYTE) {
1729             if (lut_nbands > 1) {
1730                 retStatus = 0;
1731             } else {
1732                 retStatus = lookupShortData(src, dst, &jtable[0]);
1733             }
1734         }
1735         /* How about ddata == null? */
1736     } else if ((status = (*sMlibFns[MLIB_LOOKUP].fptr)(dst, src,
1737                                       (void **)mlib_lookupTable) != MLIB_SUCCESS)) {
1738         printMedialibError(status);
1739         retStatus = 0;
1740     }
1741 
1742     /* Release the LUT */
1743     for (i=0; i < lut_nbands; i++) {
1744         (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray,
1745                                               (jbyte *) jtable[i].table, JNI_ABORT);
1746     }
1747 
1748     /*
1749      * Means that we couldn't write directly into
1750      * the destination buffer
1751      */
1752     if (ddata == NULL) {
1753         if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) {
1754             retStatus = setPixelsFormMlibImage(env, dstRasterP, dst);
1755         }
1756     }
1757 
1758     /* Release the pinned memory */
1759     freeDataArray(env, srcRasterP->jdata, src, sdata,
1760                   dstRasterP->jdata, dst, ddata);
1761 
1762     awt_freeParsedRaster(srcRasterP, TRUE);
1763     awt_freeParsedRaster(dstRasterP, TRUE);
1764 
1765     if (s_timeIt) (*stop_timer)(3600, 1);
1766 
1767     return retStatus;
1768 }
1769 
1770 
1771 JNIEXPORT jboolean JNICALL
1772 Java_sun_awt_image_ImagingLib_init(JNIEnv *env, jclass thisClass) {
1773     char *start;
1774     if (getenv("IMLIB_DEBUG")) {
1775         start_timer = awt_setMlibStartTimer();
1776         stop_timer = awt_setMlibStopTimer();
1777         if (start_timer && stop_timer) {
1778             s_timeIt = 1;
1779         }
1780     }
1781 
1782     if (getenv("IMLIB_PRINT")) {
1783         s_printIt = 1;
1784     }
1785     if ((start = getenv("IMLIB_START")) != NULL) {
1786         sscanf(start, "%d", &s_startOff);
1787     }
1788 
1789     if (getenv ("IMLIB_NOMLIB")) {
1790         s_nomlib = 1;
1791         return JNI_FALSE;
1792     }
1793 
1794     /* This function is platform-dependent and is in awt_mlib.c */
1795     if (awt_getImagingLib(env, (mlibFnS_t *)&sMlibFns, &sMlibSysFns) !=
1796         MLIB_SUCCESS)
1797     {
1798         s_nomlib = 1;
1799         return JNI_FALSE;
1800     }
1801     return JNI_TRUE;
1802 }
1803 
1804 /* REMIND: How to specify border? */
1805 static void extendEdge(JNIEnv *env, BufImageS_t *imageP,
1806                        int *widthP, int *heightP) {
1807     RasterS_t *rasterP = &imageP->raster;
1808     int width;
1809     int height;
1810     /* Useful for convolution? */
1811 
1812     jobject jbaseraster = (*env)->GetObjectField(env, rasterP->jraster,
1813                                                  g_RasterBaseRasterID);
1814     width = rasterP->width;
1815     height = rasterP->height;
1816 #ifdef WORKING
1817     if (! JNU_IsNull(env, jbaseraster) &&
1818         !(*env)->IsSameObject(env, rasterP->jraster, jbaseraster)) {
1819         int xOff;
1820         int yOff;
1821         int baseWidth;
1822         int baseHeight;
1823         int baseXoff;
1824         int baseYoff;
1825         /* Not the same object so get the width and height */
1826         xOff = (*env)->GetIntField(env, rasterP->jraster, g_RasterXOffsetID);
1827         yOff = (*env)->GetIntField(env, rasterP->jraster, g_RasterYOffsetID);
1828         baseWidth  = (*env)->GetIntField(env, jbaseraster, g_RasterWidthID);
1829         baseHeight = (*env)->GetIntField(env, jbaseraster, g_RasterHeightID);
1830         baseXoff   = (*env)->GetIntField(env, jbaseraster, g_RasterXOffsetID);
1831         baseYoff   = (*env)->GetIntField(env, jbaseraster, g_RasterYOffsetID);
1832 
1833         if (xOff + rasterP->width < baseXoff + baseWidth) {
1834             /* Can use edge */
1835             width++;
1836         }
1837         if (yOff + rasterP->height < baseYoff + baseHeight) {
1838             /* Can use edge */
1839             height++;
1840         }
1841 
1842     }
1843 #endif
1844 
1845 }
1846 
1847 static int
1848 setImageHints(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
1849               int expandICM, int useAlpha,
1850               int premultiply, mlibHintS_t *hintP)
1851 {
1852     ColorModelS_t *srcCMP = &srcP->cmodel;
1853     ColorModelS_t *dstCMP = &dstP->cmodel;
1854     int nbands = 0;
1855     int ncomponents;
1856 
1857     hintP->dataType = srcP->raster.dataType;
1858     hintP->addAlpha = FALSE;
1859 
1860     /* Are the color spaces the same? */
1861     if (srcCMP->csType != dstCMP->csType) {
1862         /* If the src is GRAY and dst RGB, we can handle it */
1863         if (!(srcCMP->csType == java_awt_color_ColorSpace_TYPE_GRAY &&
1864               dstCMP->csType == java_awt_color_ColorSpace_TYPE_RGB)) {
1865             /* Nope, need to handle that in java for now */
1866             return -1;
1867         }
1868         else {
1869             hintP->cvtSrcToDefault = TRUE;
1870         }
1871     }
1872     else {
1873         if (srcP->hints.needToExpand) {
1874             hintP->cvtSrcToDefault = TRUE;
1875         }
1876         else {
1877             /* Need to initialize this */
1878             hintP->cvtSrcToDefault = FALSE;
1879         }
1880     }
1881 
1882     ncomponents = srcCMP->numComponents;
1883     if ((useAlpha == 0) && srcCMP->supportsAlpha) {
1884         ncomponents--;  /* ?? */
1885         /* Not really, more like shrink src to get rid of alpha */
1886         hintP->cvtSrcToDefault = TRUE;
1887     }
1888 
1889     hintP->dataType = srcP->raster.dataType;
1890     if (hintP->cvtSrcToDefault == FALSE) {
1891         if (srcCMP->cmType == INDEX_CM_TYPE) {
1892             if (expandICM) {
1893                 nbands = srcCMP->numComponents;
1894                 hintP->cvtSrcToDefault = TRUE;
1895 
1896                 if (dstCMP->isDefaultCompatCM) {
1897                     hintP->allocDefaultDst = FALSE;
1898                     hintP->cvtToDst = FALSE;
1899                 }
1900                 else if (dstCMP->isDefaultCompatCM) {
1901                     hintP->allocDefaultDst = FALSE;
1902                     hintP->cvtToDst = FALSE;
1903                 }
1904             }
1905             else {
1906                 nbands = 1;
1907                 hintP->cvtSrcToDefault = FALSE;
1908             }
1909 
1910         }
1911         else {
1912             if (srcP->hints.packing & INTERLEAVED) {
1913                 nbands = srcCMP->numComponents;
1914             }
1915             else {
1916                 nbands = 1;
1917             }
1918 
1919             /* Look at the packing */
1920             if ((srcP->hints.packing&BYTE_INTERLEAVED)==BYTE_INTERLEAVED ||
1921                 (srcP->hints.packing&SHORT_INTERLEAVED)==SHORT_INTERLEAVED||
1922                 (srcP->hints.packing&BYTE_SINGLE_BAND) == BYTE_SINGLE_BAND||
1923                 (srcP->hints.packing&SHORT_SINGLE_BAND)==SHORT_SINGLE_BAND||
1924                 (srcP->hints.packing&BYTE_BANDED)  == BYTE_BANDED       ||
1925                 (srcP->hints.packing&SHORT_BANDED) == SHORT_BANDED) {
1926                 /* Can use src directly */
1927                 hintP->cvtSrcToDefault = FALSE;
1928             }
1929             else {
1930                 /* Must be packed or custom */
1931                 hintP->cvtSrcToDefault = TRUE;
1932             }
1933         }
1934     }
1935     if (hintP->cvtSrcToDefault) {
1936         /* By definition */
1937         nbands = 4;  /* What about alpha? */
1938         hintP->dataType = BYTE_DATA_TYPE;
1939         hintP->needToCopy = TRUE;
1940 
1941         if (srcP->imageType == dstP->imageType) {
1942             hintP->cvtToDst = TRUE;
1943         }
1944         else if (dstP->cmodel.isDefaultCM) {
1945             /* Not necessarily */
1946             hintP->cvtToDst = FALSE;
1947         }
1948         else {
1949             hintP->cvtToDst = TRUE;
1950         }
1951     }
1952     else {
1953         int srcImageType = srcP->imageType;
1954         int dstImageType = dstP->imageType;
1955         /* Special case where we need to fill in alpha values */
1956         if (srcCMP->isDefaultCompatCM && dstCMP->isDefaultCompatCM) {
1957             int i;
1958             if (!srcCMP->supportsAlpha &&dstCMP->supportsAlpha) {
1959                 hintP->addAlpha = TRUE;
1960             }
1961             for (i=0; i < srcCMP->numComponents; i++) {
1962                 if (srcP->hints.colorOrder[i] != dstP->hints.colorOrder[i]){
1963                     if (!srcCMP->isDefaultCM) {
1964                         hintP->cvtSrcToDefault = TRUE;
1965                         srcImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1966                     }
1967                     if (!dstCMP->isDefaultCM) {
1968                         hintP->cvtToDst = TRUE;
1969                         dstImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1970                     }
1971 
1972                     break;
1973                 }
1974             }
1975         }
1976         else if (srcCMP->cmType != INDEX_CM_TYPE &&
1977                  !srcCMP->supportsAlpha && dstCMP->supportsAlpha)
1978         {
1979             /* We've already handled the index case.  This is for the rest of the cases */
1980             srcImageType = java_awt_image_BufferedImage_TYPE_INT_ARGB;
1981             hintP->cvtSrcToDefault = TRUE;
1982         }
1983 
1984         hintP->allocDefaultDst = FALSE;
1985         if (srcImageType == dstImageType) {
1986             /* Same image type so use it */
1987             hintP->cvtToDst = FALSE;
1988         }
1989         else if (srcImageType == TYPE_INT_RGB &&
1990                  (dstImageType == TYPE_INT_ARGB ||
1991                   dstImageType == TYPE_INT_ARGB_PRE)) {
1992             hintP->cvtToDst = FALSE;
1993         }
1994         else if (srcImageType == TYPE_INT_BGR &&
1995                  (dstImageType == TYPE_4BYTE_ABGR ||
1996                   dstImageType == TYPE_4BYTE_ABGR_PRE)) {
1997             hintP->cvtToDst = FALSE;
1998         }
1999         else if (srcP->hints.packing == dstP->hints.packing) {
2000             /* Now what? */
2001 
2002             /* Check color order */
2003 
2004             /* Check if just need to scale the data */
2005 
2006             hintP->cvtToDst = TRUE;
2007         }
2008         else {
2009             /* Don't know what it is so convert it */
2010             hintP->allocDefaultDst = TRUE;
2011             hintP->cvtToDst = TRUE;
2012         }
2013         hintP->needToCopy = (ncomponents > nbands);
2014     }
2015 
2016     return nbands;
2017 }
2018 
2019 
2020 static int
2021 expandPacked(JNIEnv *env, BufImageS_t *img, ColorModelS_t *cmP,
2022              RasterS_t *rasterP, int component, unsigned char *bdataP) {
2023 
2024     if (rasterP->rasterType == COMPONENT_RASTER_TYPE) {
2025         switch (rasterP->dataType) {
2026         case BYTE_DATA_TYPE:
2027             if (expandPackedBCR(env, rasterP, component, bdataP) < 0) {
2028                 /* Must have been an error */
2029                 return -1;
2030             }
2031             break;
2032 
2033         case SHORT_DATA_TYPE:
2034             if (expandPackedICR(env, rasterP, component, bdataP) < 0) {
2035                 /* Must have been an error */
2036                 return -1;
2037             }
2038             break;
2039 
2040         case INT_DATA_TYPE:
2041             if (expandPackedICR(env, rasterP, component, bdataP) < 0) {
2042                 /* Must have been an error */
2043                 return -1;
2044             }
2045             break;
2046 
2047         default:
2048             /* REMIND: Return some sort of error */
2049             return -1;
2050         }
2051     }
2052     else {
2053         /* REMIND: Return some sort of error */
2054         return -1;
2055     }
2056 
2057     return 0;
2058 }
2059 
2060 #define NUM_LINES    10
2061 
2062 static int
2063 cvtCustomToDefault(JNIEnv *env, BufImageS_t *imageP, int component,
2064                    unsigned char *dataP) {
2065     const RasterS_t *rasterP = &imageP->raster;
2066     const int w = rasterP->width;
2067     const int h = rasterP->height;
2068 
2069     int y;
2070     jintArray jpixels = NULL;
2071     jint *pixels;
2072     unsigned char *dP = dataP;
2073     int numLines = h > NUM_LINES ? NUM_LINES : h;
2074 
2075     /* it is safe to calculate the scan length, because width has been verified
2076      * on creation of the mlib image
2077      */
2078     const int scanLength = w * 4;
2079 
2080     int nbytes = 0;
2081     if (!SAFE_TO_MULT(numLines, scanLength)) {
2082         return -1;
2083     }
2084 
2085     nbytes = numLines * scanLength;
2086 
2087     jpixels = (*env)->NewIntArray(env, nbytes);
2088     if (JNU_IsNull(env, jpixels)) {
2089         (*env)->ExceptionClear(env);
2090         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
2091         return -1;
2092     }
2093 
2094     for (y = 0; y < h; y += numLines) {
2095         if (y + numLines > h) {
2096             numLines = h - y;
2097             nbytes = numLines * scanLength;
2098         }
2099 
2100         (*env)->CallObjectMethod(env, imageP->jimage,
2101                                  g_BImgGetRGBMID, 0, y,
2102                                  w, numLines,
2103                                  jpixels, 0, w);
2104         if ((*env)->ExceptionOccurred(env)) {
2105             (*env)->DeleteLocalRef(env, jpixels);
2106             return -1;
2107         }
2108 
2109         pixels = (*env)->GetPrimitiveArrayCritical(env, jpixels, NULL);
2110         if (pixels == NULL) {
2111             (*env)->DeleteLocalRef(env, jpixels);
2112             return -1;
2113         }
2114 
2115         memcpy(dP, pixels, nbytes);
2116         dP += nbytes;
2117 
2118         (*env)->ReleasePrimitiveArrayCritical(env, jpixels, pixels,
2119                                               JNI_ABORT);
2120     }
2121 
2122     /* Need to release the array */
2123     (*env)->DeleteLocalRef(env, jpixels);
2124 
2125     return 0;
2126 }
2127 
2128 static int
2129 cvtDefaultToCustom(JNIEnv *env, BufImageS_t *imageP, int component,
2130                    unsigned char *dataP) {
2131     const RasterS_t *rasterP = &imageP->raster;
2132     const int w = rasterP->width;
2133     const int h = rasterP->height;
2134 
2135     int y;
2136     jintArray jpixels = NULL;
2137     jint *pixels;
2138     unsigned char *dP = dataP;
2139     int numLines = h > NUM_LINES ? NUM_LINES : h;
2140 
2141     /* it is safe to calculate the scan length, because width has been verified
2142      * on creation of the mlib image
2143      */
2144     const int scanLength = w * 4;
2145 
2146     int nbytes = 0;
2147     if (!SAFE_TO_MULT(numLines, scanLength)) {
2148         return -1;
2149     }
2150 
2151     nbytes = numLines * scanLength;
2152 
2153     jpixels = (*env)->NewIntArray(env, nbytes);
2154     if (JNU_IsNull(env, jpixels)) {
2155         (*env)->ExceptionClear(env);
2156         JNU_ThrowOutOfMemoryError(env, "Out of Memory");
2157         return -1;
2158     }
2159 
2160     for (y = 0; y < h; y += numLines) {
2161         if (y + numLines > h) {
2162             numLines = h - y;
2163             nbytes = numLines * scanLength;
2164         }
2165 
2166         pixels = (*env)->GetPrimitiveArrayCritical(env, jpixels, NULL);
2167         if (pixels == NULL) {
2168             (*env)->DeleteLocalRef(env, jpixels);
2169             return -1;
2170         }
2171 
2172         memcpy(pixels, dP, nbytes);
2173         dP += nbytes;
2174 
2175        (*env)->ReleasePrimitiveArrayCritical(env, jpixels, pixels, 0);
2176 
2177        (*env)->CallVoidMethod(env, imageP->jimage, g_BImgSetRGBMID, 0, y,
2178                                 w, numLines, jpixels,
2179                                 0, w);
2180        if ((*env)->ExceptionOccurred(env)) {
2181            (*env)->DeleteLocalRef(env, jpixels);
2182            return -1;
2183        }
2184     }
2185 
2186     /* Need to release the array */
2187     (*env)->DeleteLocalRef(env, jpixels);
2188 
2189     return 0;
2190 }
2191 
2192 static int
2193 allocateArray(JNIEnv *env, BufImageS_t *imageP,
2194               mlib_image **mlibImagePP, void **dataPP, int isSrc,
2195               int cvtToDefault, int addAlpha) {
2196     void *dataP;
2197     unsigned char *cDataP;
2198     RasterS_t *rasterP = &imageP->raster;
2199     ColorModelS_t *cmP = &imageP->cmodel;
2200     int dataType = BYTE_DATA_TYPE;
2201     int width;
2202     int height;
2203     HintS_t *hintP = &imageP->hints;
2204     *dataPP = NULL;
2205 
2206     width = rasterP->width;
2207     height = rasterP->height;
2208 
2209     /* Useful for convolution? */
2210     /* This code is zero'ed out so that it cannot be called */
2211 
2212     /* To do this correctly, we need to expand src and dst in the     */
2213     /* same direction up/down/left/right only if both can be expanded */
2214     /* in that direction.  Expanding right and down is easy -         */
2215     /* increment width.  Expanding top and left requires bumping      */
2216     /* around pointers and incrementing the width/height              */
2217 
2218 #if 0
2219     if (0 && useEdges) {
2220         baseWidth  = rasterP->baseRasterWidth;
2221         baseHeight = rasterP->baseRasterHeight;
2222         baseXoff = rasterP->baseOriginX;
2223         baseYoff = rasterP->baseOriginY;
2224 
2225         if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
2226             /* Can use edge */
2227             width++;
2228         }
2229         if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
2230             /* Can use edge */
2231             height++;
2232         }
2233 
2234         if (rasterP->minX > baseXoff ) {
2235             /* Can use edge */
2236             width++;
2237             /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
2238         }
2239         if (rasterP->minY  > baseYoff) {
2240             /* Can use edge */
2241             height++;
2242             /* NEED TO BUMP POINTER BACK A SCANLINE */
2243         }
2244 
2245 
2246     }
2247 #endif
2248     if (cvtToDefault) {
2249         int status = 0;
2250         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
2251         if (*mlibImagePP == NULL) {
2252             return -1;
2253         }
2254         cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2255         /* Make sure the image is cleared.
2256          * NB: the image dimension is already verified, so we can
2257          * safely calculate the length of the buffer.
2258          */
2259         memset(cDataP, 0, width*height*4);
2260 
2261         if (!isSrc) {
2262             return 0;
2263         }
2264 
2265         switch(imageP->cmodel.cmType) {
2266         case INDEX_CM_TYPE:
2267             /* REMIND: Need to rearrange according to dst cm */
2268             /* Fix 4213160, 4184283 */
2269             if (rasterP->rasterType == COMPONENT_RASTER_TYPE) {
2270                 return expandICM(env, imageP, (unsigned int *)cDataP);
2271             }
2272             else {
2273                 return cvtCustomToDefault(env, imageP, -1, cDataP);
2274             }
2275 
2276         case DIRECT_CM_TYPE:
2277             switch(imageP->raster.dataType) {
2278             case BYTE_DATA_TYPE:
2279                 return expandPackedBCRdefault(env, rasterP, -1, cDataP,
2280                                               !imageP->cmodel.supportsAlpha);
2281             case SHORT_DATA_TYPE:
2282                 return expandPackedSCRdefault(env, rasterP, -1, cDataP,
2283                                               !imageP->cmodel.supportsAlpha);
2284             case INT_DATA_TYPE:
2285                 return expandPackedICRdefault(env, rasterP, -1, cDataP,
2286                                               !imageP->cmodel.supportsAlpha);
2287             }
2288         } /* switch(imageP->cmodel.cmType) */
2289 
2290         return cvtCustomToDefault(env, imageP, -1, cDataP);
2291     }
2292 
2293     /* Interleaved with shared data */
2294     dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2295                                                        NULL);
2296     if (dataP == NULL) {
2297         return -1;
2298     }
2299 
2300     /* Means we need to fill in alpha */
2301     if (!cvtToDefault && addAlpha) {
2302         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
2303         if (*mlibImagePP != NULL) {
2304             unsigned int *dstP  = (unsigned int *)
2305                 mlib_ImageGetData(*mlibImagePP);
2306             int dstride = (*mlibImagePP)->stride>>2;
2307             int sstride = hintP->sStride>>2;
2308             unsigned int *srcP = (unsigned int *)
2309                 ((unsigned char *)dataP + hintP->dataOffset);
2310             unsigned int *dP, *sP;
2311             int x, y;
2312             for (y=0; y < height; y++, srcP += sstride, dstP += dstride){
2313                 sP = srcP;
2314                 dP = dstP;
2315                 for (x=0; x < width; x++) {
2316                     dP[x] = sP[x] | 0xff000000;
2317                 }
2318             }
2319         }
2320         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2321                                               JNI_ABORT);
2322         return 0;
2323     }
2324     else if ((hintP->packing & BYTE_INTERLEAVED) == BYTE_INTERLEAVED) {
2325         int nChans = (cmP->isDefaultCompatCM ? 4 : hintP->numChans);
2326         /* Easy case.  It is or is similar to the default CM so use
2327      * the array.  Must be byte data.
2328          */
2329             /* Create the medialib image */
2330         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE,
2331                                               nChans,
2332                                               width,
2333                                               height,
2334                                               hintP->sStride,
2335                                               (unsigned char *)dataP
2336                                               + hintP->dataOffset);
2337     }
2338     else if ((hintP->packing & SHORT_INTERLEAVED) == SHORT_INTERLEAVED) {
2339         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
2340                                               hintP->numChans,
2341                                               width,
2342                                               height,
2343                                               imageP->raster.scanlineStride*2,
2344                                               (unsigned short *)dataP
2345                                               + hintP->channelOffset);
2346     }
2347     else {
2348         /* Release the data array */
2349         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2350                                               JNI_ABORT);
2351         return -1;
2352     }
2353 
2354     *dataPP = dataP;
2355     return 0;
2356 }
2357 
2358 static int
2359 allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
2360                     mlib_image **mlibImagePP, void **dataPP, int isSrc) {
2361     void *dataP;
2362     unsigned char *cDataP;
2363     int dataType = BYTE_DATA_TYPE;
2364     int width;
2365     int height;
2366     int dataSize;
2367     int offset;
2368 
2369     *dataPP = NULL;
2370 
2371     width = rasterP->width;
2372     height = rasterP->height;
2373 
2374     if (rasterP->numBands <= 0 || rasterP->numBands > 4) {
2375         /* REMIND: Fix this */
2376         return -1;
2377     }
2378 
2379     /* Useful for convolution? */
2380     /* This code is zero'ed out so that it cannot be called */
2381 
2382     /* To do this correctly, we need to expand src and dst in the     */
2383     /* same direction up/down/left/right only if both can be expanded */
2384     /* in that direction.  Expanding right and down is easy -         */
2385     /* increment width.  Expanding top and left requires bumping      */
2386     /* around pointers and incrementing the width/height              */
2387 
2388 #if 0
2389     if (0 && useEdges) {
2390         baseWidth  = rasterP->baseRasterWidth;
2391         baseHeight = rasterP->baseRasterHeight;
2392         baseXoff = rasterP->baseOriginX;
2393         baseYoff = rasterP->baseOriginY;
2394 
2395         if (rasterP->minX + rasterP->width < baseXoff + baseWidth) {
2396             /* Can use edge */
2397             width++;
2398         }
2399         if (rasterP->minY + rasterP->height < baseYoff + baseHeight) {
2400             /* Can use edge */
2401             height++;
2402         }
2403 
2404         if (rasterP->minX > baseXoff ) {
2405             /* Can use edge */
2406             width++;
2407             /* NEED TO BUMP POINTER BACK A PIXELSTRIDE */
2408         }
2409         if (rasterP->minY  > baseYoff) {
2410             /* Can use edge */
2411             height++;
2412             /* NEED TO BUMP POINTER BACK A SCANLINE */
2413         }
2414 
2415 
2416     }
2417 #endif
2418     switch (rasterP->type) {
2419     case sun_awt_image_IntegerComponentRaster_TYPE_INT_8BIT_SAMPLES:
2420         if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 4)) &&
2421               SAFE_TO_ALLOC_2(width, 4) &&
2422               SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 4)))
2423         {
2424             return -1;
2425         }
2426         offset = 4 * rasterP->chanOffsets[0];
2427         dataSize = 4 * (*env)->GetArrayLength(env, rasterP->jdata);
2428 
2429         if (offset < 0 || offset >= dataSize ||
2430             width > rasterP->scanlineStride ||
2431             height * rasterP->scanlineStride * 4 > dataSize - offset)
2432         {
2433             // raster data buffer is too short
2434             return -1;
2435         }
2436         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2437                                                            NULL);
2438         if (dataP == NULL) {
2439             return -1;
2440         }
2441         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE, 4,
2442                                               width, height,
2443                                               rasterP->scanlineStride*4,
2444                                               (unsigned char *)dataP + offset);
2445         *dataPP = dataP;
2446         return 0;
2447     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_SAMPLES:
2448         if (!(SAFE_TO_ALLOC_2(width, rasterP->numBands) &&
2449               SAFE_TO_ALLOC_2(height, rasterP->scanlineStride)))
2450         {
2451             return -1;
2452         }
2453         offset = rasterP->chanOffsets[0];
2454         dataSize = (*env)->GetArrayLength(env, rasterP->jdata);
2455 
2456         if (offset < 0 || offset >= dataSize ||
2457             width * rasterP->numBands > rasterP->scanlineStride ||
2458             height * rasterP->scanlineStride > dataSize - offset)
2459         {
2460             // raster data buffer is too short
2461             return -1;
2462         }
2463         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2464                                                            NULL);
2465         if (dataP == NULL) {
2466             return -1;
2467         }
2468         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE, rasterP->numBands,
2469                                               width, height,
2470                                               rasterP->scanlineStride,
2471                                               (unsigned char *)dataP + offset);
2472         *dataPP = dataP;
2473         return 0;
2474     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_SAMPLES:
2475         if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 2)) &&
2476               SAFE_TO_ALLOC_3(width, rasterP->numBands, 2) &&
2477               SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 2)))
2478         {
2479               return -1;
2480         }
2481         offset = rasterP->chanOffsets[0] * 2;
2482         dataSize = 2 * (*env)->GetArrayLength(env, rasterP->jdata);
2483 
2484         if (offset < 0 || offset >= dataSize ||
2485             width * rasterP->numBands > rasterP->scanlineStride ||
2486             height * rasterP->scanlineStride * 2 > dataSize - offset)
2487         {
2488             // raster data buffer is too short
2489              return -1;
2490         }
2491         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2492                                                            NULL);
2493         if (dataP == NULL) {
2494             return -1;
2495         }
2496         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
2497                                                      rasterP->numBands,
2498                                                      width, height,
2499                                                      rasterP->scanlineStride*2,
2500                                                      (unsigned char *)dataP + offset);
2501         *dataPP = dataP;
2502         return 0;
2503 
2504     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2505         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2506                                         width, height);
2507         if (*mlibImagePP == NULL) {
2508             return -1;
2509         }
2510         if (!isSrc) return 0;
2511         cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2512         return expandPackedBCR(env, rasterP, -1, cDataP);
2513 
2514     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2515         if (rasterP->sppsm.maxBitSize <= 8) {
2516             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2517                                             width, height);
2518             if (*mlibImagePP == NULL) {
2519                 return -1;
2520             }
2521             if (!isSrc) return 0;
2522             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2523             return expandPackedSCR(env, rasterP, -1, cDataP);
2524         }
2525         break;
2526     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2527         if (rasterP->sppsm.maxBitSize <= 8) {
2528             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2529                                             width, height);
2530             if (*mlibImagePP == NULL) {
2531                 return -1;
2532             }
2533             if (!isSrc) return 0;
2534             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2535             return expandPackedICR(env, rasterP, -1, cDataP);
2536         }
2537         break;
2538     }
2539 
2540     /* Just expand it right now */
2541     switch (rasterP->dataType) {
2542     case BYTE_DATA_TYPE:
2543         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2544                                              width, height)) == NULL) {
2545             return -1;
2546         }
2547         if (isSrc) {
2548             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2549                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2550                 return -1;
2551             }
2552         }
2553         break;
2554 
2555     case SHORT_DATA_TYPE:
2556         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_SHORT,
2557                                                     rasterP->numBands,
2558                                                     width, height)) == NULL) {
2559             return -1;
2560         }
2561         if (isSrc) {
2562             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2563                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2564                 return -1;
2565             }
2566         }
2567         break;
2568 
2569     default:
2570         return -1;
2571     }
2572     return 0;
2573 }
2574 
2575 static void
2576 freeArray(JNIEnv *env, BufImageS_t *srcimageP, mlib_image *srcmlibImP,
2577           void *srcdataP, BufImageS_t *dstimageP, mlib_image *dstmlibImP,
2578           void *dstdataP) {
2579     jobject srcJdata = (srcimageP != NULL ? srcimageP->raster.jdata : NULL);
2580     jobject dstJdata = (dstimageP != NULL ? dstimageP->raster.jdata : NULL);
2581     freeDataArray(env, srcJdata, srcmlibImP, srcdataP,
2582                   dstJdata, dstmlibImP, dstdataP);
2583 }
2584 static void
2585 freeDataArray(JNIEnv *env, jobject srcJdata, mlib_image *srcmlibImP,
2586           void *srcdataP, jobject dstJdata, mlib_image *dstmlibImP,
2587           void *dstdataP)
2588 {
2589     /* Free the medialib image */
2590     if (srcmlibImP) {
2591         (*sMlibSysFns.deleteImageFP)(srcmlibImP);
2592     }
2593 
2594     /* Release the array */
2595     if (srcdataP) {
2596         (*env)->ReleasePrimitiveArrayCritical(env, srcJdata,
2597                                               srcdataP, JNI_ABORT);
2598     }
2599 
2600     /* Free the medialib image */
2601     if (dstmlibImP) {
2602         (*sMlibSysFns.deleteImageFP)(dstmlibImP);
2603     }
2604 
2605     /* Release the array */
2606     if (dstdataP) {
2607         (*env)->ReleasePrimitiveArrayCritical(env, dstJdata,
2608                                               dstdataP, 0);
2609     }
2610 }
2611 
2612 #define ERR_BAD_IMAGE_LAYOUT (-2)
2613 
2614 #define CHECK_DST_ARRAY(start_offset, elements_per_scan, elements_per_pixel) \
2615     do {                                                                     \
2616         int offset = (start_offset);                                         \
2617         int lastScanOffset;                                                  \
2618                                                                              \
2619         if (!SAFE_TO_MULT((elements_per_scan),                               \
2620                           (rasterP->height - 1)))                            \
2621         {                                                                    \
2622             return ERR_BAD_IMAGE_LAYOUT;                                     \
2623         }                                                                    \
2624         lastScanOffset = (elements_per_scan) * (rasterP->height - 1);        \
2625                                                                              \
2626         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2627             return ERR_BAD_IMAGE_LAYOUT;                                     \
2628         }                                                                    \
2629         lastScanOffset += offset;                                            \
2630                                                                              \
2631         if (!SAFE_TO_MULT((elements_per_pixel), rasterP->width)) {           \
2632             return ERR_BAD_IMAGE_LAYOUT;                                     \
2633         }                                                                    \
2634         offset = (elements_per_pixel) * rasterP->width;                      \
2635                                                                              \
2636         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2637             return ERR_BAD_IMAGE_LAYOUT;                                     \
2638         }                                                                    \
2639         lastScanOffset += offset;                                            \
2640                                                                              \
2641         if (dataArrayLength < lastScanOffset) {                              \
2642             return ERR_BAD_IMAGE_LAYOUT;                                     \
2643         }                                                                    \
2644     } while(0);                                                              \
2645 
2646 static int
2647 storeImageArray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2648                 mlib_image *mlibImP) {
2649     int mStride;
2650     unsigned char *cmDataP, *dataP, *cDataP;
2651     HintS_t *hintP = &dstP->hints;
2652     RasterS_t *rasterP = &dstP->raster;
2653     jsize dataArrayLength = (*env)->GetArrayLength(env, rasterP->jdata);
2654     int y;
2655 
2656     /* REMIND: Store mlib data type? */
2657 
2658     /* Check if it is an IndexColorModel */
2659     if (dstP->cmodel.cmType == INDEX_CM_TYPE) {
2660         if (dstP->raster.rasterType == COMPONENT_RASTER_TYPE) {
2661             return storeICMarray(env, srcP, dstP, mlibImP);
2662         }
2663         else {
2664             /* Packed or some other custom raster */
2665             cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2666             return cvtDefaultToCustom(env, dstP, -1, cmDataP);
2667         }
2668     }
2669 
2670     if (hintP->packing == BYTE_INTERLEAVED) {
2671         /* Write it back to the destination */
2672         if (rasterP->dataType != BYTE_DATA_TYPE) {
2673             /* We are working with a raster which was marked
2674                as a byte interleaved due to performance reasons.
2675                So, we have to convert the length of the data
2676                array to bytes as well.
2677             */
2678             if (!SAFE_TO_MULT(rasterP->dataSize, dataArrayLength)) {
2679                 return ERR_BAD_IMAGE_LAYOUT;
2680             }
2681             dataArrayLength *= rasterP->dataSize;
2682         }
2683 
2684         CHECK_DST_ARRAY(hintP->dataOffset, hintP->sStride, hintP->numChans);
2685         cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2686         mStride = mlib_ImageGetStride(mlibImP);
2687         dataP = (unsigned char *)(*env)->GetPrimitiveArrayCritical(env,
2688                                                       rasterP->jdata, NULL);
2689         if (dataP == NULL) return 0;
2690         cDataP = dataP + hintP->dataOffset;
2691         for (y=0; y < rasterP->height;
2692              y++, cmDataP += mStride, cDataP += hintP->sStride)
2693         {
2694             memcpy(cDataP, cmDataP, rasterP->width*hintP->numChans);
2695         }
2696         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2697                                               JNI_ABORT);
2698     }
2699     else if (dstP->cmodel.cmType == DIRECT_CM_TYPE) {
2700         /* Just need to move bits */
2701         if (mlibImP->type == MLIB_BYTE) {
2702             if (dstP->hints.packing == PACKED_BYTE_INTER) {
2703                 return setPackedBCRdefault(env, rasterP, -1,
2704                                            (unsigned char *) mlibImP->data,
2705                                            dstP->cmodel.supportsAlpha);
2706             } else if (dstP->hints.packing == PACKED_SHORT_INTER) {
2707                 return setPackedSCRdefault(env, rasterP, -1,
2708                                            (unsigned char *) mlibImP->data,
2709                                            dstP->cmodel.supportsAlpha);
2710             } else if (dstP->hints.packing == PACKED_INT_INTER) {
2711                 return setPackedICRdefault(env, rasterP, -1,
2712                                            (unsigned char *) mlibImP->data,
2713                                            dstP->cmodel.supportsAlpha);
2714             }
2715         }
2716         else if (mlibImP->type == MLIB_SHORT) {
2717             return setPixelsFormMlibImage(env, rasterP, mlibImP);
2718         }
2719     }
2720     else {
2721         return cvtDefaultToCustom(env, dstP, -1,
2722                                   (unsigned char *)mlibImP->data);
2723     }
2724 
2725     return 0;
2726 }
2727 
2728 static int
2729 storeRasterArray(JNIEnv *env, RasterS_t *srcP, RasterS_t *dstP,
2730                 mlib_image *mlibImP) {
2731     unsigned char *cDataP;
2732 
2733     switch(dstP->type) {
2734     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2735         cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2736         return setPackedBCR(env, dstP, -1, cDataP);
2737 
2738     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2739         if (dstP->sppsm.maxBitSize <= 8) {
2740             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2741             return setPackedSCR(env, dstP, -1, cDataP);
2742         }
2743         break;
2744     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2745         if (dstP->sppsm.maxBitSize <= 8) {
2746             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2747             return setPackedICR(env, dstP, -1, cDataP);
2748         }
2749     }
2750 
2751     return -1;
2752 }
2753 
2754 
2755 static int
2756 storeICMarray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2757               mlib_image *mlibImP)
2758 {
2759     int *argb;
2760     int x, y;
2761     unsigned char *dataP, *cDataP, *cP;
2762     unsigned char *sP;
2763     int aIdx, rIdx, gIdx, bIdx;
2764     ColorModelS_t *cmodelP = &dstP->cmodel;
2765     RasterS_t *rasterP = &dstP->raster;
2766 
2767     /* REMIND: Only works for RGB */
2768     if (cmodelP->csType != java_awt_color_ColorSpace_TYPE_RGB) {
2769         JNU_ThrowInternalError(env, "Writing to non-RGB images not implemented yet");
2770         return -1;
2771     }
2772 
2773     if (srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
2774         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
2775         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
2776     {
2777         aIdx = 0;
2778         rIdx = 1;
2779         gIdx = 2;
2780         bIdx = 3;
2781     }
2782     else if (srcP->imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR||
2783         srcP->imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE)
2784     {
2785         aIdx = 0;
2786         rIdx = 3;
2787         gIdx = 2;
2788         bIdx = 1;
2789     }
2790     else if (srcP->imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR){
2791         rIdx = 2;
2792         gIdx = 1;
2793         bIdx = 0;
2794         aIdx = 0;       /* Ignored */
2795     }
2796     else if (srcP->cmodel.cmType == INDEX_CM_TYPE) {
2797         rIdx = 0;
2798         gIdx = 1;
2799         bIdx = 2;
2800         aIdx = 3;   /* Use supportsAlpha to see if it is really there */
2801     }
2802     else {
2803         return -1;
2804     }
2805 
2806     /* Lock down the destination raster */
2807     dataP = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env,
2808                                                   rasterP->jdata, NULL);
2809     if (dataP == NULL) {
2810         return -1;
2811     }
2812     argb = (*env)->GetPrimitiveArrayCritical(env, cmodelP->jrgb, NULL);
2813     if (argb == NULL) {
2814         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2815                                               JNI_ABORT);
2816         return -1;
2817     }
2818 
2819     cDataP = dataP + dstP->hints.dataOffset;
2820     sP = (unsigned char *) mlib_ImageGetData(mlibImP);
2821 
2822     for (y=0; y < rasterP->height; y++, cDataP += rasterP->scanlineStride) {
2823         cP = cDataP;
2824         for (x=0; x < rasterP->width; x++, cP += rasterP->pixelStride) {
2825             *cP = colorMatch(sP[rIdx], sP[gIdx], sP[bIdx], sP[aIdx],
2826                              (unsigned char *)argb, cmodelP->mapSize);
2827             sP += cmodelP->numComponents;
2828         }
2829     }
2830 
2831     (*env)->ReleasePrimitiveArrayCritical(env, cmodelP->jrgb, argb, JNI_ABORT);
2832     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2833                                           JNI_ABORT);
2834     return -1;
2835 }
2836 
2837 static int expandICM(JNIEnv *env, BufImageS_t *imageP, unsigned int *mDataP)
2838 {
2839     ColorModelS_t *cmP = &imageP->cmodel;
2840     RasterS_t *rasterP = &imageP->raster;
2841     HintS_t *hintP     = &imageP->hints;
2842     int *rgb;
2843     int status = 0;
2844     unsigned char *dataP, *cP;
2845     unsigned int *mP;
2846     int width = rasterP->width;
2847     int height = rasterP->height;
2848     int x, y;
2849 
2850     /* Need to grab the lookup tables.  Right now only bytes */
2851     rgb = (int *) (*env)->GetPrimitiveArrayCritical(env, cmP->jrgb, NULL);
2852     CHECK_NULL_RETURN(rgb, -1);
2853 
2854     /* Interleaved with shared data */
2855     dataP = (void *) (*env)->GetPrimitiveArrayCritical(env,
2856                                                        rasterP->jdata, NULL);
2857     if (dataP == NULL) {
2858         /* Release the lookup tables */
2859         (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb, JNI_ABORT);
2860         return -1;
2861     }
2862 
2863     if (rasterP->dataType == BYTE_DATA_TYPE) {
2864         unsigned char *cDataP = ((unsigned char *)dataP) + hintP->dataOffset;
2865 
2866         for (y=0; y < height; y++) {
2867             mP = mDataP;
2868             cP = cDataP;
2869             for (x=0; x < width; x++, cP += rasterP->pixelStride) {
2870                 *mP++ = rgb[*cP];
2871             }
2872             mDataP += width;
2873             cDataP += rasterP->scanlineStride;
2874         }
2875     }
2876     else if (rasterP->dataType == SHORT_DATA_TYPE) {
2877         unsigned short *sDataP, *sP;
2878         sDataP = ((unsigned short *)dataP) + hintP->channelOffset;
2879 
2880         for (y=0; y < height; y++) {
2881             mP = mDataP;
2882             sP = sDataP;
2883             for (x=0; x < width; x++, sP+=rasterP->pixelStride) {
2884                 *mP++ = rgb[*sP];
2885             }
2886             mDataP += width;
2887             sDataP += rasterP->scanlineStride;
2888         }
2889     }
2890     else {
2891         /* Unknown type */
2892         status = -1;
2893     }
2894     /* Release the lookup table data */
2895     (*env)->ReleasePrimitiveArrayCritical(env, imageP->cmodel.jrgb,
2896                                           rgb, JNI_ABORT);
2897     /* Release the data array */
2898     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata,
2899                                           dataP, JNI_ABORT);
2900     return status;
2901 }
2902 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2903 static int expandPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
2904                            unsigned char *outDataP)
2905 {
2906     int x, y, c;
2907     unsigned char *outP = outDataP;
2908     unsigned char *lineInP, *inP;
2909     jarray jInDataP;
2910     jint   *inDataP;
2911     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
2912 
2913     if (rasterP->numBands > MAX_NUMBANDS) {
2914         return -1;
2915     }
2916 
2917     /* Grab data ptr, strides, offsets from raster */
2918     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
2919     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
2920     if (inDataP == NULL) {
2921         return -1;
2922     }
2923     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
2924 
2925     if (component < 0) {
2926         for (c=0; c < rasterP->numBands; c++) {
2927             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2928             if (roff[c] < 0) {
2929                 loff[c] = -roff[c];
2930                 roff[c] = 0;
2931             }
2932             else loff[c] = 0;
2933         }
2934         /* Convert the all bands */
2935         if (rasterP->numBands < 4) {
2936             /* Need to put in alpha */
2937             for (y=0; y < rasterP->height; y++) {
2938                 inP = lineInP;
2939                 for (x=0; x < rasterP->width; x++) {
2940                     for (c=0; c < rasterP->numBands; c++) {
2941                         *outP++ = (unsigned char)
2942                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2943                              <<loff[c]);
2944                     }
2945                     inP++;
2946                 }
2947                 lineInP += rasterP->scanlineStride;
2948             }
2949         }
2950         else {
2951             for (y=0; y < rasterP->height; y++) {
2952                 inP = lineInP;
2953                 for (x=0; x < rasterP->width; x++) {
2954                     for (c=0; c < rasterP->numBands; c++) {
2955                         *outP++ = (unsigned char)
2956                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2957                              <<loff[c]);
2958                     }
2959                     inP++;
2960                 }
2961                 lineInP += rasterP->scanlineStride;
2962             }
2963         }
2964     }
2965     else {
2966         c = component;
2967         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2968         if (roff[0] < 0) {
2969             loff[0] = -roff[0];
2970             roff[0] = 0;
2971         }
2972         else loff[c] = 0;
2973         for (y=0; y < rasterP->height; y++) {
2974             inP = lineInP;
2975             for (x=0; x < rasterP->width; x++) {
2976                 *outP++ = (unsigned char)
2977                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
2978                 inP++;
2979             }
2980             lineInP += rasterP->scanlineStride;
2981         }
2982     }
2983 
2984     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
2985 
2986     return 0;
2987 }
2988 
2989 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2990 static int expandPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
2991                                   int component, unsigned char *outDataP,
2992                                   int forceAlpha)
2993 {
2994     int x, y, c;
2995     unsigned char *outP = outDataP;
2996     unsigned char *lineInP, *inP;
2997     jarray jInDataP;
2998     jint   *inDataP;
2999     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3000     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3001     int a = numBands;
3002 
3003     if (rasterP->numBands > MAX_NUMBANDS) {
3004         return -1;
3005     }
3006 
3007     /* Grab data ptr, strides, offsets from raster */
3008     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3009     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3010     if (inDataP == NULL) {
3011         return -1;
3012     }
3013     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
3014 
3015     if (component < 0) {
3016         for (c=0; c < rasterP->numBands; c++) {
3017             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3018             if (roff[c] < 0) {
3019                 loff[c] = -roff[c];
3020                 roff[c] = 0;
3021             }
3022             else loff[c] = 0;
3023         }
3024 
3025         /* Need to put in alpha */
3026         if (forceAlpha) {
3027             for (y=0; y < rasterP->height; y++) {
3028                 inP = lineInP;
3029                 for (x=0; x < rasterP->width; x++) {
3030                     *outP++ = 0xff;
3031                     for (c=0; c < numBands; c++) {
3032                         *outP++ = (unsigned char)
3033                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3034                              <<loff[c]);
3035                     }
3036                     inP++;
3037                 }
3038                 lineInP += rasterP->scanlineStride;
3039             }
3040         }
3041         else {
3042             for (y=0; y < rasterP->height; y++) {
3043                 inP = lineInP;
3044                 for (x=0; x < rasterP->width; x++) {
3045                     *outP++ = (unsigned char)
3046                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3047                          <<loff[a]);
3048                     for (c=0; c < numBands; c++) {
3049                         *outP++ = (unsigned char)
3050                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3051                              <<loff[c]);
3052                     }
3053                     inP++;
3054                 }
3055                 lineInP += rasterP->scanlineStride;
3056             }
3057         }
3058     }
3059     else {
3060         c = component;
3061         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3062         if (roff[0] < 0) {
3063             loff[0] = -roff[0];
3064             roff[0] = 0;
3065         }
3066         else loff[c] = 0;
3067         for (y=0; y < rasterP->height; y++) {
3068             inP = lineInP;
3069             for (x=0; x < rasterP->width; x++) {
3070                 *outP++ = (unsigned char)
3071                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3072                 inP++;
3073             }
3074             lineInP += rasterP->scanlineStride;
3075         }
3076     }
3077 
3078     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3079 
3080     return 0;
3081 }
3082 
3083 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3084 static int expandPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3085                            unsigned char *outDataP)
3086 {
3087     int x, y, c;
3088     unsigned char *outP = outDataP;
3089     unsigned short *lineInP, *inP;
3090     jarray jInDataP;
3091     jint   *inDataP;
3092     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3093 
3094     if (rasterP->numBands > MAX_NUMBANDS) {
3095         return -1;
3096     }
3097 
3098     /* Grab data ptr, strides, offsets from raster */
3099     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3100     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3101     if (inDataP == NULL) {
3102         return -1;
3103     }
3104     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3105 
3106     if (component < 0) {
3107         for (c=0; c < rasterP->numBands; c++) {
3108             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3109             if (roff[c] < 0) {
3110                 loff[c] = -roff[c];
3111                 roff[c] = 0;
3112             }
3113             else loff[c] = 0;
3114         }
3115         /* Convert the all bands */
3116         if (rasterP->numBands < 4) {
3117             /* Need to put in alpha */
3118             for (y=0; y < rasterP->height; y++) {
3119                 inP = lineInP;
3120                 for (x=0; x < rasterP->width; x++) {
3121                     for (c=0; c < rasterP->numBands; c++) {
3122                         /*
3123                          *Not correct.  Might need to unpremult,
3124                          * shift, etc
3125                          */
3126                         *outP++ = (unsigned char)
3127                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3128                              <<loff[c]);
3129                     }
3130                     inP++;
3131                 }
3132                 lineInP += rasterP->scanlineStride;
3133             }
3134         } else {
3135             for (y=0; y < rasterP->height; y++) {
3136                 inP = lineInP;
3137                 for (x=0; x < rasterP->width; x++) {
3138                     for (c=0; c < rasterP->numBands; c++) {
3139                         /*
3140                          *Not correct.  Might need to unpremult,
3141                          * shift, etc
3142                          */
3143                         *outP++ = (unsigned char)
3144                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3145                              <<loff[c]);
3146                     }
3147                     inP++;
3148                 }
3149                 lineInP += rasterP->scanlineStride;
3150             }
3151         }
3152     }
3153     else {
3154         c = component;
3155         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3156         if (roff[0] < 0) {
3157             loff[0] = -roff[0];
3158             roff[0] = 0;
3159         }
3160         else loff[c] = 0;
3161         for (y=0; y < rasterP->height; y++) {
3162             inP = lineInP;
3163             for (x=0; x < rasterP->width; x++) {
3164                 *outP++ = (unsigned char)
3165                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3166                 inP++;
3167             }
3168             lineInP += rasterP->scanlineStride;
3169         }
3170     }
3171 
3172     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3173 
3174     return 0;
3175 }
3176 
3177 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3178 static int expandPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3179                                   int component, unsigned char *outDataP,
3180                                   int forceAlpha)
3181 {
3182     int x, y, c;
3183     unsigned char *outP = outDataP;
3184     unsigned short *lineInP, *inP;
3185     jarray jInDataP;
3186     jint   *inDataP;
3187     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3188     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3189     int a = numBands;
3190 
3191     if (rasterP->numBands > MAX_NUMBANDS) {
3192         return -1;
3193     }
3194 
3195     /* Grab data ptr, strides, offsets from raster */
3196     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3197     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3198     if (inDataP == NULL) {
3199         return -1;
3200     }
3201     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3202 
3203     if (component < 0) {
3204         for (c=0; c < rasterP->numBands; c++) {
3205             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3206             if (roff[c] < 0) {
3207                 loff[c] = -roff[c];
3208                 roff[c] = 0;
3209             }
3210             else loff[c] = 0;
3211         }
3212 
3213         /* Need to put in alpha */
3214         if (forceAlpha) {
3215             for (y=0; y < rasterP->height; y++) {
3216                 inP = lineInP;
3217                 for (x=0; x < rasterP->width; x++) {
3218                     *outP++ = 0xff;
3219                     for (c=0; c < numBands; c++) {
3220                         /*
3221                          * Not correct.  Might need to unpremult,
3222                          * shift, etc
3223                          */
3224                         *outP++ = (unsigned char)
3225                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3226                                    <<loff[c]);
3227                     }
3228                     inP++;
3229                 }
3230                 lineInP += rasterP->scanlineStride;
3231             }
3232         }
3233         else {
3234             for (y=0; y < rasterP->height; y++) {
3235                 inP = lineInP;
3236                 for (x=0; x < rasterP->width; x++) {
3237                     *outP++ = (unsigned char)
3238                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3239                                    <<loff[a]);
3240                     for (c=0; c < numBands; c++) {
3241                         /*
3242                          * Not correct.  Might need to
3243                          * unpremult, shift, etc
3244                          */
3245                         *outP++ = (unsigned char)
3246                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3247                                    <<loff[c]);
3248                     }
3249                     inP++;
3250                 }
3251                 lineInP += rasterP->scanlineStride;
3252             }
3253         }
3254     }
3255     else {
3256         c = component;
3257         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3258         if (roff[0] < 0) {
3259             loff[0] = -roff[0];
3260             roff[0] = 0;
3261         }
3262         else loff[c] = 0;
3263         for (y=0; y < rasterP->height; y++) {
3264             inP = lineInP;
3265             for (x=0; x < rasterP->width; x++) {
3266                 *outP++ = (unsigned char)
3267                         ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3268                 inP++;
3269             }
3270             lineInP += rasterP->scanlineStride;
3271         }
3272     }
3273 
3274     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3275 
3276     return 0;
3277 
3278 }
3279 
3280 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3281 static int expandPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3282                            unsigned char *outDataP)
3283 {
3284     int x, y, c;
3285     unsigned char *outP = outDataP;
3286     unsigned int *lineInP, *inP;
3287     jarray jInDataP;
3288     jint   *inDataP;
3289     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3290 
3291     if (rasterP->numBands > MAX_NUMBANDS) {
3292         return -1;
3293     }
3294 
3295     /* Grab data ptr, strides, offsets from raster */
3296     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3297     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3298     if (inDataP == NULL) {
3299         return -1;
3300     }
3301     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3302 
3303     if (component < 0) {
3304         for (c=0; c < rasterP->numBands; c++) {
3305             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3306             if (roff[c] < 0) {
3307                 loff[c] = -roff[c];
3308                 roff[c] = 0;
3309             }
3310             else loff[c] = 0;
3311         }
3312         /* Convert the all bands */
3313         if (rasterP->numBands < 4) {
3314             for (y=0; y < rasterP->height; y++) {
3315                 inP = lineInP;
3316                 for (x=0; x < rasterP->width; x++) {
3317                     for (c=0; c < rasterP->numBands; c++) {
3318                         /*
3319                          * Not correct.  Might need to unpremult,
3320                          * shift, etc
3321                          */
3322                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3323                                    <<loff[c]);
3324                     }
3325                     inP++;
3326                 }
3327                 lineInP += rasterP->scanlineStride;
3328             }
3329         }
3330         else {
3331             for (y=0; y < rasterP->height; y++) {
3332                 inP = lineInP;
3333                 for (x=0; x < rasterP->width; x++) {
3334                     for (c=0; c < rasterP->numBands; c++) {
3335                         /*
3336                          * Not correct.  Might need to
3337                          * unpremult, shift, etc
3338                          */
3339                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3340                                    <<loff[c]);
3341                     }
3342                     inP++;
3343                 }
3344                 lineInP += rasterP->scanlineStride;
3345             }
3346         }
3347     }
3348     else {
3349         c = component;
3350         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3351         if (roff[0] < 0) {
3352             loff[0] = -roff[0];
3353             roff[0] = 0;
3354         }
3355         else loff[c] = 0;
3356         for (y=0; y < rasterP->height; y++) {
3357             inP = lineInP;
3358             for (x=0; x < rasterP->width; x++) {
3359                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3360                 inP++;
3361             }
3362             lineInP += rasterP->scanlineStride;
3363         }
3364     }
3365 
3366     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3367 
3368     return 0;
3369 }
3370 
3371 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3372 static int expandPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3373                                   int component, unsigned char *outDataP,
3374                                   int forceAlpha)
3375 {
3376     int x, y, c;
3377     unsigned char *outP = outDataP;
3378     unsigned int *lineInP, *inP;
3379     jarray jInDataP;
3380     jint   *inDataP;
3381     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3382     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3383     int a = numBands;
3384 
3385     if (rasterP->numBands > MAX_NUMBANDS) {
3386         return -1;
3387     }
3388 
3389     /* Grab data ptr, strides, offsets from raster */
3390     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3391     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3392     if (inDataP == NULL) {
3393         return -1;
3394     }
3395     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3396 
3397     if (component < 0) {
3398         for (c=0; c < rasterP->numBands; c++) {
3399             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3400             if (roff[c] < 0) {
3401                 loff[c] = -roff[c];
3402                 roff[c] = 0;
3403             }
3404             else loff[c] = 0;
3405         }
3406 
3407         /* Need to put in alpha */
3408         if (forceAlpha) {
3409             for (y=0; y < rasterP->height; y++) {
3410                 inP = lineInP;
3411                 for (x=0; x < rasterP->width; x++) {
3412                     *outP++ = 0xff;
3413                     for (c=0; c < numBands; c++) {
3414                         /*
3415                          * Not correct.  Might need to unpremult,
3416                          * shift, etc
3417                          */
3418                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3419                                    <<loff[c]);
3420                     }
3421                     inP++;
3422                 }
3423                 lineInP += rasterP->scanlineStride;
3424             }
3425         }
3426         else {
3427             for (y=0; y < rasterP->height; y++) {
3428                 inP = lineInP;
3429                 for (x=0; x < rasterP->width; x++) {
3430                     *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3431                                    <<loff[a]);
3432                     for (c=0; c < numBands; c++) {
3433                         /*
3434                          * Not correct.  Might need to
3435                          * unpremult, shift, etc
3436                          */
3437                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3438                                    <<loff[c]);
3439                     }
3440                     inP++;
3441                 }
3442                 lineInP += rasterP->scanlineStride;
3443             }
3444         }
3445     }
3446     else {
3447         c = component;
3448         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3449         if (roff[0] < 0) {
3450             loff[0] = -roff[0];
3451             roff[0] = 0;
3452         }
3453         else loff[c] = 0;
3454         for (y=0; y < rasterP->height; y++) {
3455             inP = lineInP;
3456             for (x=0; x < rasterP->width; x++) {
3457                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3458                 inP++;
3459             }
3460             lineInP += rasterP->scanlineStride;
3461         }
3462     }
3463 
3464     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3465 
3466     return 0;
3467 }
3468 
3469 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3470 static int setPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
3471                         unsigned char *inDataP)
3472 {
3473     int x, y, c;
3474     unsigned char *inP = inDataP;
3475     unsigned char *lineOutP, *outP;
3476     jarray jOutDataP;
3477     jsize dataArrayLength;
3478     unsigned char *outDataP;
3479     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3480 
3481     if (rasterP->numBands > MAX_NUMBANDS) {
3482         return -1;
3483     }
3484 
3485     /* Grab data ptr, strides, offsets from raster */
3486     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3487     if (JNU_IsNull(env, jOutDataP)) {
3488         return -1;
3489     }
3490 
3491     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3492     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3493 
3494     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3495     if (outDataP == NULL) {
3496         return -1;
3497     }
3498     lineOutP = outDataP + rasterP->chanOffsets[0];
3499 
3500     if (component < 0) {
3501         for (c=0; c < rasterP->numBands; c++) {
3502             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3503             if (loff[c] < 0) {
3504                 roff[c] = -loff[c];
3505                 loff[c] = 0;
3506             }
3507             else roff[c] = 0;
3508         }
3509         /* Convert the all bands */
3510         for (y=0; y < rasterP->height; y++) {
3511             outP = lineOutP;
3512             *outP = 0;
3513             for (x=0; x < rasterP->width; x++) {
3514                 for (c=0; c < rasterP->numBands; c++, inP++) {
3515                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3516                 }
3517                 outP++;
3518             }
3519             lineOutP += rasterP->scanlineStride;
3520         }
3521     }
3522     else {
3523         c = component;
3524         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3525         if (loff[0] < 0) {
3526             roff[0] = -loff[0];
3527             loff[0] = 0;
3528         }
3529         else roff[c] = 0;
3530         for (y=0; y < rasterP->height; y++) {
3531             outP = lineOutP;
3532             for (x=0; x < rasterP->width; x++, inP++) {
3533                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3534                 outP++;
3535             }
3536             lineOutP += rasterP->scanlineStride;
3537         }
3538     }
3539 
3540     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3541 
3542     return 0;
3543 }
3544 
3545 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3546 static int setPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3547                            unsigned char *inDataP)
3548 {
3549     int x, y, c;
3550     unsigned char *inP = inDataP;
3551     unsigned short *lineOutP, *outP;
3552     jarray jOutDataP;
3553     jsize dataArrayLength;
3554     unsigned short *outDataP;
3555     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3556 
3557     if (rasterP->numBands > MAX_NUMBANDS) {
3558         return -1;
3559     }
3560 
3561     /* Grab data ptr, strides, offsets from raster */
3562     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3563     if (JNU_IsNull(env, jOutDataP)) {
3564         return -1;
3565     }
3566 
3567     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3568     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3569 
3570     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3571     if (outDataP == NULL) {
3572         return -1;
3573     }
3574     lineOutP = outDataP + rasterP->chanOffsets[0];
3575 
3576     if (component < 0) {
3577         for (c=0; c < rasterP->numBands; c++) {
3578             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3579             if (loff[c] < 0) {
3580                 roff[c] = -loff[c];
3581                 loff[c] = 0;
3582             }
3583             else roff[c] = 0;
3584         }
3585         /* Convert the all bands */
3586         for (y=0; y < rasterP->height; y++) {
3587             outP = lineOutP;
3588             for (x=0; x < rasterP->width; x++) {
3589                 for (c=0; c < rasterP->numBands; c++, inP++) {
3590                     /* Not correct.  Might need to unpremult, shift, etc */
3591                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3592                 }
3593                 outP++;
3594             }
3595             lineOutP += rasterP->scanlineStride;
3596         }
3597     }
3598     else {
3599         c = component;
3600         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3601         if (loff[0] < 0) {
3602             roff[0] = -loff[0];
3603             loff[0] = 0;
3604         }
3605         else roff[c] = 0;
3606         for (y=0; y < rasterP->height; y++) {
3607             outP = lineOutP;
3608             for (x=0; x < rasterP->width; x++, inP++) {
3609                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3610                 outP++;
3611             }
3612             lineOutP += rasterP->scanlineStride;
3613         }
3614     }
3615 
3616     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3617 
3618     return 0;
3619 }
3620 
3621 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3622 static int setPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3623                            unsigned char *inDataP)
3624 {
3625     int x, y, c;
3626     unsigned char *inP = inDataP;
3627     unsigned int *lineOutP, *outP;
3628     jarray jOutDataP;
3629     jsize dataArrayLength;
3630     unsigned int *outDataP;
3631     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3632 
3633     if (rasterP->numBands > MAX_NUMBANDS) {
3634         return -1;
3635     }
3636 
3637     /* Grab data ptr, strides, offsets from raster */
3638     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3639     if (JNU_IsNull(env, jOutDataP)) {
3640         return -1;
3641     }
3642 
3643     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3644     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3645 
3646     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3647     if (outDataP == NULL) {
3648         return -1;
3649     }
3650     lineOutP = outDataP + rasterP->chanOffsets[0];
3651 
3652     if (component < 0) {
3653         for (c=0; c < rasterP->numBands; c++) {
3654             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3655             if (loff[c] < 0) {
3656                 roff[c] = -loff[c];
3657                 loff[c] = 0;
3658             }
3659             else roff[c] = 0;
3660         }
3661         /* Convert the all bands */
3662         for (y=0; y < rasterP->height; y++) {
3663             outP = lineOutP;
3664             for (x=0; x < rasterP->width; x++) {
3665                 for (c=0; c < rasterP->numBands; c++, inP++) {
3666                     /* Not correct.  Might need to unpremult, shift, etc */
3667                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3668                 }
3669                 outP++;
3670             }
3671             lineOutP += rasterP->scanlineStride;
3672         }
3673     }
3674     else {
3675         c = component;
3676         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3677         if (loff[0] < 0) {
3678             roff[0] = -loff[0];
3679             loff[0] = 0;
3680         }
3681         else roff[c] = 0;
3682 
3683         for (y=0; y < rasterP->height; y++) {
3684             outP = lineOutP;
3685             for (x=0; x < rasterP->width; x++, inP++) {
3686                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3687                 outP++;
3688             }
3689             lineOutP += rasterP->scanlineStride;
3690         }
3691     }
3692 
3693     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3694 
3695     return 0;
3696 }
3697 
3698 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3699 static int setPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
3700                                int component, unsigned char *inDataP,
3701                                int supportsAlpha)
3702 {
3703     int x, y, c;
3704     unsigned char *inP = inDataP;
3705     unsigned char *lineOutP, *outP;
3706     jarray jOutDataP;
3707     jsize  dataArrayLength;
3708     unsigned char *outDataP;
3709     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3710     int a = rasterP->numBands - 1;
3711 
3712     if (rasterP->numBands > MAX_NUMBANDS) {
3713         return -1;
3714     }
3715 
3716     /* Grab data ptr, strides, offsets from raster */
3717     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3718     if (JNU_IsNull(env, jOutDataP)) {
3719         return -1;
3720     }
3721 
3722     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3723     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3724 
3725     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3726     if (outDataP == NULL) {
3727         return -1;
3728     }
3729     lineOutP = outDataP + rasterP->chanOffsets[0];
3730 
3731     if (component < 0) {
3732         for (c=0; c < rasterP->numBands; c++) {
3733             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3734             if (loff[c] < 0) {
3735                 roff[c] = -loff[c];
3736                 loff[c] = 0;
3737             }
3738             else roff[c] = 0;
3739         }
3740         /* Convert the all bands */
3741         if (supportsAlpha) {
3742             for (y=0; y < rasterP->height; y++) {
3743                 outP = lineOutP;
3744                 *outP = 0;
3745                 for (x=0; x < rasterP->width; x++) {
3746                     *outP |= (*inP<<loff[a]>>roff[a])&
3747                         rasterP->sppsm.maskArray[a];
3748                     inP++;
3749                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3750                         *outP |= (*inP<<loff[c]>>roff[c])&
3751                             rasterP->sppsm.maskArray[c];
3752                     }
3753                     outP++;
3754                 }
3755                 lineOutP += rasterP->scanlineStride;
3756             }
3757         }
3758         else {
3759             for (y=0; y < rasterP->height; y++) {
3760                 outP = lineOutP;
3761                 *outP = 0;
3762                 for (x=0; x < rasterP->width; x++) {
3763                     inP++;
3764                     for (c=0; c < rasterP->numBands; c++, inP++) {
3765                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3766                     }
3767                     outP++;
3768                 }
3769                 lineOutP += rasterP->scanlineStride;
3770             }
3771         }
3772     }
3773     else {
3774         c = component;
3775         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3776         if (loff[0] < 0) {
3777             roff[0] = -loff[0];
3778             loff[0] = 0;
3779         }
3780         else roff[c] = 0;
3781         for (y=0; y < rasterP->height; y++) {
3782             outP = lineOutP;
3783             for (x=0; x < rasterP->width; x++, inP++) {
3784                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3785                 outP++;
3786             }
3787             lineOutP += rasterP->scanlineStride;
3788         }
3789     }
3790 
3791     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3792 
3793     return 0;
3794 }
3795 
3796 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3797 static int setPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3798                                int component, unsigned char *inDataP,
3799                                int supportsAlpha)
3800 {
3801     int x, y, c;
3802     unsigned char *inP = inDataP;
3803     unsigned short *lineOutP, *outP;
3804     jarray jOutDataP;
3805     jsize dataArrayLength;
3806     unsigned short *outDataP;
3807     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3808     int a = rasterP->numBands - 1;
3809 
3810     if (rasterP->numBands > MAX_NUMBANDS) {
3811         return -1;
3812     }
3813 
3814     /* Grab data ptr, strides, offsets from raster */
3815     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3816     if (JNU_IsNull(env, jOutDataP)) {
3817         return -1;
3818     }
3819     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3820     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3821 
3822     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3823     if (outDataP == NULL) {
3824         return -1;
3825     }
3826     lineOutP = outDataP + rasterP->chanOffsets[0];
3827 
3828     if (component < 0) {
3829         for (c=0; c < rasterP->numBands; c++) {
3830             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3831             if (loff[c] < 0) {
3832                 roff[c] = -loff[c];
3833                 loff[c] = 0;
3834             }
3835             else roff[c] = 0;
3836         }
3837         /* Convert the all bands */
3838         if (supportsAlpha) {
3839             for (y=0; y < rasterP->height; y++) {
3840                 outP = lineOutP;
3841                 for (x=0; x < rasterP->width; x++) {
3842                     *outP |= (*inP<<loff[a]>>roff[a])&
3843                         rasterP->sppsm.maskArray[a];
3844                     inP++;
3845                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3846                         /* Not correct.  Might need to unpremult, shift, etc */
3847                         *outP |= (*inP<<loff[c]>>roff[c])&
3848                             rasterP->sppsm.maskArray[c];
3849                     }
3850                     outP++;
3851                 }
3852                 lineOutP += rasterP->scanlineStride;
3853             }
3854         }
3855         else {
3856             for (y=0; y < rasterP->height; y++) {
3857                 outP = lineOutP;
3858                 for (x=0; x < rasterP->width; x++) {
3859                     inP++;
3860                     for (c=0; c < rasterP->numBands; c++, inP++) {
3861                         /* Not correct.  Might need to unpremult, shift, etc */
3862                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3863                     }
3864                     outP++;
3865                 }
3866                 lineOutP += rasterP->scanlineStride;
3867             }
3868         }
3869     }
3870     else {
3871         c = component;
3872         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3873         if (loff[0] < 0) {
3874             roff[0] = -loff[0];
3875             loff[0] = 0;
3876         }
3877         else roff[c] = 0;
3878         for (y=0; y < rasterP->height; y++) {
3879             outP = lineOutP;
3880             for (x=0; x < rasterP->width; x++, inP++) {
3881                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3882                 outP++;
3883             }
3884             lineOutP += rasterP->scanlineStride;
3885         }
3886     }
3887 
3888     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3889 
3890     return 0;
3891 }
3892 
3893 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3894 static int setPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3895                                int component, unsigned char *inDataP,
3896                                int supportsAlpha)
3897 {
3898     int x, y, c;
3899     unsigned char *inP = inDataP;
3900     unsigned int *lineOutP, *outP;
3901     jarray jOutDataP;
3902     jsize dataArrayLength;
3903     unsigned int *outDataP;
3904     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3905     int a = rasterP->numBands - 1;
3906 
3907     if (rasterP->numBands > MAX_NUMBANDS) {
3908         return -1;
3909     }
3910 
3911     /* Grab data ptr, strides, offsets from raster */
3912     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3913     if (JNU_IsNull(env, jOutDataP)) {
3914         return -1;
3915     }
3916 
3917     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3918     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3919 
3920     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3921     if (outDataP == NULL) {
3922         return -1;
3923     }
3924     lineOutP = outDataP + rasterP->chanOffsets[0];
3925 
3926     if (component < 0) {
3927         for (c=0; c < rasterP->numBands; c++) {
3928             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3929             if (loff[c] < 0) {
3930                 roff[c] = -loff[c];
3931                 loff[c] = 0;
3932             }
3933             else roff[c] = 0;
3934         }
3935         /* Convert the all bands */
3936         if (supportsAlpha) {
3937             for (y=0; y < rasterP->height; y++) {
3938                 outP = lineOutP;
3939                 for (x=0; x < rasterP->width; x++) {
3940                     *outP |= (*inP<<loff[a]>>roff[a])&
3941                         rasterP->sppsm.maskArray[a];
3942                     inP++;
3943                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3944                         /* Not correct.  Might need to unpremult, shift, etc */
3945                         *outP |= (*inP<<loff[c]>>roff[c])&
3946                             rasterP->sppsm.maskArray[c];
3947                     }
3948                     outP++;
3949                 }
3950                 lineOutP += rasterP->scanlineStride;
3951             }
3952         }
3953         else {
3954             for (y=0; y < rasterP->height; y++) {
3955                 outP = lineOutP;
3956                 for (x=0; x < rasterP->width; x++) {
3957                     inP++;
3958                     for (c=0; c < rasterP->numBands; c++, inP++) {
3959                         /* Not correct.  Might need to unpremult, shift, etc */
3960                         *outP |= (*inP<<loff[c]>>roff[c])&
3961                             rasterP->sppsm.maskArray[c];
3962                     }
3963                     outP++;
3964                 }
3965                 lineOutP += rasterP->scanlineStride;
3966             }
3967         }
3968     }
3969     else {
3970         c = component;
3971         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3972         if (loff[0] < 0) {
3973             roff[0] = -loff[0];
3974             loff[0] = 0;
3975         }
3976         else roff[c] = 0;
3977 
3978         for (y=0; y < rasterP->height; y++) {
3979             outP = lineOutP;
3980             for (x=0; x < rasterP->width; x++, inP++) {
3981                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3982                 outP++;
3983             }
3984             lineOutP += rasterP->scanlineStride;
3985         }
3986     }
3987 
3988     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3989 
3990     return 0;
3991 }
3992 
3993 /* This is temporary code.  Should go away when there is better color
3994  * conversion code available.
3995  * REMIND:  Ignoring alpha
3996  */
3997 /* returns the absolute value x */
3998 #define ABS(x) ((x) < 0 ? -(x) : (x))
3999 #define CLIP(val,min,max)       ((val < min) ? min : ((val > max) ? max : val))
4000 
4001 static int
4002 colorMatch(int r, int g, int b, int a, unsigned char *argb, int numColors) {
4003     int besti = 0;
4004     int mindist, i, t, d;
4005     unsigned char red, green, blue;
4006 
4007     r = CLIP(r, 0, 255);
4008     g = CLIP(g, 0, 255);
4009     b = CLIP(b, 0, 255);
4010 
4011     /* look for pure gray match */
4012     if ((r == g) && (g == b)) {
4013         mindist = 256;
4014         for (i = 0 ; i < numColors ; i++, argb+=4) {
4015             red = argb[1];
4016             green = argb[2];
4017             blue = argb[3];
4018             if (! ((red == green) && (green == blue)) ) {
4019                 continue;
4020             }
4021             d = ABS(red - r);
4022             if (d == 0)
4023                 return i;
4024             if (d < mindist) {
4025                 besti = i;
4026                 mindist = d;
4027             }
4028         }
4029         return besti;
4030     }
4031 
4032     /* look for non-pure gray match */
4033     mindist = 256 * 256 * 256;
4034     for (i = 0 ; i < numColors ; i++, argb+=4) {
4035         red = argb[1];
4036         green = argb[2];
4037         blue = argb[3];
4038         t = red - r;
4039         d = t * t;
4040         if (d >= mindist) {
4041             continue;
4042         }
4043         t = green - g;
4044         d += t * t;
4045         if (d >= mindist) {
4046             continue;
4047         }
4048         t = blue - b;
4049         d += t * t;
4050         if (d >= mindist) {
4051             continue;
4052         }
4053         if (d == 0)
4054             return i;
4055         if (d < mindist) {
4056             besti = i;
4057             mindist = d;
4058         }
4059     }
4060 
4061     return besti;
4062 }