/* * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include #include #include "awt_parseImage.h" #include "imageInitIDs.h" #include "java_awt_Transparency.h" #include "java_awt_image_BufferedImage.h" #include "sun_awt_image_IntegerComponentRaster.h" #include "sun_awt_image_ImagingLib.h" #include "java_awt_color_ColorSpace.h" #include "awt_Mlib.h" #include "safe_alloc.h" #include "safe_math.h" static int setHints(JNIEnv *env, BufImageS_t *imageP); /* Parse the buffered image. All of the raster information is returned in the * imagePP structure. * * The handleCustom parameter specifies whether or not the caller * can use custom channels. If it is false and a custom channel * is encountered, the returned value will be 0 and all structures * will be deallocated. * * Return value: * -1: Exception * 0: Can't do it. * 1: Success */ int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP, int handleCustom) { BufImageS_t *imageP; int status; jobject jraster; jobject jcmodel; /* Make sure the image exists */ if (JNU_IsNull(env, jimage)) { JNU_ThrowNullPointerException(env, "null BufferedImage object"); return -1; } if ((imageP = (BufImageS_t *) calloc(1, sizeof(BufImageS_t))) == NULL) { JNU_ThrowOutOfMemoryError(env, "Out of memory"); return -1; } imageP->jimage = jimage; /* Retrieve the raster */ if ((jraster = (*env)->GetObjectField(env, jimage, g_BImgRasterID)) == NULL) { free((void *) imageP); JNU_ThrowNullPointerException(env, "null Raster object"); return 0; } /* Retrieve the image type */ imageP->imageType = (*env)->GetIntField(env, jimage, g_BImgTypeID); /* Parse the raster */ if ((status = awt_parseRaster(env, jraster, &imageP->raster)) <= 0) { free((void *)imageP); return status; } /* Retrieve the color model */ if ((jcmodel = (*env)->GetObjectField(env, jimage, g_BImgCMID)) == NULL) { free((void *) imageP); JNU_ThrowNullPointerException(env, "null Raster object"); return 0; } /* Parse the color model */ if ((status = awt_parseColorModel(env, jcmodel, imageP->imageType, &imageP->cmodel)) <= 0) { awt_freeParsedRaster(&imageP->raster, FALSE); free((void *)imageP); return 0; } /* Set hints */ if ((status = setHints(env, imageP)) <= 0) { awt_freeParsedImage(imageP, TRUE); return 0; } *imagePP = imageP; return status; } /* Verifies whether the channel offsets are sane and correspond to the type of * the raster. * * Return value: * 0: Failure: channel offsets are invalid * 1: Success */ static int checkChannelOffsets(RasterS_t *rasterP, int dataArrayLength) { int i, lastPixelOffset, lastScanOffset; switch (rasterP->rasterType) { case COMPONENT_RASTER_TYPE: if (!SAFE_TO_MULT(rasterP->height, rasterP->scanlineStride)) { return 0; } if (!SAFE_TO_MULT(rasterP->width, rasterP->pixelStride)) { return 0; } lastScanOffset = (rasterP->height - 1) * rasterP->scanlineStride; lastPixelOffset = (rasterP->width - 1) * rasterP->pixelStride; if (!SAFE_TO_ADD(lastPixelOffset, lastScanOffset)) { return 0; } lastPixelOffset += lastScanOffset; for (i = 0; i < rasterP->numDataElements; i++) { int off = rasterP->chanOffsets[i]; int size = lastPixelOffset + off; if (off < 0 || !SAFE_TO_ADD(lastPixelOffset, off)) { return 0; } if (size < lastPixelOffset || size >= dataArrayLength) { // an overflow, or insufficient buffer capacity return 0; } } return 1; case BANDED_RASTER_TYPE: // NB:caller does not support the banded rasters yet, // so this branch of the code must be re-defined in // order to provide valid criteria for the data offsets // verification, when/if banded rasters will be supported. // At the moment, we prohibit banded rasters as well. return 0; default: // PACKED_RASTER_TYPE: does not support channel offsets // UNKNOWN_RASTER_TYPE: should not be used, likely indicates an error return 0; } } /* Parse the raster. All of the raster information is returned in the * rasterP structure. * * Return value: * -1: Exception * 0: Can't do it (Custom channel) * 1: Success */ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { jobject joffs = NULL; /* int status;*/ jclass singlePixelPackedSampleModelClass = NULL; jclass integerComponentRasterClass = NULL; jclass byteComponentRasterClass = NULL; jclass shortComponentRasterClass = NULL; jclass bytePackedRasterClass = NULL; if (JNU_IsNull(env, jraster)) { JNU_ThrowNullPointerException(env, "null Raster object"); return -1; } rasterP->jraster = jraster; rasterP->width = (*env)->GetIntField(env, jraster, g_RasterWidthID); rasterP->height = (*env)->GetIntField(env, jraster, g_RasterHeightID); rasterP->numDataElements = (*env)->GetIntField(env, jraster, g_RasterNumDataElementsID); rasterP->numBands = (*env)->GetIntField(env, jraster, g_RasterNumBandsID); rasterP->baseOriginX = (*env)->GetIntField(env, jraster, g_RasterBaseOriginXID); rasterP->baseOriginY = (*env)->GetIntField(env, jraster, g_RasterBaseOriginYID); rasterP->minX = (*env)->GetIntField(env, jraster, g_RasterMinXID); rasterP->minY = (*env)->GetIntField(env, jraster, g_RasterMinYID); rasterP->jsampleModel = (*env)->GetObjectField(env, jraster, g_RasterSampleModelID); if (JNU_IsNull(env, rasterP->jsampleModel)) { JNU_ThrowNullPointerException(env, "null Raster object"); return -1; } // make sure that the raster type is initialized rasterP->rasterType = UNKNOWN_RASTER_TYPE; if (rasterP->numBands <= 0 || rasterP->numBands > MAX_NUMBANDS) { /* * we can't handle such kind of rasters due to limitations * of SPPSampleModelS_t structure and expand/set methods. */ return 0; } rasterP->sppsm.isUsed = 0; singlePixelPackedSampleModelClass = (*env)->FindClass(env, "java/awt/image/SinglePixelPackedSampleModel"); CHECK_NULL_RETURN(singlePixelPackedSampleModelClass, -1); if ((*env)->IsInstanceOf(env, rasterP->jsampleModel, singlePixelPackedSampleModelClass)) { jobject jmask, joffs, jnbits; rasterP->sppsm.isUsed = 1; rasterP->sppsm.maxBitSize = (*env)->GetIntField(env, rasterP->jsampleModel, g_SPPSMmaxBitID); jmask = (*env)->GetObjectField(env, rasterP->jsampleModel, g_SPPSMmaskArrID); joffs = (*env)->GetObjectField(env, rasterP->jsampleModel, g_SPPSMmaskOffID); jnbits = (*env)->GetObjectField(env, rasterP->jsampleModel, g_SPPSMnBitsID); if (jmask == NULL || joffs == NULL || jnbits == NULL || rasterP->sppsm.maxBitSize < 0) { JNU_ThrowInternalError(env, "Can't grab SPPSM fields"); return -1; } (*env)->GetIntArrayRegion(env, jmask, 0, rasterP->numBands, rasterP->sppsm.maskArray); (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numBands, rasterP->sppsm.offsets); (*env)->GetIntArrayRegion(env, jnbits, 0, rasterP->numBands, rasterP->sppsm.nBits); } rasterP->baseRasterWidth = (*env)->GetIntField(env, rasterP->jsampleModel, g_SMWidthID); rasterP->baseRasterHeight = (*env)->GetIntField(env, rasterP->jsampleModel, g_SMHeightID); integerComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/IntegerComponentRaster"); CHECK_NULL_RETURN(integerComponentRasterClass, -1); byteComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/ByteComponentRaster"); CHECK_NULL_RETURN(byteComponentRasterClass, -1); shortComponentRasterClass = (*env)->FindClass(env,"sun/awt/image/ShortComponentRaster"); CHECK_NULL_RETURN(shortComponentRasterClass, -1); bytePackedRasterClass = (*env)->FindClass(env, "sun/awt/image/BytePackedRaster"); CHECK_NULL_RETURN(bytePackedRasterClass, -1); if ((*env)->IsInstanceOf(env, jraster, integerComponentRasterClass)){ rasterP->jdata = (*env)->GetObjectField(env, jraster, g_ICRdataID); rasterP->dataType = INT_DATA_TYPE; rasterP->dataSize = 4; rasterP->dataIsShared = TRUE; rasterP->rasterType = COMPONENT_RASTER_TYPE; rasterP->type = (*env)->GetIntField(env, jraster, g_ICRtypeID); rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_ICRscanstrID); rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_ICRpixstrID); joffs = (*env)->GetObjectField(env, jraster, g_ICRdataOffsetsID); } else if ((*env)->IsInstanceOf(env, jraster, byteComponentRasterClass)){ rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BCRdataID); rasterP->dataType = BYTE_DATA_TYPE; rasterP->dataSize = 1; rasterP->dataIsShared = TRUE; rasterP->rasterType = COMPONENT_RASTER_TYPE; rasterP->type = (*env)->GetIntField(env, jraster, g_BCRtypeID); rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BCRscanstrID); rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BCRpixstrID); joffs = (*env)->GetObjectField(env, jraster, g_BCRdataOffsetsID); } else if ((*env)->IsInstanceOf(env, jraster, shortComponentRasterClass)){ rasterP->jdata = (*env)->GetObjectField(env, jraster, g_SCRdataID); rasterP->dataType = SHORT_DATA_TYPE; rasterP->dataSize = 2; rasterP->dataIsShared = TRUE; rasterP->rasterType = COMPONENT_RASTER_TYPE; rasterP->type = (*env)->GetIntField(env, jraster, g_SCRtypeID); rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_SCRscanstrID); rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_SCRpixstrID); joffs = (*env)->GetObjectField(env, jraster, g_SCRdataOffsetsID); } else if ((*env)->IsInstanceOf(env, jraster, bytePackedRasterClass)){ rasterP->rasterType = PACKED_RASTER_TYPE; rasterP->dataType = BYTE_DATA_TYPE; rasterP->dataSize = 1; rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BPRscanstrID); rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BPRpixstrID); rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BPRdataID); rasterP->type = (*env)->GetIntField(env, jraster, g_BPRtypeID); rasterP->chanOffsets = NULL; if (SAFE_TO_ALLOC_2(rasterP->numDataElements, (int)sizeof(jint))) { rasterP->chanOffsets = (jint *)malloc(rasterP->numDataElements * sizeof(jint)); } if (rasterP->chanOffsets == NULL) { /* Out of memory */ JNU_ThrowOutOfMemoryError(env, "Out of memory"); return -1; } rasterP->chanOffsets[0] = (*env)->GetIntField(env, jraster, g_BPRdataBitOffsetID); rasterP->dataType = BYTE_DATA_TYPE; } else { rasterP->type = sun_awt_image_IntegerComponentRaster_TYPE_CUSTOM; rasterP->dataType = UNKNOWN_DATA_TYPE; rasterP->rasterType = UNKNOWN_RASTER_TYPE; rasterP->chanOffsets = NULL; /* Custom raster */ return 0; } // do basic validation of the raster structure if (rasterP->width <= 0 || rasterP->height <= 0 || rasterP->pixelStride <= 0 || rasterP->scanlineStride <= 0) { // invalid raster return -1; } // channel (data) offsets switch (rasterP->rasterType) { case COMPONENT_RASTER_TYPE: case BANDED_RASTER_TYPE: // note that this routine does not support banded rasters at the moment // get channel (data) offsets rasterP->chanOffsets = NULL; if (SAFE_TO_ALLOC_2(rasterP->numDataElements, (int)sizeof(jint))) { rasterP->chanOffsets = (jint *)malloc(rasterP->numDataElements * sizeof(jint)); } if (rasterP->chanOffsets == NULL) { /* Out of memory */ JNU_ThrowOutOfMemoryError(env, "Out of memory"); return -1; } (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numDataElements, rasterP->chanOffsets); if (rasterP->jdata == NULL) { // unable to verify the raster return -1; } // verify whether channel offsets look sane if (!checkChannelOffsets(rasterP, (*env)->GetArrayLength(env, rasterP->jdata))) { return -1; } break; default: ; // PACKED_RASTER_TYPE does not use the channel offsets. } /* additional check for sppsm fields validity: make sure that * size of raster samples doesn't exceed the data type capacity. */ if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */ rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */ rasterP->sppsm.maxBitSize > (rasterP->dataSize * 8)) { JNU_ThrowInternalError(env, "Raster samples are too big"); return -1; } #if 0 fprintf(stderr,"---------------------\n"); fprintf(stderr,"Width : %d\n",rasterP->width); fprintf(stderr,"Height : %d\n",rasterP->height); fprintf(stderr,"X : %d\n",rasterP->x); fprintf(stderr,"Y : %d\n",rasterP->y); fprintf(stderr,"numC : %d\n",rasterP->numDataElements); fprintf(stderr,"SS : %d\n",rasterP->scanlineStride); fprintf(stderr,"PS : %d\n",rasterP->pixelStride); fprintf(stderr,"CO : %d\n",rasterP->chanOffsets); fprintf(stderr,"shared?: %d\n",rasterP->dataIsShared); fprintf(stderr,"RasterT: %d\n",rasterP->rasterType); fprintf(stderr,"DataT : %d\n",rasterP->dataType); fprintf(stderr,"---------------------\n"); #endif return 1; } static int getColorModelType(JNIEnv *env, jobject jcmodel) { jclass colorModelClass; colorModelClass = (*env)->FindClass(env, "java/awt/image/IndexColorModel"); CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) { return INDEX_CM_TYPE; } colorModelClass = (*env)->FindClass(env, "java/awt/image/PackedColorModel"); CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) { colorModelClass = (*env)->FindClass(env, "java/awt/image/DirectColorModel"); CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) { return DIRECT_CM_TYPE; } else { return PACKED_CM_TYPE; } } colorModelClass = (*env)->FindClass(env, "java/awt/image/ComponentColorModel"); CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) { return COMPONENT_CM_TYPE; } return UNKNOWN_CM_TYPE; } int awt_parseColorModel (JNIEnv *env, jobject jcmodel, int imageType, ColorModelS_t *cmP) { /*jmethodID jID; */ jobject jnBits; jsize nBitsLength; int i; static jobject s_jdefCM = NULL; if (JNU_IsNull(env, jcmodel)) { JNU_ThrowNullPointerException(env, "null ColorModel object"); return -1; } cmP->jcmodel = jcmodel; cmP->jcspace = (*env)->GetObjectField(env, jcmodel, g_CMcspaceID); cmP->numComponents = (*env)->GetIntField(env, jcmodel, g_CMnumComponentsID); cmP->supportsAlpha = (*env)->GetBooleanField(env, jcmodel, g_CMsuppAlphaID); cmP->isAlphaPre = (*env)->GetBooleanField(env,jcmodel, g_CMisAlphaPreID); cmP->transparency = (*env)->GetIntField(env, jcmodel, g_CMtransparencyID); jnBits = (*env)->GetObjectField(env, jcmodel, g_CMnBitsID); if (jnBits == NULL) { JNU_ThrowNullPointerException(env, "null nBits structure in CModel"); return -1; } nBitsLength = (*env)->GetArrayLength(env, jnBits); if (nBitsLength != cmP->numComponents) { // invalid number of components? return -1; } cmP->nBits = NULL; if (SAFE_TO_ALLOC_2(cmP->numComponents, (int)sizeof(jint))) { cmP->nBits = (jint *)malloc(cmP->numComponents * sizeof(jint)); } if (cmP->nBits == NULL){ JNU_ThrowOutOfMemoryError(env, "Out of memory"); return -1; } (*env)->GetIntArrayRegion(env, jnBits, 0, cmP->numComponents, cmP->nBits); cmP->maxNbits = 0; for (i=0; i < cmP->numComponents; i++) { if (cmP->maxNbits < cmP->nBits[i]) { cmP->maxNbits = cmP->nBits[i]; } } cmP->is_sRGB = (*env)->GetBooleanField(env, cmP->jcmodel, g_CMis_sRGBID); cmP->csType = (*env)->GetIntField(env, cmP->jcmodel, g_CMcsTypeID); cmP->cmType = getColorModelType(env, jcmodel); JNU_CHECK_EXCEPTION_RETURN(env, -1); cmP->isDefaultCM = FALSE; cmP->isDefaultCompatCM = FALSE; /* look for standard cases */ if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB) { cmP->isDefaultCM = TRUE; cmP->isDefaultCompatCM = TRUE; } else if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE || imageType == java_awt_image_BufferedImage_TYPE_INT_RGB || imageType == java_awt_image_BufferedImage_TYPE_INT_BGR || imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR || imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE) { cmP->isDefaultCompatCM = TRUE; } else { /* Figure out if this is the default CM */ if (s_jdefCM == NULL) { jobject defCM; jclass jcm = (*env)->FindClass(env, "java/awt/image/ColorModel"); CHECK_NULL_RETURN(jcm, -1); defCM = (*env)->CallStaticObjectMethod(env, jcm, g_CMgetRGBdefaultMID, NULL); s_jdefCM = (*env)->NewGlobalRef(env, defCM); if (defCM == NULL || s_jdefCM == NULL) { (*env)->ExceptionClear(env); JNU_ThrowNullPointerException(env, "Unable to find default CM"); return -1; } } cmP->isDefaultCM = ((*env)->IsSameObject(env, s_jdefCM, jcmodel)); cmP->isDefaultCompatCM = cmP->isDefaultCM; } /* check whether image attributes correspond to default cm */ if (cmP->isDefaultCompatCM) { if (cmP->csType != java_awt_color_ColorSpace_TYPE_RGB || !cmP->is_sRGB) { return -1; } for (i = 0; i < cmP->numComponents; i++) { if (cmP->nBits[i] != 8) { return -1; } } } /* Get index color model attributes */ if (imageType == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED || cmP->cmType == INDEX_CM_TYPE) { cmP->transIdx = (*env)->GetIntField(env, jcmodel, g_ICMtransIdxID); cmP->mapSize = (*env)->GetIntField(env, jcmodel, g_ICMmapSizeID); cmP->jrgb = (*env)->GetObjectField(env, jcmodel, g_ICMrgbID); if (cmP->transIdx == -1) { /* Need to find the transparent index */ int *rgb = (int *) (*env)->GetPrimitiveArrayCritical(env, cmP->jrgb, NULL); if (rgb == NULL) { return -1; } for (i=0; i < cmP->mapSize; i++) { if ((rgb[i]&0xff000000) == 0) { cmP->transIdx = i; break; } } (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb, JNI_ABORT); if (cmP->transIdx == -1) { /* Now what? No transparent pixel... */ cmP->transIdx = 0; } } } return 1; } void awt_freeParsedRaster(RasterS_t *rasterP, int freeRasterP) { if (rasterP->chanOffsets) { free((void *) rasterP->chanOffsets); } if (freeRasterP) { free((void *) rasterP); } } void awt_freeParsedImage(BufImageS_t *imageP, int freeImageP) { if (imageP->hints.colorOrder) { free ((void *) imageP->hints.colorOrder); } if (imageP->cmodel.nBits) { free ((void *) imageP->cmodel.nBits); } /* Free the raster */ awt_freeParsedRaster(&imageP->raster, FALSE); if (freeImageP) { free((void *) imageP); } } static void awt_getBIColorOrder(int type, int *colorOrder) { switch(type) { case java_awt_image_BufferedImage_TYPE_INT_ARGB: case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE: #ifdef _LITTLE_ENDIAN colorOrder[0] = 2; colorOrder[1] = 1; colorOrder[2] = 0; colorOrder[3] = 3; #else colorOrder[0] = 1; colorOrder[1] = 2; colorOrder[2] = 3; colorOrder[3] = 0; #endif break; case java_awt_image_BufferedImage_TYPE_INT_BGR: #ifdef _LITTLE_ENDIAN colorOrder[0] = 0; colorOrder[1] = 1; colorOrder[2] = 2; #else colorOrder[0] = 3; colorOrder[1] = 2; colorOrder[2] = 1; #endif break; case java_awt_image_BufferedImage_TYPE_INT_RGB: #ifdef _LITTLE_ENDIAN colorOrder[0] = 2; colorOrder[1] = 1; colorOrder[2] = 0; #else colorOrder[0] = 1; colorOrder[1] = 2; colorOrder[2] = 3; #endif break; case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR: case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE: colorOrder[0] = 3; colorOrder[1] = 2; colorOrder[2] = 1; colorOrder[3] = 0; break; case java_awt_image_BufferedImage_TYPE_3BYTE_BGR: colorOrder[0] = 2; colorOrder[1] = 1; colorOrder[2] = 0; break; case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB: case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB: colorOrder[0] = 0; colorOrder[1] = 1; colorOrder[2] = 2; break; case java_awt_image_BufferedImage_TYPE_BYTE_GRAY: case java_awt_image_BufferedImage_TYPE_USHORT_GRAY: case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED: colorOrder[0] = 0; break; } } static int setHints(JNIEnv *env, BufImageS_t *imageP) { HintS_t *hintP = &imageP->hints; RasterS_t *rasterP = &imageP->raster; ColorModelS_t *cmodelP = &imageP->cmodel; int imageType = imageP->imageType; // check whether raster and color model are compatible if (cmodelP->numComponents != rasterP->numBands) { if (cmodelP->cmType != INDEX_CM_TYPE) { return -1; } } hintP->numChans = imageP->cmodel.numComponents; hintP->colorOrder = NULL; if (SAFE_TO_ALLOC_2(hintP->numChans, (int)sizeof(int))) { hintP->colorOrder = (int *)malloc(hintP->numChans * sizeof(int)); } if (hintP->colorOrder == NULL) { JNU_ThrowOutOfMemoryError(env, "Out of memory"); return -1; } if (imageType != java_awt_image_BufferedImage_TYPE_CUSTOM) { awt_getBIColorOrder(imageType, hintP->colorOrder); } if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB || imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE || imageType == java_awt_image_BufferedImage_TYPE_INT_RGB) { hintP->channelOffset = rasterP->chanOffsets[0]; /* These hints are #bytes */ hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; hintP->pStride = rasterP->pixelStride*rasterP->dataSize; hintP->packing = BYTE_INTERLEAVED; } else if (imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR || imageType==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE|| imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR || imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) { if (imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) { hintP->channelOffset = rasterP->chanOffsets[0]; } else { hintP->channelOffset = rasterP->chanOffsets[hintP->numChans-1]; } hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; hintP->pStride = rasterP->pixelStride*rasterP->dataSize; hintP->packing = BYTE_INTERLEAVED; } else if (imageType==java_awt_image_BufferedImage_TYPE_USHORT_565_RGB || imageType==java_awt_image_BufferedImage_TYPE_USHORT_555_RGB) { hintP->needToExpand = TRUE; hintP->expandToNbits = 8; hintP->packing = PACKED_SHORT_INTER; } else if (cmodelP->cmType == INDEX_CM_TYPE) { int i; hintP->numChans = 1; hintP->channelOffset = rasterP->chanOffsets[0]; hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; hintP->pStride = rasterP->pixelStride*rasterP->dataSize; switch(rasterP->dataType ) { case BYTE_DATA_TYPE: if (rasterP->rasterType == PACKED_RASTER_TYPE) { hintP->needToExpand = TRUE; hintP->expandToNbits = 8; hintP->packing = BYTE_PACKED_BAND; } else { hintP->packing = BYTE_SINGLE_BAND; } break; case SHORT_DATA_TYPE: hintP->packing = SHORT_SINGLE_BAND; break; case INT_DATA_TYPE: default: hintP->packing = UNKNOWN_PACKING; break; } for (i=0; i < hintP->numChans; i++) { hintP->colorOrder[i] = i; } } else if (cmodelP->cmType == COMPONENT_CM_TYPE) { /* Figure out if it is interleaved */ int bits=1; int i; int low = rasterP->chanOffsets[0]; int diff; int banded = 0; for (i=1; i < hintP->numChans; i++) { if (rasterP->chanOffsets[i] < low) { low = rasterP->chanOffsets[i]; } } for (i=1; i < hintP->numChans; i++) { diff = rasterP->chanOffsets[i]-low; if (diff < hintP->numChans) { if (bits & (1<= rasterP->width) { banded = 1; } /* Ignore the case if bands are overlapping */ } hintP->channelOffset = low; hintP->dataOffset = low*rasterP->dataSize; hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; hintP->pStride = rasterP->pixelStride*rasterP->dataSize; switch(rasterP->dataType) { case BYTE_DATA_TYPE: hintP->packing = BYTE_COMPONENTS; break; case SHORT_DATA_TYPE: hintP->packing = SHORT_COMPONENTS; break; default: /* Don't handle any other case */ return -1; } if (bits == ((1<numChans)-1)) { hintP->packing |= INTERLEAVED; for (i=0; i < hintP->numChans; i++) { hintP->colorOrder[rasterP->chanOffsets[i]-low] = i; } } else if (banded == 1) { int bandSize = rasterP->width*rasterP->height; hintP->packing |= BANDED; for (i=0; i < hintP->numChans; i++) { /* REMIND: Not necessarily correct */ hintP->colorOrder[(rasterP->chanOffsets[i]-low)%bandSize] = i; } } else { return -1; } } else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) { int i; /* do some sanity check first: make sure that * - sample model is SinglePixelPackedSampleModel * - number of bands in the raster corresponds to the number * of color components in the color model */ if (!rasterP->sppsm.isUsed || rasterP->numBands != cmodelP->numComponents) { /* given raster is not compatible with the color model, * so the operation has to be aborted. */ return -1; } if (cmodelP->maxNbits > 8) { hintP->needToExpand = TRUE; hintP->expandToNbits = cmodelP->maxNbits; } else { for (i=0; i < rasterP->numBands; i++) { if (!(rasterP->sppsm.offsets[i] % 8)) { hintP->needToExpand = TRUE; hintP->expandToNbits = 8; break; } else { hintP->colorOrder[i] = rasterP->sppsm.offsets[i]>>3; } } } hintP->channelOffset = rasterP->chanOffsets[0]; hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; hintP->pStride = rasterP->pixelStride*rasterP->dataSize; if (hintP->needToExpand) { switch(rasterP->dataType) { case BYTE_DATA_TYPE: hintP->packing = PACKED_BYTE_INTER; break; case SHORT_DATA_TYPE: hintP->packing = PACKED_SHORT_INTER; break; case INT_DATA_TYPE: hintP->packing = PACKED_INT_INTER; break; default: /* Don't know what it is */ return -1; } } else { hintP->packing = BYTE_INTERLEAVED; } } else { /* REMIND: Need to handle more cases */ return -1; } return 1; } #define MAX_TO_GRAB (10240) typedef union { void *pv; unsigned char *pb; unsigned short *ps; } PixelData_t; int awt_getPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) { const int w = rasterP->width; const int h = rasterP->height; const int numBands = rasterP->numBands; int y; int i; int maxLines; jobject jsm; int off = 0; jarray jdata = NULL; jobject jdatabuffer; int *dataP; int maxSamples; PixelData_t p; if (bufferP == NULL) { return -1; } if (rasterP->dataType != BYTE_DATA_TYPE && rasterP->dataType != SHORT_DATA_TYPE) { return -1; } p.pv = bufferP; if (!SAFE_TO_MULT(w, numBands)) { return -1; } maxSamples = w * numBands; maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples); if (maxLines > h) { maxLines = h; } if (!SAFE_TO_MULT(maxSamples, maxLines)) { return -1; } maxSamples *= maxLines; jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, g_RasterDataBufferID); jdata = (*env)->NewIntArray(env, maxSamples); if (JNU_IsNull(env, jdata)) { (*env)->ExceptionClear(env); JNU_ThrowOutOfMemoryError(env, "Out of Memory"); return -1; } for (y = 0; y < h; y += maxLines) { if (y + maxLines > h) { maxLines = h - y; maxSamples = w * numBands * maxLines; } (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, 0, y, w, maxLines, jdata, jdatabuffer); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, jdata); return -1; } dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL); if (dataP == NULL) { (*env)->DeleteLocalRef(env, jdata); return -1; } switch (rasterP->dataType) { case BYTE_DATA_TYPE: for (i = 0; i < maxSamples; i ++) { p.pb[off++] = (unsigned char) dataP[i]; } break; case SHORT_DATA_TYPE: for (i = 0; i < maxSamples; i ++) { p.ps[off++] = (unsigned short) dataP[i]; } break; } (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, JNI_ABORT); } (*env)->DeleteLocalRef(env, jdata); return 1; } int awt_setPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) { const int w = rasterP->width; const int h = rasterP->height; const int numBands = rasterP->numBands; int y; int i; int maxLines; jobject jsm; int off = 0; jarray jdata = NULL; jobject jdatabuffer; int *dataP; int maxSamples; PixelData_t p; if (bufferP == NULL) { return -1; } if (rasterP->dataType != BYTE_DATA_TYPE && rasterP->dataType != SHORT_DATA_TYPE) { return -1; } p.pv = bufferP; if (!SAFE_TO_MULT(w, numBands)) { return -1; } maxSamples = w * numBands; maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples); if (maxLines > h) { maxLines = h; } if (!SAFE_TO_MULT(maxSamples, maxLines)) { return -1; } maxSamples *= maxLines; jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, g_RasterDataBufferID); jdata = (*env)->NewIntArray(env, maxSamples); if (JNU_IsNull(env, jdata)) { (*env)->ExceptionClear(env); JNU_ThrowOutOfMemoryError(env, "Out of Memory"); return -1; } for (y = 0; y < h; y += maxLines) { if (y + maxLines > h) { maxLines = h - y; maxSamples = w * numBands * maxLines; } dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL); if (dataP == NULL) { (*env)->DeleteLocalRef(env, jdata); return -1; } switch (rasterP->dataType) { case BYTE_DATA_TYPE: for (i = 0; i < maxSamples; i ++) { dataP[i] = p.pb[off++]; } break; case SHORT_DATA_TYPE: for (i = 0; i < maxSamples; i ++) { dataP[i] = p.ps[off++]; } break; } (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, JNI_ABORT); (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, 0, y, w, maxLines, jdata, jdatabuffer); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, jdata); return -1; } } (*env)->DeleteLocalRef(env, jdata); return 1; }