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 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <setjmp.h> 29 #include <assert.h> 30 #include <string.h> 31 32 #include "jni.h" 33 34 #include "com_sun_javafx_iio_jpeg_JPEGImageLoader.h" 35 36 /* headers from libjpeg */ 37 #include <jpeglib.h> 38 #include <jerror.h> 39 40 #if defined (_LP64) || defined(_WIN64) 41 #define jlong_to_ptr(a) ((void*)(a)) 42 #define ptr_to_jlong(a) ((jlong)(a)) 43 #else 44 #define jlong_to_ptr(a) ((void*)(int)(a)) 45 #define ptr_to_jlong(a) ((jlong)(int)(a)) 46 #endif 47 48 /* On non iOS platforms we use JNI_OnLoad() shared library entrypoint. */ 49 #define USING_BUILTIN_LIBRARY_ENTRYPOINT 0 50 51 /* On iOS we use builtin libraries, thus JNI_OnLoad_javafx_iio() is the entrypoint */ 52 #ifdef __APPLE__ 53 54 #include <TargetConditionals.h> 55 56 /* RT-37125: use setjmp/longjmp versions that do not save/restore the signal mask */ 57 #define longjmp _longjmp 58 #define setjmp _setjmp 59 60 #if TARGET_OS_IPHONE /* iOS */ 61 #undef USING_BUILTIN_LIBRARY_ENTRYPOINT 62 #define USING_BUILTIN_LIBRARY_ENTRYPOINT 1 63 #endif 64 #endif 65 66 static jboolean checkAndClearException(JNIEnv *env) { 67 if (!(*env)->ExceptionCheck(env)) { 68 return JNI_FALSE; 69 } 70 (*env)->ExceptionClear(env); 71 return JNI_TRUE; 72 } 73 74 /***************** Begin verbatim copy from jni_util.c ***************/ 75 76 /** 77 * Throw a Java exception by name. Similar to SignalError. 78 */ 79 JNIEXPORT void JNICALL 80 ThrowByName(JNIEnv *env, const char *name, const char *msg) { 81 jclass cls = (*env)->FindClass(env, name); 82 if (!(*env)->ExceptionCheck(env) && cls != 0) {/* Otherwise an exception has already been thrown */ 83 (*env)->ThrowNew(env, cls, msg); 84 } 85 } 86 87 JNIEXPORT void * JNICALL 88 GetEnv(JavaVM *vm, jint version) { 89 void *env; 90 (*vm)->GetEnv(vm, &env, version); 91 return env; 92 } 93 94 /***************** Begin verbatim copy from jni_util.c ***************/ 95 96 #undef MAX 97 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 98 99 /* Cached Java method IDs */ 100 static jmethodID InputStream_readID; 101 static jmethodID InputStream_skipID; 102 static jmethodID JPEGImageLoader_setInputAttributesID; 103 static jmethodID JPEGImageLoader_setOutputAttributesID; 104 static jmethodID JPEGImageLoader_updateImageProgressID; 105 static jmethodID JPEGImageLoader_emitWarningID; 106 107 /* Initialize the Java VM instance variable when the library is 108 first loaded */ 109 static JavaVM *jvm; 110 111 #if USING_BUILTIN_LIBRARY_ENTRYPOINT 112 113 JNIEXPORT jint JNICALL 114 JNI_OnLoad_javafx_iio(JavaVM *vm, void *reserved) { 115 jvm = vm; 116 #ifdef JNI_VERSION_1_8 117 //min. returned JNI_VERSION required by JDK8 for builtin libraries 118 JNIEnv *env; 119 if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) { 120 return JNI_VERSION_1_2; 121 } 122 return JNI_VERSION_1_8; 123 #else 124 return JNI_VERSION_1_2; 125 #endif 126 } 127 128 #else 129 130 JNIEXPORT jint JNICALL 131 JNI_OnLoad(JavaVM *vm, void *reserved) { 132 jvm = vm; 133 return JNI_VERSION_1_2; 134 } 135 136 #endif 137 138 139 /* 140 * The following sets of defines must match the warning messages in the 141 * Java code. 142 */ 143 144 /* Loader warnings */ 145 #define READ_NO_EOI 0 146 147 /* Saver warnings */ 148 149 /* Return codes for various ops */ 150 #define OK 1 151 #define NOT_OK 0 152 153 /* 154 * First we define two objects, one for the stream and buffer and one 155 * for pixels. Both contain references to Java objects and pointers to 156 * pinned arrays. These objects can be used for either input or 157 * output. Pixels can be accessed as either INT32s or bytes. 158 * Every I/O operation will have one of each these objects, one for 159 * the stream and the other to hold pixels, regardless of the I/O direction. 160 */ 161 162 /******************** StreamBuffer definition ************************/ 163 164 typedef struct streamBufferStruct { 165 jobject stream; // ImageInputStream or ImageOutputStream 166 jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream 167 JOCTET *buf; // Pinned buffer pointer */ 168 int bufferOffset; // holds offset between unpin and the next pin 169 int bufferLength; // Allocated, nut just used 170 int suspendable; // Set to true to suspend input 171 long remaining_skip; // Used only on input 172 } streamBuffer, *streamBufferPtr; 173 174 /* 175 * This buffer size was set to 64K in the old classes, 4K by default in the 176 * IJG library, with the comment "an efficiently freadable size", and 1K 177 * in AWT. 178 * Unlike in the other Java designs, these objects will persist, so 64K 179 * seems too big and 1K seems too small. If 4K was good enough for the 180 * IJG folks, it's good enough for me. 181 */ 182 #define STREAMBUF_SIZE 4096 183 184 /* 185 * Used to signal that no data need be restored from an unpin to a pin. 186 * I.e. the buffer is empty. 187 */ 188 #define NO_DATA -1 189 190 // Forward reference 191 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb); 192 193 /* 194 * Initialize a freshly allocated StreamBuffer object. The stream is left 195 * null, as it will be set from Java by setSource, but the buffer object 196 * is created and a global reference kept. Returns OK on success, NOT_OK 197 * if allocating the buffer or getting a global reference for it failed. 198 */ 199 static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 200 /* Initialize a new buffer */ 201 jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE); 202 if (hInputBuffer == NULL) { 203 return NOT_OK; 204 } 205 sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer); 206 sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer); 207 if (sb->hstreamBuffer == NULL) { 208 return NOT_OK; 209 } 210 211 212 sb->stream = NULL; 213 214 sb->buf = NULL; 215 216 resetStreamBuffer(env, sb); 217 218 return OK; 219 } 220 221 /* 222 * Free all resources associated with this streamBuffer. This must 223 * be called to dispose the object to avoid leaking global references, as 224 * resetStreamBuffer does not release the buffer reference. 225 */ 226 static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 227 resetStreamBuffer(env, sb); 228 if (sb->hstreamBuffer != NULL) { 229 (*env)->DeleteGlobalRef(env, sb->hstreamBuffer); 230 } 231 } 232 233 // Forward reference 234 static void unpinStreamBuffer(JNIEnv *env, 235 streamBufferPtr sb, 236 const JOCTET *next_byte); 237 238 /* 239 * Resets the state of a streamBuffer object that has been in use. 240 * The global reference to the stream is released, but the reference 241 * to the buffer is retained. The buffer is unpinned if it was pinned. 242 * All other state is reset. 243 */ 244 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 245 if (sb->stream != NULL) { 246 (*env)->DeleteGlobalRef(env, sb->stream); 247 sb->stream = NULL; 248 } 249 unpinStreamBuffer(env, sb, NULL); 250 sb->bufferOffset = NO_DATA; 251 sb->suspendable = FALSE; 252 sb->remaining_skip = 0; 253 } 254 255 /* 256 * Pins the data buffer associated with this stream. Returns OK on 257 * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail. 258 */ 259 static int pinStreamBuffer(JNIEnv *env, 260 streamBufferPtr sb, 261 const JOCTET **next_byte) { 262 if (sb->hstreamBuffer != NULL) { 263 assert(sb->buf == NULL); 264 sb->buf = 265 (JOCTET *) (*env)->GetPrimitiveArrayCritical(env, 266 sb->hstreamBuffer, 267 NULL); 268 if (sb->buf == NULL) { 269 return NOT_OK; 270 } 271 if (sb->bufferOffset != NO_DATA) { 272 *next_byte = sb->buf + sb->bufferOffset; 273 } 274 } 275 return OK; 276 } 277 278 /* 279 * Unpins the data buffer associated with this stream. 280 */ 281 static void unpinStreamBuffer(JNIEnv *env, 282 streamBufferPtr sb, 283 const JOCTET *next_byte) { 284 if (sb->buf != NULL) { 285 assert(sb->hstreamBuffer != NULL); 286 if (next_byte == NULL) { 287 sb->bufferOffset = NO_DATA; 288 } else { 289 sb->bufferOffset = next_byte - sb->buf; 290 } 291 (*env)->ReleasePrimitiveArrayCritical(env, 292 sb->hstreamBuffer, 293 sb->buf, 294 0); 295 sb->buf = NULL; 296 } 297 } 298 299 /* 300 * Clear out the streamBuffer. This just invalidates the data in the buffer. 301 */ 302 static void clearStreamBuffer(streamBufferPtr sb) { 303 sb->bufferOffset = NO_DATA; 304 } 305 306 /*************************** end StreamBuffer definition *************/ 307 308 /*************************** Pixel Buffer definition ******************/ 309 310 typedef struct pixelBufferStruct { 311 jobject hpixelObject; // Usually a DataBuffer bank as a byte array 312 313 union pixptr { 314 INT32 *ip; // Pinned buffer pointer, as 32-bit ints 315 unsigned char *bp; // Pinned buffer pointer, as bytes 316 } buf; 317 } pixelBuffer, *pixelBufferPtr; 318 319 /* 320 * Initialize a freshly allocated PixelBuffer. All fields are simply 321 * set to NULL, as we have no idea what size buffer we will need. 322 */ 323 static void initPixelBuffer(pixelBufferPtr pb) { 324 pb->hpixelObject = NULL; 325 pb->buf.ip = NULL; 326 } 327 328 /* 329 * Set the pixelBuffer to use the given buffer, acquiring a new global 330 * reference for it. Returns OK on success, NOT_OK on failure. 331 */ 332 static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) { 333 pb->hpixelObject = (*env)->NewGlobalRef(env, obj); 334 335 if (pb->hpixelObject == NULL) { 336 ThrowByName(env, 337 "java/lang/OutOfMemoryError", 338 "Setting Pixel Buffer"); 339 return NOT_OK; 340 } 341 return OK; 342 } 343 344 // Forward reference 345 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb); 346 347 /* 348 * Resets a pixel buffer to its initial state. Unpins any pixel buffer, 349 * releases the global reference, and resets fields to NULL. Use this 350 * method to dispose the object as well (there is no destroyPixelBuffer). 351 */ 352 static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 353 if (pb->hpixelObject != NULL) { 354 unpinPixelBuffer(env, pb); 355 (*env)->DeleteGlobalRef(env, pb->hpixelObject); 356 pb->hpixelObject = NULL; 357 } 358 } 359 360 /* 361 * Pins the data buffer. Returns OK on success, NOT_OK on failure. 362 */ 363 static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 364 if (pb->hpixelObject != NULL) { 365 assert(pb->buf.ip == NULL); 366 pb->buf.bp = (unsigned char *) (*env)->GetPrimitiveArrayCritical 367 (env, pb->hpixelObject, NULL); 368 if (pb->buf.bp == NULL) { 369 return NOT_OK; 370 } 371 } 372 return OK; 373 } 374 375 /* 376 * Unpins the data buffer. 377 */ 378 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 379 380 if (pb->buf.ip != NULL) { 381 assert(pb->hpixelObject != NULL); 382 (*env)->ReleasePrimitiveArrayCritical(env, 383 pb->hpixelObject, 384 pb->buf.ip, 385 0); 386 pb->buf.ip = NULL; 387 } 388 } 389 390 /********************* end PixelBuffer definition *******************/ 391 392 /********************* ImageIOData definition ***********************/ 393 394 #define MAX_BANDS 4 395 #define JPEG_BAND_SIZE 8 396 #define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE) 397 #define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1) 398 #define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1) 399 400 /* The number of possible incoming values to be scaled. */ 401 #define NUM_INPUT_VALUES (1 << 16) 402 403 /* 404 * The principal imageioData object, opaque to I/O direction. 405 * Each JPEGImageReader will have associated with it a 406 * jpeg_decompress_struct, and similarly each JPEGImageWriter will 407 * have associated with it a jpeg_compress_struct. In order to 408 * ensure that these associations persist from one native call to 409 * the next, and to provide a central locus of imageio-specific 410 * data, we define an imageioData struct containing references 411 * to the Java object and the IJG structs. The functions 412 * that manipulate these objects know whether input or output is being 413 * performed and therefore know how to manipulate the contents correctly. 414 * If for some reason they don't, the direction can be determined by 415 * checking the is_decompressor field of the jpegObj. 416 * In order for lower level code to determine a 417 * Java object given an IJG struct, such as for dispatching warnings, 418 * we use the client_data field of the jpeg object to store a pointer 419 * to the imageIOData object. Maintenance of this pointer is performed 420 * exclusively within the following access functions. If you 421 * change that, you run the risk of dangling pointers. 422 */ 423 typedef struct imageIODataStruct { 424 j_common_ptr jpegObj; // Either struct is fine 425 jobject imageIOobj; // A JPEGImageLoader 426 427 streamBuffer streamBuf; // Buffer for the stream 428 pixelBuffer pixelBuf; // Buffer for pixels 429 430 jboolean abortFlag; // Passed down from Java abort method 431 } imageIOData, *imageIODataPtr; 432 433 /* 434 * Allocate and initialize a new imageIOData object to associate the 435 * jpeg object and the Java object. Returns a pointer to the new object 436 * on success, NULL on failure. 437 */ 438 static imageIODataPtr initImageioData(JNIEnv *env, 439 j_common_ptr cinfo, 440 jobject obj) { 441 imageIODataPtr data = (imageIODataPtr) malloc(sizeof (imageIOData)); 442 if (data == NULL) { 443 return NULL; 444 } 445 446 data->jpegObj = cinfo; 447 cinfo->client_data = data; 448 449 #ifdef DEBUG_IIO_JPEG 450 printf("new structures: data is %p, cinfo is %p\n", data, cinfo); 451 #endif 452 453 data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj); 454 if (data->imageIOobj == NULL) { 455 free(data); 456 return NULL; 457 } 458 if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) { 459 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 460 free(data); 461 return NULL; 462 } 463 initPixelBuffer(&data->pixelBuf); 464 465 data->abortFlag = JNI_FALSE; 466 467 return data; 468 } 469 470 /* 471 * Resets the imageIOData object to its initial state, as though 472 * it had just been allocated and initialized. 473 */ 474 static void resetImageIOData(JNIEnv *env, imageIODataPtr data) { 475 resetStreamBuffer(env, &data->streamBuf); 476 resetPixelBuffer(env, &data->pixelBuf); 477 data->abortFlag = JNI_FALSE; 478 } 479 480 /* 481 * Releases all resources held by this object and its subobjects, 482 * frees the object, and returns the jpeg object. This method must 483 * be called to avoid leaking global references. 484 * Note that the jpeg object is not freed or destroyed, as that is 485 * the client's responsibility, although the client_data field is 486 * cleared. 487 */ 488 static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) { 489 j_common_ptr ret = data->jpegObj; 490 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 491 destroyStreamBuffer(env, &data->streamBuf); 492 resetPixelBuffer(env, &data->pixelBuf); 493 ret->client_data = NULL; 494 free(data); 495 return ret; 496 } 497 498 /******************** end ImageIOData definition ***********************/ 499 500 /******************** Java array pinning and unpinning *****************/ 501 502 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid 503 * the need to copy array elements for the above two objects. 504 * 505 * MAKE SURE TO: 506 * 507 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around 508 * callbacks to Java. 509 * - call RELEASE_ARRAYS before returning to Java. 510 * 511 * Otherwise things will go horribly wrong. There may be memory leaks, 512 * excessive pinning, or even VM crashes! 513 * 514 * Note that GetPrimitiveArrayCritical may fail! 515 */ 516 517 /* 518 * Release (unpin) all the arrays in use during a read. 519 */ 520 static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte) { 521 unpinStreamBuffer(env, &data->streamBuf, next_byte); 522 523 unpinPixelBuffer(env, &data->pixelBuf); 524 525 } 526 527 /* 528 * Get (pin) all the arrays in use during a read. 529 */ 530 static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) { 531 if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) { 532 return NOT_OK; 533 } 534 535 if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) { 536 RELEASE_ARRAYS(env, data, *next_byte); 537 return NOT_OK; 538 } 539 return OK; 540 } 541 542 /****** end of Java array pinning and unpinning ***********/ 543 544 /****** Error Handling *******/ 545 546 /* 547 * Set up error handling to use setjmp/longjmp. This is the third such 548 * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes 549 * setup thier own. Ultimately these should be integrated, as they all 550 * do pretty much the same thing. 551 */ 552 553 struct sun_jpeg_error_mgr { 554 struct jpeg_error_mgr pub; /* "public" fields */ 555 556 jmp_buf setjmp_buffer; /* for return to caller */ 557 }; 558 559 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr; 560 561 /* 562 * Here's the routine that will replace the standard error_exit method: 563 */ 564 565 METHODDEF(void) 566 sun_jpeg_error_exit(j_common_ptr cinfo) { 567 /* cinfo->err really points to a sun_jpeg_error_mgr struct */ 568 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err; 569 570 /* For Java, we will format the message and put it in the error we throw. */ 571 572 /* Return control to the setjmp point */ 573 longjmp(myerr->setjmp_buffer, 1); 574 } 575 576 /* 577 * Error Message handling 578 * 579 * This overrides the output_message method to send JPEG messages 580 * 581 */ 582 583 METHODDEF(void) 584 sun_jpeg_output_message(j_common_ptr cinfo) { 585 char buffer[JMSG_LENGTH_MAX]; 586 jstring string; 587 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 588 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 589 jobject theObject; 590 j_decompress_ptr dinfo; 591 592 /* Create the message */ 593 (*cinfo->err->format_message) (cinfo, buffer); 594 595 if (cinfo->is_decompressor) { 596 dinfo = (j_decompress_ptr)cinfo; 597 RELEASE_ARRAYS(env, data, dinfo->src->next_input_byte); 598 } 599 // Create a new java string from the message 600 string = (*env)->NewStringUTF(env, buffer); 601 602 theObject = data->imageIOobj; 603 604 if (cinfo->is_decompressor) { 605 (*env)->CallVoidMethod(env, theObject, 606 JPEGImageLoader_emitWarningID, 607 string); 608 checkAndClearException(env); 609 if (!GET_ARRAYS(env, data, &(dinfo->src->next_input_byte))) { 610 cinfo->err->error_exit(cinfo); 611 } 612 } 613 } 614 615 /* End of verbatim copy from jpegdecoder.c */ 616 617 /*************** end of error handling *********************/ 618 619 /*************** Shared utility code ***********************/ 620 621 static void imageio_set_stream(JNIEnv *env, 622 j_common_ptr cinfo, 623 imageIODataPtr data, 624 jobject stream) { 625 streamBufferPtr sb; 626 sun_jpeg_error_ptr jerr; 627 628 sb = &data->streamBuf; 629 630 resetStreamBuffer(env, sb); // Removes any old stream 631 632 /* Now we need a new global reference for the stream */ 633 if (stream != NULL) { // Fix for 4411955 634 sb->stream = (*env)->NewGlobalRef(env, stream); 635 if (sb->stream == NULL) { 636 ThrowByName(env, 637 "java/lang/OutOfMemoryError", 638 "Setting Stream"); 639 return; 640 } 641 } 642 643 /* And finally reset state */ 644 data->abortFlag = JNI_FALSE; 645 646 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 647 jerr = (sun_jpeg_error_ptr) cinfo->err; 648 649 if (setjmp(jerr->setjmp_buffer)) { 650 /* If we get here, the JPEG code has signaled an error 651 while aborting. */ 652 if (!(*env)->ExceptionOccurred(env)) { 653 char buffer[JMSG_LENGTH_MAX]; 654 (*cinfo->err->format_message) (cinfo, 655 buffer); 656 ThrowByName(env, "java/io/IOException", buffer); 657 } 658 return; 659 } 660 661 jpeg_abort(cinfo); // Frees any markers, but not tables 662 663 } 664 665 static void imageio_dispose(j_common_ptr info) { 666 667 if (info != NULL) { 668 free(info->err); 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 /* 714 * Initialize source. This is called by jpeg_read_header() before any 715 * data is actually read. Unlike init_destination(), it may leave 716 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call 717 * will occur immediately). 718 */ 719 720 GLOBAL(void) 721 imageio_init_source(j_decompress_ptr cinfo) { 722 struct jpeg_source_mgr *src = cinfo->src; 723 src->next_input_byte = NULL; 724 src->bytes_in_buffer = 0; 725 } 726 727 /* 728 * This is called whenever bytes_in_buffer has reached zero and more 729 * data is wanted. In typical applications, it should read fresh data 730 * into the buffer (ignoring the current state of next_input_byte and 731 * bytes_in_buffer), reset the pointer & count to the start of the 732 * buffer, and return TRUE indicating that the buffer has been reloaded. 733 * It is not necessary to fill the buffer entirely, only to obtain at 734 * least one more byte. bytes_in_buffer MUST be set to a positive value 735 * if TRUE is returned. A FALSE return should only be used when I/O 736 * suspension is desired (this mode is discussed in the next section). 737 */ 738 739 /* 740 * Note that with I/O suspension turned on, this procedure should not 741 * do any work since the JPEG library has a very simple backtracking 742 * mechanism which relies on the fact that the buffer will be filled 743 * only when it has backed out to the top application level. When 744 * suspendable is turned on, imageio_fill_suspended_buffer will 745 * do the actual work of filling the buffer. 746 */ 747 748 GLOBAL(boolean) 749 imageio_fill_input_buffer(j_decompress_ptr cinfo) { 750 struct jpeg_source_mgr *src = cinfo->src; 751 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 752 streamBufferPtr sb = &data->streamBuf; 753 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 754 int ret; 755 756 /* This is where input suspends */ 757 if (sb->suspendable) { 758 return FALSE; 759 } 760 761 #ifdef DEBUG_IIO_JPEG 762 printf("Filling input buffer, remaining skip is %ld, ", 763 sb->remaining_skip); 764 printf("Buffer length is %d\n", sb->bufferLength); 765 #endif 766 767 /* 768 * Definitively skips. Could be left over if we tried to skip 769 * more than a buffer's worth but suspended when getting the next 770 * buffer. Now we aren't suspended, so we can catch up. 771 */ 772 if (sb->remaining_skip) { 773 src->skip_input_data(cinfo, 0); 774 } 775 776 /* 777 * Now fill a complete buffer, or as much of one as the stream 778 * will give us if we are near the end. 779 */ 780 RELEASE_ARRAYS(env, data, src->next_input_byte); 781 ret = (*env)->CallIntMethod(env, 782 sb->stream, 783 InputStream_readID, 784 sb->hstreamBuffer, 0, 785 sb->bufferLength); 786 if (ret > sb->bufferLength) ret = sb->bufferLength; 787 if ((*env)->ExceptionOccurred(env) 788 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 789 cinfo->err->error_exit((j_common_ptr) cinfo); 790 } 791 792 #ifdef DEBUG_IIO_JPEG 793 printf("Buffer filled. ret = %d\n", ret); 794 #endif 795 /* 796 * If we have reached the end of the stream, then the EOI marker 797 * is missing. We accept such streams but generate a warning. 798 * The image is likely to be corrupted, though everything through 799 * the end of the last complete MCU should be usable. 800 */ 801 if (ret <= 0) { 802 jobject reader = data->imageIOobj; 803 #ifdef DEBUG_IIO_JPEG 804 printf("YO! Early EOI! ret = %d\n", ret); 805 #endif 806 RELEASE_ARRAYS(env, data, src->next_input_byte); 807 (*env)->CallVoidMethod(env, reader, 808 JPEGImageLoader_emitWarningID, 809 READ_NO_EOI); 810 if ((*env)->ExceptionOccurred(env) 811 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 812 cinfo->err->error_exit((j_common_ptr) cinfo); 813 } 814 815 sb->buf[0] = (JOCTET) 0xFF; 816 sb->buf[1] = (JOCTET) JPEG_EOI; 817 ret = 2; 818 } 819 820 src->next_input_byte = sb->buf; 821 src->bytes_in_buffer = ret; 822 823 return TRUE; 824 } 825 826 /* 827 * With I/O suspension turned on, the JPEG library requires that all 828 * buffer filling be done at the top application level, using this 829 * function. Due to the way that backtracking works, this procedure 830 * saves all of the data that was left in the buffer when suspension 831 * occured and read new data only at the end. 832 */ 833 834 GLOBAL(void) 835 imageio_fill_suspended_buffer(j_decompress_ptr cinfo) { 836 struct jpeg_source_mgr *src = cinfo->src; 837 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 838 streamBufferPtr sb = &data->streamBuf; 839 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 840 jint ret; 841 int offset, buflen; 842 843 /* 844 * The original (jpegdecoder.c) had code here that called 845 * InputStream.available and just returned if the number of bytes 846 * available was less than any remaining skip. Presumably this was 847 * to avoid blocking, although the benefit was unclear, as no more 848 * decompression can take place until more data is available, so 849 * the code would block on input a little further along anyway. 850 * ImageInputStreams don't have an available method, so we'll just 851 * block in the skip if we have to. 852 */ 853 854 if (sb->remaining_skip) { 855 src->skip_input_data(cinfo, 0); 856 } 857 858 /* Save the data currently in the buffer */ 859 offset = src->bytes_in_buffer; 860 if (src->next_input_byte > sb->buf) { 861 memcpy(sb->buf, src->next_input_byte, offset); 862 } 863 RELEASE_ARRAYS(env, data, src->next_input_byte); 864 buflen = sb->bufferLength - offset; 865 if (buflen <= 0) { 866 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) { 867 cinfo->err->error_exit((j_common_ptr) cinfo); 868 } 869 return; 870 } 871 872 ret = (*env)->CallIntMethod(env, sb->stream, 873 InputStream_readID, 874 sb->hstreamBuffer, 875 offset, buflen); 876 if (ret > buflen) ret = buflen; 877 if ((*env)->ExceptionOccurred(env) 878 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 879 cinfo->err->error_exit((j_common_ptr) cinfo); 880 } 881 /* 882 * If we have reached the end of the stream, then the EOI marker 883 * is missing. We accept such streams but generate a warning. 884 * The image is likely to be corrupted, though everything through 885 * the end of the last complete MCU should be usable. 886 */ 887 if (ret <= 0) { 888 jobject reader = data->imageIOobj; 889 RELEASE_ARRAYS(env, data, src->next_input_byte); 890 (*env)->CallVoidMethod(env, reader, 891 JPEGImageLoader_emitWarningID, 892 READ_NO_EOI); 893 if ((*env)->ExceptionOccurred(env) 894 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 895 cinfo->err->error_exit((j_common_ptr) cinfo); 896 } 897 898 sb->buf[offset] = (JOCTET) 0xFF; 899 sb->buf[offset + 1] = (JOCTET) JPEG_EOI; 900 ret = 2; 901 } 902 903 src->next_input_byte = sb->buf; 904 src->bytes_in_buffer = ret + offset; 905 906 return; 907 } 908 909 /* 910 * Skip num_bytes worth of data. The buffer pointer and count are 911 * advanced over num_bytes input bytes, using the input stream 912 * skipBytes method if the skip is greater than the number of bytes 913 * in the buffer. This is used to skip over a potentially large amount of 914 * uninteresting data (such as an APPn marker). bytes_in_buffer will be 915 * zero on return if the skip is larger than the current contents of the 916 * buffer. 917 * 918 * A negative skip count is treated as a no-op. A zero skip count 919 * skips any remaining skip from a previous skip while suspended. 920 * 921 * Note that with I/O suspension turned on, this procedure does not 922 * call skipBytes since the JPEG library has a very simple backtracking 923 * mechanism which relies on the fact that the application level has 924 * exclusive control over actual I/O. 925 */ 926 927 GLOBAL(void) 928 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { 929 struct jpeg_source_mgr *src = cinfo->src; 930 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 931 streamBufferPtr sb = &data->streamBuf; 932 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 933 jlong ret; 934 jobject reader; 935 936 if (num_bytes < 0) { 937 return; 938 } 939 num_bytes += sb->remaining_skip; 940 sb->remaining_skip = 0; 941 942 /* First the easy case where we are skipping <= the current contents. */ 943 ret = src->bytes_in_buffer; 944 if (ret >= num_bytes) { 945 src->next_input_byte += num_bytes; 946 src->bytes_in_buffer -= num_bytes; 947 return; 948 } 949 950 /* 951 * We are skipping more than is in the buffer. We empty the buffer and, 952 * if we aren't suspended, call the Java skipBytes method. We always 953 * leave the buffer empty, to be filled by either fill method above. 954 */ 955 src->bytes_in_buffer = 0; 956 src->next_input_byte = sb->buf; 957 958 num_bytes -= (long) ret; 959 if (sb->suspendable) { 960 sb->remaining_skip = num_bytes; 961 return; 962 } 963 964 RELEASE_ARRAYS(env, data, src->next_input_byte); 965 ret = (*env)->CallLongMethod(env, 966 sb->stream, 967 InputStream_skipID, 968 (jlong) num_bytes); 969 if ((*env)->ExceptionOccurred(env) 970 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 971 cinfo->err->error_exit((j_common_ptr) cinfo); 972 } 973 974 /* 975 * If we have reached the end of the stream, then the EOI marker 976 * is missing. We accept such streams but generate a warning. 977 * The image is likely to be corrupted, though everything through 978 * the end of the last complete MCU should be usable. 979 */ 980 if (ret <= 0) { 981 reader = data->imageIOobj; 982 RELEASE_ARRAYS(env, data, src->next_input_byte); 983 (*env)->CallVoidMethod(env, 984 reader, 985 JPEGImageLoader_emitWarningID, 986 READ_NO_EOI); 987 988 if ((*env)->ExceptionOccurred(env) 989 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 990 cinfo->err->error_exit((j_common_ptr) cinfo); 991 } 992 sb->buf[0] = (JOCTET) 0xFF; 993 sb->buf[1] = (JOCTET) JPEG_EOI; 994 src->bytes_in_buffer = 2; 995 src->next_input_byte = sb->buf; 996 } 997 } 998 999 /* 1000 * Terminate source --- called by jpeg_finish_decompress() after all 1001 * data for an image has been read. In our case pushes back any 1002 * remaining data, as it will be for another image and must be available 1003 * for java to find out that there is another image. Also called if 1004 * reseting state after reading a tables-only image. 1005 */ 1006 1007 GLOBAL(void) 1008 imageio_term_source(j_decompress_ptr cinfo) { 1009 // To pushback, just seek back by src->bytes_in_buffer 1010 struct jpeg_source_mgr *src = cinfo->src; 1011 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 1012 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 1013 jobject reader = data->imageIOobj; 1014 if (src->bytes_in_buffer > 0) { 1015 RELEASE_ARRAYS(env, data, src->next_input_byte); 1016 1017 if ((*env)->ExceptionOccurred(env) 1018 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1019 cinfo->err->error_exit((j_common_ptr) cinfo); 1020 } 1021 src->bytes_in_buffer = 0; 1022 //src->next_input_byte = sb->buf; 1023 } 1024 } 1025 1026 /********************* end of source manager ******************/ 1027 1028 /********************* ICC profile support ********************/ 1029 /* 1030 * The following routines are modified versions of the ICC 1031 * profile support routines available from the IJG website. 1032 * The originals were written by Todd Newman 1033 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for 1034 * the IJG. They are further modified to fit in the context 1035 * of the imageio JPEG plug-in. 1036 */ 1037 1038 /* 1039 * Since an ICC profile can be larger than the maximum size of a JPEG marker 1040 * (64K), we need provisions to split it into multiple markers. The format 1041 * defined by the ICC specifies one or more APP2 markers containing the 1042 * following data: 1043 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes) 1044 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte) 1045 * Number of markers Total number of APP2's used (1 byte) 1046 * Profile data (remainder of APP2 data) 1047 * Decoders should use the marker sequence numbers to reassemble the profile, 1048 * rather than assuming that the APP2 markers appear in the correct sequence. 1049 */ 1050 1051 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ 1052 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ 1053 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ 1054 #define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) 1055 1056 /* 1057 * Handy subroutine to test whether a saved marker is an ICC profile marker. 1058 */ 1059 1060 static boolean 1061 marker_is_icc(jpeg_saved_marker_ptr marker) { 1062 return 1063 marker->marker == ICC_MARKER && 1064 marker->data_length >= ICC_OVERHEAD_LEN && 1065 /* verify the identifying string */ 1066 GETJOCTET(marker->data[0]) == 0x49 && 1067 GETJOCTET(marker->data[1]) == 0x43 && 1068 GETJOCTET(marker->data[2]) == 0x43 && 1069 GETJOCTET(marker->data[3]) == 0x5F && 1070 GETJOCTET(marker->data[4]) == 0x50 && 1071 GETJOCTET(marker->data[5]) == 0x52 && 1072 GETJOCTET(marker->data[6]) == 0x4F && 1073 GETJOCTET(marker->data[7]) == 0x46 && 1074 GETJOCTET(marker->data[8]) == 0x49 && 1075 GETJOCTET(marker->data[9]) == 0x4C && 1076 GETJOCTET(marker->data[10]) == 0x45 && 1077 GETJOCTET(marker->data[11]) == 0x0; 1078 } 1079 1080 /* 1081 * See if there was an ICC profile in the JPEG file being read; 1082 * if so, reassemble and return the profile data as a new Java byte array. 1083 * If there was no ICC profile, return NULL. 1084 * 1085 * If the file contains invalid ICC APP2 markers, we throw an IIOException 1086 * with an appropriate message. 1087 */ 1088 1089 jbyteArray 1090 read_icc_profile(JNIEnv *env, j_decompress_ptr cinfo) { 1091 jpeg_saved_marker_ptr marker; 1092 int num_markers = 0; 1093 int num_found_markers = 0; 1094 int seq_no; 1095 JOCTET *icc_data; 1096 JOCTET *dst_ptr; 1097 unsigned int total_length; 1098 #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes 1099 jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1]; 1100 int first; // index of the first marker in the icc_markers array 1101 int last; // index of the last marker in the icc_markers array 1102 jbyteArray data = NULL; 1103 1104 /* This first pass over the saved markers discovers whether there are 1105 * any ICC markers and verifies the consistency of the marker numbering. 1106 */ 1107 1108 for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++) 1109 icc_markers[seq_no] = NULL; 1110 1111 1112 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { 1113 if (marker_is_icc(marker)) { 1114 if (num_markers == 0) 1115 num_markers = GETJOCTET(marker->data[13]); 1116 else if (num_markers != GETJOCTET(marker->data[13])) { 1117 ThrowByName(env, "java/io/IOException", 1118 "Invalid icc profile: inconsistent num_markers fields"); 1119 return NULL; 1120 } 1121 seq_no = GETJOCTET(marker->data[12]); 1122 1123 /* Some third-party tools produce images with profile chunk 1124 * numeration started from zero. It is inconsistent with ICC 1125 * spec, but seems to be recognized by majority of image 1126 * processing tools, so we should be more tolerant to this 1127 * departure from the spec. 1128 */ 1129 if (seq_no < 0 || seq_no > num_markers) { 1130 ThrowByName(env, "java/io/IOException", 1131 "Invalid icc profile: bad sequence number"); 1132 return NULL; 1133 } 1134 if (icc_markers[seq_no] != NULL) { 1135 ThrowByName(env, "java/io/IOException", 1136 "Invalid icc profile: duplicate sequence numbers"); 1137 return NULL; 1138 } 1139 icc_markers[seq_no] = marker; 1140 num_found_markers++; 1141 } 1142 } 1143 1144 if (num_markers == 0) 1145 return NULL; // There is no profile 1146 1147 if (num_markers != num_found_markers) { 1148 ThrowByName(env, "java/io/IOException", 1149 "Invalid icc profile: invalid number of icc markers"); 1150 return NULL; 1151 } 1152 1153 first = icc_markers[0] ? 0 : 1; 1154 last = num_found_markers + first; 1155 1156 /* Check for missing markers, count total space needed. 1157 */ 1158 total_length = 0; 1159 for (seq_no = first; seq_no < last; seq_no++) { 1160 unsigned int length; 1161 if (icc_markers[seq_no] == NULL) { 1162 ThrowByName(env, "java/io/IOException", 1163 "Invalid icc profile: missing sequence number"); 1164 return NULL; 1165 } 1166 /* check the data length correctness */ 1167 length = icc_markers[seq_no]->data_length; 1168 if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) { 1169 ThrowByName(env, "java/io/IOException", 1170 "Invalid icc profile: invalid data length"); 1171 return NULL; 1172 } 1173 total_length += (length - ICC_OVERHEAD_LEN); 1174 } 1175 1176 if (total_length <= 0) { 1177 ThrowByName(env, "java/io/IOException", 1178 "Invalid icc profile: found only empty markers"); 1179 return NULL; 1180 } 1181 1182 /* Allocate a Java byte array for assembled data */ 1183 1184 data = (*env)->NewByteArray(env, total_length); 1185 if (data == NULL) { 1186 ThrowByName(env, 1187 "java/lang/OutOfMemoryError", 1188 "Reading ICC profile"); 1189 return NULL; 1190 } 1191 1192 icc_data = (JOCTET *) (*env)->GetPrimitiveArrayCritical(env, 1193 data, 1194 NULL); 1195 if (icc_data == NULL) { 1196 ThrowByName(env, "java/io/IOException", 1197 "Unable to pin icc profile data array"); 1198 return NULL; 1199 } 1200 1201 /* and fill it in */ 1202 dst_ptr = icc_data; 1203 for (seq_no = first; seq_no < last; seq_no++) { 1204 JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN; 1205 unsigned int length = 1206 icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN; 1207 1208 memcpy(dst_ptr, src_ptr, length); 1209 dst_ptr += length; 1210 } 1211 1212 /* finally, unpin the array */ 1213 (*env)->ReleasePrimitiveArrayCritical(env, 1214 data, 1215 icc_data, 1216 0); 1217 1218 1219 return data; 1220 } 1221 1222 /********************* end of ICC profile support *************/ 1223 1224 /********************* Loader JNI calls ***********************/ 1225 1226 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initJPEGMethodIDs 1227 (JNIEnv *env, jclass cls, jclass InputStreamClass) { 1228 // InputStream methods. 1229 InputStream_readID = (*env)->GetMethodID(env, 1230 InputStreamClass, 1231 "read", 1232 "([BII)I"); 1233 if ((*env)->ExceptionCheck(env)) { 1234 return; 1235 } 1236 1237 InputStream_skipID = (*env)->GetMethodID(env, 1238 InputStreamClass, 1239 "skip", 1240 "(J)J"); 1241 if ((*env)->ExceptionCheck(env)) { 1242 return; 1243 } 1244 1245 // JPEGImageLoader IDs. 1246 JPEGImageLoader_setInputAttributesID = (*env)->GetMethodID(env, 1247 cls, 1248 "setInputAttributes", 1249 "(IIIII[B)V"); 1250 if ((*env)->ExceptionCheck(env)) { 1251 return; 1252 } 1253 1254 JPEGImageLoader_setOutputAttributesID = (*env)->GetMethodID(env, 1255 cls, 1256 "setOutputAttributes", 1257 "(II)V"); 1258 if ((*env)->ExceptionCheck(env)) { 1259 return; 1260 } 1261 1262 JPEGImageLoader_updateImageProgressID = (*env)->GetMethodID(env, 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 */ 1304 struct jpeg_decompress_struct *cinfo; 1305 int jret; 1306 int h_samp0, h_samp1, h_samp2; 1307 int v_samp0, v_samp1, v_samp2; 1308 struct jpeg_source_mgr *src; 1309 sun_jpeg_error_ptr jerr; 1310 jbyteArray profileData = NULL; 1311 1312 cinfo = malloc(sizeof (struct jpeg_decompress_struct)); 1313 if (cinfo == NULL) { 1314 ThrowByName(env, 1315 "java/lang/OutOfMemoryError", 1316 "Initializing Reader"); 1317 return 0; 1318 } 1319 1320 /* We use our private extension JPEG error handler. 1321 */ 1322 jerr_mgr = malloc(sizeof (struct sun_jpeg_error_mgr)); 1323 if (jerr_mgr == NULL) { 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: 1439 break; 1440 case JCS_YCbCr: 1441 1442 /* 1443 * There are several possibilities: 1444 * - we got image with embeded colorspace 1445 * Use it. User knows what he is doing. 1446 * - we got JFIF image 1447 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2) 1448 * - we got EXIF image 1449 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63) 1450 * - something else 1451 * Apply heuristical rules to identify actual colorspace. 1452 */ 1453 1454 if (cinfo->saw_Adobe_marker) { 1455 if (cinfo->Adobe_transform != 1) { 1456 /* 1457 * IJG guesses this is YCbCr and emits a warning 1458 * We would rather not guess. Then the user knows 1459 * To read this as a Raster if at all 1460 */ 1461 cinfo->jpeg_color_space = JCS_UNKNOWN; 1462 cinfo->out_color_space = JCS_UNKNOWN; 1463 } 1464 } 1465 break; 1466 #ifdef YCCALPHA 1467 case JCS_YCC: 1468 cinfo->out_color_space = JCS_YCC; 1469 break; 1470 #endif 1471 case JCS_YCCK: 1472 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) { 1473 /* 1474 * IJG guesses this is YCCK and emits a warning 1475 * We would rather not guess. Then the user knows 1476 * To read this as a Raster if at all 1477 */ 1478 cinfo->jpeg_color_space = JCS_UNKNOWN; 1479 cinfo->out_color_space = JCS_UNKNOWN; 1480 } else { 1481 /* There is no support for YCCK on jfx side, so request RGB output */ 1482 cinfo->out_color_space = JCS_RGB; 1483 } 1484 break; 1485 case JCS_CMYK: 1486 /* 1487 * IJG assumes all unidentified 4-channels are CMYK. 1488 * We assume that only if the second two channels are 1489 * not subsampled (either horizontally or vertically). 1490 * If they are, we assume YCCK. 1491 */ 1492 h_samp0 = cinfo->comp_info[0].h_samp_factor; 1493 h_samp1 = cinfo->comp_info[1].h_samp_factor; 1494 h_samp2 = cinfo->comp_info[2].h_samp_factor; 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, 1549 "java/io/IOException", 1550 "Array pin failed"); 1551 return JCS_UNKNOWN; 1552 } 1553 1554 cinfo = (j_decompress_ptr) data->jpegObj; 1555 1556 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1557 jerr = (sun_jpeg_error_ptr) cinfo->err; 1558 1559 if (setjmp(jerr->setjmp_buffer)) { 1560 /* If we get here, the JPEG code has signaled an error 1561 while initializing compression. */ 1562 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1563 if (!(*env)->ExceptionOccurred(env)) { 1564 char buffer[JMSG_LENGTH_MAX]; 1565 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1566 buffer); 1567 ThrowByName(env, "java/io/IOException", buffer); 1568 } 1569 return JCS_UNKNOWN; 1570 } 1571 1572 cinfo->out_color_space = outCS; 1573 1574 /* decide how much we want to sub-sample the incoming jpeg image. 1575 * The libjpeg docs say: 1576 * 1577 * unsigned int scale_num, scale_denom 1578 * 1579 * Scale the image by the fraction scale_num/scale_denom. Default is 1580 * 1/1, or no scaling. Currently, the only supported scaling ratios 1581 * are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary 1582 * scaling ratios but this is not likely to be implemented any time soon.) 1583 * Smaller scaling ratios permit significantly faster decoding since 1584 * fewer pixels need be processed and a simpler IDCT method can be used. 1585 */ 1586 1587 cinfo->scale_num = 1; 1588 1589 x_scale = (jfloat) dest_width / (jfloat) cinfo->image_width; 1590 y_scale = (jfloat) dest_height / (jfloat) cinfo->image_height; 1591 max_scale = x_scale > y_scale ? x_scale : y_scale; 1592 1593 if (max_scale > 0.5) { 1594 cinfo->scale_denom = 1; 1595 } else if (max_scale > 0.25) { 1596 cinfo->scale_denom = 2; 1597 } else if (max_scale > 0.125) { 1598 cinfo->scale_denom = 4; 1599 } else { 1600 cinfo->scale_denom = 8; 1601 } 1602 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 }