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