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(rasterP->scanlineStride, height, 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             ((width + (height - 1) * 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(rasterP->scanlineStride, height)))
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             ((width * rasterP->numBands) +
2459              (height - 1) * rasterP->scanlineStride) > dataSize - offset)
2460         {
2461             // raster data buffer is too short
2462             return -1;
2463         }
2464         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2465                                                            NULL);
2466         if (dataP == NULL) {
2467             return -1;
2468         }
2469         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_BYTE, rasterP->numBands,
2470                                               width, height,
2471                                               rasterP->scanlineStride,
2472                                               (unsigned char *)dataP + offset);
2473         *dataPP = dataP;
2474         return 0;
2475     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_SAMPLES:
2476         if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 2)) &&
2477               SAFE_TO_ALLOC_3(width, rasterP->numBands, 2) &&
2478               SAFE_TO_ALLOC_3(rasterP->scanlineStride, height, 2)))
2479         {
2480               return -1;
2481         }
2482         offset = rasterP->chanOffsets[0] * 2;
2483         dataSize = 2 * (*env)->GetArrayLength(env, rasterP->jdata);
2484 
2485         if (offset < 0 || offset >= dataSize ||
2486             width * rasterP->numBands > rasterP->scanlineStride ||
2487             (((width * rasterP->numBands) +
2488              (height - 1) * rasterP->scanlineStride)) * 2 > dataSize - offset)
2489         {
2490             // raster data buffer is too short
2491              return -1;
2492         }
2493         dataP = (void *) (*env)->GetPrimitiveArrayCritical(env, rasterP->jdata,
2494                                                            NULL);
2495         if (dataP == NULL) {
2496             return -1;
2497         }
2498         *mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
2499                                                      rasterP->numBands,
2500                                                      width, height,
2501                                                      rasterP->scanlineStride*2,
2502                                                      (unsigned char *)dataP + offset);
2503         *dataPP = dataP;
2504         return 0;
2505 
2506     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2507         *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2508                                         width, height);
2509         if (*mlibImagePP == NULL) {
2510             return -1;
2511         }
2512         if (!isSrc) return 0;
2513         cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2514         return expandPackedBCR(env, rasterP, -1, cDataP);
2515 
2516     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2517         if (rasterP->sppsm.maxBitSize <= 8) {
2518             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2519                                             width, height);
2520             if (*mlibImagePP == NULL) {
2521                 return -1;
2522             }
2523             if (!isSrc) return 0;
2524             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2525             return expandPackedSCR(env, rasterP, -1, cDataP);
2526         }
2527         break;
2528     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2529         if (rasterP->sppsm.maxBitSize <= 8) {
2530             *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2531                                             width, height);
2532             if (*mlibImagePP == NULL) {
2533                 return -1;
2534             }
2535             if (!isSrc) return 0;
2536             cDataP  = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
2537             return expandPackedICR(env, rasterP, -1, cDataP);
2538         }
2539         break;
2540     }
2541 
2542     /* Just expand it right now */
2543     switch (rasterP->dataType) {
2544     case BYTE_DATA_TYPE:
2545         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
2546                                              width, height)) == NULL) {
2547             return -1;
2548         }
2549         if (isSrc) {
2550             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2551                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2552                 return -1;
2553             }
2554         }
2555         break;
2556 
2557     case SHORT_DATA_TYPE:
2558         if ((*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_SHORT,
2559                                                     rasterP->numBands,
2560                                                     width, height)) == NULL) {
2561             return -1;
2562         }
2563         if (isSrc) {
2564             if (awt_getPixels(env, rasterP, mlib_ImageGetData(*mlibImagePP)) < 0) {
2565                 (*sMlibSysFns.deleteImageFP)(*mlibImagePP);
2566                 return -1;
2567             }
2568         }
2569         break;
2570 
2571     default:
2572         return -1;
2573     }
2574     return 0;
2575 }
2576 
2577 static void
2578 freeArray(JNIEnv *env, BufImageS_t *srcimageP, mlib_image *srcmlibImP,
2579           void *srcdataP, BufImageS_t *dstimageP, mlib_image *dstmlibImP,
2580           void *dstdataP) {
2581     jobject srcJdata = (srcimageP != NULL ? srcimageP->raster.jdata : NULL);
2582     jobject dstJdata = (dstimageP != NULL ? dstimageP->raster.jdata : NULL);
2583     freeDataArray(env, srcJdata, srcmlibImP, srcdataP,
2584                   dstJdata, dstmlibImP, dstdataP);
2585 }
2586 static void
2587 freeDataArray(JNIEnv *env, jobject srcJdata, mlib_image *srcmlibImP,
2588           void *srcdataP, jobject dstJdata, mlib_image *dstmlibImP,
2589           void *dstdataP)
2590 {
2591     /* Free the medialib image */
2592     if (srcmlibImP) {
2593         (*sMlibSysFns.deleteImageFP)(srcmlibImP);
2594     }
2595 
2596     /* Release the array */
2597     if (srcdataP) {
2598         (*env)->ReleasePrimitiveArrayCritical(env, srcJdata,
2599                                               srcdataP, JNI_ABORT);
2600     }
2601 
2602     /* Free the medialib image */
2603     if (dstmlibImP) {
2604         (*sMlibSysFns.deleteImageFP)(dstmlibImP);
2605     }
2606 
2607     /* Release the array */
2608     if (dstdataP) {
2609         (*env)->ReleasePrimitiveArrayCritical(env, dstJdata,
2610                                               dstdataP, 0);
2611     }
2612 }
2613 
2614 #define ERR_BAD_IMAGE_LAYOUT (-2)
2615 
2616 #define CHECK_DST_ARRAY(start_offset, elements_per_scan, elements_per_pixel) \
2617     do {                                                                     \
2618         int offset = (start_offset);                                         \
2619         int lastScanOffset;                                                  \
2620                                                                              \
2621         if (!SAFE_TO_MULT((elements_per_scan),                               \
2622                           (rasterP->height - 1)))                            \
2623         {                                                                    \
2624             return ERR_BAD_IMAGE_LAYOUT;                                     \
2625         }                                                                    \
2626         lastScanOffset = (elements_per_scan) * (rasterP->height - 1);        \
2627                                                                              \
2628         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2629             return ERR_BAD_IMAGE_LAYOUT;                                     \
2630         }                                                                    \
2631         lastScanOffset += offset;                                            \
2632                                                                              \
2633         if (!SAFE_TO_MULT((elements_per_pixel), rasterP->width)) {           \
2634             return ERR_BAD_IMAGE_LAYOUT;                                     \
2635         }                                                                    \
2636         offset = (elements_per_pixel) * rasterP->width;                      \
2637                                                                              \
2638         if (!SAFE_TO_ADD(offset, lastScanOffset)) {                          \
2639             return ERR_BAD_IMAGE_LAYOUT;                                     \
2640         }                                                                    \
2641         lastScanOffset += offset;                                            \
2642                                                                              \
2643         if (dataArrayLength < lastScanOffset) {                              \
2644             return ERR_BAD_IMAGE_LAYOUT;                                     \
2645         }                                                                    \
2646     } while(0);                                                              \
2647 
2648 static int
2649 storeImageArray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2650                 mlib_image *mlibImP) {
2651     int mStride;
2652     unsigned char *cmDataP, *dataP, *cDataP;
2653     HintS_t *hintP = &dstP->hints;
2654     RasterS_t *rasterP = &dstP->raster;
2655     jsize dataArrayLength = (*env)->GetArrayLength(env, rasterP->jdata);
2656     int y;
2657 
2658     /* REMIND: Store mlib data type? */
2659 
2660     /* Check if it is an IndexColorModel */
2661     if (dstP->cmodel.cmType == INDEX_CM_TYPE) {
2662         if (dstP->raster.rasterType == COMPONENT_RASTER_TYPE) {
2663             return storeICMarray(env, srcP, dstP, mlibImP);
2664         }
2665         else {
2666             /* Packed or some other custom raster */
2667             cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2668             return cvtDefaultToCustom(env, dstP, -1, cmDataP);
2669         }
2670     }
2671 
2672     if (hintP->packing == BYTE_INTERLEAVED) {
2673         /* Write it back to the destination */
2674         if (rasterP->dataType != BYTE_DATA_TYPE) {
2675             /* We are working with a raster which was marked
2676                as a byte interleaved due to performance reasons.
2677                So, we have to convert the length of the data
2678                array to bytes as well.
2679             */
2680             if (!SAFE_TO_MULT(rasterP->dataSize, dataArrayLength)) {
2681                 return ERR_BAD_IMAGE_LAYOUT;
2682             }
2683             dataArrayLength *= rasterP->dataSize;
2684         }
2685 
2686         CHECK_DST_ARRAY(hintP->dataOffset, hintP->sStride, hintP->numChans);
2687         cmDataP = (unsigned char *) mlib_ImageGetData(mlibImP);
2688         mStride = mlib_ImageGetStride(mlibImP);
2689         dataP = (unsigned char *)(*env)->GetPrimitiveArrayCritical(env,
2690                                                       rasterP->jdata, NULL);
2691         if (dataP == NULL) return 0;
2692         cDataP = dataP + hintP->dataOffset;
2693         for (y=0; y < rasterP->height;
2694              y++, cmDataP += mStride, cDataP += hintP->sStride)
2695         {
2696             memcpy(cDataP, cmDataP, rasterP->width*hintP->numChans);
2697         }
2698         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2699                                               JNI_ABORT);
2700     }
2701     else if (dstP->cmodel.cmType == DIRECT_CM_TYPE) {
2702         /* Just need to move bits */
2703         if (mlibImP->type == MLIB_BYTE) {
2704             if (dstP->hints.packing == PACKED_BYTE_INTER) {
2705                 return setPackedBCRdefault(env, rasterP, -1,
2706                                            (unsigned char *) mlibImP->data,
2707                                            dstP->cmodel.supportsAlpha);
2708             } else if (dstP->hints.packing == PACKED_SHORT_INTER) {
2709                 return setPackedSCRdefault(env, rasterP, -1,
2710                                            (unsigned char *) mlibImP->data,
2711                                            dstP->cmodel.supportsAlpha);
2712             } else if (dstP->hints.packing == PACKED_INT_INTER) {
2713                 return setPackedICRdefault(env, rasterP, -1,
2714                                            (unsigned char *) mlibImP->data,
2715                                            dstP->cmodel.supportsAlpha);
2716             }
2717         }
2718         else if (mlibImP->type == MLIB_SHORT) {
2719             return setPixelsFormMlibImage(env, rasterP, mlibImP);
2720         }
2721     }
2722     else {
2723         return cvtDefaultToCustom(env, dstP, -1,
2724                                   (unsigned char *)mlibImP->data);
2725     }
2726 
2727     return 0;
2728 }
2729 
2730 static int
2731 storeRasterArray(JNIEnv *env, RasterS_t *srcP, RasterS_t *dstP,
2732                 mlib_image *mlibImP) {
2733     unsigned char *cDataP;
2734 
2735     switch(dstP->type) {
2736     case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
2737         cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2738         return setPackedBCR(env, dstP, -1, cDataP);
2739 
2740     case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_PACKED_SAMPLES:
2741         if (dstP->sppsm.maxBitSize <= 8) {
2742             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2743             return setPackedSCR(env, dstP, -1, cDataP);
2744         }
2745         break;
2746     case sun_awt_image_IntegerComponentRaster_TYPE_INT_PACKED_SAMPLES:
2747         if (dstP->sppsm.maxBitSize <= 8) {
2748             cDataP  = (unsigned char *) mlib_ImageGetData(mlibImP);
2749             return setPackedICR(env, dstP, -1, cDataP);
2750         }
2751     }
2752 
2753     return -1;
2754 }
2755 
2756 
2757 static int
2758 storeICMarray(JNIEnv *env, BufImageS_t *srcP, BufImageS_t *dstP,
2759               mlib_image *mlibImP)
2760 {
2761     int *argb;
2762     int x, y;
2763     unsigned char *dataP, *cDataP, *cP;
2764     unsigned char *sP;
2765     int aIdx, rIdx, gIdx, bIdx;
2766     ColorModelS_t *cmodelP = &dstP->cmodel;
2767     RasterS_t *rasterP = &dstP->raster;
2768 
2769     /* REMIND: Only works for RGB */
2770     if (cmodelP->csType != java_awt_color_ColorSpace_TYPE_RGB) {
2771         JNU_ThrowInternalError(env, "Writing to non-RGB images not implemented yet");
2772         return -1;
2773     }
2774 
2775     if (srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB ||
2776         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE ||
2777         srcP->imageType == java_awt_image_BufferedImage_TYPE_INT_RGB)
2778     {
2779         aIdx = 0;
2780         rIdx = 1;
2781         gIdx = 2;
2782         bIdx = 3;
2783     }
2784     else if (srcP->imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR||
2785         srcP->imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE)
2786     {
2787         aIdx = 0;
2788         rIdx = 3;
2789         gIdx = 2;
2790         bIdx = 1;
2791     }
2792     else if (srcP->imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR){
2793         rIdx = 2;
2794         gIdx = 1;
2795         bIdx = 0;
2796         aIdx = 0;       /* Ignored */
2797     }
2798     else if (srcP->cmodel.cmType == INDEX_CM_TYPE) {
2799         rIdx = 0;
2800         gIdx = 1;
2801         bIdx = 2;
2802         aIdx = 3;   /* Use supportsAlpha to see if it is really there */
2803     }
2804     else {
2805         return -1;
2806     }
2807 
2808     /* Lock down the destination raster */
2809     dataP = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env,
2810                                                   rasterP->jdata, NULL);
2811     if (dataP == NULL) {
2812         return -1;
2813     }
2814     argb = (*env)->GetPrimitiveArrayCritical(env, cmodelP->jrgb, NULL);
2815     if (argb == NULL) {
2816         (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2817                                               JNI_ABORT);
2818         return -1;
2819     }
2820 
2821     cDataP = dataP + dstP->hints.dataOffset;
2822     sP = (unsigned char *) mlib_ImageGetData(mlibImP);
2823 
2824     for (y=0; y < rasterP->height; y++, cDataP += rasterP->scanlineStride) {
2825         cP = cDataP;
2826         for (x=0; x < rasterP->width; x++, cP += rasterP->pixelStride) {
2827             *cP = colorMatch(sP[rIdx], sP[gIdx], sP[bIdx], sP[aIdx],
2828                              (unsigned char *)argb, cmodelP->mapSize);
2829             sP += cmodelP->numComponents;
2830         }
2831     }
2832 
2833     (*env)->ReleasePrimitiveArrayCritical(env, cmodelP->jrgb, argb, JNI_ABORT);
2834     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
2835                                           JNI_ABORT);
2836     return -1;
2837 }
2838 
2839 static int expandICM(JNIEnv *env, BufImageS_t *imageP, unsigned int *mDataP)
2840 {
2841     ColorModelS_t *cmP = &imageP->cmodel;
2842     RasterS_t *rasterP = &imageP->raster;
2843     HintS_t *hintP     = &imageP->hints;
2844     int *rgb;
2845     int status = 0;
2846     unsigned char *dataP, *cP;
2847     unsigned int *mP;
2848     int width = rasterP->width;
2849     int height = rasterP->height;
2850     int x, y;
2851 
2852     /* Need to grab the lookup tables.  Right now only bytes */
2853     rgb = (int *) (*env)->GetPrimitiveArrayCritical(env, cmP->jrgb, NULL);
2854     CHECK_NULL_RETURN(rgb, -1);
2855 
2856     /* Interleaved with shared data */
2857     dataP = (void *) (*env)->GetPrimitiveArrayCritical(env,
2858                                                        rasterP->jdata, NULL);
2859     if (dataP == NULL) {
2860         /* Release the lookup tables */
2861         (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb, JNI_ABORT);
2862         return -1;
2863     }
2864 
2865     if (rasterP->dataType == BYTE_DATA_TYPE) {
2866         unsigned char *cDataP = ((unsigned char *)dataP) + hintP->dataOffset;
2867 
2868         for (y=0; y < height; y++) {
2869             mP = mDataP;
2870             cP = cDataP;
2871             for (x=0; x < width; x++, cP += rasterP->pixelStride) {
2872                 *mP++ = rgb[*cP];
2873             }
2874             mDataP += width;
2875             cDataP += rasterP->scanlineStride;
2876         }
2877     }
2878     else if (rasterP->dataType == SHORT_DATA_TYPE) {
2879         unsigned short *sDataP, *sP;
2880         sDataP = ((unsigned short *)dataP) + hintP->channelOffset;
2881 
2882         for (y=0; y < height; y++) {
2883             mP = mDataP;
2884             sP = sDataP;
2885             for (x=0; x < width; x++, sP+=rasterP->pixelStride) {
2886                 *mP++ = rgb[*sP];
2887             }
2888             mDataP += width;
2889             sDataP += rasterP->scanlineStride;
2890         }
2891     }
2892     else {
2893         /* Unknown type */
2894         status = -1;
2895     }
2896     /* Release the lookup table data */
2897     (*env)->ReleasePrimitiveArrayCritical(env, imageP->cmodel.jrgb,
2898                                           rgb, JNI_ABORT);
2899     /* Release the data array */
2900     (*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata,
2901                                           dataP, JNI_ABORT);
2902     return status;
2903 }
2904 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2905 static int expandPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
2906                            unsigned char *outDataP)
2907 {
2908     int x, y, c;
2909     unsigned char *outP = outDataP;
2910     unsigned char *lineInP, *inP;
2911     jarray jInDataP;
2912     jint   *inDataP;
2913     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
2914 
2915     if (rasterP->numBands > MAX_NUMBANDS) {
2916         return -1;
2917     }
2918 
2919     /* Grab data ptr, strides, offsets from raster */
2920     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
2921     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
2922     if (inDataP == NULL) {
2923         return -1;
2924     }
2925     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
2926 
2927     if (component < 0) {
2928         for (c=0; c < rasterP->numBands; c++) {
2929             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2930             if (roff[c] < 0) {
2931                 loff[c] = -roff[c];
2932                 roff[c] = 0;
2933             }
2934             else loff[c] = 0;
2935         }
2936         /* Convert the all bands */
2937         if (rasterP->numBands < 4) {
2938             /* Need to put in alpha */
2939             for (y=0; y < rasterP->height; y++) {
2940                 inP = lineInP;
2941                 for (x=0; x < rasterP->width; x++) {
2942                     for (c=0; c < rasterP->numBands; c++) {
2943                         *outP++ = (unsigned char)
2944                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2945                              <<loff[c]);
2946                     }
2947                     inP++;
2948                 }
2949                 lineInP += rasterP->scanlineStride;
2950             }
2951         }
2952         else {
2953             for (y=0; y < rasterP->height; y++) {
2954                 inP = lineInP;
2955                 for (x=0; x < rasterP->width; x++) {
2956                     for (c=0; c < rasterP->numBands; c++) {
2957                         *outP++ = (unsigned char)
2958                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
2959                              <<loff[c]);
2960                     }
2961                     inP++;
2962                 }
2963                 lineInP += rasterP->scanlineStride;
2964             }
2965         }
2966     }
2967     else {
2968         c = component;
2969         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
2970         if (roff[0] < 0) {
2971             loff[0] = -roff[0];
2972             roff[0] = 0;
2973         }
2974         else loff[c] = 0;
2975         for (y=0; y < rasterP->height; y++) {
2976             inP = lineInP;
2977             for (x=0; x < rasterP->width; x++) {
2978                 *outP++ = (unsigned char)
2979                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
2980                 inP++;
2981             }
2982             lineInP += rasterP->scanlineStride;
2983         }
2984     }
2985 
2986     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
2987 
2988     return 0;
2989 }
2990 
2991 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
2992 static int expandPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
2993                                   int component, unsigned char *outDataP,
2994                                   int forceAlpha)
2995 {
2996     int x, y, c;
2997     unsigned char *outP = outDataP;
2998     unsigned char *lineInP, *inP;
2999     jarray jInDataP;
3000     jint   *inDataP;
3001     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3002     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3003     int a = numBands;
3004 
3005     if (rasterP->numBands > MAX_NUMBANDS) {
3006         return -1;
3007     }
3008 
3009     /* Grab data ptr, strides, offsets from raster */
3010     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3011     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3012     if (inDataP == NULL) {
3013         return -1;
3014     }
3015     lineInP =  (unsigned char *)inDataP + rasterP->chanOffsets[0];
3016 
3017     if (component < 0) {
3018         for (c=0; c < rasterP->numBands; c++) {
3019             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3020             if (roff[c] < 0) {
3021                 loff[c] = -roff[c];
3022                 roff[c] = 0;
3023             }
3024             else loff[c] = 0;
3025         }
3026 
3027         /* Need to put in alpha */
3028         if (forceAlpha) {
3029             for (y=0; y < rasterP->height; y++) {
3030                 inP = lineInP;
3031                 for (x=0; x < rasterP->width; x++) {
3032                     *outP++ = 0xff;
3033                     for (c=0; c < numBands; c++) {
3034                         *outP++ = (unsigned char)
3035                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3036                              <<loff[c]);
3037                     }
3038                     inP++;
3039                 }
3040                 lineInP += rasterP->scanlineStride;
3041             }
3042         }
3043         else {
3044             for (y=0; y < rasterP->height; y++) {
3045                 inP = lineInP;
3046                 for (x=0; x < rasterP->width; x++) {
3047                     *outP++ = (unsigned char)
3048                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3049                          <<loff[a]);
3050                     for (c=0; c < numBands; c++) {
3051                         *outP++ = (unsigned char)
3052                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3053                              <<loff[c]);
3054                     }
3055                     inP++;
3056                 }
3057                 lineInP += rasterP->scanlineStride;
3058             }
3059         }
3060     }
3061     else {
3062         c = component;
3063         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3064         if (roff[0] < 0) {
3065             loff[0] = -roff[0];
3066             roff[0] = 0;
3067         }
3068         else loff[c] = 0;
3069         for (y=0; y < rasterP->height; y++) {
3070             inP = lineInP;
3071             for (x=0; x < rasterP->width; x++) {
3072                 *outP++ = (unsigned char)
3073                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3074                 inP++;
3075             }
3076             lineInP += rasterP->scanlineStride;
3077         }
3078     }
3079 
3080     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3081 
3082     return 0;
3083 }
3084 
3085 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3086 static int expandPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3087                            unsigned char *outDataP)
3088 {
3089     int x, y, c;
3090     unsigned char *outP = outDataP;
3091     unsigned short *lineInP, *inP;
3092     jarray jInDataP;
3093     jint   *inDataP;
3094     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3095 
3096     if (rasterP->numBands > MAX_NUMBANDS) {
3097         return -1;
3098     }
3099 
3100     /* Grab data ptr, strides, offsets from raster */
3101     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3102     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3103     if (inDataP == NULL) {
3104         return -1;
3105     }
3106     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3107 
3108     if (component < 0) {
3109         for (c=0; c < rasterP->numBands; c++) {
3110             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3111             if (roff[c] < 0) {
3112                 loff[c] = -roff[c];
3113                 roff[c] = 0;
3114             }
3115             else loff[c] = 0;
3116         }
3117         /* Convert the all bands */
3118         if (rasterP->numBands < 4) {
3119             /* Need to put in alpha */
3120             for (y=0; y < rasterP->height; y++) {
3121                 inP = lineInP;
3122                 for (x=0; x < rasterP->width; x++) {
3123                     for (c=0; c < rasterP->numBands; c++) {
3124                         /*
3125                          *Not correct.  Might need to unpremult,
3126                          * shift, etc
3127                          */
3128                         *outP++ = (unsigned char)
3129                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3130                              <<loff[c]);
3131                     }
3132                     inP++;
3133                 }
3134                 lineInP += rasterP->scanlineStride;
3135             }
3136         } else {
3137             for (y=0; y < rasterP->height; y++) {
3138                 inP = lineInP;
3139                 for (x=0; x < rasterP->width; x++) {
3140                     for (c=0; c < rasterP->numBands; c++) {
3141                         /*
3142                          *Not correct.  Might need to unpremult,
3143                          * shift, etc
3144                          */
3145                         *outP++ = (unsigned char)
3146                             (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3147                              <<loff[c]);
3148                     }
3149                     inP++;
3150                 }
3151                 lineInP += rasterP->scanlineStride;
3152             }
3153         }
3154     }
3155     else {
3156         c = component;
3157         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3158         if (roff[0] < 0) {
3159             loff[0] = -roff[0];
3160             roff[0] = 0;
3161         }
3162         else loff[c] = 0;
3163         for (y=0; y < rasterP->height; y++) {
3164             inP = lineInP;
3165             for (x=0; x < rasterP->width; x++) {
3166                 *outP++ = (unsigned char)
3167                     ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3168                 inP++;
3169             }
3170             lineInP += rasterP->scanlineStride;
3171         }
3172     }
3173 
3174     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3175 
3176     return 0;
3177 }
3178 
3179 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3180 static int expandPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3181                                   int component, unsigned char *outDataP,
3182                                   int forceAlpha)
3183 {
3184     int x, y, c;
3185     unsigned char *outP = outDataP;
3186     unsigned short *lineInP, *inP;
3187     jarray jInDataP;
3188     jint   *inDataP;
3189     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3190     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3191     int a = numBands;
3192 
3193     if (rasterP->numBands > MAX_NUMBANDS) {
3194         return -1;
3195     }
3196 
3197     /* Grab data ptr, strides, offsets from raster */
3198     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3199     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3200     if (inDataP == NULL) {
3201         return -1;
3202     }
3203     lineInP =  (unsigned short *)inDataP + rasterP->chanOffsets[0];
3204 
3205     if (component < 0) {
3206         for (c=0; c < rasterP->numBands; c++) {
3207             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3208             if (roff[c] < 0) {
3209                 loff[c] = -roff[c];
3210                 roff[c] = 0;
3211             }
3212             else loff[c] = 0;
3213         }
3214 
3215         /* Need to put in alpha */
3216         if (forceAlpha) {
3217             for (y=0; y < rasterP->height; y++) {
3218                 inP = lineInP;
3219                 for (x=0; x < rasterP->width; x++) {
3220                     *outP++ = 0xff;
3221                     for (c=0; c < numBands; c++) {
3222                         /*
3223                          * Not correct.  Might need to unpremult,
3224                          * shift, etc
3225                          */
3226                         *outP++ = (unsigned char)
3227                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3228                                    <<loff[c]);
3229                     }
3230                     inP++;
3231                 }
3232                 lineInP += rasterP->scanlineStride;
3233             }
3234         }
3235         else {
3236             for (y=0; y < rasterP->height; y++) {
3237                 inP = lineInP;
3238                 for (x=0; x < rasterP->width; x++) {
3239                     *outP++ = (unsigned char)
3240                         (((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3241                                    <<loff[a]);
3242                     for (c=0; c < numBands; c++) {
3243                         /*
3244                          * Not correct.  Might need to
3245                          * unpremult, shift, etc
3246                          */
3247                         *outP++ = (unsigned char)
3248                                 (((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3249                                    <<loff[c]);
3250                     }
3251                     inP++;
3252                 }
3253                 lineInP += rasterP->scanlineStride;
3254             }
3255         }
3256     }
3257     else {
3258         c = component;
3259         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3260         if (roff[0] < 0) {
3261             loff[0] = -roff[0];
3262             roff[0] = 0;
3263         }
3264         else loff[c] = 0;
3265         for (y=0; y < rasterP->height; y++) {
3266             inP = lineInP;
3267             for (x=0; x < rasterP->width; x++) {
3268                 *outP++ = (unsigned char)
3269                         ((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0];
3270                 inP++;
3271             }
3272             lineInP += rasterP->scanlineStride;
3273         }
3274     }
3275 
3276     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3277 
3278     return 0;
3279 
3280 }
3281 
3282 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3283 static int expandPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3284                            unsigned char *outDataP)
3285 {
3286     int x, y, c;
3287     unsigned char *outP = outDataP;
3288     unsigned int *lineInP, *inP;
3289     jarray jInDataP;
3290     jint   *inDataP;
3291     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3292 
3293     if (rasterP->numBands > MAX_NUMBANDS) {
3294         return -1;
3295     }
3296 
3297     /* Grab data ptr, strides, offsets from raster */
3298     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3299     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3300     if (inDataP == NULL) {
3301         return -1;
3302     }
3303     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3304 
3305     if (component < 0) {
3306         for (c=0; c < rasterP->numBands; c++) {
3307             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3308             if (roff[c] < 0) {
3309                 loff[c] = -roff[c];
3310                 roff[c] = 0;
3311             }
3312             else loff[c] = 0;
3313         }
3314         /* Convert the all bands */
3315         if (rasterP->numBands < 4) {
3316             for (y=0; y < rasterP->height; y++) {
3317                 inP = lineInP;
3318                 for (x=0; x < rasterP->width; x++) {
3319                     for (c=0; c < rasterP->numBands; c++) {
3320                         /*
3321                          * Not correct.  Might need to unpremult,
3322                          * shift, etc
3323                          */
3324                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3325                                    <<loff[c]);
3326                     }
3327                     inP++;
3328                 }
3329                 lineInP += rasterP->scanlineStride;
3330             }
3331         }
3332         else {
3333             for (y=0; y < rasterP->height; y++) {
3334                 inP = lineInP;
3335                 for (x=0; x < rasterP->width; x++) {
3336                     for (c=0; c < rasterP->numBands; c++) {
3337                         /*
3338                          * Not correct.  Might need to
3339                          * unpremult, shift, etc
3340                          */
3341                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3342                                    <<loff[c]);
3343                     }
3344                     inP++;
3345                 }
3346                 lineInP += rasterP->scanlineStride;
3347             }
3348         }
3349     }
3350     else {
3351         c = component;
3352         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3353         if (roff[0] < 0) {
3354             loff[0] = -roff[0];
3355             roff[0] = 0;
3356         }
3357         else loff[c] = 0;
3358         for (y=0; y < rasterP->height; y++) {
3359             inP = lineInP;
3360             for (x=0; x < rasterP->width; x++) {
3361                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3362                 inP++;
3363             }
3364             lineInP += rasterP->scanlineStride;
3365         }
3366     }
3367 
3368     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3369 
3370     return 0;
3371 }
3372 
3373 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3374 static int expandPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3375                                   int component, unsigned char *outDataP,
3376                                   int forceAlpha)
3377 {
3378     int x, y, c;
3379     unsigned char *outP = outDataP;
3380     unsigned int *lineInP, *inP;
3381     jarray jInDataP;
3382     jint   *inDataP;
3383     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3384     int numBands = rasterP->numBands - (forceAlpha ? 0 : 1);
3385     int a = numBands;
3386 
3387     if (rasterP->numBands > MAX_NUMBANDS) {
3388         return -1;
3389     }
3390 
3391     /* Grab data ptr, strides, offsets from raster */
3392     jInDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3393     inDataP = (*env)->GetPrimitiveArrayCritical(env, jInDataP, 0);
3394     if (inDataP == NULL) {
3395         return -1;
3396     }
3397     lineInP =  (unsigned int *)inDataP + rasterP->chanOffsets[0];
3398 
3399     if (component < 0) {
3400         for (c=0; c < rasterP->numBands; c++) {
3401             roff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3402             if (roff[c] < 0) {
3403                 loff[c] = -roff[c];
3404                 roff[c] = 0;
3405             }
3406             else loff[c] = 0;
3407         }
3408 
3409         /* Need to put in alpha */
3410         if (forceAlpha) {
3411             for (y=0; y < rasterP->height; y++) {
3412                 inP = lineInP;
3413                 for (x=0; x < rasterP->width; x++) {
3414                     *outP++ = 0xff;
3415                     for (c=0; c < numBands; c++) {
3416                         /*
3417                          * Not correct.  Might need to unpremult,
3418                          * shift, etc
3419                          */
3420                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3421                                    <<loff[c]);
3422                     }
3423                     inP++;
3424                 }
3425                 lineInP += rasterP->scanlineStride;
3426             }
3427         }
3428         else {
3429             for (y=0; y < rasterP->height; y++) {
3430                 inP = lineInP;
3431                 for (x=0; x < rasterP->width; x++) {
3432                     *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[a]) >> roff[a])
3433                                    <<loff[a]);
3434                     for (c=0; c < numBands; c++) {
3435                         /*
3436                          * Not correct.  Might need to
3437                          * unpremult, shift, etc
3438                          */
3439                         *outP++ = (unsigned char)(((*inP&rasterP->sppsm.maskArray[c]) >> roff[c])
3440                                    <<loff[c]);
3441                     }
3442                     inP++;
3443                 }
3444                 lineInP += rasterP->scanlineStride;
3445             }
3446         }
3447     }
3448     else {
3449         c = component;
3450         roff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3451         if (roff[0] < 0) {
3452             loff[0] = -roff[0];
3453             roff[0] = 0;
3454         }
3455         else loff[c] = 0;
3456         for (y=0; y < rasterP->height; y++) {
3457             inP = lineInP;
3458             for (x=0; x < rasterP->width; x++) {
3459                 *outP++ = (unsigned char)(((*inP & rasterP->sppsm.maskArray[c])>>roff[0])<<loff[0]);
3460                 inP++;
3461             }
3462             lineInP += rasterP->scanlineStride;
3463         }
3464     }
3465 
3466     (*env)->ReleasePrimitiveArrayCritical(env, jInDataP, inDataP, JNI_ABORT);
3467 
3468     return 0;
3469 }
3470 
3471 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3472 static int setPackedBCR(JNIEnv *env, RasterS_t *rasterP, int component,
3473                         unsigned char *inDataP)
3474 {
3475     int x, y, c;
3476     unsigned char *inP = inDataP;
3477     unsigned char *lineOutP, *outP;
3478     jarray jOutDataP;
3479     jsize dataArrayLength;
3480     unsigned char *outDataP;
3481     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3482 
3483     if (rasterP->numBands > MAX_NUMBANDS) {
3484         return -1;
3485     }
3486 
3487     /* Grab data ptr, strides, offsets from raster */
3488     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3489     if (JNU_IsNull(env, jOutDataP)) {
3490         return -1;
3491     }
3492 
3493     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3494     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3495 
3496     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3497     if (outDataP == NULL) {
3498         return -1;
3499     }
3500     lineOutP = outDataP + rasterP->chanOffsets[0];
3501 
3502     if (component < 0) {
3503         for (c=0; c < rasterP->numBands; c++) {
3504             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3505             if (loff[c] < 0) {
3506                 roff[c] = -loff[c];
3507                 loff[c] = 0;
3508             }
3509             else roff[c] = 0;
3510         }
3511         /* Convert the all bands */
3512         for (y=0; y < rasterP->height; y++) {
3513             outP = lineOutP;
3514             *outP = 0;
3515             for (x=0; x < rasterP->width; x++) {
3516                 for (c=0; c < rasterP->numBands; c++, inP++) {
3517                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3518                 }
3519                 outP++;
3520             }
3521             lineOutP += rasterP->scanlineStride;
3522         }
3523     }
3524     else {
3525         c = component;
3526         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3527         if (loff[0] < 0) {
3528             roff[0] = -loff[0];
3529             loff[0] = 0;
3530         }
3531         else roff[c] = 0;
3532         for (y=0; y < rasterP->height; y++) {
3533             outP = lineOutP;
3534             for (x=0; x < rasterP->width; x++, inP++) {
3535                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3536                 outP++;
3537             }
3538             lineOutP += rasterP->scanlineStride;
3539         }
3540     }
3541 
3542     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3543 
3544     return 0;
3545 }
3546 
3547 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3548 static int setPackedSCR(JNIEnv *env, RasterS_t *rasterP, int component,
3549                            unsigned char *inDataP)
3550 {
3551     int x, y, c;
3552     unsigned char *inP = inDataP;
3553     unsigned short *lineOutP, *outP;
3554     jarray jOutDataP;
3555     jsize dataArrayLength;
3556     unsigned short *outDataP;
3557     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3558 
3559     if (rasterP->numBands > MAX_NUMBANDS) {
3560         return -1;
3561     }
3562 
3563     /* Grab data ptr, strides, offsets from raster */
3564     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3565     if (JNU_IsNull(env, jOutDataP)) {
3566         return -1;
3567     }
3568 
3569     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3570     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3571 
3572     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3573     if (outDataP == NULL) {
3574         return -1;
3575     }
3576     lineOutP = outDataP + rasterP->chanOffsets[0];
3577 
3578     if (component < 0) {
3579         for (c=0; c < rasterP->numBands; c++) {
3580             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3581             if (loff[c] < 0) {
3582                 roff[c] = -loff[c];
3583                 loff[c] = 0;
3584             }
3585             else roff[c] = 0;
3586         }
3587         /* Convert the all bands */
3588         for (y=0; y < rasterP->height; y++) {
3589             outP = lineOutP;
3590             for (x=0; x < rasterP->width; x++) {
3591                 for (c=0; c < rasterP->numBands; c++, inP++) {
3592                     /* Not correct.  Might need to unpremult, shift, etc */
3593                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3594                 }
3595                 outP++;
3596             }
3597             lineOutP += rasterP->scanlineStride;
3598         }
3599     }
3600     else {
3601         c = component;
3602         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3603         if (loff[0] < 0) {
3604             roff[0] = -loff[0];
3605             loff[0] = 0;
3606         }
3607         else roff[c] = 0;
3608         for (y=0; y < rasterP->height; y++) {
3609             outP = lineOutP;
3610             for (x=0; x < rasterP->width; x++, inP++) {
3611                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3612                 outP++;
3613             }
3614             lineOutP += rasterP->scanlineStride;
3615         }
3616     }
3617 
3618     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3619 
3620     return 0;
3621 }
3622 
3623 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3624 static int setPackedICR(JNIEnv *env, RasterS_t *rasterP, int component,
3625                            unsigned char *inDataP)
3626 {
3627     int x, y, c;
3628     unsigned char *inP = inDataP;
3629     unsigned int *lineOutP, *outP;
3630     jarray jOutDataP;
3631     jsize dataArrayLength;
3632     unsigned int *outDataP;
3633     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3634 
3635     if (rasterP->numBands > MAX_NUMBANDS) {
3636         return -1;
3637     }
3638 
3639     /* Grab data ptr, strides, offsets from raster */
3640     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3641     if (JNU_IsNull(env, jOutDataP)) {
3642         return -1;
3643     }
3644 
3645     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3646     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3647 
3648     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3649     if (outDataP == NULL) {
3650         return -1;
3651     }
3652     lineOutP = outDataP + rasterP->chanOffsets[0];
3653 
3654     if (component < 0) {
3655         for (c=0; c < rasterP->numBands; c++) {
3656             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3657             if (loff[c] < 0) {
3658                 roff[c] = -loff[c];
3659                 loff[c] = 0;
3660             }
3661             else roff[c] = 0;
3662         }
3663         /* Convert the all bands */
3664         for (y=0; y < rasterP->height; y++) {
3665             outP = lineOutP;
3666             for (x=0; x < rasterP->width; x++) {
3667                 for (c=0; c < rasterP->numBands; c++, inP++) {
3668                     /* Not correct.  Might need to unpremult, shift, etc */
3669                     *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3670                 }
3671                 outP++;
3672             }
3673             lineOutP += rasterP->scanlineStride;
3674         }
3675     }
3676     else {
3677         c = component;
3678         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3679         if (loff[0] < 0) {
3680             roff[0] = -loff[0];
3681             loff[0] = 0;
3682         }
3683         else roff[c] = 0;
3684 
3685         for (y=0; y < rasterP->height; y++) {
3686             outP = lineOutP;
3687             for (x=0; x < rasterP->width; x++, inP++) {
3688                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3689                 outP++;
3690             }
3691             lineOutP += rasterP->scanlineStride;
3692         }
3693     }
3694 
3695     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3696 
3697     return 0;
3698 }
3699 
3700 /* This routine is expecting a ByteComponentRaster with a PackedColorModel */
3701 static int setPackedBCRdefault(JNIEnv *env, RasterS_t *rasterP,
3702                                int component, unsigned char *inDataP,
3703                                int supportsAlpha)
3704 {
3705     int x, y, c;
3706     unsigned char *inP = inDataP;
3707     unsigned char *lineOutP, *outP;
3708     jarray jOutDataP;
3709     jsize  dataArrayLength;
3710     unsigned char *outDataP;
3711     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3712     int a = rasterP->numBands - 1;
3713 
3714     if (rasterP->numBands > MAX_NUMBANDS) {
3715         return -1;
3716     }
3717 
3718     /* Grab data ptr, strides, offsets from raster */
3719     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_BCRdataID);
3720     if (JNU_IsNull(env, jOutDataP)) {
3721         return -1;
3722     }
3723 
3724     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3725     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3726 
3727     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3728     if (outDataP == NULL) {
3729         return -1;
3730     }
3731     lineOutP = outDataP + rasterP->chanOffsets[0];
3732 
3733     if (component < 0) {
3734         for (c=0; c < rasterP->numBands; c++) {
3735             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3736             if (loff[c] < 0) {
3737                 roff[c] = -loff[c];
3738                 loff[c] = 0;
3739             }
3740             else roff[c] = 0;
3741         }
3742         /* Convert the all bands */
3743         if (supportsAlpha) {
3744             for (y=0; y < rasterP->height; y++) {
3745                 outP = lineOutP;
3746                 *outP = 0;
3747                 for (x=0; x < rasterP->width; x++) {
3748                     *outP |= (*inP<<loff[a]>>roff[a])&
3749                         rasterP->sppsm.maskArray[a];
3750                     inP++;
3751                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3752                         *outP |= (*inP<<loff[c]>>roff[c])&
3753                             rasterP->sppsm.maskArray[c];
3754                     }
3755                     outP++;
3756                 }
3757                 lineOutP += rasterP->scanlineStride;
3758             }
3759         }
3760         else {
3761             for (y=0; y < rasterP->height; y++) {
3762                 outP = lineOutP;
3763                 *outP = 0;
3764                 for (x=0; x < rasterP->width; x++) {
3765                     inP++;
3766                     for (c=0; c < rasterP->numBands; c++, inP++) {
3767                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3768                     }
3769                     outP++;
3770                 }
3771                 lineOutP += rasterP->scanlineStride;
3772             }
3773         }
3774     }
3775     else {
3776         c = component;
3777         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3778         if (loff[0] < 0) {
3779             roff[0] = -loff[0];
3780             loff[0] = 0;
3781         }
3782         else roff[c] = 0;
3783         for (y=0; y < rasterP->height; y++) {
3784             outP = lineOutP;
3785             for (x=0; x < rasterP->width; x++, inP++) {
3786                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3787                 outP++;
3788             }
3789             lineOutP += rasterP->scanlineStride;
3790         }
3791     }
3792 
3793     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3794 
3795     return 0;
3796 }
3797 
3798 /* This routine is expecting a ShortComponentRaster with a PackedColorModel */
3799 static int setPackedSCRdefault(JNIEnv *env, RasterS_t *rasterP,
3800                                int component, unsigned char *inDataP,
3801                                int supportsAlpha)
3802 {
3803     int x, y, c;
3804     unsigned char *inP = inDataP;
3805     unsigned short *lineOutP, *outP;
3806     jarray jOutDataP;
3807     jsize dataArrayLength;
3808     unsigned short *outDataP;
3809     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3810     int a = rasterP->numBands - 1;
3811 
3812     if (rasterP->numBands > MAX_NUMBANDS) {
3813         return -1;
3814     }
3815 
3816     /* Grab data ptr, strides, offsets from raster */
3817     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_SCRdataID);
3818     if (JNU_IsNull(env, jOutDataP)) {
3819         return -1;
3820     }
3821     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3822     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3823 
3824     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3825     if (outDataP == NULL) {
3826         return -1;
3827     }
3828     lineOutP = outDataP + rasterP->chanOffsets[0];
3829 
3830     if (component < 0) {
3831         for (c=0; c < rasterP->numBands; c++) {
3832             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3833             if (loff[c] < 0) {
3834                 roff[c] = -loff[c];
3835                 loff[c] = 0;
3836             }
3837             else roff[c] = 0;
3838         }
3839         /* Convert the all bands */
3840         if (supportsAlpha) {
3841             for (y=0; y < rasterP->height; y++) {
3842                 outP = lineOutP;
3843                 for (x=0; x < rasterP->width; x++) {
3844                     *outP |= (*inP<<loff[a]>>roff[a])&
3845                         rasterP->sppsm.maskArray[a];
3846                     inP++;
3847                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3848                         /* Not correct.  Might need to unpremult, shift, etc */
3849                         *outP |= (*inP<<loff[c]>>roff[c])&
3850                             rasterP->sppsm.maskArray[c];
3851                     }
3852                     outP++;
3853                 }
3854                 lineOutP += rasterP->scanlineStride;
3855             }
3856         }
3857         else {
3858             for (y=0; y < rasterP->height; y++) {
3859                 outP = lineOutP;
3860                 for (x=0; x < rasterP->width; x++) {
3861                     inP++;
3862                     for (c=0; c < rasterP->numBands; c++, inP++) {
3863                         /* Not correct.  Might need to unpremult, shift, etc */
3864                         *outP |= (*inP<<loff[c]>>roff[c])&rasterP->sppsm.maskArray[c];
3865                     }
3866                     outP++;
3867                 }
3868                 lineOutP += rasterP->scanlineStride;
3869             }
3870         }
3871     }
3872     else {
3873         c = component;
3874         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3875         if (loff[0] < 0) {
3876             roff[0] = -loff[0];
3877             loff[0] = 0;
3878         }
3879         else roff[c] = 0;
3880         for (y=0; y < rasterP->height; y++) {
3881             outP = lineOutP;
3882             for (x=0; x < rasterP->width; x++, inP++) {
3883                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3884                 outP++;
3885             }
3886             lineOutP += rasterP->scanlineStride;
3887         }
3888     }
3889 
3890     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3891 
3892     return 0;
3893 }
3894 
3895 /* This routine is expecting a IntegerComponentRaster with a PackedColorModel*/
3896 static int setPackedICRdefault(JNIEnv *env, RasterS_t *rasterP,
3897                                int component, unsigned char *inDataP,
3898                                int supportsAlpha)
3899 {
3900     int x, y, c;
3901     unsigned char *inP = inDataP;
3902     unsigned int *lineOutP, *outP;
3903     jarray jOutDataP;
3904     jsize dataArrayLength;
3905     unsigned int *outDataP;
3906     int loff[MAX_NUMBANDS], roff[MAX_NUMBANDS];
3907     int a = rasterP->numBands - 1;
3908 
3909     if (rasterP->numBands > MAX_NUMBANDS) {
3910         return -1;
3911     }
3912 
3913     /* Grab data ptr, strides, offsets from raster */
3914     jOutDataP = (*env)->GetObjectField(env, rasterP->jraster, g_ICRdataID);
3915     if (JNU_IsNull(env, jOutDataP)) {
3916         return -1;
3917     }
3918 
3919     dataArrayLength = (*env)->GetArrayLength(env, jOutDataP);
3920     CHECK_DST_ARRAY(rasterP->chanOffsets[0], rasterP->scanlineStride, 1);
3921 
3922     outDataP = (*env)->GetPrimitiveArrayCritical(env, jOutDataP, 0);
3923     if (outDataP == NULL) {
3924         return -1;
3925     }
3926     lineOutP = outDataP + rasterP->chanOffsets[0];
3927 
3928     if (component < 0) {
3929         for (c=0; c < rasterP->numBands; c++) {
3930             loff[c] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3931             if (loff[c] < 0) {
3932                 roff[c] = -loff[c];
3933                 loff[c] = 0;
3934             }
3935             else roff[c] = 0;
3936         }
3937         /* Convert the all bands */
3938         if (supportsAlpha) {
3939             for (y=0; y < rasterP->height; y++) {
3940                 outP = lineOutP;
3941                 for (x=0; x < rasterP->width; x++) {
3942                     *outP |= (*inP<<loff[a]>>roff[a])&
3943                         rasterP->sppsm.maskArray[a];
3944                     inP++;
3945                     for (c=0; c < rasterP->numBands-1; c++, inP++) {
3946                         /* Not correct.  Might need to unpremult, shift, etc */
3947                         *outP |= (*inP<<loff[c]>>roff[c])&
3948                             rasterP->sppsm.maskArray[c];
3949                     }
3950                     outP++;
3951                 }
3952                 lineOutP += rasterP->scanlineStride;
3953             }
3954         }
3955         else {
3956             for (y=0; y < rasterP->height; y++) {
3957                 outP = lineOutP;
3958                 for (x=0; x < rasterP->width; x++) {
3959                     inP++;
3960                     for (c=0; c < rasterP->numBands; c++, inP++) {
3961                         /* Not correct.  Might need to unpremult, shift, etc */
3962                         *outP |= (*inP<<loff[c]>>roff[c])&
3963                             rasterP->sppsm.maskArray[c];
3964                     }
3965                     outP++;
3966                 }
3967                 lineOutP += rasterP->scanlineStride;
3968             }
3969         }
3970     }
3971     else {
3972         c = component;
3973         loff[0] = rasterP->sppsm.offsets[c] + (rasterP->sppsm.nBits[c]-8);
3974         if (loff[0] < 0) {
3975             roff[0] = -loff[0];
3976             loff[0] = 0;
3977         }
3978         else roff[c] = 0;
3979 
3980         for (y=0; y < rasterP->height; y++) {
3981             outP = lineOutP;
3982             for (x=0; x < rasterP->width; x++, inP++) {
3983                 *outP |= (*inP<<loff[0]>>roff[0])&rasterP->sppsm.maskArray[c];
3984                 outP++;
3985             }
3986             lineOutP += rasterP->scanlineStride;
3987         }
3988     }
3989 
3990     (*env)->ReleasePrimitiveArrayCritical(env, jOutDataP, outDataP, JNI_ABORT);
3991 
3992     return 0;
3993 }
3994 
3995 /* This is temporary code.  Should go away when there is better color
3996  * conversion code available.
3997  * REMIND:  Ignoring alpha
3998  */
3999 /* returns the absolute value x */
4000 #define ABS(x) ((x) < 0 ? -(x) : (x))
4001 #define CLIP(val,min,max)       ((val < min) ? min : ((val > max) ? max : val))
4002 
4003 static int
4004 colorMatch(int r, int g, int b, int a, unsigned char *argb, int numColors) {
4005     int besti = 0;
4006     int mindist, i, t, d;
4007     unsigned char red, green, blue;
4008 
4009     r = CLIP(r, 0, 255);
4010     g = CLIP(g, 0, 255);
4011     b = CLIP(b, 0, 255);
4012 
4013     /* look for pure gray match */
4014     if ((r == g) && (g == b)) {
4015         mindist = 256;
4016         for (i = 0 ; i < numColors ; i++, argb+=4) {
4017             red = argb[1];
4018             green = argb[2];
4019             blue = argb[3];
4020             if (! ((red == green) && (green == blue)) ) {
4021                 continue;
4022             }
4023             d = ABS(red - r);
4024             if (d == 0)
4025                 return i;
4026             if (d < mindist) {
4027                 besti = i;
4028                 mindist = d;
4029             }
4030         }
4031         return besti;
4032     }
4033 
4034     /* look for non-pure gray match */
4035     mindist = 256 * 256 * 256;
4036     for (i = 0 ; i < numColors ; i++, argb+=4) {
4037         red = argb[1];
4038         green = argb[2];
4039         blue = argb[3];
4040         t = red - r;
4041         d = t * t;
4042         if (d >= mindist) {
4043             continue;
4044         }
4045         t = green - g;
4046         d += t * t;
4047         if (d >= mindist) {
4048             continue;
4049         }
4050         t = blue - b;
4051         d += t * t;
4052         if (d >= mindist) {
4053             continue;
4054         }
4055         if (d == 0)
4056             return i;
4057         if (d < mindist) {
4058             besti = i;
4059             mindist = d;
4060         }
4061     }
4062 
4063     return besti;
4064 }