| /* |
| * Copyright (c) 1997, 2010, 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 <stdio.h> |
| #include <stdlib.h> |
| #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" |
| |
| 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; |
| } |
| |
| /* 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;*/ |
| int isDiscrete = TRUE; |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| if ((*env)->IsInstanceOf(env, rasterP->jsampleModel, |
| (*env)->FindClass(env,"java/awt/image/SinglePixelPackedSampleModel"))) { |
| jobject jmask, joffs, jnbits; |
| 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); |
| |
| if ((*env)->IsInstanceOf(env, jraster, |
| (*env)->FindClass(env, "sun/awt/image/IntegerComponentRaster"))){ |
| 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, |
| (*env)->FindClass(env, "sun/awt/image/ByteComponentRaster"))){ |
| 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, |
| (*env)->FindClass(env, "sun/awt/image/ShortComponentRaster"))){ |
| 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, |
| (*env)->FindClass(env, "sun/awt/image/BytePackedRaster"))){ |
| 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, 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; |
| isDiscrete = FALSE; |
| } |
| 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; |
| } |
| |
| if (isDiscrete) { |
| rasterP->chanOffsets = NULL; |
| if (SAFE_TO_ALLOC_2(rasterP->numDataElements, 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); |
| } |
| |
| /* additioanl check for sppsm fields validity: make sure that |
| * size of raster samples doesn't exceed the data type cpacity. |
| */ |
| 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; |
| } |
| |
| int awt_parseColorModel (JNIEnv *env, jobject jcmodel, int imageType, |
| ColorModelS_t *cmP) { |
| /*jmethodID jID; */ |
| jobject jnBits; |
| 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); |
| |
| 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) { |
| cmP->isDefaultCompatCM = TRUE; |
| } else if (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"); |
| defCM = (*env)->CallStaticObjectMethod(env, jcm, |
| g_CMgetRGBdefaultMID, NULL); |
| s_jdefCM = (*env)->NewGlobalRef(env, defCM); |
| if (defCM == NULL || s_jdefCM == NULL) { |
| JNU_ThrowNullPointerException(env, |
| "Unable to find default CM"); |
| return -1; |
| } |
| } |
| cmP->isDefaultCM = ((*env)->IsSameObject(env, s_jdefCM, jcmodel)); |
| cmP->isDefaultCompatCM = cmP->isDefaultCM; |
| } |
| |
| if (cmP->isDefaultCompatCM) { |
| cmP->cmType = DIRECT_CM_TYPE; |
| cmP->nBits = (jint *) malloc(sizeof(jint)*4); |
| cmP->nBits[0] = cmP->nBits[1] = cmP->nBits[2] = cmP->nBits[3] = 8; |
| cmP->maxNbits = 8; |
| cmP->is_sRGB = TRUE; |
| cmP->csType = java_awt_color_ColorSpace_TYPE_RGB; |
| |
| return 1; |
| } |
| |
| jnBits = (*env)->GetObjectField(env, jcmodel, g_CMnBitsID); |
| if (jnBits == NULL) { |
| JNU_ThrowNullPointerException(env, "null nBits structure in CModel"); |
| return -1; |
| } |
| |
| cmP->nBits = NULL; |
| if (SAFE_TO_ALLOC_2(cmP->numComponents, 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); |
| |
| /* Find out what type of colol model */ |
| if (imageType == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED || |
| (*env)->IsInstanceOf(env, jcmodel, |
| (*env)->FindClass(env, "java/awt/image/IndexColorModel"))) |
| { |
| 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; |
| } |
| } |
| } |
| else if ((*env)->IsInstanceOf(env, jcmodel, |
| (*env)->FindClass(env, "java/awt/image/PackedColorModel"))) |
| { |
| if ((*env)->IsInstanceOf(env, jcmodel, |
| (*env)->FindClass(env, "java/awt/image/DirectColorModel"))){ |
| cmP->cmType = DIRECT_CM_TYPE; |
| } |
| else { |
| cmP->cmType = PACKED_CM_TYPE; |
| } |
| } |
| else if ((*env)->IsInstanceOf(env, jcmodel, |
| (*env)->FindClass(env, "java/awt/image/ComponentColorModel"))) |
| { |
| cmP->cmType = COMPONENT_CM_TYPE; |
| } |
| else if ((*env)->IsInstanceOf(env, jcmodel, |
| (*env)->FindClass(env, "java/awt/image/PackedColorModel"))) |
| { |
| cmP->cmType = PACKED_CM_TYPE; |
| } |
| else { |
| cmP->cmType = UNKNOWN_CM_TYPE; |
| } |
| |
| |
| 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; |
| |
| hintP->numChans = imageP->cmodel.numComponents; |
| hintP->colorOrder = NULL; |
| if (SAFE_TO_ALLOC_2(hintP->numChans, 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<<diff)) { |
| /* Overlapping samples */ |
| /* Could just copy */ |
| return -1; |
| } |
| bits |= (1<<diff); |
| } |
| else if (diff >= 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<<hintP->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; |
| if (cmodelP->maxNbits > 8) { |
| hintP->needToExpand = TRUE; |
| hintP->expandToNbits = cmodelP->maxNbits; |
| } |
| else if (rasterP->sppsm.offsets != NULL) { |
| 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; |
| } |
| |
| /* |
| * This routine will fill in a buffer of data for either 1 band or all |
| * bands (if band == -1). |
| */ |
| #define MAX_TO_GRAB (10240) |
| |
| int awt_getPixelByte(JNIEnv *env, int band, RasterS_t *rasterP, |
| unsigned char *bufferP) { |
| int w = rasterP->width; |
| int h = rasterP->height; |
| int numBands = rasterP->numBands; |
| int y; |
| int i; |
| int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w); |
| jobject jsm; |
| int off; |
| jarray jdata = NULL; |
| jobject jdatabuffer; |
| int *dataP; |
| int maxBytes = w; |
| |
| jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
| jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
| g_RasterDataBufferID); |
| jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines); |
| if (JNU_IsNull(env, jdata)) { |
| JNU_ThrowOutOfMemoryError(env, "Out of Memory"); |
| return -1; |
| } |
| |
| /* Here is the generic code */ |
| if (band >= 0) { |
| int dOff; |
| if (band >= numBands) { |
| (*env)->DeleteLocalRef(env, jdata); |
| JNU_ThrowInternalError(env, "Band out of range."); |
| return -1; |
| } |
| off = 0; |
| for (y=0; y < h; ) { |
| (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| dOff = band; |
| for (i=0; i < maxBytes; i++, dOff += numBands) { |
| bufferP[off++] = (unsigned char) dataP[dOff]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| if (y+maxLines < h) { |
| y += maxLines; |
| } |
| else { |
| y++; |
| maxBytes = w; |
| } |
| } |
| } |
| else { |
| off = 0; |
| maxBytes *= numBands; |
| for (y=0; y < h; ) { |
| (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| for (i=0; i < maxBytes; i++) { |
| bufferP[off++] = (unsigned char) dataP[i]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| if (y+maxLines < h) { |
| y += maxLines; |
| } |
| else { |
| y++; |
| maxBytes = w*numBands; |
| } |
| } |
| |
| } |
| (*env)->DeleteLocalRef(env, jdata); |
| |
| return 0; |
| } |
| int awt_setPixelByte(JNIEnv *env, int band, RasterS_t *rasterP, |
| unsigned char *bufferP) { |
| int w = rasterP->width; |
| int h = rasterP->height; |
| int numBands = rasterP->numBands; |
| int y; |
| int i; |
| int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w); |
| jobject jsm; |
| int off; |
| jarray jdata = NULL; |
| jobject jdatabuffer; |
| int *dataP; |
| int maxBytes = w; |
| |
| jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
| jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
| g_RasterDataBufferID); |
| /* Here is the generic code */ |
| jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines); |
| if (JNU_IsNull(env, jdata)) { |
| JNU_ThrowOutOfMemoryError(env, "Out of Memory"); |
| return -1; |
| } |
| if (band >= 0) { |
| int dOff; |
| if (band >= numBands) { |
| (*env)->DeleteLocalRef(env, jdata); |
| JNU_ThrowInternalError(env, "Band out of range."); |
| return -1; |
| } |
| off = 0; |
| for (y=0; y < h; y+=maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| dOff = band; |
| for (i=0; i < maxBytes; i++, dOff += numBands) { |
| dataP[dOff] = bufferP[off++]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| } |
| } |
| else { |
| off = 0; |
| maxBytes *= numBands; |
| for (y=0; y < h; y+=maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| for (i=0; i < maxBytes; i++) { |
| dataP[i] = bufferP[off++]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| } |
| |
| } |
| |
| (*env)->DeleteLocalRef(env, jdata); |
| |
| return 0; |
| } |
| int awt_getPixelShort(JNIEnv *env, int band, RasterS_t *rasterP, |
| unsigned short *bufferP) { |
| int w = rasterP->width; |
| int h = rasterP->height; |
| int numBands = rasterP->numBands; |
| int y; |
| int i; |
| int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w); |
| jobject jsm; |
| int off; |
| jarray jdata = NULL; |
| jobject jdatabuffer; |
| int *dataP; |
| int maxBytes = w*maxLines; |
| |
| jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
| jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
| g_RasterDataBufferID); |
| jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines); |
| if (JNU_IsNull(env, jdata)) { |
| JNU_ThrowOutOfMemoryError(env, "Out of Memory"); |
| return -1; |
| } |
| /* Here is the generic code */ |
| if (band >= 0) { |
| int dOff; |
| if (band >= numBands) { |
| (*env)->DeleteLocalRef(env, jdata); |
| JNU_ThrowInternalError(env, "Band out of range."); |
| return -1; |
| } |
| off = 0; |
| for (y=0; y < h; y += maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| |
| dOff = band; |
| for (i=0; i < maxBytes; i++, dOff += numBands) { |
| bufferP[off++] = (unsigned short) dataP[dOff]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| } |
| } |
| else { |
| off = 0; |
| maxBytes *= numBands; |
| for (y=0; y < h; y+=maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| for (i=0; i < maxBytes; i++) { |
| bufferP[off++] = (unsigned short) dataP[i]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| } |
| |
| } |
| |
| (*env)->DeleteLocalRef(env, jdata); |
| return 0; |
| } |
| int awt_setPixelShort(JNIEnv *env, int band, RasterS_t *rasterP, |
| unsigned short *bufferP) { |
| int w = rasterP->width; |
| int h = rasterP->height; |
| int numBands = rasterP->numBands; |
| int y; |
| int i; |
| int maxLines = (h < MAX_TO_GRAB/w ? h : MAX_TO_GRAB/w); |
| jobject jsm; |
| int off; |
| jarray jdata = NULL; |
| jobject jdatabuffer; |
| int *dataP; |
| int maxBytes = w; |
| |
| jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
| jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
| g_RasterDataBufferID); |
| /* Here is the generic code */ |
| jdata = (*env)->NewIntArray(env, maxBytes*rasterP->numBands*maxLines); |
| if (JNU_IsNull(env, jdata)) { |
| JNU_ThrowOutOfMemoryError(env, "Out of Memory"); |
| return -1; |
| } |
| if (band >= 0) { |
| int dOff; |
| if (band >= numBands) { |
| (*env)->DeleteLocalRef(env, jdata); |
| JNU_ThrowInternalError(env, "Band out of range."); |
| return -1; |
| } |
| off = 0; |
| for (y=0; y < h; y+=maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| dOff = band; |
| for (i=0; i < maxBytes; i++, dOff += numBands) { |
| dataP[dOff] = bufferP[off++]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| } |
| } |
| else { |
| off = 0; |
| maxBytes *= numBands; |
| for (y=0; y < h; y+=maxLines) { |
| if (y+maxLines > h) { |
| maxBytes = w*numBands; |
| maxLines = h - y; |
| } |
| dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
| NULL); |
| if (dataP == NULL) { |
| (*env)->DeleteLocalRef(env, jdata); |
| return -1; |
| } |
| for (i=0; i < maxBytes; i++) { |
| dataP[i] = bufferP[off++]; |
| } |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
| JNI_ABORT); |
| |
| (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, |
| 0, y, w, |
| maxLines, jdata, jdatabuffer); |
| } |
| |
| } |
| |
| (*env)->DeleteLocalRef(env, jdata); |
| return 0; |
| } |