1 | /* |
2 | * Copyright (c) 1997, 2014, 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 "awt_parseImage.h" |
29 | #include "imageInitIDs.h" |
30 | #include "java_awt_Transparency.h" |
31 | #include "java_awt_image_BufferedImage.h" |
32 | #include "sun_awt_image_IntegerComponentRaster.h" |
33 | #include "sun_awt_image_ImagingLib.h" |
34 | #include "java_awt_color_ColorSpace.h" |
35 | #include "awt_Mlib.h" |
36 | #include "safe_alloc.h" |
37 | #include "safe_math.h" |
38 | |
39 | static int setHints(JNIEnv *env, BufImageS_t *imageP); |
40 | |
41 | |
42 | |
43 | /* Parse the buffered image. All of the raster information is returned in the |
44 | * imagePP structure. |
45 | * |
46 | * The handleCustom parameter specifies whether or not the caller |
47 | * can use custom channels. If it is false and a custom channel |
48 | * is encountered, the returned value will be 0 and all structures |
49 | * will be deallocated. |
50 | * |
51 | * Return value: |
52 | * -1: Exception |
53 | * 0: Can't do it. |
54 | * 1: Success |
55 | */ |
56 | int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP, |
57 | int handleCustom) { |
58 | BufImageS_t *imageP; |
59 | int status; |
60 | jobject jraster; |
61 | jobject jcmodel; |
62 | |
63 | /* Make sure the image exists */ |
64 | if (JNU_IsNull(env, jimage)) { |
65 | JNU_ThrowNullPointerException(env, "null BufferedImage object" ); |
66 | return -1; |
67 | } |
68 | |
69 | if ((imageP = (BufImageS_t *) calloc(1, sizeof(BufImageS_t))) == NULL) { |
70 | JNU_ThrowOutOfMemoryError(env, "Out of memory" ); |
71 | return -1; |
72 | } |
73 | imageP->jimage = jimage; |
74 | |
75 | /* Retrieve the raster */ |
76 | if ((jraster = (*env)->GetObjectField(env, jimage, |
77 | g_BImgRasterID)) == NULL) { |
78 | free((void *) imageP); |
79 | JNU_ThrowNullPointerException(env, "null Raster object" ); |
80 | return 0; |
81 | } |
82 | |
83 | /* Retrieve the image type */ |
84 | imageP->imageType = (*env)->GetIntField(env, jimage, g_BImgTypeID); |
85 | |
86 | /* Parse the raster */ |
87 | if ((status = awt_parseRaster(env, jraster, &imageP->raster)) <= 0) { |
88 | free((void *)imageP); |
89 | return status; |
90 | } |
91 | |
92 | /* Retrieve the color model */ |
93 | if ((jcmodel = (*env)->GetObjectField(env, jimage, g_BImgCMID)) == NULL) { |
94 | free((void *) imageP); |
95 | JNU_ThrowNullPointerException(env, "null Raster object" ); |
96 | return 0; |
97 | } |
98 | |
99 | /* Parse the color model */ |
100 | if ((status = awt_parseColorModel(env, jcmodel, imageP->imageType, |
101 | &imageP->cmodel)) <= 0) { |
102 | awt_freeParsedRaster(&imageP->raster, FALSE); |
103 | free((void *)imageP); |
104 | return 0; |
105 | } |
106 | |
107 | /* Set hints */ |
108 | if ((status = setHints(env, imageP)) <= 0) { |
109 | awt_freeParsedImage(imageP, TRUE); |
110 | return 0; |
111 | } |
112 | |
113 | *imagePP = imageP; |
114 | |
115 | return status; |
116 | } |
117 | |
118 | /* Verifies whether the channel offsets are sane and correspond to the type of |
119 | * the raster. |
120 | * |
121 | * Return value: |
122 | * 0: Failure: channel offsets are invalid |
123 | * 1: Success |
124 | */ |
125 | static int checkChannelOffsets(RasterS_t *rasterP, int dataArrayLength) { |
126 | int i, lastPixelOffset, lastScanOffset; |
127 | switch (rasterP->rasterType) { |
128 | case COMPONENT_RASTER_TYPE: |
129 | if (!SAFE_TO_MULT(rasterP->height, rasterP->scanlineStride)) { |
130 | return 0; |
131 | } |
132 | if (!SAFE_TO_MULT(rasterP->width, rasterP->pixelStride)) { |
133 | return 0; |
134 | } |
135 | |
136 | lastScanOffset = (rasterP->height - 1) * rasterP->scanlineStride; |
137 | lastPixelOffset = (rasterP->width - 1) * rasterP->pixelStride; |
138 | |
139 | |
140 | if (!SAFE_TO_ADD(lastPixelOffset, lastScanOffset)) { |
141 | return 0; |
142 | } |
143 | |
144 | lastPixelOffset += lastScanOffset; |
145 | |
146 | for (i = 0; i < rasterP->numDataElements; i++) { |
147 | int off = rasterP->chanOffsets[i]; |
148 | int size = lastPixelOffset + off; |
149 | |
150 | if (off < 0 || !SAFE_TO_ADD(lastPixelOffset, off)) { |
151 | return 0; |
152 | } |
153 | |
154 | if (size < lastPixelOffset || size >= dataArrayLength) { |
155 | // an overflow, or insufficient buffer capacity |
156 | return 0; |
157 | } |
158 | } |
159 | return 1; |
160 | case BANDED_RASTER_TYPE: |
161 | // NB:caller does not support the banded rasters yet, |
162 | // so this branch of the code must be re-defined in |
163 | // order to provide valid criteria for the data offsets |
164 | // verification, when/if banded rasters will be supported. |
165 | // At the moment, we prohibit banded rasters as well. |
166 | return 0; |
167 | default: |
168 | // PACKED_RASTER_TYPE: does not support channel offsets |
169 | // UNKNOWN_RASTER_TYPE: should not be used, likely indicates an error |
170 | return 0; |
171 | } |
172 | } |
173 | |
174 | /* Parse the raster. All of the raster information is returned in the |
175 | * rasterP structure. |
176 | * |
177 | * Return value: |
178 | * -1: Exception |
179 | * 0: Can't do it (Custom channel) |
180 | * 1: Success |
181 | */ |
182 | int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { |
183 | jobject joffs = NULL; |
184 | /* int status;*/ |
185 | jclass singlePixelPackedSampleModelClass = NULL; |
186 | jclass integerComponentRasterClass = NULL; |
187 | jclass byteComponentRasterClass = NULL; |
188 | jclass shortComponentRasterClass = NULL; |
189 | jclass bytePackedRasterClass = NULL; |
190 | |
191 | if (JNU_IsNull(env, jraster)) { |
192 | JNU_ThrowNullPointerException(env, "null Raster object" ); |
193 | return -1; |
194 | } |
195 | |
196 | rasterP->jraster = jraster; |
197 | rasterP->width = (*env)->GetIntField(env, jraster, g_RasterWidthID); |
198 | rasterP->height = (*env)->GetIntField(env, jraster, g_RasterHeightID); |
199 | rasterP->numDataElements = (*env)->GetIntField(env, jraster, |
200 | g_RasterNumDataElementsID); |
201 | rasterP->numBands = (*env)->GetIntField(env, jraster, |
202 | g_RasterNumBandsID); |
203 | |
204 | rasterP->baseOriginX = (*env)->GetIntField(env, jraster, |
205 | g_RasterBaseOriginXID); |
206 | rasterP->baseOriginY = (*env)->GetIntField(env, jraster, |
207 | g_RasterBaseOriginYID); |
208 | rasterP->minX = (*env)->GetIntField(env, jraster, g_RasterMinXID); |
209 | rasterP->minY = (*env)->GetIntField(env, jraster, g_RasterMinYID); |
210 | |
211 | rasterP->jsampleModel = (*env)->GetObjectField(env, jraster, |
212 | g_RasterSampleModelID); |
213 | |
214 | if (JNU_IsNull(env, rasterP->jsampleModel)) { |
215 | JNU_ThrowNullPointerException(env, "null Raster object" ); |
216 | return -1; |
217 | } |
218 | |
219 | // make sure that the raster type is initialized |
220 | rasterP->rasterType = UNKNOWN_RASTER_TYPE; |
221 | |
222 | if (rasterP->numBands <= 0 || |
223 | rasterP->numBands > MAX_NUMBANDS) |
224 | { |
225 | /* |
226 | * we can't handle such kind of rasters due to limitations |
227 | * of SPPSampleModelS_t structure and expand/set methods. |
228 | */ |
229 | return 0; |
230 | } |
231 | |
232 | rasterP->sppsm.isUsed = 0; |
233 | |
234 | singlePixelPackedSampleModelClass = (*env)->FindClass(env, |
235 | "java/awt/image/SinglePixelPackedSampleModel" ); |
236 | CHECK_NULL_RETURN(singlePixelPackedSampleModelClass, -1); |
237 | if ((*env)->IsInstanceOf(env, rasterP->jsampleModel, |
238 | singlePixelPackedSampleModelClass)) { |
239 | jobject jmask, joffs, jnbits; |
240 | |
241 | rasterP->sppsm.isUsed = 1; |
242 | |
243 | rasterP->sppsm.maxBitSize = (*env)->GetIntField(env, |
244 | rasterP->jsampleModel, |
245 | g_SPPSMmaxBitID); |
246 | jmask = (*env)->GetObjectField(env, rasterP->jsampleModel, |
247 | g_SPPSMmaskArrID); |
248 | joffs = (*env)->GetObjectField(env, rasterP->jsampleModel, |
249 | g_SPPSMmaskOffID); |
250 | jnbits = (*env)->GetObjectField(env, rasterP->jsampleModel, |
251 | g_SPPSMnBitsID); |
252 | if (jmask == NULL || joffs == NULL || jnbits == NULL || |
253 | rasterP->sppsm.maxBitSize < 0) |
254 | { |
255 | JNU_ThrowInternalError(env, "Can't grab SPPSM fields" ); |
256 | return -1; |
257 | } |
258 | (*env)->GetIntArrayRegion(env, jmask, 0, |
259 | rasterP->numBands, rasterP->sppsm.maskArray); |
260 | (*env)->GetIntArrayRegion(env, joffs, 0, |
261 | rasterP->numBands, rasterP->sppsm.offsets); |
262 | (*env)->GetIntArrayRegion(env, jnbits, 0, |
263 | rasterP->numBands, rasterP->sppsm.nBits); |
264 | |
265 | } |
266 | rasterP->baseRasterWidth = (*env)->GetIntField(env, rasterP->jsampleModel, |
267 | g_SMWidthID); |
268 | rasterP->baseRasterHeight = (*env)->GetIntField(env, |
269 | rasterP->jsampleModel, |
270 | g_SMHeightID); |
271 | |
272 | integerComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/IntegerComponentRaster" ); |
273 | CHECK_NULL_RETURN(integerComponentRasterClass, -1); |
274 | byteComponentRasterClass = (*env)->FindClass(env, "sun/awt/image/ByteComponentRaster" ); |
275 | CHECK_NULL_RETURN(byteComponentRasterClass, -1); |
276 | shortComponentRasterClass = (*env)->FindClass(env,"sun/awt/image/ShortComponentRaster" ); |
277 | CHECK_NULL_RETURN(shortComponentRasterClass, -1); |
278 | bytePackedRasterClass = (*env)->FindClass(env, "sun/awt/image/BytePackedRaster" ); |
279 | CHECK_NULL_RETURN(bytePackedRasterClass, -1); |
280 | if ((*env)->IsInstanceOf(env, jraster, integerComponentRasterClass)){ |
281 | rasterP->jdata = (*env)->GetObjectField(env, jraster, g_ICRdataID); |
282 | rasterP->dataType = INT_DATA_TYPE; |
283 | rasterP->dataSize = 4; |
284 | rasterP->dataIsShared = TRUE; |
285 | rasterP->rasterType = COMPONENT_RASTER_TYPE; |
286 | rasterP->type = (*env)->GetIntField(env, jraster, g_ICRtypeID); |
287 | rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_ICRscanstrID); |
288 | rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_ICRpixstrID); |
289 | joffs = (*env)->GetObjectField(env, jraster, g_ICRdataOffsetsID); |
290 | } |
291 | else if ((*env)->IsInstanceOf(env, jraster, byteComponentRasterClass)){ |
292 | rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BCRdataID); |
293 | rasterP->dataType = BYTE_DATA_TYPE; |
294 | rasterP->dataSize = 1; |
295 | rasterP->dataIsShared = TRUE; |
296 | rasterP->rasterType = COMPONENT_RASTER_TYPE; |
297 | rasterP->type = (*env)->GetIntField(env, jraster, g_BCRtypeID); |
298 | rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BCRscanstrID); |
299 | rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BCRpixstrID); |
300 | joffs = (*env)->GetObjectField(env, jraster, g_BCRdataOffsetsID); |
301 | } |
302 | else if ((*env)->IsInstanceOf(env, jraster, shortComponentRasterClass)){ |
303 | rasterP->jdata = (*env)->GetObjectField(env, jraster, g_SCRdataID); |
304 | rasterP->dataType = SHORT_DATA_TYPE; |
305 | rasterP->dataSize = 2; |
306 | rasterP->dataIsShared = TRUE; |
307 | rasterP->rasterType = COMPONENT_RASTER_TYPE; |
308 | rasterP->type = (*env)->GetIntField(env, jraster, g_SCRtypeID); |
309 | rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_SCRscanstrID); |
310 | rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_SCRpixstrID); |
311 | joffs = (*env)->GetObjectField(env, jraster, g_SCRdataOffsetsID); |
312 | } |
313 | else if ((*env)->IsInstanceOf(env, jraster, bytePackedRasterClass)){ |
314 | rasterP->rasterType = PACKED_RASTER_TYPE; |
315 | rasterP->dataType = BYTE_DATA_TYPE; |
316 | rasterP->dataSize = 1; |
317 | rasterP->scanlineStride = (*env)->GetIntField(env, jraster, g_BPRscanstrID); |
318 | rasterP->pixelStride = (*env)->GetIntField(env, jraster, g_BPRpixstrID); |
319 | rasterP->jdata = (*env)->GetObjectField(env, jraster, g_BPRdataID); |
320 | rasterP->type = (*env)->GetIntField(env, jraster, g_BPRtypeID); |
321 | rasterP->chanOffsets = NULL; |
322 | if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) { |
323 | rasterP->chanOffsets = |
324 | (jint *)malloc(rasterP->numDataElements * sizeof(jint)); |
325 | } |
326 | if (rasterP->chanOffsets == NULL) { |
327 | /* Out of memory */ |
328 | JNU_ThrowOutOfMemoryError(env, "Out of memory" ); |
329 | return -1; |
330 | } |
331 | rasterP->chanOffsets[0] = (*env)->GetIntField(env, jraster, g_BPRdataBitOffsetID); |
332 | rasterP->dataType = BYTE_DATA_TYPE; |
333 | } |
334 | else { |
335 | rasterP->type = sun_awt_image_IntegerComponentRaster_TYPE_CUSTOM; |
336 | rasterP->dataType = UNKNOWN_DATA_TYPE; |
337 | rasterP->rasterType = UNKNOWN_RASTER_TYPE; |
338 | rasterP->chanOffsets = NULL; |
339 | /* Custom raster */ |
340 | return 0; |
341 | } |
342 | |
343 | // do basic validation of the raster structure |
344 | if (rasterP->width <= 0 || rasterP->height <= 0 || |
345 | rasterP->pixelStride <= 0 || rasterP->scanlineStride <= 0) |
346 | { |
347 | // invalid raster |
348 | return -1; |
349 | } |
350 | |
351 | // channel (data) offsets |
352 | switch (rasterP->rasterType) { |
353 | case COMPONENT_RASTER_TYPE: |
354 | case BANDED_RASTER_TYPE: // note that this routine does not support banded rasters at the moment |
355 | // get channel (data) offsets |
356 | rasterP->chanOffsets = NULL; |
357 | if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) { |
358 | rasterP->chanOffsets = |
359 | (jint *)malloc(rasterP->numDataElements * sizeof(jint)); |
360 | } |
361 | if (rasterP->chanOffsets == NULL) { |
362 | /* Out of memory */ |
363 | JNU_ThrowOutOfMemoryError(env, "Out of memory" ); |
364 | return -1; |
365 | } |
366 | (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numDataElements, |
367 | rasterP->chanOffsets); |
368 | if (rasterP->jdata == NULL) { |
369 | // unable to verify the raster |
370 | return -1; |
371 | } |
372 | // verify whether channel offsets look sane |
373 | if (!checkChannelOffsets(rasterP, (*env)->GetArrayLength(env, rasterP->jdata))) { |
374 | return -1; |
375 | } |
376 | break; |
377 | default: |
378 | ; // PACKED_RASTER_TYPE does not use the channel offsets. |
379 | } |
380 | |
381 | /* additional check for sppsm fields validity: make sure that |
382 | * size of raster samples doesn't exceed the data type capacity. |
383 | */ |
384 | if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */ |
385 | rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */ |
386 | rasterP->sppsm.maxBitSize > (rasterP->dataSize * 8)) |
387 | { |
388 | JNU_ThrowInternalError(env, "Raster samples are too big" ); |
389 | return -1; |
390 | } |
391 | |
392 | #if 0 |
393 | fprintf(stderr,"---------------------\n" ); |
394 | fprintf(stderr,"Width : %d\n" ,rasterP->width); |
395 | fprintf(stderr,"Height : %d\n" ,rasterP->height); |
396 | fprintf(stderr,"X : %d\n" ,rasterP->x); |
397 | fprintf(stderr,"Y : %d\n" ,rasterP->y); |
398 | fprintf(stderr,"numC : %d\n" ,rasterP->numDataElements); |
399 | fprintf(stderr,"SS : %d\n" ,rasterP->scanlineStride); |
400 | fprintf(stderr,"PS : %d\n" ,rasterP->pixelStride); |
401 | fprintf(stderr,"CO : %d\n" ,rasterP->chanOffsets); |
402 | fprintf(stderr,"shared?: %d\n" ,rasterP->dataIsShared); |
403 | fprintf(stderr,"RasterT: %d\n" ,rasterP->rasterType); |
404 | fprintf(stderr,"DataT : %d\n" ,rasterP->dataType); |
405 | fprintf(stderr,"---------------------\n" ); |
406 | #endif |
407 | |
408 | return 1; |
409 | } |
410 | |
411 | static int getColorModelType(JNIEnv *env, jobject jcmodel) { |
412 | jclass colorModelClass; |
413 | |
414 | colorModelClass = (*env)->FindClass(env, |
415 | "java/awt/image/IndexColorModel" ); |
416 | CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); |
417 | |
418 | if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) |
419 | { |
420 | return INDEX_CM_TYPE; |
421 | } |
422 | |
423 | colorModelClass = (*env)->FindClass(env, |
424 | "java/awt/image/PackedColorModel" ); |
425 | CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); |
426 | if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) |
427 | { |
428 | colorModelClass = (*env)->FindClass(env, |
429 | "java/awt/image/DirectColorModel" ); |
430 | CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); |
431 | if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) { |
432 | return DIRECT_CM_TYPE; |
433 | } |
434 | else { |
435 | return PACKED_CM_TYPE; |
436 | } |
437 | } |
438 | colorModelClass = (*env)->FindClass(env, |
439 | "java/awt/image/ComponentColorModel" ); |
440 | CHECK_NULL_RETURN(colorModelClass, UNKNOWN_CM_TYPE); |
441 | if ((*env)->IsInstanceOf(env, jcmodel, colorModelClass)) |
442 | { |
443 | return COMPONENT_CM_TYPE; |
444 | } |
445 | |
446 | return UNKNOWN_CM_TYPE; |
447 | } |
448 | |
449 | int awt_parseColorModel (JNIEnv *env, jobject jcmodel, int imageType, |
450 | ColorModelS_t *cmP) { |
451 | /*jmethodID jID; */ |
452 | jobject jnBits; |
453 | jsize nBitsLength; |
454 | |
455 | int i; |
456 | static jobject s_jdefCM = NULL; |
457 | |
458 | if (JNU_IsNull(env, jcmodel)) { |
459 | JNU_ThrowNullPointerException(env, "null ColorModel object" ); |
460 | return -1; |
461 | } |
462 | |
463 | cmP->jcmodel = jcmodel; |
464 | |
465 | cmP->jcspace = (*env)->GetObjectField(env, jcmodel, g_CMcspaceID); |
466 | |
467 | cmP->numComponents = (*env)->GetIntField(env, jcmodel, |
468 | g_CMnumComponentsID); |
469 | cmP->supportsAlpha = (*env)->GetBooleanField(env, jcmodel, |
470 | g_CMsuppAlphaID); |
471 | cmP->isAlphaPre = (*env)->GetBooleanField(env,jcmodel, |
472 | g_CMisAlphaPreID); |
473 | cmP->transparency = (*env)->GetIntField(env, jcmodel, |
474 | g_CMtransparencyID); |
475 | |
476 | jnBits = (*env)->GetObjectField(env, jcmodel, g_CMnBitsID); |
477 | if (jnBits == NULL) { |
478 | JNU_ThrowNullPointerException(env, "null nBits structure in CModel" ); |
479 | return -1; |
480 | } |
481 | |
482 | nBitsLength = (*env)->GetArrayLength(env, jnBits); |
483 | if (nBitsLength != cmP->numComponents) { |
484 | // invalid number of components? |
485 | return -1; |
486 | } |
487 | |
488 | cmP->nBits = NULL; |
489 | if (SAFE_TO_ALLOC_2(cmP->numComponents, sizeof(jint))) { |
490 | cmP->nBits = (jint *)malloc(cmP->numComponents * sizeof(jint)); |
491 | } |
492 | |
493 | if (cmP->nBits == NULL){ |
494 | JNU_ThrowOutOfMemoryError(env, "Out of memory" ); |
495 | return -1; |
496 | } |
497 | (*env)->GetIntArrayRegion(env, jnBits, 0, cmP->numComponents, |
498 | cmP->nBits); |
499 | cmP->maxNbits = 0; |
500 | for (i=0; i < cmP->numComponents; i++) { |
501 | if (cmP->maxNbits < cmP->nBits[i]) { |
502 | cmP->maxNbits = cmP->nBits[i]; |
503 | } |
504 | } |
505 | |
506 | cmP->is_sRGB = (*env)->GetBooleanField(env, cmP->jcmodel, g_CMis_sRGBID); |
507 | |
508 | cmP->csType = (*env)->GetIntField(env, cmP->jcmodel, g_CMcsTypeID); |
509 | |
510 | cmP->cmType = getColorModelType(env, jcmodel); |
511 | JNU_CHECK_EXCEPTION_RETURN(env, -1); |
512 | |
513 | cmP->isDefaultCM = FALSE; |
514 | cmP->isDefaultCompatCM = FALSE; |
515 | |
516 | /* look for standard cases */ |
517 | if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB) { |
518 | cmP->isDefaultCM = TRUE; |
519 | cmP->isDefaultCompatCM = TRUE; |
520 | } else if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE || |
521 | imageType == java_awt_image_BufferedImage_TYPE_INT_RGB || |
522 | imageType == java_awt_image_BufferedImage_TYPE_INT_BGR || |
523 | imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR || |
524 | imageType == java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE) |
525 | { |
526 | cmP->isDefaultCompatCM = TRUE; |
527 | } |
528 | else { |
529 | /* Figure out if this is the default CM */ |
530 | if (s_jdefCM == NULL) { |
531 | jobject defCM; |
532 | jclass jcm = (*env)->FindClass(env, "java/awt/image/ColorModel" ); |
533 | CHECK_NULL_RETURN(jcm, -1); |
534 | defCM = (*env)->CallStaticObjectMethod(env, jcm, |
535 | g_CMgetRGBdefaultMID, NULL); |
536 | s_jdefCM = (*env)->NewGlobalRef(env, defCM); |
537 | if (defCM == NULL || s_jdefCM == NULL) { |
538 | (*env)->ExceptionClear(env); |
539 | JNU_ThrowNullPointerException(env, "Unable to find default CM" ); |
540 | return -1; |
541 | } |
542 | } |
543 | cmP->isDefaultCM = ((*env)->IsSameObject(env, s_jdefCM, jcmodel)); |
544 | cmP->isDefaultCompatCM = cmP->isDefaultCM; |
545 | } |
546 | |
547 | /* check whether image attributes correspond to default cm */ |
548 | if (cmP->isDefaultCompatCM) { |
549 | if (cmP->csType != java_awt_color_ColorSpace_TYPE_RGB || |
550 | !cmP->is_sRGB) |
551 | { |
552 | return -1; |
553 | } |
554 | |
555 | for (i = 0; i < cmP->numComponents; i++) { |
556 | if (cmP->nBits[i] != 8) { |
557 | return -1; |
558 | } |
559 | } |
560 | } |
561 | |
562 | /* Get index color model attributes */ |
563 | if (imageType == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED || |
564 | cmP->cmType == INDEX_CM_TYPE) |
565 | { |
566 | cmP->transIdx = (*env)->GetIntField(env, jcmodel, g_ICMtransIdxID); |
567 | cmP->mapSize = (*env)->GetIntField(env, jcmodel, g_ICMmapSizeID); |
568 | cmP->jrgb = (*env)->GetObjectField(env, jcmodel, g_ICMrgbID); |
569 | if (cmP->transIdx == -1) { |
570 | /* Need to find the transparent index */ |
571 | int *rgb = (int *) (*env)->GetPrimitiveArrayCritical(env, |
572 | cmP->jrgb, |
573 | NULL); |
574 | if (rgb == NULL) { |
575 | return -1; |
576 | } |
577 | for (i=0; i < cmP->mapSize; i++) { |
578 | if ((rgb[i]&0xff000000) == 0) { |
579 | cmP->transIdx = i; |
580 | break; |
581 | } |
582 | } |
583 | (*env)->ReleasePrimitiveArrayCritical(env, cmP->jrgb, rgb, |
584 | JNI_ABORT); |
585 | if (cmP->transIdx == -1) { |
586 | /* Now what? No transparent pixel... */ |
587 | cmP->transIdx = 0; |
588 | } |
589 | } |
590 | } |
591 | |
592 | return 1; |
593 | } |
594 | |
595 | void awt_freeParsedRaster(RasterS_t *rasterP, int freeRasterP) { |
596 | if (rasterP->chanOffsets) { |
597 | free((void *) rasterP->chanOffsets); |
598 | } |
599 | |
600 | if (freeRasterP) { |
601 | free((void *) rasterP); |
602 | } |
603 | } |
604 | |
605 | void awt_freeParsedImage(BufImageS_t *imageP, int freeImageP) { |
606 | if (imageP->hints.colorOrder) { |
607 | free ((void *) imageP->hints.colorOrder); |
608 | } |
609 | |
610 | if (imageP->cmodel.nBits) { |
611 | free ((void *) imageP->cmodel.nBits); |
612 | } |
613 | |
614 | /* Free the raster */ |
615 | awt_freeParsedRaster(&imageP->raster, FALSE); |
616 | |
617 | if (freeImageP) { |
618 | free((void *) imageP); |
619 | } |
620 | } |
621 | |
622 | static void |
623 | awt_getBIColorOrder(int type, int *colorOrder) { |
624 | switch(type) { |
625 | case java_awt_image_BufferedImage_TYPE_INT_ARGB: |
626 | case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE: |
627 | #ifdef _LITTLE_ENDIAN |
628 | colorOrder[0] = 2; |
629 | colorOrder[1] = 1; |
630 | colorOrder[2] = 0; |
631 | colorOrder[3] = 3; |
632 | #else |
633 | colorOrder[0] = 1; |
634 | colorOrder[1] = 2; |
635 | colorOrder[2] = 3; |
636 | colorOrder[3] = 0; |
637 | #endif |
638 | break; |
639 | case java_awt_image_BufferedImage_TYPE_INT_BGR: |
640 | #ifdef _LITTLE_ENDIAN |
641 | colorOrder[0] = 0; |
642 | colorOrder[1] = 1; |
643 | colorOrder[2] = 2; |
644 | #else |
645 | colorOrder[0] = 3; |
646 | colorOrder[1] = 2; |
647 | colorOrder[2] = 1; |
648 | #endif |
649 | break; |
650 | case java_awt_image_BufferedImage_TYPE_INT_RGB: |
651 | #ifdef _LITTLE_ENDIAN |
652 | colorOrder[0] = 2; |
653 | colorOrder[1] = 1; |
654 | colorOrder[2] = 0; |
655 | #else |
656 | colorOrder[0] = 1; |
657 | colorOrder[1] = 2; |
658 | colorOrder[2] = 3; |
659 | #endif |
660 | break; |
661 | case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR: |
662 | case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE: |
663 | colorOrder[0] = 3; |
664 | colorOrder[1] = 2; |
665 | colorOrder[2] = 1; |
666 | colorOrder[3] = 0; |
667 | break; |
668 | case java_awt_image_BufferedImage_TYPE_3BYTE_BGR: |
669 | colorOrder[0] = 2; |
670 | colorOrder[1] = 1; |
671 | colorOrder[2] = 0; |
672 | break; |
673 | case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB: |
674 | case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB: |
675 | colorOrder[0] = 0; |
676 | colorOrder[1] = 1; |
677 | colorOrder[2] = 2; |
678 | break; |
679 | case java_awt_image_BufferedImage_TYPE_BYTE_GRAY: |
680 | case java_awt_image_BufferedImage_TYPE_USHORT_GRAY: |
681 | case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: |
682 | case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED: |
683 | colorOrder[0] = 0; |
684 | break; |
685 | } |
686 | } |
687 | |
688 | static int |
689 | setHints(JNIEnv *env, BufImageS_t *imageP) { |
690 | HintS_t *hintP = &imageP->hints; |
691 | RasterS_t *rasterP = &imageP->raster; |
692 | ColorModelS_t *cmodelP = &imageP->cmodel; |
693 | int imageType = imageP->imageType; |
694 | |
695 | // check whether raster and color model are compatible |
696 | if (cmodelP->numComponents != rasterP->numBands) { |
697 | if (cmodelP->cmType != INDEX_CM_TYPE) { |
698 | return -1; |
699 | } |
700 | } |
701 | |
702 | hintP->numChans = imageP->cmodel.numComponents; |
703 | hintP->colorOrder = NULL; |
704 | if (SAFE_TO_ALLOC_2(hintP->numChans, sizeof(int))) { |
705 | hintP->colorOrder = (int *)malloc(hintP->numChans * sizeof(int)); |
706 | } |
707 | if (hintP->colorOrder == NULL) { |
708 | JNU_ThrowOutOfMemoryError(env, "Out of memory" ); |
709 | return -1; |
710 | } |
711 | if (imageType != java_awt_image_BufferedImage_TYPE_CUSTOM) { |
712 | awt_getBIColorOrder(imageType, hintP->colorOrder); |
713 | } |
714 | if (imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB || |
715 | imageType == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE || |
716 | imageType == java_awt_image_BufferedImage_TYPE_INT_RGB) |
717 | { |
718 | hintP->channelOffset = rasterP->chanOffsets[0]; |
719 | /* These hints are #bytes */ |
720 | hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; |
721 | hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; |
722 | hintP->pStride = rasterP->pixelStride*rasterP->dataSize; |
723 | hintP->packing = BYTE_INTERLEAVED; |
724 | } else if (imageType ==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR || |
725 | imageType==java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE|| |
726 | imageType == java_awt_image_BufferedImage_TYPE_3BYTE_BGR || |
727 | imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) |
728 | { |
729 | if (imageType == java_awt_image_BufferedImage_TYPE_INT_BGR) { |
730 | hintP->channelOffset = rasterP->chanOffsets[0]; |
731 | } |
732 | else { |
733 | hintP->channelOffset = rasterP->chanOffsets[hintP->numChans-1]; |
734 | } |
735 | hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; |
736 | hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; |
737 | hintP->pStride = rasterP->pixelStride*rasterP->dataSize; |
738 | hintP->packing = BYTE_INTERLEAVED; |
739 | } else if (imageType==java_awt_image_BufferedImage_TYPE_USHORT_565_RGB || |
740 | imageType==java_awt_image_BufferedImage_TYPE_USHORT_555_RGB) { |
741 | hintP->needToExpand = TRUE; |
742 | hintP->expandToNbits = 8; |
743 | hintP->packing = PACKED_SHORT_INTER; |
744 | } else if (cmodelP->cmType == INDEX_CM_TYPE) { |
745 | int i; |
746 | hintP->numChans = 1; |
747 | hintP->channelOffset = rasterP->chanOffsets[0]; |
748 | hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; |
749 | hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; |
750 | hintP->pStride = rasterP->pixelStride*rasterP->dataSize; |
751 | switch(rasterP->dataType ) { |
752 | case BYTE_DATA_TYPE: |
753 | if (rasterP->rasterType == PACKED_RASTER_TYPE) { |
754 | hintP->needToExpand = TRUE; |
755 | hintP->expandToNbits = 8; |
756 | hintP->packing = BYTE_PACKED_BAND; |
757 | } |
758 | else { |
759 | hintP->packing = BYTE_SINGLE_BAND; |
760 | } |
761 | break; |
762 | case SHORT_DATA_TYPE: |
763 | hintP->packing = SHORT_SINGLE_BAND; |
764 | break; |
765 | case INT_DATA_TYPE: |
766 | default: |
767 | hintP->packing = UNKNOWN_PACKING; |
768 | break; |
769 | } |
770 | for (i=0; i < hintP->numChans; i++) { |
771 | hintP->colorOrder[i] = i; |
772 | } |
773 | } |
774 | else if (cmodelP->cmType == COMPONENT_CM_TYPE) { |
775 | /* Figure out if it is interleaved */ |
776 | int bits=1; |
777 | int i; |
778 | int low = rasterP->chanOffsets[0]; |
779 | int diff; |
780 | int banded = 0; |
781 | for (i=1; i < hintP->numChans; i++) { |
782 | if (rasterP->chanOffsets[i] < low) { |
783 | low = rasterP->chanOffsets[i]; |
784 | } |
785 | } |
786 | for (i=1; i < hintP->numChans; i++) { |
787 | diff = rasterP->chanOffsets[i]-low; |
788 | if (diff < hintP->numChans) { |
789 | if (bits & (1<<diff)) { |
790 | /* Overlapping samples */ |
791 | /* Could just copy */ |
792 | return -1; |
793 | } |
794 | bits |= (1<<diff); |
795 | } |
796 | else if (diff >= rasterP->width) { |
797 | banded = 1; |
798 | } |
799 | /* Ignore the case if bands are overlapping */ |
800 | } |
801 | hintP->channelOffset = low; |
802 | hintP->dataOffset = low*rasterP->dataSize; |
803 | hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; |
804 | hintP->pStride = rasterP->pixelStride*rasterP->dataSize; |
805 | switch(rasterP->dataType) { |
806 | case BYTE_DATA_TYPE: |
807 | hintP->packing = BYTE_COMPONENTS; |
808 | break; |
809 | case SHORT_DATA_TYPE: |
810 | hintP->packing = SHORT_COMPONENTS; |
811 | break; |
812 | default: |
813 | /* Don't handle any other case */ |
814 | return -1; |
815 | } |
816 | if (bits == ((1<<hintP->numChans)-1)) { |
817 | hintP->packing |= INTERLEAVED; |
818 | for (i=0; i < hintP->numChans; i++) { |
819 | hintP->colorOrder[rasterP->chanOffsets[i]-low] = i; |
820 | } |
821 | } |
822 | else if (banded == 1) { |
823 | int bandSize = rasterP->width*rasterP->height; |
824 | hintP->packing |= BANDED; |
825 | for (i=0; i < hintP->numChans; i++) { |
826 | /* REMIND: Not necessarily correct */ |
827 | hintP->colorOrder[(rasterP->chanOffsets[i]-low)%bandSize] = i; |
828 | } |
829 | } |
830 | else { |
831 | return -1; |
832 | } |
833 | } |
834 | else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) { |
835 | int i; |
836 | |
837 | /* do some sanity check first: make sure that |
838 | * - sample model is SinglePixelPackedSampleModel |
839 | * - number of bands in the raster corresponds to the number |
840 | * of color components in the color model |
841 | */ |
842 | if (!rasterP->sppsm.isUsed || |
843 | rasterP->numBands != cmodelP->numComponents) |
844 | { |
845 | /* given raster is not compatible with the color model, |
846 | * so the operation has to be aborted. |
847 | */ |
848 | return -1; |
849 | } |
850 | |
851 | if (cmodelP->maxNbits > 8) { |
852 | hintP->needToExpand = TRUE; |
853 | hintP->expandToNbits = cmodelP->maxNbits; |
854 | } |
855 | else { |
856 | for (i=0; i < rasterP->numBands; i++) { |
857 | if (!(rasterP->sppsm.offsets[i] % 8)) { |
858 | hintP->needToExpand = TRUE; |
859 | hintP->expandToNbits = 8; |
860 | break; |
861 | } |
862 | else { |
863 | hintP->colorOrder[i] = rasterP->sppsm.offsets[i]>>3; |
864 | } |
865 | } |
866 | } |
867 | |
868 | hintP->channelOffset = rasterP->chanOffsets[0]; |
869 | hintP->dataOffset = hintP->channelOffset*rasterP->dataSize; |
870 | hintP->sStride = rasterP->scanlineStride*rasterP->dataSize; |
871 | hintP->pStride = rasterP->pixelStride*rasterP->dataSize; |
872 | if (hintP->needToExpand) { |
873 | switch(rasterP->dataType) { |
874 | case BYTE_DATA_TYPE: |
875 | hintP->packing = PACKED_BYTE_INTER; |
876 | break; |
877 | case SHORT_DATA_TYPE: |
878 | hintP->packing = PACKED_SHORT_INTER; |
879 | break; |
880 | case INT_DATA_TYPE: |
881 | hintP->packing = PACKED_INT_INTER; |
882 | break; |
883 | default: |
884 | /* Don't know what it is */ |
885 | return -1; |
886 | } |
887 | } |
888 | else { |
889 | hintP->packing = BYTE_INTERLEAVED; |
890 | |
891 | } |
892 | } |
893 | else { |
894 | /* REMIND: Need to handle more cases */ |
895 | return -1; |
896 | } |
897 | |
898 | return 1; |
899 | } |
900 | |
901 | #define MAX_TO_GRAB (10240) |
902 | |
903 | typedef union { |
904 | void *pv; |
905 | unsigned char *pb; |
906 | unsigned short *ps; |
907 | } PixelData_t; |
908 | |
909 | |
910 | int awt_getPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) { |
911 | const int w = rasterP->width; |
912 | const int h = rasterP->height; |
913 | const int numBands = rasterP->numBands; |
914 | int y; |
915 | int i; |
916 | int maxLines; |
917 | jobject jsm; |
918 | int off = 0; |
919 | jarray jdata = NULL; |
920 | jobject jdatabuffer; |
921 | int *dataP; |
922 | int maxSamples; |
923 | PixelData_t p; |
924 | |
925 | if (bufferP == NULL) { |
926 | return -1; |
927 | } |
928 | |
929 | if (rasterP->dataType != BYTE_DATA_TYPE && |
930 | rasterP->dataType != SHORT_DATA_TYPE) |
931 | { |
932 | return -1; |
933 | } |
934 | |
935 | p.pv = bufferP; |
936 | |
937 | if (!SAFE_TO_MULT(w, numBands)) { |
938 | return -1; |
939 | } |
940 | maxSamples = w * numBands; |
941 | |
942 | maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples); |
943 | if (maxLines > h) { |
944 | maxLines = h; |
945 | } |
946 | |
947 | if (!SAFE_TO_MULT(maxSamples, maxLines)) { |
948 | return -1; |
949 | } |
950 | |
951 | maxSamples *= maxLines; |
952 | |
953 | jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
954 | jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
955 | g_RasterDataBufferID); |
956 | |
957 | jdata = (*env)->NewIntArray(env, maxSamples); |
958 | if (JNU_IsNull(env, jdata)) { |
959 | (*env)->ExceptionClear(env); |
960 | JNU_ThrowOutOfMemoryError(env, "Out of Memory" ); |
961 | return -1; |
962 | } |
963 | |
964 | for (y = 0; y < h; y += maxLines) { |
965 | if (y + maxLines > h) { |
966 | maxLines = h - y; |
967 | maxSamples = w * numBands * maxLines; |
968 | } |
969 | |
970 | (*env)->CallObjectMethod(env, jsm, g_SMGetPixelsMID, |
971 | 0, y, w, |
972 | maxLines, jdata, jdatabuffer); |
973 | |
974 | if ((*env)->ExceptionOccurred(env)) { |
975 | (*env)->DeleteLocalRef(env, jdata); |
976 | return -1; |
977 | } |
978 | |
979 | dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
980 | NULL); |
981 | if (dataP == NULL) { |
982 | (*env)->DeleteLocalRef(env, jdata); |
983 | return -1; |
984 | } |
985 | |
986 | switch (rasterP->dataType) { |
987 | case BYTE_DATA_TYPE: |
988 | for (i = 0; i < maxSamples; i ++) { |
989 | p.pb[off++] = (unsigned char) dataP[i]; |
990 | } |
991 | break; |
992 | case SHORT_DATA_TYPE: |
993 | for (i = 0; i < maxSamples; i ++) { |
994 | p.ps[off++] = (unsigned short) dataP[i]; |
995 | } |
996 | break; |
997 | } |
998 | |
999 | (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
1000 | JNI_ABORT); |
1001 | } |
1002 | (*env)->DeleteLocalRef(env, jdata); |
1003 | |
1004 | return 1; |
1005 | } |
1006 | |
1007 | int awt_setPixels(JNIEnv *env, RasterS_t *rasterP, void *bufferP) { |
1008 | const int w = rasterP->width; |
1009 | const int h = rasterP->height; |
1010 | const int numBands = rasterP->numBands; |
1011 | |
1012 | int y; |
1013 | int i; |
1014 | int maxLines; |
1015 | jobject jsm; |
1016 | int off = 0; |
1017 | jarray jdata = NULL; |
1018 | jobject jdatabuffer; |
1019 | int *dataP; |
1020 | int maxSamples; |
1021 | PixelData_t p; |
1022 | |
1023 | if (bufferP == NULL) { |
1024 | return -1; |
1025 | } |
1026 | |
1027 | if (rasterP->dataType != BYTE_DATA_TYPE && |
1028 | rasterP->dataType != SHORT_DATA_TYPE) |
1029 | { |
1030 | return -1; |
1031 | } |
1032 | |
1033 | p.pv = bufferP; |
1034 | |
1035 | if (!SAFE_TO_MULT(w, numBands)) { |
1036 | return -1; |
1037 | } |
1038 | maxSamples = w * numBands; |
1039 | |
1040 | maxLines = maxSamples > MAX_TO_GRAB ? 1 : (MAX_TO_GRAB / maxSamples); |
1041 | if (maxLines > h) { |
1042 | maxLines = h; |
1043 | } |
1044 | |
1045 | if (!SAFE_TO_MULT(maxSamples, maxLines)) { |
1046 | return -1; |
1047 | } |
1048 | |
1049 | maxSamples *= maxLines; |
1050 | |
1051 | jsm = (*env)->GetObjectField(env, rasterP->jraster, g_RasterSampleModelID); |
1052 | jdatabuffer = (*env)->GetObjectField(env, rasterP->jraster, |
1053 | g_RasterDataBufferID); |
1054 | |
1055 | jdata = (*env)->NewIntArray(env, maxSamples); |
1056 | if (JNU_IsNull(env, jdata)) { |
1057 | (*env)->ExceptionClear(env); |
1058 | JNU_ThrowOutOfMemoryError(env, "Out of Memory" ); |
1059 | return -1; |
1060 | } |
1061 | |
1062 | for (y = 0; y < h; y += maxLines) { |
1063 | if (y + maxLines > h) { |
1064 | maxLines = h - y; |
1065 | maxSamples = w * numBands * maxLines; |
1066 | } |
1067 | dataP = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, |
1068 | NULL); |
1069 | if (dataP == NULL) { |
1070 | (*env)->DeleteLocalRef(env, jdata); |
1071 | return -1; |
1072 | } |
1073 | |
1074 | switch (rasterP->dataType) { |
1075 | case BYTE_DATA_TYPE: |
1076 | for (i = 0; i < maxSamples; i ++) { |
1077 | dataP[i] = p.pb[off++]; |
1078 | } |
1079 | break; |
1080 | case SHORT_DATA_TYPE: |
1081 | for (i = 0; i < maxSamples; i ++) { |
1082 | dataP[i] = p.ps[off++]; |
1083 | } |
1084 | break; |
1085 | } |
1086 | |
1087 | (*env)->ReleasePrimitiveArrayCritical(env, jdata, dataP, |
1088 | JNI_ABORT); |
1089 | |
1090 | (*env)->CallVoidMethod(env, jsm, g_SMSetPixelsMID, |
1091 | 0, y, w, |
1092 | maxLines, jdata, jdatabuffer); |
1093 | |
1094 | if ((*env)->ExceptionOccurred(env)) { |
1095 | (*env)->DeleteLocalRef(env, jdata); |
1096 | return -1; |
1097 | } |
1098 | } |
1099 | |
1100 | (*env)->DeleteLocalRef(env, jdata); |
1101 | |
1102 | return 1; |
1103 | } |
1104 | |