661 info->err = NULL;
662 if (info->is_decompressor) {
663 j_decompress_ptr dinfo = (j_decompress_ptr) info;
664 free(dinfo->src);
665 dinfo->src = NULL;
666 } else {
667 j_compress_ptr cinfo = (j_compress_ptr) info;
668 free(cinfo->dest);
669 cinfo->dest = NULL;
670 }
671 jpeg_destroy(info);
672 free(info);
673 }
674 }
675
676 static void imageio_abort(JNIEnv *env, jobject this,
677 imageIODataPtr data) {
678 data->abortFlag = JNI_TRUE;
679 }
680
681 /*************** end of shared utility code ****************/
682
683 /********************** Loader Support **************************/
684
685 /********************** Source Management ***********************/
686
687 /*
688 * INPUT HANDLING:
689 *
690 * The JPEG library's input management is defined by the jpeg_source_mgr
691 * structure which contains two fields to convey the information in the
692 * buffer and 5 methods which perform all buffer management. The library
693 * defines a standard input manager that uses stdio for obtaining compressed
694 * jpeg data, but here we need to use Java to get our data.
695 *
696 * We use the library jpeg_source_mgr but our own routines that access
697 * imageio-specific information in the imageIOData structure.
698 */
699
700 /*
1250 cls,
1251 "updateImageProgress",
1252 "(I)V");
1253 if ((*env)->ExceptionCheck(env)) {
1254 return;
1255 }
1256
1257 JPEGImageLoader_emitWarningID = (*env)->GetMethodID(env,
1258 cls,
1259 "emitWarning",
1260 "(Ljava/lang/String;)V");
1261 if ((*env)->ExceptionCheck(env)) {
1262 return;
1263 }
1264
1265 }
1266
1267 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_disposeNative
1268 (JNIEnv *env, jclass cls, jlong ptr) {
1269 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1270 j_common_ptr info = destroyImageioData(env, data);
1271
1272 imageio_dispose(info);
1273 }
1274
1275 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */
1276
1277 /*
1278 * For EXIF images, the APP1 will appear immediately after the SOI,
1279 * so it's safe to only look at the first marker in the list.
1280 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1281 */
1282 #define IS_EXIF(c) \
1283 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1284
1285 JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initDecompressor
1286 (JNIEnv *env, jobject this, jobject stream) {
1287 imageIODataPtr data;
1288 struct sun_jpeg_error_mgr *jerr_mgr;
1289
1290 /* This struct contains the JPEG decompression parameters and pointers to
1291 * working space (which is allocated as needed by the JPEG library).
1292 */
1313 free(cinfo);
1314 ThrowByName(env,
1315 "java/lang/OutOfMemoryError",
1316 "Initializing Reader");
1317 return 0;
1318 }
1319
1320 /* We set up the normal JPEG error routines, then override error_exit. */
1321 cinfo->err = jpeg_std_error(&(jerr_mgr->pub));
1322 jerr_mgr->pub.error_exit = sun_jpeg_error_exit;
1323 /* We need to setup our own print routines */
1324 jerr_mgr->pub.output_message = sun_jpeg_output_message;
1325 /* Now we can setjmp before every call to the library */
1326
1327 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1328 if (setjmp(jerr_mgr->setjmp_buffer)) {
1329 /* If we get here, the JPEG code has signaled an error. */
1330 char buffer[JMSG_LENGTH_MAX];
1331 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1332 buffer);
1333 ThrowByName(env, "java/io/IOException", buffer);
1334 return 0;
1335 }
1336
1337 /* Perform library initialization */
1338 jpeg_create_decompress(cinfo);
1339
1340 // Set up to keep any APP2 markers, as these might contain ICC profile
1341 // data
1342 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1343
1344 /*
1345 * Now set up our source.
1346 */
1347 cinfo->src =
1348 (struct jpeg_source_mgr *) malloc(sizeof (struct jpeg_source_mgr));
1349 if (cinfo->src == NULL) {
1350 ThrowByName(env,
1351 "java/lang/OutOfMemoryError",
1352 "Initializing Reader");
1353 return 0;
1354 }
1355 cinfo->src->bytes_in_buffer = 0;
1356 cinfo->src->next_input_byte = NULL;
1357 cinfo->src->init_source = imageio_init_source;
1358 cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1359 cinfo->src->skip_input_data = imageio_skip_input_data;
1360 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1361 cinfo->src->term_source = imageio_term_source;
1362
1363 /* set up the association to persist for future calls */
1364 data = initImageioData(env, (j_common_ptr) cinfo, this);
1365 if (data == NULL) {
1366 ThrowByName(env,
1367 "java/lang/OutOfMemoryError",
1368 "Initializing Reader");
1369 return 0;
1370 }
1371
1372 imageio_set_stream(env, (j_common_ptr) cinfo, data, stream);
1373
1374 if ((*env)->ExceptionCheck(env)) return 0;
1375
1376 imageio_init_source((j_decompress_ptr) cinfo);
1377
1378 src = cinfo->src;
1379 jerr = (sun_jpeg_error_ptr) cinfo->err;
1380
1381 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1382 if (setjmp(jerr->setjmp_buffer)) {
1383 /* If we get here, the JPEG code has signaled an error
1384 while reading the header. */
1385 RELEASE_ARRAYS(env, data, src->next_input_byte);
1386 if (!(*env)->ExceptionOccurred(env)) {
1387 char buffer[JMSG_LENGTH_MAX];
1388 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1389 buffer);
1390 ThrowByName(env, "java/io/IOException", buffer);
1391 }
1392 return 0;
1393 }
1394
1395 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1396 ThrowByName(env,
1397 "java/io/IOException",
1398 "Array pin failed");
1399 return 0;
1400 }
1401
1402 jret = jpeg_read_header(cinfo, FALSE);
1403
1404 if (jret == JPEG_HEADER_TABLES_ONLY) {
1405 imageio_term_source(cinfo); // Pushback remaining buffer contents
1406 #ifdef DEBUG_IIO_JPEG
1407 printf("just read tables-only image; q table 0 at %p\n",
1408 cinfo->quant_tbl_ptrs[0]);
1409 #endif
1410 RELEASE_ARRAYS(env, data, src->next_input_byte);
1411 } else {
1412 /*
1413 * Now adjust the jpeg_color_space variable, which was set in
1414 * default_decompress_parms, to reflect our differences from IJG
1415 */
1416
1417 switch (cinfo->jpeg_color_space) {
1418 default:
1475
1476 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1477 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1478 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1479
1480 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1481 (v_samp1 > v_samp0) && (v_samp2 > v_samp0)) {
1482 cinfo->jpeg_color_space = JCS_YCCK;
1483 /* Leave the output space as CMYK */
1484 }
1485
1486 /* There is no support for CMYK on jfx side, so request RGB output */
1487 cinfo->out_color_space = JCS_RGB;
1488 }
1489 RELEASE_ARRAYS(env, data, src->next_input_byte);
1490
1491 /* read icc profile data */
1492 profileData = read_icc_profile(env, cinfo);
1493
1494 if ((*env)->ExceptionCheck(env)) {
1495 return 0;
1496 }
1497
1498 (*env)->CallVoidMethod(env, this,
1499 JPEGImageLoader_setInputAttributesID,
1500 cinfo->image_width,
1501 cinfo->image_height,
1502 cinfo->jpeg_color_space,
1503 cinfo->out_color_space,
1504 cinfo->num_components,
1505 profileData);
1506 if ((*env)->ExceptionCheck(env)) {
1507 return 0;
1508 }
1509 }
1510
1511 return ptr_to_jlong(data);
1512 }
1513
1514 JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_startDecompression
1515 (JNIEnv *env, jobject this, jlong ptr, jint outCS, jint dest_width, jint dest_height) {
1516 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1517 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1518 struct jpeg_source_mgr *src = cinfo->src;
1519 sun_jpeg_error_ptr jerr;
1520
1521 jfloat x_scale;
1522 jfloat y_scale;
1523 jfloat max_scale;
1524
1525 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1526 ThrowByName(env,
1581 jpeg_start_decompress(cinfo);
1582
1583 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1584 (*env)->CallVoidMethod(env, this,
1585 JPEGImageLoader_setOutputAttributesID,
1586 cinfo->output_width,
1587 cinfo->output_height);
1588
1589 return cinfo->output_components;
1590 }
1591
1592 #define SAFE_TO_MULT(a, b) (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
1593
1594 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_decompressIndirect
1595 (JNIEnv *env, jobject this, jlong ptr, jboolean report_progress, jbyteArray barray) {
1596 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1597 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1598 struct jpeg_source_mgr *src = cinfo->src;
1599 sun_jpeg_error_ptr jerr;
1600 int bytes_per_row = cinfo->output_width * cinfo->output_components;
1601 JSAMPROW scanline_ptr = (JSAMPROW) malloc(bytes_per_row * sizeof (JSAMPLE));
1602 int offset = 0;
1603
1604 if (!SAFE_TO_MULT(cinfo->output_width, cinfo->output_components) ||
1605 !SAFE_TO_MULT(bytes_per_row, cinfo->output_height) ||
1606 ((*env)->GetArrayLength(env, barray) <
1607 (bytes_per_row * cinfo->output_height)))
1608 {
1609 ThrowByName(env,
1610 "java/lang/OutOfMemoryError",
1611 "Reading JPEG Stream");
1612 return JNI_FALSE;
1613 }
1614
1615 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1616 ThrowByName(env,
1617 "java/io/IOException",
1618 "Array pin failed");
1619 return JNI_FALSE;
1620 }
1621
1622 if (scanline_ptr == NULL) {
1623 ThrowByName(env,
1624 "java/lang/OutOfMemoryError",
1625 "Reading JPEG Stream");
1626 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1627 return JNI_FALSE;
1628 }
1629
1630 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1631 jerr = (sun_jpeg_error_ptr) cinfo->err;
1632
1633 if (setjmp(jerr->setjmp_buffer)) {
1634 /* If we get here, the JPEG code has signaled an error
1635 while reading. */
1636 if (!(*env)->ExceptionOccurred(env)) {
1637 char buffer[JMSG_LENGTH_MAX];
1638 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1639 buffer);
1640 ThrowByName(env, "java/io/IOException", buffer);
1641 }
1642 if (scanline_ptr != NULL) {
1643 free(scanline_ptr);
1644 }
1645 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1646 return JNI_FALSE;
1647 }
1648
1649 while (cinfo->output_scanline < cinfo->output_height) {
1650 int num_scanlines;
1651 if (report_progress == JNI_TRUE) {
1652 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1653 (*env)->CallVoidMethod(env, this,
1654 JPEGImageLoader_updateImageProgressID,
1655 cinfo->output_scanline);
1656 if ((*env)->ExceptionCheck(env)) return JNI_FALSE;
1657 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1658 ThrowByName(env,
1659 "java/io/IOException",
1660 "Array pin failed");
1661 return JNI_FALSE;
1662 }
1663 }
1664
1665 num_scanlines = jpeg_read_scanlines(cinfo, &scanline_ptr, 1);
1666 if (num_scanlines == 1) {
1667 jbyte *body = (*env)->GetPrimitiveArrayCritical(env, barray, NULL);
1668 if (body == NULL) {
1669 fprintf(stderr, "decompressIndirect: GetPrimitiveArrayCritical returns NULL: out of memory\n");
1670 return JNI_FALSE;
1671 }
1672 memcpy(body+offset,scanline_ptr, bytes_per_row);
1673 (*env)->ReleasePrimitiveArrayCritical(env, barray, body, JNI_ABORT);
1674 offset += bytes_per_row;
1675 }
1676 }
1677
1678 if (report_progress == JNI_TRUE) {
1679 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1680 (*env)->CallVoidMethod(env, this,
1681 JPEGImageLoader_updateImageProgressID,
1682 cinfo->output_height);
1683 if ((*env)->ExceptionCheck(env)) return JNI_FALSE;
1684 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1685 ThrowByName(env,
1686 "java/io/IOException",
1687 "Array pin failed");
1688 return JNI_FALSE;
1689 }
1690 }
1691
1692 jpeg_finish_decompress(cinfo);
1693 free(scanline_ptr);
1694
1695 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1696 return JNI_TRUE;
1697 }
|
661 info->err = NULL;
662 if (info->is_decompressor) {
663 j_decompress_ptr dinfo = (j_decompress_ptr) info;
664 free(dinfo->src);
665 dinfo->src = NULL;
666 } else {
667 j_compress_ptr cinfo = (j_compress_ptr) info;
668 free(cinfo->dest);
669 cinfo->dest = NULL;
670 }
671 jpeg_destroy(info);
672 free(info);
673 }
674 }
675
676 static void imageio_abort(JNIEnv *env, jobject this,
677 imageIODataPtr data) {
678 data->abortFlag = JNI_TRUE;
679 }
680
681 static void disposeIIO(JNIEnv *env, imageIODataPtr data) {
682 j_common_ptr info = destroyImageioData(env, data);
683 imageio_dispose(info);
684 }
685
686 /*************** end of shared utility code ****************/
687
688 /********************** Loader Support **************************/
689
690 /********************** Source Management ***********************/
691
692 /*
693 * INPUT HANDLING:
694 *
695 * The JPEG library's input management is defined by the jpeg_source_mgr
696 * structure which contains two fields to convey the information in the
697 * buffer and 5 methods which perform all buffer management. The library
698 * defines a standard input manager that uses stdio for obtaining compressed
699 * jpeg data, but here we need to use Java to get our data.
700 *
701 * We use the library jpeg_source_mgr but our own routines that access
702 * imageio-specific information in the imageIOData structure.
703 */
704
705 /*
1255 cls,
1256 "updateImageProgress",
1257 "(I)V");
1258 if ((*env)->ExceptionCheck(env)) {
1259 return;
1260 }
1261
1262 JPEGImageLoader_emitWarningID = (*env)->GetMethodID(env,
1263 cls,
1264 "emitWarning",
1265 "(Ljava/lang/String;)V");
1266 if ((*env)->ExceptionCheck(env)) {
1267 return;
1268 }
1269
1270 }
1271
1272 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_disposeNative
1273 (JNIEnv *env, jclass cls, jlong ptr) {
1274 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1275 disposeIIO(env, data);
1276 }
1277
1278 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */
1279
1280 /*
1281 * For EXIF images, the APP1 will appear immediately after the SOI,
1282 * so it's safe to only look at the first marker in the list.
1283 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1284 */
1285 #define IS_EXIF(c) \
1286 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1287
1288 JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initDecompressor
1289 (JNIEnv *env, jobject this, jobject stream) {
1290 imageIODataPtr data;
1291 struct sun_jpeg_error_mgr *jerr_mgr;
1292
1293 /* This struct contains the JPEG decompression parameters and pointers to
1294 * working space (which is allocated as needed by the JPEG library).
1295 */
1316 free(cinfo);
1317 ThrowByName(env,
1318 "java/lang/OutOfMemoryError",
1319 "Initializing Reader");
1320 return 0;
1321 }
1322
1323 /* We set up the normal JPEG error routines, then override error_exit. */
1324 cinfo->err = jpeg_std_error(&(jerr_mgr->pub));
1325 jerr_mgr->pub.error_exit = sun_jpeg_error_exit;
1326 /* We need to setup our own print routines */
1327 jerr_mgr->pub.output_message = sun_jpeg_output_message;
1328 /* Now we can setjmp before every call to the library */
1329
1330 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1331 if (setjmp(jerr_mgr->setjmp_buffer)) {
1332 /* If we get here, the JPEG code has signaled an error. */
1333 char buffer[JMSG_LENGTH_MAX];
1334 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1335 buffer);
1336 free(cinfo->err);
1337 free(cinfo);
1338 ThrowByName(env, "java/io/IOException", buffer);
1339 return 0;
1340 }
1341
1342 /* Perform library initialization */
1343 jpeg_create_decompress(cinfo);
1344
1345 // Set up to keep any APP2 markers, as these might contain ICC profile
1346 // data
1347 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1348
1349 /*
1350 * Now set up our source.
1351 */
1352 cinfo->src =
1353 (struct jpeg_source_mgr *) malloc(sizeof (struct jpeg_source_mgr));
1354 if (cinfo->src == NULL) {
1355 imageio_dispose((j_common_ptr) cinfo);
1356 ThrowByName(env,
1357 "java/lang/OutOfMemoryError",
1358 "Initializing Reader");
1359 return 0;
1360 }
1361 cinfo->src->bytes_in_buffer = 0;
1362 cinfo->src->next_input_byte = NULL;
1363 cinfo->src->init_source = imageio_init_source;
1364 cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1365 cinfo->src->skip_input_data = imageio_skip_input_data;
1366 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1367 cinfo->src->term_source = imageio_term_source;
1368
1369 /* set up the association to persist for future calls */
1370 data = initImageioData(env, (j_common_ptr) cinfo, this);
1371 if (data == NULL) {
1372 imageio_dispose((j_common_ptr) cinfo);
1373 ThrowByName(env,
1374 "java/lang/OutOfMemoryError",
1375 "Initializing Reader");
1376 return 0;
1377 }
1378
1379 imageio_set_stream(env, (j_common_ptr) cinfo, data, stream);
1380
1381 if ((*env)->ExceptionCheck(env)) {
1382 disposeIIO(env, data);
1383 return 0;
1384 }
1385
1386 imageio_init_source((j_decompress_ptr) cinfo);
1387
1388 src = cinfo->src;
1389 jerr = (sun_jpeg_error_ptr) cinfo->err;
1390
1391 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1392 if (setjmp(jerr->setjmp_buffer)) {
1393 /* If we get here, the JPEG code has signaled an error
1394 while reading the header. */
1395 disposeIIO(env, data);
1396 if (!(*env)->ExceptionOccurred(env)) {
1397 char buffer[JMSG_LENGTH_MAX];
1398 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1399 buffer);
1400 ThrowByName(env, "java/io/IOException", buffer);
1401 }
1402
1403 return 0;
1404 }
1405
1406 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1407 ThrowByName(env,
1408 "java/io/IOException",
1409 "Array pin failed");
1410 disposeIIO(env, data);
1411 return 0;
1412 }
1413
1414 jret = jpeg_read_header(cinfo, FALSE);
1415
1416 if (jret == JPEG_HEADER_TABLES_ONLY) {
1417 imageio_term_source(cinfo); // Pushback remaining buffer contents
1418 #ifdef DEBUG_IIO_JPEG
1419 printf("just read tables-only image; q table 0 at %p\n",
1420 cinfo->quant_tbl_ptrs[0]);
1421 #endif
1422 RELEASE_ARRAYS(env, data, src->next_input_byte);
1423 } else {
1424 /*
1425 * Now adjust the jpeg_color_space variable, which was set in
1426 * default_decompress_parms, to reflect our differences from IJG
1427 */
1428
1429 switch (cinfo->jpeg_color_space) {
1430 default:
1487
1488 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1489 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1490 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1491
1492 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1493 (v_samp1 > v_samp0) && (v_samp2 > v_samp0)) {
1494 cinfo->jpeg_color_space = JCS_YCCK;
1495 /* Leave the output space as CMYK */
1496 }
1497
1498 /* There is no support for CMYK on jfx side, so request RGB output */
1499 cinfo->out_color_space = JCS_RGB;
1500 }
1501 RELEASE_ARRAYS(env, data, src->next_input_byte);
1502
1503 /* read icc profile data */
1504 profileData = read_icc_profile(env, cinfo);
1505
1506 if ((*env)->ExceptionCheck(env)) {
1507 disposeIIO(env, data);
1508 return 0;
1509 }
1510
1511 (*env)->CallVoidMethod(env, this,
1512 JPEGImageLoader_setInputAttributesID,
1513 cinfo->image_width,
1514 cinfo->image_height,
1515 cinfo->jpeg_color_space,
1516 cinfo->out_color_space,
1517 cinfo->num_components,
1518 profileData);
1519 if ((*env)->ExceptionCheck(env)) {
1520 disposeIIO(env, data);
1521 return 0;
1522 }
1523 }
1524
1525 return ptr_to_jlong(data);
1526 }
1527
1528 JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_startDecompression
1529 (JNIEnv *env, jobject this, jlong ptr, jint outCS, jint dest_width, jint dest_height) {
1530 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1531 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1532 struct jpeg_source_mgr *src = cinfo->src;
1533 sun_jpeg_error_ptr jerr;
1534
1535 jfloat x_scale;
1536 jfloat y_scale;
1537 jfloat max_scale;
1538
1539 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1540 ThrowByName(env,
1595 jpeg_start_decompress(cinfo);
1596
1597 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1598 (*env)->CallVoidMethod(env, this,
1599 JPEGImageLoader_setOutputAttributesID,
1600 cinfo->output_width,
1601 cinfo->output_height);
1602
1603 return cinfo->output_components;
1604 }
1605
1606 #define SAFE_TO_MULT(a, b) (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
1607
1608 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_decompressIndirect
1609 (JNIEnv *env, jobject this, jlong ptr, jboolean report_progress, jbyteArray barray) {
1610 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1611 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1612 struct jpeg_source_mgr *src = cinfo->src;
1613 sun_jpeg_error_ptr jerr;
1614 int bytes_per_row = cinfo->output_width * cinfo->output_components;
1615 int offset = 0;
1616 JSAMPROW scanline_ptr = NULL;
1617
1618 if (!SAFE_TO_MULT(cinfo->output_width, cinfo->output_components) ||
1619 !SAFE_TO_MULT(bytes_per_row, cinfo->output_height) ||
1620 ((*env)->GetArrayLength(env, barray) <
1621 (bytes_per_row * cinfo->output_height)))
1622 {
1623 ThrowByName(env,
1624 "java/lang/OutOfMemoryError",
1625 "Reading JPEG Stream");
1626 return JNI_FALSE;
1627 }
1628
1629 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1630 ThrowByName(env,
1631 "java/io/IOException",
1632 "Array pin failed");
1633 return JNI_FALSE;
1634 }
1635
1636 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1637 jerr = (sun_jpeg_error_ptr) cinfo->err;
1638
1639 if (setjmp(jerr->setjmp_buffer)) {
1640 /* If we get here, the JPEG code has signaled an error
1641 while reading. */
1642 if (!(*env)->ExceptionOccurred(env)) {
1643 char buffer[JMSG_LENGTH_MAX];
1644 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1645 buffer);
1646 ThrowByName(env, "java/io/IOException", buffer);
1647 }
1648 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1649 return JNI_FALSE;
1650 }
1651
1652 scanline_ptr = (JSAMPROW) malloc(bytes_per_row * sizeof(JSAMPLE));
1653 if (scanline_ptr == NULL) {
1654 ThrowByName(env,
1655 "java/lang/OutOfMemoryError",
1656 "Reading JPEG Stream");
1657 return JNI_FALSE;
1658 }
1659
1660 while (cinfo->output_scanline < cinfo->output_height) {
1661 int num_scanlines;
1662 if (report_progress == JNI_TRUE) {
1663 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1664 (*env)->CallVoidMethod(env, this,
1665 JPEGImageLoader_updateImageProgressID,
1666 cinfo->output_scanline);
1667 if ((*env)->ExceptionCheck(env)) {
1668 free(scanline_ptr);
1669 return JNI_FALSE;
1670 }
1671 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1672 free(scanline_ptr);
1673 ThrowByName(env,
1674 "java/io/IOException",
1675 "Array pin failed");
1676 return JNI_FALSE;
1677 }
1678 }
1679
1680 num_scanlines = jpeg_read_scanlines(cinfo, &scanline_ptr, 1);
1681 if (num_scanlines == 1) {
1682 jbyte *body = (*env)->GetPrimitiveArrayCritical(env, barray, NULL);
1683 if (body == NULL) {
1684 fprintf(stderr, "decompressIndirect: GetPrimitiveArrayCritical returns NULL: out of memory\n");
1685 free(scanline_ptr);
1686 return JNI_FALSE;
1687 }
1688 memcpy(body+offset,scanline_ptr, bytes_per_row);
1689 (*env)->ReleasePrimitiveArrayCritical(env, barray, body, JNI_ABORT);
1690 offset += bytes_per_row;
1691 }
1692 }
1693 free(scanline_ptr);
1694
1695 if (report_progress == JNI_TRUE) {
1696 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1697 (*env)->CallVoidMethod(env, this,
1698 JPEGImageLoader_updateImageProgressID,
1699 cinfo->output_height);
1700 if ((*env)->ExceptionCheck(env)) {
1701 return JNI_FALSE;
1702 }
1703 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1704 ThrowByName(env,
1705 "java/io/IOException",
1706 "Array pin failed");
1707 return JNI_FALSE;
1708 }
1709 }
1710
1711 jpeg_finish_decompress(cinfo);
1712
1713 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1714 return JNI_TRUE;
1715 }
|