1 /* 2 * Copyright (c) 2000, 2016, 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 /* 27 * This file contains the code to link the Java Image I/O JPEG plug-in 28 * to the IJG library used to read and write JPEG files. Much of it has 29 * been copied, updated, and annotated from the jpegdecoder.c AWT JPEG 30 * decoder. Where that code was unclear, the present author has either 31 * rewritten the relevant section or commented it for the sake of future 32 * maintainers. 33 * 34 * In particular, the way the AWT code handled progressive JPEGs seems 35 * to me to be only accidentally correct and somewhat inefficient. The 36 * scheme used here represents the way I think it should work. (REV 11/00) 37 */ 38 39 #include <stdlib.h> 40 #include <setjmp.h> 41 #include <assert.h> 42 #include <string.h> 43 #include <limits.h> 44 45 /* java native interface headers */ 46 #include "jni.h" 47 #include "jni_util.h" 48 49 #include "com_sun_imageio_plugins_jpeg_JPEGImageReader.h" 50 #include "com_sun_imageio_plugins_jpeg_JPEGImageWriter.h" 51 52 /* headers from the JPEG library */ 53 #include <jpeglib.h> 54 #include <jerror.h> 55 56 #undef MAX 57 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 58 59 #ifdef __APPLE__ 60 /* use setjmp/longjmp versions that do not save/restore the signal mask */ 61 #define setjmp _setjmp 62 #define longjmp _longjmp 63 #endif 64 65 /* Cached Java method ids */ 66 static jmethodID JPEGImageReader_readInputDataID; 67 static jmethodID JPEGImageReader_skipInputBytesID; 68 static jmethodID JPEGImageReader_warningOccurredID; 69 static jmethodID JPEGImageReader_warningWithMessageID; 70 static jmethodID JPEGImageReader_setImageDataID; 71 static jmethodID JPEGImageReader_acceptPixelsID; 72 static jmethodID JPEGImageReader_pushBackID; 73 static jmethodID JPEGImageReader_passStartedID; 74 static jmethodID JPEGImageReader_passCompleteID; 75 static jmethodID JPEGImageWriter_writeOutputDataID; 76 static jmethodID JPEGImageWriter_warningOccurredID; 77 static jmethodID JPEGImageWriter_warningWithMessageID; 78 static jmethodID JPEGImageWriter_writeMetadataID; 79 static jmethodID JPEGImageWriter_grabPixelsID; 80 static jfieldID JPEGQTable_tableID; 81 static jfieldID JPEGHuffmanTable_lengthsID; 82 static jfieldID JPEGHuffmanTable_valuesID; 83 84 /* 85 * Defined in jpegdecoder.c. Copy code from there if and 86 * when that disappears. */ 87 extern JavaVM *jvm; 88 89 /* 90 * The following sets of defines must match the warning messages in the 91 * Java code. 92 */ 93 94 /* Reader warnings */ 95 #define READ_NO_EOI 0 96 97 /* Writer warnings */ 98 99 /* Return codes for various ops */ 100 #define OK 1 101 #define NOT_OK 0 102 103 /* 104 * First we define two objects, one for the stream and buffer and one 105 * for pixels. Both contain references to Java objects and pointers to 106 * pinned arrays. These objects can be used for either input or 107 * output. Pixels can be accessed as either INT32s or bytes. 108 * Every I/O operation will have one of each these objects, one for 109 * the stream and the other to hold pixels, regardless of the I/O direction. 110 */ 111 112 /******************** StreamBuffer definition ************************/ 113 114 typedef struct streamBufferStruct { 115 jweak ioRef; // weak reference to a provider of I/O routines 116 jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream 117 JOCTET *buf; // Pinned buffer pointer */ 118 size_t bufferOffset; // holds offset between unpin and the next pin 119 size_t bufferLength; // Allocated, nut just used 120 int suspendable; // Set to true to suspend input 121 long remaining_skip; // Used only on input 122 } streamBuffer, *streamBufferPtr; 123 124 /* 125 * This buffer size was set to 64K in the old classes, 4K by default in the 126 * IJG library, with the comment "an efficiently freadable size", and 1K 127 * in AWT. 128 * Unlike in the other Java designs, these objects will persist, so 64K 129 * seems too big and 1K seems too small. If 4K was good enough for the 130 * IJG folks, it's good enough for me. 131 */ 132 #define STREAMBUF_SIZE 4096 133 134 #define GET_IO_REF(io_name) \ 135 do { \ 136 if ((*env)->IsSameObject(env, sb->ioRef, NULL) || \ 137 ((io_name) = (*env)->NewLocalRef(env, sb->ioRef)) == NULL) \ 138 { \ 139 cinfo->err->error_exit((j_common_ptr) cinfo); \ 140 } \ 141 } while (0) \ 142 143 /* 144 * Used to signal that no data need be restored from an unpin to a pin. 145 * I.e. the buffer is empty. 146 */ 147 #define NO_DATA ((size_t)-1) 148 149 // Forward reference 150 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb); 151 152 /* 153 * Initialize a freshly allocated StreamBuffer object. The stream is left 154 * null, as it will be set from Java by setSource, but the buffer object 155 * is created and a global reference kept. Returns OK on success, NOT_OK 156 * if allocating the buffer or getting a global reference for it failed. 157 */ 158 static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 159 /* Initialize a new buffer */ 160 jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE); 161 if (hInputBuffer == NULL) { 162 (*env)->ExceptionClear(env); 163 JNU_ThrowByName( env, 164 "java/lang/OutOfMemoryError", 165 "Initializing Reader"); 166 return NOT_OK; 167 } 168 sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer); 169 sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer); 170 if (sb->hstreamBuffer == NULL) { 171 JNU_ThrowByName( env, 172 "java/lang/OutOfMemoryError", 173 "Initializing Reader"); 174 return NOT_OK; 175 } 176 177 178 sb->ioRef = NULL; 179 180 sb->buf = NULL; 181 182 resetStreamBuffer(env, sb); 183 184 return OK; 185 } 186 187 /* 188 * Free all resources associated with this streamBuffer. This must 189 * be called to dispose the object to avoid leaking global references, as 190 * resetStreamBuffer does not release the buffer reference. 191 */ 192 static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 193 resetStreamBuffer(env, sb); 194 if (sb->hstreamBuffer != NULL) { 195 (*env)->DeleteGlobalRef(env, sb->hstreamBuffer); 196 } 197 } 198 199 // Forward reference 200 static void unpinStreamBuffer(JNIEnv *env, 201 streamBufferPtr sb, 202 const JOCTET *next_byte); 203 /* 204 * Resets the state of a streamBuffer object that has been in use. 205 * The global reference to the stream is released, but the reference 206 * to the buffer is retained. The buffer is unpinned if it was pinned. 207 * All other state is reset. 208 */ 209 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 210 if (sb->ioRef != NULL) { 211 (*env)->DeleteWeakGlobalRef(env, sb->ioRef); 212 sb->ioRef = NULL; 213 } 214 unpinStreamBuffer(env, sb, NULL); 215 sb->bufferOffset = NO_DATA; 216 sb->suspendable = FALSE; 217 sb->remaining_skip = 0; 218 } 219 220 /* 221 * Pins the data buffer associated with this stream. Returns OK on 222 * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail. 223 */ 224 static int pinStreamBuffer(JNIEnv *env, 225 streamBufferPtr sb, 226 const JOCTET **next_byte) { 227 if (sb->hstreamBuffer != NULL) { 228 assert(sb->buf == NULL); 229 sb->buf = 230 (JOCTET *)(*env)->GetPrimitiveArrayCritical(env, 231 sb->hstreamBuffer, 232 NULL); 233 if (sb->buf == NULL) { 234 return NOT_OK; 235 } 236 if (sb->bufferOffset != NO_DATA) { 237 *next_byte = sb->buf + sb->bufferOffset; 238 } 239 } 240 return OK; 241 } 242 243 /* 244 * Unpins the data buffer associated with this stream. 245 */ 246 static void unpinStreamBuffer(JNIEnv *env, 247 streamBufferPtr sb, 248 const JOCTET *next_byte) { 249 if (sb->buf != NULL) { 250 assert(sb->hstreamBuffer != NULL); 251 if (next_byte == NULL) { 252 sb->bufferOffset = NO_DATA; 253 } else { 254 sb->bufferOffset = next_byte - sb->buf; 255 } 256 (*env)->ReleasePrimitiveArrayCritical(env, 257 sb->hstreamBuffer, 258 sb->buf, 259 0); 260 sb->buf = NULL; 261 } 262 } 263 264 /* 265 * Clear out the streamBuffer. This just invalidates the data in the buffer. 266 */ 267 static void clearStreamBuffer(streamBufferPtr sb) { 268 sb->bufferOffset = NO_DATA; 269 } 270 271 /*************************** end StreamBuffer definition *************/ 272 273 /*************************** Pixel Buffer definition ******************/ 274 275 typedef struct pixelBufferStruct { 276 jobject hpixelObject; // Usually a DataBuffer bank as a byte array 277 unsigned int byteBufferLength; 278 union pixptr { 279 INT32 *ip; // Pinned buffer pointer, as 32-bit ints 280 unsigned char *bp; // Pinned buffer pointer, as bytes 281 } buf; 282 } pixelBuffer, *pixelBufferPtr; 283 284 /* 285 * Initialize a freshly allocated PixelBuffer. All fields are simply 286 * set to NULL, as we have no idea what size buffer we will need. 287 */ 288 static void initPixelBuffer(pixelBufferPtr pb) { 289 pb->hpixelObject = NULL; 290 pb->byteBufferLength = 0; 291 pb->buf.ip = NULL; 292 } 293 294 /* 295 * Set the pixelBuffer to use the given buffer, acquiring a new global 296 * reference for it. Returns OK on success, NOT_OK on failure. 297 */ 298 static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) { 299 pb->hpixelObject = (*env)->NewGlobalRef(env, obj); 300 if (pb->hpixelObject == NULL) { 301 JNU_ThrowByName( env, 302 "java/lang/OutOfMemoryError", 303 "Setting Pixel Buffer"); 304 return NOT_OK; 305 } 306 pb->byteBufferLength = (*env)->GetArrayLength(env, pb->hpixelObject); 307 return OK; 308 } 309 310 // Forward reference 311 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb); 312 313 /* 314 * Resets a pixel buffer to its initial state. Unpins any pixel buffer, 315 * releases the global reference, and resets fields to NULL. Use this 316 * method to dispose the object as well (there is no destroyPixelBuffer). 317 */ 318 static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 319 if (pb->hpixelObject != NULL) { 320 unpinPixelBuffer(env, pb); 321 (*env)->DeleteGlobalRef(env, pb->hpixelObject); 322 pb->hpixelObject = NULL; 323 pb->byteBufferLength = 0; 324 } 325 } 326 327 /* 328 * Pins the data buffer. Returns OK on success, NOT_OK on failure. 329 */ 330 static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 331 if (pb->hpixelObject != NULL) { 332 assert(pb->buf.ip == NULL); 333 pb->buf.bp = (unsigned char *)(*env)->GetPrimitiveArrayCritical 334 (env, pb->hpixelObject, NULL); 335 if (pb->buf.bp == NULL) { 336 return NOT_OK; 337 } 338 } 339 return OK; 340 } 341 342 /* 343 * Unpins the data buffer. 344 */ 345 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 346 347 if (pb->buf.ip != NULL) { 348 assert(pb->hpixelObject != NULL); 349 (*env)->ReleasePrimitiveArrayCritical(env, 350 pb->hpixelObject, 351 pb->buf.ip, 352 0); 353 pb->buf.ip = NULL; 354 } 355 } 356 357 /********************* end PixelBuffer definition *******************/ 358 359 /********************* ImageIOData definition ***********************/ 360 361 #define MAX_BANDS 4 362 #define JPEG_BAND_SIZE 8 363 #define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE) 364 #define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1) 365 #define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1) 366 367 /* The number of possible incoming values to be scaled. */ 368 #define NUM_INPUT_VALUES (1 << 16) 369 370 /* 371 * The principal imageioData object, opaque to I/O direction. 372 * Each JPEGImageReader will have associated with it a 373 * jpeg_decompress_struct, and similarly each JPEGImageWriter will 374 * have associated with it a jpeg_compress_struct. In order to 375 * ensure that these associations persist from one native call to 376 * the next, and to provide a central locus of imageio-specific 377 * data, we define an imageioData struct containing references 378 * to the Java object and the IJG structs. The functions 379 * that manipulate these objects know whether input or output is being 380 * performed and therefore know how to manipulate the contents correctly. 381 * If for some reason they don't, the direction can be determined by 382 * checking the is_decompressor field of the jpegObj. 383 * In order for lower level code to determine a 384 * Java object given an IJG struct, such as for dispatching warnings, 385 * we use the client_data field of the jpeg object to store a pointer 386 * to the imageIOData object. Maintenance of this pointer is performed 387 * exclusively within the following access functions. If you 388 * change that, you run the risk of dangling pointers. 389 */ 390 typedef struct imageIODataStruct { 391 j_common_ptr jpegObj; // Either struct is fine 392 jobject imageIOobj; // A JPEGImageReader or a JPEGImageWriter 393 394 streamBuffer streamBuf; // Buffer for the stream 395 pixelBuffer pixelBuf; // Buffer for pixels 396 397 jboolean abortFlag; // Passed down from Java abort method 398 } imageIOData, *imageIODataPtr; 399 400 /* 401 * Allocate and initialize a new imageIOData object to associate the 402 * jpeg object and the Java object. Returns a pointer to the new object 403 * on success, NULL on failure. 404 */ 405 static imageIODataPtr initImageioData (JNIEnv *env, 406 j_common_ptr cinfo, 407 jobject obj) { 408 409 imageIODataPtr data = (imageIODataPtr) malloc (sizeof(imageIOData)); 410 if (data == NULL) { 411 return NULL; 412 } 413 414 data->jpegObj = cinfo; 415 cinfo->client_data = data; 416 417 #ifdef DEBUG_IIO_JPEG 418 printf("new structures: data is %p, cinfo is %p\n", data, cinfo); 419 #endif 420 421 data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj); 422 if (data->imageIOobj == NULL) { 423 free (data); 424 return NULL; 425 } 426 if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) { 427 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 428 free (data); 429 return NULL; 430 } 431 initPixelBuffer(&data->pixelBuf); 432 433 data->abortFlag = JNI_FALSE; 434 435 return data; 436 } 437 438 /* 439 * Resets the imageIOData object to its initial state, as though 440 * it had just been allocated and initialized. 441 */ 442 static void resetImageIOData(JNIEnv *env, imageIODataPtr data) { 443 resetStreamBuffer(env, &data->streamBuf); 444 resetPixelBuffer(env, &data->pixelBuf); 445 data->abortFlag = JNI_FALSE; 446 } 447 448 /* 449 * Releases all resources held by this object and its subobjects, 450 * frees the object, and returns the jpeg object. This method must 451 * be called to avoid leaking global references. 452 * Note that the jpeg object is not freed or destroyed, as that is 453 * the client's responsibility, although the client_data field is 454 * cleared. 455 */ 456 static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) { 457 j_common_ptr ret = data->jpegObj; 458 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 459 destroyStreamBuffer(env, &data->streamBuf); 460 resetPixelBuffer(env, &data->pixelBuf); 461 ret->client_data = NULL; 462 free(data); 463 return ret; 464 } 465 466 /******************** end ImageIOData definition ***********************/ 467 468 /******************** Java array pinning and unpinning *****************/ 469 470 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid 471 * the need to copy array elements for the above two objects. 472 * 473 * MAKE SURE TO: 474 * 475 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around 476 * callbacks to Java. 477 * - call RELEASE_ARRAYS before returning to Java. 478 * 479 * Otherwise things will go horribly wrong. There may be memory leaks, 480 * excessive pinning, or even VM crashes! 481 * 482 * Note that GetPrimitiveArrayCritical may fail! 483 */ 484 485 /* 486 * Release (unpin) all the arrays in use during a read. 487 */ 488 static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte) 489 { 490 unpinStreamBuffer(env, &data->streamBuf, next_byte); 491 492 unpinPixelBuffer(env, &data->pixelBuf); 493 494 } 495 496 /* 497 * Get (pin) all the arrays in use during a read. 498 */ 499 static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) { 500 if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) { 501 return NOT_OK; 502 } 503 504 if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) { 505 RELEASE_ARRAYS(env, data, *next_byte); 506 return NOT_OK; 507 } 508 return OK; 509 } 510 511 /****** end of Java array pinning and unpinning ***********/ 512 513 /****** Error Handling *******/ 514 515 /* 516 * Set up error handling to use setjmp/longjmp. This is the third such 517 * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes 518 * setup thier own. Ultimately these should be integrated, as they all 519 * do pretty much the same thing. 520 */ 521 522 struct sun_jpeg_error_mgr { 523 struct jpeg_error_mgr pub; /* "public" fields */ 524 525 jmp_buf setjmp_buffer; /* for return to caller */ 526 }; 527 528 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr; 529 530 /* 531 * Here's the routine that will replace the standard error_exit method: 532 */ 533 534 METHODDEF(void) 535 sun_jpeg_error_exit (j_common_ptr cinfo) 536 { 537 /* cinfo->err really points to a sun_jpeg_error_mgr struct */ 538 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err; 539 540 /* For Java, we will format the message and put it in the error we throw. */ 541 542 /* Return control to the setjmp point */ 543 longjmp(myerr->setjmp_buffer, 1); 544 } 545 546 /* 547 * Error Message handling 548 * 549 * This overrides the output_message method to send JPEG messages 550 * 551 */ 552 553 METHODDEF(void) 554 sun_jpeg_output_message (j_common_ptr cinfo) 555 { 556 char buffer[JMSG_LENGTH_MAX]; 557 jstring string; 558 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 559 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 560 jobject theObject; 561 562 /* Create the message */ 563 (*cinfo->err->format_message) (cinfo, buffer); 564 565 // Create a new java string from the message 566 string = (*env)->NewStringUTF(env, buffer); 567 CHECK_NULL(string); 568 569 theObject = data->imageIOobj; 570 571 if (cinfo->is_decompressor) { 572 struct jpeg_source_mgr *src = ((j_decompress_ptr)cinfo)->src; 573 RELEASE_ARRAYS(env, data, src->next_input_byte); 574 (*env)->CallVoidMethod(env, theObject, 575 JPEGImageReader_warningWithMessageID, 576 string); 577 if ((*env)->ExceptionOccurred(env) 578 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 579 cinfo->err->error_exit(cinfo); 580 } 581 } else { 582 struct jpeg_destination_mgr *dest = ((j_compress_ptr)cinfo)->dest; 583 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 584 (*env)->CallVoidMethod(env, theObject, 585 JPEGImageWriter_warningWithMessageID, 586 string); 587 if ((*env)->ExceptionOccurred(env) 588 || !GET_ARRAYS(env, data, 589 (const JOCTET **)(&dest->next_output_byte))) { 590 cinfo->err->error_exit(cinfo); 591 } 592 } 593 } 594 595 /* End of verbatim copy from jpegdecoder.c */ 596 597 /*************** end of error handling *********************/ 598 599 /*************** Shared utility code ***********************/ 600 601 static void imageio_set_stream(JNIEnv *env, 602 j_common_ptr cinfo, 603 imageIODataPtr data, 604 jobject io){ 605 streamBufferPtr sb; 606 sun_jpeg_error_ptr jerr; 607 608 sb = &data->streamBuf; 609 610 resetStreamBuffer(env, sb); // Removes any old stream 611 612 /* Now we need a new weak global reference for the I/O provider */ 613 if (io != NULL) { // Fix for 4411955 614 sb->ioRef = (*env)->NewWeakGlobalRef(env, io); 615 CHECK_NULL(sb->ioRef); 616 } 617 618 /* And finally reset state */ 619 data->abortFlag = JNI_FALSE; 620 621 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 622 jerr = (sun_jpeg_error_ptr) cinfo->err; 623 624 if (setjmp(jerr->setjmp_buffer)) { 625 /* If we get here, the JPEG code has signaled an error 626 while aborting. */ 627 if (!(*env)->ExceptionOccurred(env)) { 628 char buffer[JMSG_LENGTH_MAX]; 629 (*cinfo->err->format_message) (cinfo, 630 buffer); 631 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 632 } 633 return; 634 } 635 636 jpeg_abort(cinfo); // Frees any markers, but not tables 637 638 } 639 640 static void imageio_reset(JNIEnv *env, 641 j_common_ptr cinfo, 642 imageIODataPtr data) { 643 sun_jpeg_error_ptr jerr; 644 645 resetImageIOData(env, data); // Mapping to jpeg object is retained. 646 647 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 648 jerr = (sun_jpeg_error_ptr) cinfo->err; 649 650 if (setjmp(jerr->setjmp_buffer)) { 651 /* If we get here, the JPEG code has signaled an error 652 while aborting. */ 653 if (!(*env)->ExceptionOccurred(env)) { 654 char buffer[JMSG_LENGTH_MAX]; 655 (*cinfo->err->format_message) (cinfo, buffer); 656 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 657 } 658 return; 659 } 660 661 jpeg_abort(cinfo); // Does not reset 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 int setQTables(JNIEnv *env, 690 j_common_ptr cinfo, 691 jobjectArray qtables, 692 boolean write) { 693 jsize qlen; 694 jobject table; 695 jintArray qdata; 696 jint *qdataBody; 697 JQUANT_TBL *quant_ptr; 698 int i, j; 699 j_compress_ptr comp; 700 j_decompress_ptr decomp; 701 702 qlen = (*env)->GetArrayLength(env, qtables); 703 #ifdef DEBUG_IIO_JPEG 704 printf("in setQTables, qlen = %d, write is %d\n", qlen, write); 705 #endif 706 if (qlen > NUM_QUANT_TBLS) { 707 /* Ignore extra qunterization tables. */ 708 qlen = NUM_QUANT_TBLS; 709 } 710 for (i = 0; i < qlen; i++) { 711 table = (*env)->GetObjectArrayElement(env, qtables, i); 712 CHECK_NULL_RETURN(table, 0); 713 qdata = (*env)->GetObjectField(env, table, JPEGQTable_tableID); 714 qdataBody = (*env)->GetPrimitiveArrayCritical(env, qdata, NULL); 715 716 if (cinfo->is_decompressor) { 717 decomp = (j_decompress_ptr) cinfo; 718 if (decomp->quant_tbl_ptrs[i] == NULL) { 719 decomp->quant_tbl_ptrs[i] = 720 jpeg_alloc_quant_table(cinfo); 721 } 722 quant_ptr = decomp->quant_tbl_ptrs[i]; 723 } else { 724 comp = (j_compress_ptr) cinfo; 725 if (comp->quant_tbl_ptrs[i] == NULL) { 726 comp->quant_tbl_ptrs[i] = 727 jpeg_alloc_quant_table(cinfo); 728 } 729 quant_ptr = comp->quant_tbl_ptrs[i]; 730 } 731 732 for (j = 0; j < 64; j++) { 733 quant_ptr->quantval[j] = (UINT16)qdataBody[j]; 734 } 735 quant_ptr->sent_table = !write; 736 (*env)->ReleasePrimitiveArrayCritical(env, 737 qdata, 738 qdataBody, 739 0); 740 } 741 return qlen; 742 } 743 744 static boolean setHuffTable(JNIEnv *env, 745 JHUFF_TBL *huff_ptr, 746 jobject table) { 747 748 jshortArray huffLens; 749 jshortArray huffValues; 750 jshort *hlensBody, *hvalsBody; 751 jsize hlensLen, hvalsLen; 752 int i; 753 754 // lengths 755 huffLens = (*env)->GetObjectField(env, 756 table, 757 JPEGHuffmanTable_lengthsID); 758 hlensLen = (*env)->GetArrayLength(env, huffLens); 759 hlensBody = (*env)->GetShortArrayElements(env, 760 huffLens, 761 NULL); 762 CHECK_NULL_RETURN(hlensBody, FALSE); 763 764 if (hlensLen > 16) { 765 /* Ignore extra elements of bits array. Only 16 elements can be 766 stored. 0-th element is not used. (see jpeglib.h, line 107) */ 767 hlensLen = 16; 768 } 769 for (i = 1; i <= hlensLen; i++) { 770 huff_ptr->bits[i] = (UINT8)hlensBody[i-1]; 771 } 772 (*env)->ReleaseShortArrayElements(env, 773 huffLens, 774 hlensBody, 775 JNI_ABORT); 776 // values 777 huffValues = (*env)->GetObjectField(env, 778 table, 779 JPEGHuffmanTable_valuesID); 780 hvalsLen = (*env)->GetArrayLength(env, huffValues); 781 hvalsBody = (*env)->GetShortArrayElements(env, 782 huffValues, 783 NULL); 784 CHECK_NULL_RETURN(hvalsBody, FALSE); 785 786 if (hvalsLen > 256) { 787 /* Ignore extra elements of hufval array. Only 256 elements 788 can be stored. (see jpeglib.h, line 109) */ 789 hlensLen = 256; 790 } 791 for (i = 0; i < hvalsLen; i++) { 792 huff_ptr->huffval[i] = (UINT8)hvalsBody[i]; 793 } 794 (*env)->ReleaseShortArrayElements(env, 795 huffValues, 796 hvalsBody, 797 JNI_ABORT); 798 return TRUE; 799 } 800 801 static int setHTables(JNIEnv *env, 802 j_common_ptr cinfo, 803 jobjectArray DCHuffmanTables, 804 jobjectArray ACHuffmanTables, 805 boolean write) { 806 int i; 807 jobject table; 808 JHUFF_TBL *huff_ptr; 809 j_compress_ptr comp; 810 j_decompress_ptr decomp; 811 jsize hlen = (*env)->GetArrayLength(env, DCHuffmanTables); 812 813 if (hlen > NUM_HUFF_TBLS) { 814 /* Ignore extra DC huffman tables. */ 815 hlen = NUM_HUFF_TBLS; 816 } 817 for (i = 0; i < hlen; i++) { 818 if (cinfo->is_decompressor) { 819 decomp = (j_decompress_ptr) cinfo; 820 if (decomp->dc_huff_tbl_ptrs[i] == NULL) { 821 decomp->dc_huff_tbl_ptrs[i] = 822 jpeg_alloc_huff_table(cinfo); 823 } 824 huff_ptr = decomp->dc_huff_tbl_ptrs[i]; 825 } else { 826 comp = (j_compress_ptr) cinfo; 827 if (comp->dc_huff_tbl_ptrs[i] == NULL) { 828 comp->dc_huff_tbl_ptrs[i] = 829 jpeg_alloc_huff_table(cinfo); 830 } 831 huff_ptr = comp->dc_huff_tbl_ptrs[i]; 832 } 833 table = (*env)->GetObjectArrayElement(env, DCHuffmanTables, i); 834 if (table == NULL || !setHuffTable(env, huff_ptr, table)) { 835 return 0; 836 } 837 huff_ptr->sent_table = !write; 838 } 839 hlen = (*env)->GetArrayLength(env, ACHuffmanTables); 840 if (hlen > NUM_HUFF_TBLS) { 841 /* Ignore extra AC huffman tables. */ 842 hlen = NUM_HUFF_TBLS; 843 } 844 for (i = 0; i < hlen; i++) { 845 if (cinfo->is_decompressor) { 846 decomp = (j_decompress_ptr) cinfo; 847 if (decomp->ac_huff_tbl_ptrs[i] == NULL) { 848 decomp->ac_huff_tbl_ptrs[i] = 849 jpeg_alloc_huff_table(cinfo); 850 } 851 huff_ptr = decomp->ac_huff_tbl_ptrs[i]; 852 } else { 853 comp = (j_compress_ptr) cinfo; 854 if (comp->ac_huff_tbl_ptrs[i] == NULL) { 855 comp->ac_huff_tbl_ptrs[i] = 856 jpeg_alloc_huff_table(cinfo); 857 } 858 huff_ptr = comp->ac_huff_tbl_ptrs[i]; 859 } 860 table = (*env)->GetObjectArrayElement(env, ACHuffmanTables, i); 861 if(table == NULL || !setHuffTable(env, huff_ptr, table)) { 862 return 0; 863 } 864 huff_ptr->sent_table = !write; 865 } 866 return hlen; 867 } 868 869 870 /*************** end of shared utility code ****************/ 871 872 /********************** Reader Support **************************/ 873 874 /********************** Source Management ***********************/ 875 876 /* 877 * INPUT HANDLING: 878 * 879 * The JPEG library's input management is defined by the jpeg_source_mgr 880 * structure which contains two fields to convey the information in the 881 * buffer and 5 methods which perform all buffer management. The library 882 * defines a standard input manager that uses stdio for obtaining compressed 883 * jpeg data, but here we need to use Java to get our data. 884 * 885 * We use the library jpeg_source_mgr but our own routines that access 886 * imageio-specific information in the imageIOData structure. 887 */ 888 889 /* 890 * Initialize source. This is called by jpeg_read_header() before any 891 * data is actually read. Unlike init_destination(), it may leave 892 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call 893 * will occur immediately). 894 */ 895 896 GLOBAL(void) 897 imageio_init_source(j_decompress_ptr cinfo) 898 { 899 struct jpeg_source_mgr *src = cinfo->src; 900 src->next_input_byte = NULL; 901 src->bytes_in_buffer = 0; 902 } 903 904 /* 905 * This is called whenever bytes_in_buffer has reached zero and more 906 * data is wanted. In typical applications, it should read fresh data 907 * into the buffer (ignoring the current state of next_input_byte and 908 * bytes_in_buffer), reset the pointer & count to the start of the 909 * buffer, and return TRUE indicating that the buffer has been reloaded. 910 * It is not necessary to fill the buffer entirely, only to obtain at 911 * least one more byte. bytes_in_buffer MUST be set to a positive value 912 * if TRUE is returned. A FALSE return should only be used when I/O 913 * suspension is desired (this mode is discussed in the next section). 914 */ 915 /* 916 * Note that with I/O suspension turned on, this procedure should not 917 * do any work since the JPEG library has a very simple backtracking 918 * mechanism which relies on the fact that the buffer will be filled 919 * only when it has backed out to the top application level. When 920 * suspendable is turned on, imageio_fill_suspended_buffer will 921 * do the actual work of filling the buffer. 922 */ 923 924 GLOBAL(boolean) 925 imageio_fill_input_buffer(j_decompress_ptr cinfo) 926 { 927 struct jpeg_source_mgr *src = cinfo->src; 928 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 929 streamBufferPtr sb = &data->streamBuf; 930 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 931 int ret; 932 jobject input = NULL; 933 934 /* This is where input suspends */ 935 if (sb->suspendable) { 936 return FALSE; 937 } 938 939 #ifdef DEBUG_IIO_JPEG 940 printf("Filling input buffer, remaining skip is %ld, ", 941 sb->remaining_skip); 942 printf("Buffer length is %d\n", sb->bufferLength); 943 #endif 944 945 /* 946 * Definitively skips. Could be left over if we tried to skip 947 * more than a buffer's worth but suspended when getting the next 948 * buffer. Now we aren't suspended, so we can catch up. 949 */ 950 if (sb->remaining_skip) { 951 src->skip_input_data(cinfo, 0); 952 } 953 954 /* 955 * Now fill a complete buffer, or as much of one as the stream 956 * will give us if we are near the end. 957 */ 958 RELEASE_ARRAYS(env, data, src->next_input_byte); 959 960 GET_IO_REF(input); 961 962 ret = (*env)->CallIntMethod(env, 963 input, 964 JPEGImageReader_readInputDataID, 965 sb->hstreamBuffer, 0, 966 sb->bufferLength); 967 if ((ret > 0) && ((unsigned int)ret > sb->bufferLength)) { 968 ret = (int)sb->bufferLength; 969 } 970 if ((*env)->ExceptionOccurred(env) 971 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 972 cinfo->err->error_exit((j_common_ptr) cinfo); 973 } 974 975 #ifdef DEBUG_IIO_JPEG 976 printf("Buffer filled. ret = %d\n", ret); 977 #endif 978 /* 979 * If we have reached the end of the stream, then the EOI marker 980 * is missing. We accept such streams but generate a warning. 981 * The image is likely to be corrupted, though everything through 982 * the end of the last complete MCU should be usable. 983 */ 984 if (ret <= 0) { 985 jobject reader = data->imageIOobj; 986 #ifdef DEBUG_IIO_JPEG 987 printf("YO! Early EOI! ret = %d\n", ret); 988 #endif 989 RELEASE_ARRAYS(env, data, src->next_input_byte); 990 (*env)->CallVoidMethod(env, reader, 991 JPEGImageReader_warningOccurredID, 992 READ_NO_EOI); 993 if ((*env)->ExceptionOccurred(env) 994 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 995 cinfo->err->error_exit((j_common_ptr) cinfo); 996 } 997 998 sb->buf[0] = (JOCTET) 0xFF; 999 sb->buf[1] = (JOCTET) JPEG_EOI; 1000 ret = 2; 1001 } 1002 1003 src->next_input_byte = sb->buf; 1004 src->bytes_in_buffer = ret; 1005 1006 return TRUE; 1007 } 1008 1009 /* 1010 * With I/O suspension turned on, the JPEG library requires that all 1011 * buffer filling be done at the top application level, using this 1012 * function. Due to the way that backtracking works, this procedure 1013 * saves all of the data that was left in the buffer when suspension 1014 * occurred and read new data only at the end. 1015 */ 1016 1017 GLOBAL(void) 1018 imageio_fill_suspended_buffer(j_decompress_ptr cinfo) 1019 { 1020 struct jpeg_source_mgr *src = cinfo->src; 1021 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 1022 streamBufferPtr sb = &data->streamBuf; 1023 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1024 jint ret; 1025 size_t offset, buflen; 1026 jobject input = NULL; 1027 1028 /* 1029 * The original (jpegdecoder.c) had code here that called 1030 * InputStream.available and just returned if the number of bytes 1031 * available was less than any remaining skip. Presumably this was 1032 * to avoid blocking, although the benefit was unclear, as no more 1033 * decompression can take place until more data is available, so 1034 * the code would block on input a little further along anyway. 1035 * ImageInputStreams don't have an available method, so we'll just 1036 * block in the skip if we have to. 1037 */ 1038 1039 if (sb->remaining_skip) { 1040 src->skip_input_data(cinfo, 0); 1041 } 1042 1043 /* Save the data currently in the buffer */ 1044 offset = src->bytes_in_buffer; 1045 if (src->next_input_byte > sb->buf) { 1046 memcpy(sb->buf, src->next_input_byte, offset); 1047 } 1048 1049 1050 RELEASE_ARRAYS(env, data, src->next_input_byte); 1051 1052 GET_IO_REF(input); 1053 1054 buflen = sb->bufferLength - offset; 1055 if (buflen <= 0) { 1056 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) { 1057 cinfo->err->error_exit((j_common_ptr) cinfo); 1058 } 1059 RELEASE_ARRAYS(env, data, src->next_input_byte); 1060 return; 1061 } 1062 1063 ret = (*env)->CallIntMethod(env, input, 1064 JPEGImageReader_readInputDataID, 1065 sb->hstreamBuffer, 1066 offset, buflen); 1067 if ((ret > 0) && ((unsigned int)ret > buflen)) ret = (int)buflen; 1068 if ((*env)->ExceptionOccurred(env) 1069 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1070 cinfo->err->error_exit((j_common_ptr) cinfo); 1071 } 1072 /* 1073 * If we have reached the end of the stream, then the EOI marker 1074 * is missing. We accept such streams but generate a warning. 1075 * The image is likely to be corrupted, though everything through 1076 * the end of the last complete MCU should be usable. 1077 */ 1078 if (ret <= 0) { 1079 jobject reader = data->imageIOobj; 1080 RELEASE_ARRAYS(env, data, src->next_input_byte); 1081 (*env)->CallVoidMethod(env, reader, 1082 JPEGImageReader_warningOccurredID, 1083 READ_NO_EOI); 1084 if ((*env)->ExceptionOccurred(env) 1085 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1086 cinfo->err->error_exit((j_common_ptr) cinfo); 1087 } 1088 1089 sb->buf[offset] = (JOCTET) 0xFF; 1090 sb->buf[offset + 1] = (JOCTET) JPEG_EOI; 1091 ret = 2; 1092 } 1093 1094 src->next_input_byte = sb->buf; 1095 src->bytes_in_buffer = ret + offset; 1096 1097 return; 1098 } 1099 1100 /* 1101 * Skip num_bytes worth of data. The buffer pointer and count are 1102 * advanced over num_bytes input bytes, using the input stream 1103 * skipBytes method if the skip is greater than the number of bytes 1104 * in the buffer. This is used to skip over a potentially large amount of 1105 * uninteresting data (such as an APPn marker). bytes_in_buffer will be 1106 * zero on return if the skip is larger than the current contents of the 1107 * buffer. 1108 * 1109 * A negative skip count is treated as a no-op. A zero skip count 1110 * skips any remaining skip from a previous skip while suspended. 1111 * 1112 * Note that with I/O suspension turned on, this procedure does not 1113 * call skipBytes since the JPEG library has a very simple backtracking 1114 * mechanism which relies on the fact that the application level has 1115 * exclusive control over actual I/O. 1116 */ 1117 1118 GLOBAL(void) 1119 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 1120 { 1121 struct jpeg_source_mgr *src = cinfo->src; 1122 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 1123 streamBufferPtr sb = &data->streamBuf; 1124 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1125 jlong ret; 1126 jobject reader; 1127 jobject input = NULL; 1128 1129 if (num_bytes < 0) { 1130 return; 1131 } 1132 num_bytes += sb->remaining_skip; 1133 sb->remaining_skip = 0; 1134 1135 /* First the easy case where we are skipping <= the current contents. */ 1136 ret = src->bytes_in_buffer; 1137 if (ret >= num_bytes) { 1138 src->next_input_byte += num_bytes; 1139 src->bytes_in_buffer -= num_bytes; 1140 return; 1141 } 1142 1143 /* 1144 * We are skipping more than is in the buffer. We empty the buffer and, 1145 * if we aren't suspended, call the Java skipBytes method. We always 1146 * leave the buffer empty, to be filled by either fill method above. 1147 */ 1148 src->bytes_in_buffer = 0; 1149 src->next_input_byte = sb->buf; 1150 1151 num_bytes -= (long)ret; 1152 if (sb->suspendable) { 1153 sb->remaining_skip = num_bytes; 1154 return; 1155 } 1156 1157 RELEASE_ARRAYS(env, data, src->next_input_byte); 1158 1159 GET_IO_REF(input); 1160 1161 ret = (*env)->CallLongMethod(env, 1162 input, 1163 JPEGImageReader_skipInputBytesID, 1164 (jlong) num_bytes); 1165 if ((*env)->ExceptionOccurred(env) 1166 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1167 cinfo->err->error_exit((j_common_ptr) cinfo); 1168 } 1169 1170 /* 1171 * If we have reached the end of the stream, then the EOI marker 1172 * is missing. We accept such streams but generate a warning. 1173 * The image is likely to be corrupted, though everything through 1174 * the end of the last complete MCU should be usable. 1175 */ 1176 if (ret <= 0) { 1177 reader = data->imageIOobj; 1178 RELEASE_ARRAYS(env, data, src->next_input_byte); 1179 (*env)->CallVoidMethod(env, 1180 reader, 1181 JPEGImageReader_warningOccurredID, 1182 READ_NO_EOI); 1183 1184 if ((*env)->ExceptionOccurred(env) 1185 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1186 cinfo->err->error_exit((j_common_ptr) cinfo); 1187 } 1188 sb->buf[0] = (JOCTET) 0xFF; 1189 sb->buf[1] = (JOCTET) JPEG_EOI; 1190 src->bytes_in_buffer = 2; 1191 src->next_input_byte = sb->buf; 1192 } 1193 } 1194 1195 /* 1196 * Terminate source --- called by jpeg_finish_decompress() after all 1197 * data for an image has been read. In our case pushes back any 1198 * remaining data, as it will be for another image and must be available 1199 * for java to find out that there is another image. Also called if 1200 * reseting state after reading a tables-only image. 1201 */ 1202 1203 GLOBAL(void) 1204 imageio_term_source(j_decompress_ptr cinfo) 1205 { 1206 // To pushback, just seek back by src->bytes_in_buffer 1207 struct jpeg_source_mgr *src = cinfo->src; 1208 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 1209 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1210 jobject reader = data->imageIOobj; 1211 if (src->bytes_in_buffer > 0) { 1212 RELEASE_ARRAYS(env, data, src->next_input_byte); 1213 (*env)->CallVoidMethod(env, 1214 reader, 1215 JPEGImageReader_pushBackID, 1216 src->bytes_in_buffer); 1217 1218 if ((*env)->ExceptionOccurred(env) 1219 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1220 cinfo->err->error_exit((j_common_ptr) cinfo); 1221 } 1222 src->bytes_in_buffer = 0; 1223 //src->next_input_byte = sb->buf; 1224 } 1225 } 1226 1227 /********************* end of source manager ******************/ 1228 1229 /********************* ICC profile support ********************/ 1230 /* 1231 * The following routines are modified versions of the ICC 1232 * profile support routines available from the IJG website. 1233 * The originals were written by Todd Newman 1234 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for 1235 * the IJG. They are further modified to fit in the context 1236 * of the imageio JPEG plug-in. 1237 */ 1238 1239 /* 1240 * Since an ICC profile can be larger than the maximum size of a JPEG marker 1241 * (64K), we need provisions to split it into multiple markers. The format 1242 * defined by the ICC specifies one or more APP2 markers containing the 1243 * following data: 1244 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes) 1245 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte) 1246 * Number of markers Total number of APP2's used (1 byte) 1247 * Profile data (remainder of APP2 data) 1248 * Decoders should use the marker sequence numbers to reassemble the profile, 1249 * rather than assuming that the APP2 markers appear in the correct sequence. 1250 */ 1251 1252 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ 1253 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ 1254 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ 1255 #define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) 1256 1257 1258 /* 1259 * Handy subroutine to test whether a saved marker is an ICC profile marker. 1260 */ 1261 1262 static boolean 1263 marker_is_icc (jpeg_saved_marker_ptr marker) 1264 { 1265 return 1266 marker->marker == ICC_MARKER && 1267 marker->data_length >= ICC_OVERHEAD_LEN && 1268 /* verify the identifying string */ 1269 GETJOCTET(marker->data[0]) == 0x49 && 1270 GETJOCTET(marker->data[1]) == 0x43 && 1271 GETJOCTET(marker->data[2]) == 0x43 && 1272 GETJOCTET(marker->data[3]) == 0x5F && 1273 GETJOCTET(marker->data[4]) == 0x50 && 1274 GETJOCTET(marker->data[5]) == 0x52 && 1275 GETJOCTET(marker->data[6]) == 0x4F && 1276 GETJOCTET(marker->data[7]) == 0x46 && 1277 GETJOCTET(marker->data[8]) == 0x49 && 1278 GETJOCTET(marker->data[9]) == 0x4C && 1279 GETJOCTET(marker->data[10]) == 0x45 && 1280 GETJOCTET(marker->data[11]) == 0x0; 1281 } 1282 1283 /* 1284 * See if there was an ICC profile in the JPEG file being read; 1285 * if so, reassemble and return the profile data as a new Java byte array. 1286 * If there was no ICC profile, return NULL. 1287 * 1288 * If the file contains invalid ICC APP2 markers, we throw an IIOException 1289 * with an appropriate message. 1290 */ 1291 1292 jbyteArray 1293 read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo) 1294 { 1295 jpeg_saved_marker_ptr marker; 1296 int num_markers = 0; 1297 int num_found_markers = 0; 1298 int seq_no; 1299 JOCTET *icc_data; 1300 JOCTET *dst_ptr; 1301 unsigned int total_length; 1302 #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes 1303 jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1]; 1304 int first; // index of the first marker in the icc_markers array 1305 int last; // index of the last marker in the icc_markers array 1306 jbyteArray data = NULL; 1307 1308 /* This first pass over the saved markers discovers whether there are 1309 * any ICC markers and verifies the consistency of the marker numbering. 1310 */ 1311 1312 for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++) 1313 icc_markers[seq_no] = NULL; 1314 1315 1316 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { 1317 if (marker_is_icc(marker)) { 1318 if (num_markers == 0) 1319 num_markers = GETJOCTET(marker->data[13]); 1320 else if (num_markers != GETJOCTET(marker->data[13])) { 1321 JNU_ThrowByName(env, "javax/imageio/IIOException", 1322 "Invalid icc profile: inconsistent num_markers fields"); 1323 return NULL; 1324 } 1325 seq_no = GETJOCTET(marker->data[12]); 1326 1327 /* Some third-party tools produce images with profile chunk 1328 * numeration started from zero. It is inconsistent with ICC 1329 * spec, but seems to be recognized by majority of image 1330 * processing tools, so we should be more tolerant to this 1331 * departure from the spec. 1332 */ 1333 if (seq_no < 0 || seq_no > num_markers) { 1334 JNU_ThrowByName(env, "javax/imageio/IIOException", 1335 "Invalid icc profile: bad sequence number"); 1336 return NULL; 1337 } 1338 if (icc_markers[seq_no] != NULL) { 1339 JNU_ThrowByName(env, "javax/imageio/IIOException", 1340 "Invalid icc profile: duplicate sequence numbers"); 1341 return NULL; 1342 } 1343 icc_markers[seq_no] = marker; 1344 num_found_markers ++; 1345 } 1346 } 1347 1348 if (num_markers == 0) 1349 return NULL; // There is no profile 1350 1351 if (num_markers != num_found_markers) { 1352 JNU_ThrowByName(env, "javax/imageio/IIOException", 1353 "Invalid icc profile: invalid number of icc markers"); 1354 return NULL; 1355 } 1356 1357 first = icc_markers[0] ? 0 : 1; 1358 last = num_found_markers + first; 1359 1360 /* Check for missing markers, count total space needed. 1361 */ 1362 total_length = 0; 1363 for (seq_no = first; seq_no < last; seq_no++) { 1364 unsigned int length; 1365 if (icc_markers[seq_no] == NULL) { 1366 JNU_ThrowByName(env, "javax/imageio/IIOException", 1367 "Invalid icc profile: missing sequence number"); 1368 return NULL; 1369 } 1370 /* check the data length correctness */ 1371 length = icc_markers[seq_no]->data_length; 1372 if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) { 1373 JNU_ThrowByName(env, "javax/imageio/IIOException", 1374 "Invalid icc profile: invalid data length"); 1375 return NULL; 1376 } 1377 total_length += (length - ICC_OVERHEAD_LEN); 1378 } 1379 1380 if (total_length <= 0) { 1381 JNU_ThrowByName(env, "javax/imageio/IIOException", 1382 "Invalid icc profile: found only empty markers"); 1383 return NULL; 1384 } 1385 1386 /* Allocate a Java byte array for assembled data */ 1387 1388 data = (*env)->NewByteArray(env, total_length); 1389 if (data == NULL) { 1390 JNU_ThrowByName(env, 1391 "java/lang/OutOfMemoryError", 1392 "Reading ICC profile"); 1393 return NULL; 1394 } 1395 1396 icc_data = (JOCTET *)(*env)->GetPrimitiveArrayCritical(env, 1397 data, 1398 NULL); 1399 if (icc_data == NULL) { 1400 JNU_ThrowByName(env, "javax/imageio/IIOException", 1401 "Unable to pin icc profile data array"); 1402 return NULL; 1403 } 1404 1405 /* and fill it in */ 1406 dst_ptr = icc_data; 1407 for (seq_no = first; seq_no < last; seq_no++) { 1408 JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN; 1409 unsigned int length = 1410 icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN; 1411 1412 memcpy(dst_ptr, src_ptr, length); 1413 dst_ptr += length; 1414 } 1415 1416 /* finally, unpin the array */ 1417 (*env)->ReleasePrimitiveArrayCritical(env, 1418 data, 1419 icc_data, 1420 0); 1421 1422 1423 return data; 1424 } 1425 1426 /********************* end of ICC profile support *************/ 1427 1428 /********************* Reader JNI calls ***********************/ 1429 1430 JNIEXPORT void JNICALL 1431 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initReaderIDs 1432 (JNIEnv *env, 1433 jclass cls, 1434 jclass ImageInputStreamClass, 1435 jclass qTableClass, 1436 jclass huffClass) { 1437 1438 CHECK_NULL(JPEGImageReader_readInputDataID = (*env)->GetMethodID(env, 1439 cls, 1440 "readInputData", 1441 "([BII)I")); 1442 CHECK_NULL(JPEGImageReader_skipInputBytesID = (*env)->GetMethodID(env, 1443 cls, 1444 "skipInputBytes", 1445 "(J)J")); 1446 CHECK_NULL(JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env, 1447 cls, 1448 "warningOccurred", 1449 "(I)V")); 1450 CHECK_NULL(JPEGImageReader_warningWithMessageID = 1451 (*env)->GetMethodID(env, 1452 cls, 1453 "warningWithMessage", 1454 "(Ljava/lang/String;)V")); 1455 CHECK_NULL(JPEGImageReader_setImageDataID = (*env)->GetMethodID(env, 1456 cls, 1457 "setImageData", 1458 "(IIIII[B)V")); 1459 CHECK_NULL(JPEGImageReader_acceptPixelsID = (*env)->GetMethodID(env, 1460 cls, 1461 "acceptPixels", 1462 "(IZ)V")); 1463 CHECK_NULL(JPEGImageReader_passStartedID = (*env)->GetMethodID(env, 1464 cls, 1465 "passStarted", 1466 "(I)V")); 1467 CHECK_NULL(JPEGImageReader_passCompleteID = (*env)->GetMethodID(env, 1468 cls, 1469 "passComplete", 1470 "()V")); 1471 CHECK_NULL(JPEGImageReader_pushBackID = (*env)->GetMethodID(env, 1472 cls, 1473 "pushBack", 1474 "(I)V")); 1475 CHECK_NULL(JPEGQTable_tableID = (*env)->GetFieldID(env, 1476 qTableClass, 1477 "qTable", 1478 "[I")); 1479 1480 CHECK_NULL(JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env, 1481 huffClass, 1482 "lengths", 1483 "[S")); 1484 1485 CHECK_NULL(JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env, 1486 huffClass, 1487 "values", 1488 "[S")); 1489 } 1490 1491 JNIEXPORT jlong JNICALL 1492 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader 1493 (JNIEnv *env, 1494 jobject this) { 1495 1496 imageIODataPtr ret; 1497 struct sun_jpeg_error_mgr *jerr; 1498 1499 /* This struct contains the JPEG decompression parameters and pointers to 1500 * working space (which is allocated as needed by the JPEG library). 1501 */ 1502 struct jpeg_decompress_struct *cinfo = 1503 malloc(sizeof(struct jpeg_decompress_struct)); 1504 if (cinfo == NULL) { 1505 JNU_ThrowByName( env, 1506 "java/lang/OutOfMemoryError", 1507 "Initializing Reader"); 1508 return 0; 1509 } 1510 1511 /* We use our private extension JPEG error handler. 1512 */ 1513 jerr = malloc (sizeof(struct sun_jpeg_error_mgr)); 1514 if (jerr == NULL) { 1515 JNU_ThrowByName( env, 1516 "java/lang/OutOfMemoryError", 1517 "Initializing Reader"); 1518 free(cinfo); 1519 return 0; 1520 } 1521 1522 /* We set up the normal JPEG error routines, then override error_exit. */ 1523 cinfo->err = jpeg_std_error(&(jerr->pub)); 1524 jerr->pub.error_exit = sun_jpeg_error_exit; 1525 /* We need to setup our own print routines */ 1526 jerr->pub.output_message = sun_jpeg_output_message; 1527 /* Now we can setjmp before every call to the library */ 1528 1529 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1530 if (setjmp(jerr->setjmp_buffer)) { 1531 /* If we get here, the JPEG code has signaled an error. */ 1532 char buffer[JMSG_LENGTH_MAX]; 1533 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1534 buffer); 1535 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 1536 return 0; 1537 } 1538 1539 /* Perform library initialization */ 1540 jpeg_create_decompress(cinfo); 1541 1542 // Set up to keep any APP2 markers, as these might contain ICC profile 1543 // data 1544 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF); 1545 1546 /* 1547 * Now set up our source. 1548 */ 1549 cinfo->src = 1550 (struct jpeg_source_mgr *) malloc (sizeof(struct jpeg_source_mgr)); 1551 if (cinfo->src == NULL) { 1552 JNU_ThrowByName(env, 1553 "java/lang/OutOfMemoryError", 1554 "Initializing Reader"); 1555 imageio_dispose((j_common_ptr)cinfo); 1556 return 0; 1557 } 1558 cinfo->src->bytes_in_buffer = 0; 1559 cinfo->src->next_input_byte = NULL; 1560 cinfo->src->init_source = imageio_init_source; 1561 cinfo->src->fill_input_buffer = imageio_fill_input_buffer; 1562 cinfo->src->skip_input_data = imageio_skip_input_data; 1563 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default 1564 cinfo->src->term_source = imageio_term_source; 1565 1566 /* set up the association to persist for future calls */ 1567 ret = initImageioData(env, (j_common_ptr) cinfo, this); 1568 if (ret == NULL) { 1569 (*env)->ExceptionClear(env); 1570 JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 1571 "Initializing Reader"); 1572 imageio_dispose((j_common_ptr)cinfo); 1573 return 0; 1574 } 1575 return ptr_to_jlong(ret); 1576 } 1577 1578 /* 1579 * When we set a source from Java, we set up the stream in the streamBuf 1580 * object. If there was an old one, it is released first. 1581 */ 1582 1583 JNIEXPORT void JNICALL 1584 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource 1585 (JNIEnv *env, 1586 jobject this, 1587 jlong ptr) { 1588 1589 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 1590 j_common_ptr cinfo; 1591 1592 if (data == NULL) { 1593 JNU_ThrowByName(env, 1594 "java/lang/IllegalStateException", 1595 "Attempting to use reader after dispose()"); 1596 return; 1597 } 1598 1599 cinfo = data->jpegObj; 1600 1601 imageio_set_stream(env, cinfo, data, this); 1602 1603 imageio_init_source((j_decompress_ptr) cinfo); 1604 } 1605 1606 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */ 1607 1608 /* 1609 * For EXIF images, the APP1 will appear immediately after the SOI, 1610 * so it's safe to only look at the first marker in the list. 1611 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58) 1612 */ 1613 #define IS_EXIF(c) \ 1614 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1)) 1615 1616 JNIEXPORT jboolean JNICALL 1617 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader 1618 (JNIEnv *env, 1619 jobject this, 1620 jlong ptr, 1621 jboolean clearFirst, 1622 jboolean reset) { 1623 1624 int ret; 1625 int h_samp0, h_samp1, h_samp2; 1626 int v_samp0, v_samp1, v_samp2; 1627 int cid0, cid1, cid2; 1628 jboolean retval = JNI_FALSE; 1629 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 1630 j_decompress_ptr cinfo; 1631 struct jpeg_source_mgr *src; 1632 sun_jpeg_error_ptr jerr; 1633 jbyteArray profileData = NULL; 1634 1635 if (data == NULL) { 1636 JNU_ThrowByName(env, 1637 "java/lang/IllegalStateException", 1638 "Attempting to use reader after dispose()"); 1639 return JNI_FALSE; 1640 } 1641 1642 cinfo = (j_decompress_ptr) data->jpegObj; 1643 src = cinfo->src; 1644 1645 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1646 jerr = (sun_jpeg_error_ptr) cinfo->err; 1647 1648 if (setjmp(jerr->setjmp_buffer)) { 1649 /* If we get here, the JPEG code has signaled an error 1650 while reading the header. */ 1651 RELEASE_ARRAYS(env, data, src->next_input_byte); 1652 if (!(*env)->ExceptionOccurred(env)) { 1653 char buffer[JMSG_LENGTH_MAX]; 1654 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1655 buffer); 1656 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 1657 } 1658 return retval; 1659 } 1660 1661 #ifdef DEBUG_IIO_JPEG 1662 printf("In readImageHeader, data is %p cinfo is %p\n", data, cinfo); 1663 printf("clearFirst is %d\n", clearFirst); 1664 #endif 1665 1666 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) { 1667 (*env)->ExceptionClear(env); 1668 JNU_ThrowByName(env, 1669 "javax/imageio/IIOException", 1670 "Array pin failed"); 1671 return retval; 1672 } 1673 1674 /* 1675 * Now clear the input buffer if the Java code has done a seek 1676 * on the stream since the last call, invalidating any buffer contents. 1677 */ 1678 if (clearFirst) { 1679 clearStreamBuffer(&data->streamBuf); 1680 src->next_input_byte = NULL; 1681 src->bytes_in_buffer = 0; 1682 } 1683 1684 ret = jpeg_read_header(cinfo, FALSE); 1685 1686 if (ret == JPEG_HEADER_TABLES_ONLY) { 1687 retval = JNI_TRUE; 1688 imageio_term_source(cinfo); // Pushback remaining buffer contents 1689 #ifdef DEBUG_IIO_JPEG 1690 printf("just read tables-only image; q table 0 at %p\n", 1691 cinfo->quant_tbl_ptrs[0]); 1692 #endif 1693 RELEASE_ARRAYS(env, data, src->next_input_byte); 1694 } else { 1695 /* 1696 * Now adjust the jpeg_color_space variable, which was set in 1697 * default_decompress_parms, to reflect our differences from IJG 1698 */ 1699 1700 switch (cinfo->jpeg_color_space) { 1701 default : 1702 break; 1703 case JCS_YCbCr: 1704 1705 /* 1706 * There are several possibilities: 1707 * - we got image with embeded colorspace 1708 * Use it. User knows what he is doing. 1709 * - we got JFIF image 1710 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2) 1711 * - we got EXIF image 1712 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63) 1713 * - something else 1714 * Apply heuristical rules to identify actual colorspace. 1715 */ 1716 1717 if (cinfo->saw_Adobe_marker) { 1718 if (cinfo->Adobe_transform != 1) { 1719 /* 1720 * IJG guesses this is YCbCr and emits a warning 1721 * We would rather not guess. Then the user knows 1722 * To read this as a Raster if at all 1723 */ 1724 cinfo->jpeg_color_space = JCS_UNKNOWN; 1725 cinfo->out_color_space = JCS_UNKNOWN; 1726 } 1727 } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) { 1728 /* 1729 * In the absence of certain markers, IJG has interpreted 1730 * component id's of [1,2,3] as meaning YCbCr.We follow that 1731 * interpretation, which is additionally described in the Image 1732 * I/O JPEG metadata spec.If that condition is not met here the 1733 * next step will be to examine the subsampling factors, if 1734 * there is any difference in subsampling factors we also assume 1735 * YCbCr, only if both horizontal and vertical subsampling 1736 * is same we assume JPEG color space as RGB. 1737 * This is also described in the Image I/O JPEG metadata spec. 1738 */ 1739 h_samp0 = cinfo->comp_info[0].h_samp_factor; 1740 h_samp1 = cinfo->comp_info[1].h_samp_factor; 1741 h_samp2 = cinfo->comp_info[2].h_samp_factor; 1742 1743 v_samp0 = cinfo->comp_info[0].v_samp_factor; 1744 v_samp1 = cinfo->comp_info[1].v_samp_factor; 1745 v_samp2 = cinfo->comp_info[2].v_samp_factor; 1746 1747 cid0 = cinfo->comp_info[0].component_id; 1748 cid1 = cinfo->comp_info[1].component_id; 1749 cid2 = cinfo->comp_info[2].component_id; 1750 1751 if ((!(cid0 == 1 && cid1 == 2 && cid2 == 3)) && 1752 ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) && 1753 (v_samp1 == v_samp0) && (v_samp2 == v_samp0))) 1754 { 1755 cinfo->jpeg_color_space = JCS_RGB; 1756 /* output is already RGB, so it stays the same */ 1757 } 1758 } 1759 break; 1760 #ifdef YCCALPHA 1761 case JCS_YCC: 1762 cinfo->out_color_space = JCS_YCC; 1763 break; 1764 #endif 1765 case JCS_YCCK: 1766 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) { 1767 /* 1768 * IJG guesses this is YCCK and emits a warning 1769 * We would rather not guess. Then the user knows 1770 * To read this as a Raster if at all 1771 */ 1772 cinfo->jpeg_color_space = JCS_UNKNOWN; 1773 cinfo->out_color_space = JCS_UNKNOWN; 1774 } 1775 break; 1776 case JCS_CMYK: 1777 /* 1778 * IJG assumes all unidentified 4-channels are CMYK. 1779 * We assume that only if the second two channels are 1780 * not subsampled (either horizontally or vertically). 1781 * If they are, we assume YCCK. 1782 */ 1783 h_samp0 = cinfo->comp_info[0].h_samp_factor; 1784 h_samp1 = cinfo->comp_info[1].h_samp_factor; 1785 h_samp2 = cinfo->comp_info[2].h_samp_factor; 1786 1787 v_samp0 = cinfo->comp_info[0].v_samp_factor; 1788 v_samp1 = cinfo->comp_info[1].v_samp_factor; 1789 v_samp2 = cinfo->comp_info[2].v_samp_factor; 1790 1791 if (((h_samp1 > h_samp0) && (h_samp2 > h_samp0)) || 1792 ((v_samp1 > v_samp0) && (v_samp2 > v_samp0))) 1793 { 1794 cinfo->jpeg_color_space = JCS_YCCK; 1795 /* Leave the output space as CMYK */ 1796 } 1797 } 1798 RELEASE_ARRAYS(env, data, src->next_input_byte); 1799 1800 /* read icc profile data */ 1801 profileData = read_icc_profile(env, cinfo); 1802 1803 if ((*env)->ExceptionCheck(env)) { 1804 return retval; 1805 } 1806 1807 (*env)->CallVoidMethod(env, this, 1808 JPEGImageReader_setImageDataID, 1809 cinfo->image_width, 1810 cinfo->image_height, 1811 cinfo->jpeg_color_space, 1812 cinfo->out_color_space, 1813 cinfo->num_components, 1814 profileData); 1815 if ((*env)->ExceptionOccurred(env) 1816 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1817 cinfo->err->error_exit((j_common_ptr) cinfo); 1818 } 1819 if (reset) { 1820 jpeg_abort_decompress(cinfo); 1821 } 1822 RELEASE_ARRAYS(env, data, src->next_input_byte); 1823 } 1824 1825 return retval; 1826 } 1827 1828 1829 JNIEXPORT void JNICALL 1830 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setOutColorSpace 1831 (JNIEnv *env, 1832 jobject this, 1833 jlong ptr, 1834 jint code) { 1835 1836 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 1837 j_decompress_ptr cinfo; 1838 1839 if (data == NULL) { 1840 JNU_ThrowByName(env, 1841 "java/lang/IllegalStateException", 1842 "Attempting to use reader after dispose()"); 1843 return; 1844 } 1845 1846 cinfo = (j_decompress_ptr) data->jpegObj; 1847 1848 cinfo->out_color_space = code; 1849 1850 } 1851 1852 JNIEXPORT jboolean JNICALL 1853 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage 1854 (JNIEnv *env, 1855 jobject this, 1856 jlong ptr, 1857 jbyteArray buffer, 1858 jint numBands, 1859 jintArray srcBands, 1860 jintArray bandSizes, 1861 jint sourceXStart, 1862 jint sourceYStart, 1863 jint sourceWidth, 1864 jint sourceHeight, 1865 jint stepX, 1866 jint stepY, 1867 jobjectArray qtables, 1868 jobjectArray DCHuffmanTables, 1869 jobjectArray ACHuffmanTables, 1870 jint minProgressivePass, // Counts from 0 1871 jint maxProgressivePass, 1872 jboolean wantUpdates) { 1873 1874 1875 struct jpeg_source_mgr *src; 1876 JSAMPROW scanLinePtr = NULL; 1877 jint bands[MAX_BANDS]; 1878 int i; 1879 jint *body; 1880 int scanlineLimit; 1881 int pixelStride; 1882 unsigned char *in, *out, *pixelLimit; 1883 int targetLine; 1884 int skipLines, linesLeft; 1885 pixelBufferPtr pb; 1886 sun_jpeg_error_ptr jerr; 1887 boolean done; 1888 boolean progressive = FALSE; 1889 boolean orderedBands = TRUE; 1890 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 1891 j_decompress_ptr cinfo; 1892 size_t numBytes; 1893 1894 /* verify the inputs */ 1895 1896 if (data == NULL) { 1897 JNU_ThrowByName(env, 1898 "java/lang/IllegalStateException", 1899 "Attempting to use reader after dispose()"); 1900 return JNI_FALSE; 1901 } 1902 1903 if ((buffer == NULL) || (srcBands == NULL)) { 1904 JNU_ThrowNullPointerException(env, 0); 1905 return JNI_FALSE; 1906 } 1907 1908 cinfo = (j_decompress_ptr) data->jpegObj; 1909 1910 if ((numBands < 1) || (numBands > MAX_BANDS) || 1911 (sourceXStart < 0) || (sourceXStart >= (jint)cinfo->image_width) || 1912 (sourceYStart < 0) || (sourceYStart >= (jint)cinfo->image_height) || 1913 (sourceWidth < 1) || (sourceWidth > (jint)cinfo->image_width) || 1914 (sourceHeight < 1) || (sourceHeight > (jint)cinfo->image_height) || 1915 (stepX < 1) || (stepY < 1) || 1916 (minProgressivePass < 0) || 1917 (maxProgressivePass < minProgressivePass)) 1918 { 1919 JNU_ThrowByName(env, "javax/imageio/IIOException", 1920 "Invalid argument to native readImage"); 1921 return JNI_FALSE; 1922 } 1923 1924 if (stepX > (jint)cinfo->image_width) { 1925 stepX = cinfo->image_width; 1926 } 1927 if (stepY > (jint)cinfo->image_height) { 1928 stepY = cinfo->image_height; 1929 } 1930 1931 /* 1932 * First get the source bands array and copy it to our local array 1933 * so we don't have to worry about pinning and unpinning it again. 1934 */ 1935 1936 body = (*env)->GetIntArrayElements(env, srcBands, NULL); 1937 if (body == NULL) { 1938 (*env)->ExceptionClear(env); 1939 JNU_ThrowByName( env, 1940 "java/lang/OutOfMemoryError", 1941 "Initializing Read"); 1942 return JNI_FALSE; 1943 } 1944 1945 for (i = 0; i < numBands; i++) { 1946 bands[i] = body[i]; 1947 if (orderedBands && (bands[i] != i)) { 1948 orderedBands = FALSE; 1949 } 1950 } 1951 1952 (*env)->ReleaseIntArrayElements(env, srcBands, body, JNI_ABORT); 1953 1954 #ifdef DEBUG_IIO_JPEG 1955 printf("---- in reader.read ----\n"); 1956 printf("numBands is %d\n", numBands); 1957 printf("bands array: "); 1958 for (i = 0; i < numBands; i++) { 1959 printf("%d ", bands[i]); 1960 } 1961 printf("\n"); 1962 printf("jq table 0 at %p\n", 1963 cinfo->quant_tbl_ptrs[0]); 1964 #endif 1965 1966 data = (imageIODataPtr) cinfo->client_data; 1967 src = cinfo->src; 1968 1969 /* Set the buffer as our PixelBuffer */ 1970 pb = &data->pixelBuf; 1971 1972 if (setPixelBuffer(env, pb, buffer) == NOT_OK) { 1973 return data->abortFlag; // We already threw an out of memory exception 1974 } 1975 1976 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1977 jerr = (sun_jpeg_error_ptr) cinfo->err; 1978 1979 if (setjmp(jerr->setjmp_buffer)) { 1980 /* If we get here, the JPEG code has signaled an error 1981 while reading. */ 1982 RELEASE_ARRAYS(env, data, src->next_input_byte); 1983 if (!(*env)->ExceptionOccurred(env)) { 1984 char buffer[JMSG_LENGTH_MAX]; 1985 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1986 buffer); 1987 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 1988 } 1989 if (scanLinePtr != NULL) { 1990 free(scanLinePtr); 1991 scanLinePtr = NULL; 1992 } 1993 return data->abortFlag; 1994 } 1995 1996 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) { 1997 (*env)->ExceptionClear(env); 1998 JNU_ThrowByName(env, 1999 "javax/imageio/IIOException", 2000 "Array pin failed"); 2001 return data->abortFlag; 2002 } 2003 2004 // If there are no tables in our structure and table arguments aren't 2005 // NULL, use the table arguments. 2006 if ((qtables != NULL) && (cinfo->quant_tbl_ptrs[0] == NULL)) { 2007 (void) setQTables(env, (j_common_ptr) cinfo, qtables, TRUE); 2008 } 2009 2010 if ((DCHuffmanTables != NULL) && (cinfo->dc_huff_tbl_ptrs[0] == NULL)) { 2011 setHTables(env, (j_common_ptr) cinfo, 2012 DCHuffmanTables, 2013 ACHuffmanTables, 2014 TRUE); 2015 } 2016 2017 progressive = jpeg_has_multiple_scans(cinfo); 2018 if (progressive) { 2019 cinfo->buffered_image = TRUE; 2020 cinfo->input_scan_number = minProgressivePass+1; // Java count from 0 2021 #define MAX_JAVA_INT 2147483647 // XXX Is this defined in JNI somewhere? 2022 if (maxProgressivePass < MAX_JAVA_INT) { 2023 maxProgressivePass++; // For testing 2024 } 2025 } 2026 2027 data->streamBuf.suspendable = FALSE; 2028 2029 jpeg_start_decompress(cinfo); 2030 2031 if (numBands != cinfo->output_components) { 2032 RELEASE_ARRAYS(env, data, src->next_input_byte); 2033 JNU_ThrowByName(env, "javax/imageio/IIOException", 2034 "Invalid argument to native readImage"); 2035 return data->abortFlag; 2036 } 2037 2038 if (cinfo->output_components <= 0 || 2039 cinfo->image_width > (0xffffffffu / (unsigned int)cinfo->output_components)) 2040 { 2041 RELEASE_ARRAYS(env, data, src->next_input_byte); 2042 JNU_ThrowByName(env, "javax/imageio/IIOException", 2043 "Invalid number of output components"); 2044 return data->abortFlag; 2045 } 2046 2047 // Allocate a 1-scanline buffer 2048 scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components); 2049 if (scanLinePtr == NULL) { 2050 RELEASE_ARRAYS(env, data, src->next_input_byte); 2051 JNU_ThrowByName( env, 2052 "java/lang/OutOfMemoryError", 2053 "Reading JPEG Stream"); 2054 return data->abortFlag; 2055 } 2056 2057 // loop over progressive passes 2058 done = FALSE; 2059 while (!done) { 2060 if (progressive) { 2061 // initialize the next pass. Note that this skips up to 2062 // the first interesting pass. 2063 jpeg_start_output(cinfo, cinfo->input_scan_number); 2064 if (wantUpdates) { 2065 RELEASE_ARRAYS(env, data, src->next_input_byte); 2066 (*env)->CallVoidMethod(env, this, 2067 JPEGImageReader_passStartedID, 2068 cinfo->input_scan_number-1); 2069 if ((*env)->ExceptionOccurred(env) 2070 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 2071 cinfo->err->error_exit((j_common_ptr) cinfo); 2072 } 2073 } 2074 } else if (wantUpdates) { 2075 RELEASE_ARRAYS(env, data, src->next_input_byte); 2076 (*env)->CallVoidMethod(env, this, 2077 JPEGImageReader_passStartedID, 2078 0); 2079 if ((*env)->ExceptionOccurred(env) 2080 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 2081 cinfo->err->error_exit((j_common_ptr) cinfo); 2082 } 2083 } 2084 2085 // Skip until the first interesting line 2086 while ((data->abortFlag == JNI_FALSE) 2087 && ((jint)cinfo->output_scanline < sourceYStart)) { 2088 jpeg_read_scanlines(cinfo, &scanLinePtr, 1); 2089 } 2090 2091 scanlineLimit = sourceYStart+sourceHeight; 2092 pixelLimit = scanLinePtr 2093 +(sourceXStart+sourceWidth)*cinfo->output_components; 2094 2095 pixelStride = stepX*cinfo->output_components; 2096 targetLine = 0; 2097 2098 while ((data->abortFlag == JNI_FALSE) 2099 && ((jint)cinfo->output_scanline < scanlineLimit)) { 2100 2101 jpeg_read_scanlines(cinfo, &scanLinePtr, 1); 2102 2103 // Now mangle it into our buffer 2104 out = data->pixelBuf.buf.bp; 2105 2106 if (orderedBands && (pixelStride == numBands)) { 2107 // Optimization: The component bands are ordered sequentially, 2108 // so we can simply use memcpy() to copy the intermediate 2109 // scanline buffer into the raster. 2110 in = scanLinePtr + (sourceXStart * cinfo->output_components); 2111 if (pixelLimit > in) { 2112 numBytes = pixelLimit - in; 2113 if (numBytes > data->pixelBuf.byteBufferLength) { 2114 numBytes = data->pixelBuf.byteBufferLength; 2115 } 2116 memcpy(out, in, numBytes); 2117 } 2118 } else { 2119 numBytes = numBands; 2120 for (in = scanLinePtr+sourceXStart*cinfo->output_components; 2121 in < pixelLimit && 2122 numBytes <= data->pixelBuf.byteBufferLength; 2123 in += pixelStride) { 2124 for (i = 0; i < numBands; i++) { 2125 *out++ = *(in+bands[i]); 2126 } 2127 numBytes += numBands; 2128 } 2129 } 2130 2131 // And call it back to Java 2132 RELEASE_ARRAYS(env, data, src->next_input_byte); 2133 (*env)->CallVoidMethod(env, 2134 this, 2135 JPEGImageReader_acceptPixelsID, 2136 targetLine++, 2137 progressive); 2138 2139 if ((*env)->ExceptionOccurred(env) 2140 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 2141 cinfo->err->error_exit((j_common_ptr) cinfo); 2142 } 2143 2144 // And skip over uninteresting lines to the next subsampled line 2145 // Ensure we don't go past the end of the image 2146 2147 // Lines to skip based on subsampling 2148 skipLines = stepY - 1; 2149 // Lines left in the image 2150 linesLeft = scanlineLimit - cinfo->output_scanline; 2151 // Take the minimum 2152 if (skipLines > linesLeft) { 2153 skipLines = linesLeft; 2154 } 2155 for(i = 0; i < skipLines; i++) { 2156 jpeg_read_scanlines(cinfo, &scanLinePtr, 1); 2157 } 2158 } 2159 if (progressive) { 2160 jpeg_finish_output(cinfo); // Increments pass counter 2161 // Call Java to notify pass complete 2162 if (jpeg_input_complete(cinfo) 2163 || (cinfo->input_scan_number > maxProgressivePass)) { 2164 done = TRUE; 2165 } 2166 } else { 2167 done = TRUE; 2168 } 2169 if (wantUpdates) { 2170 RELEASE_ARRAYS(env, data, src->next_input_byte); 2171 (*env)->CallVoidMethod(env, this, 2172 JPEGImageReader_passCompleteID); 2173 if ((*env)->ExceptionOccurred(env) 2174 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 2175 cinfo->err->error_exit((j_common_ptr) cinfo); 2176 } 2177 } 2178 2179 } 2180 /* 2181 * We are done, but we might not have read all the lines, or all 2182 * the passes, so use jpeg_abort instead of jpeg_finish_decompress. 2183 */ 2184 if (cinfo->output_scanline == cinfo->output_height) { 2185 // if ((cinfo->output_scanline == cinfo->output_height) && 2186 //(jpeg_input_complete(cinfo))) { // We read the whole file 2187 jpeg_finish_decompress(cinfo); 2188 } else { 2189 jpeg_abort_decompress(cinfo); 2190 } 2191 2192 free(scanLinePtr); 2193 2194 RELEASE_ARRAYS(env, data, src->next_input_byte); 2195 2196 return data->abortFlag; 2197 } 2198 2199 JNIEXPORT void JNICALL 2200 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_abortRead 2201 (JNIEnv *env, 2202 jobject this, 2203 jlong ptr) { 2204 2205 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2206 2207 if (data == NULL) { 2208 JNU_ThrowByName(env, 2209 "java/lang/IllegalStateException", 2210 "Attempting to use reader after dispose()"); 2211 return; 2212 } 2213 2214 imageio_abort(env, this, data); 2215 2216 } 2217 2218 JNIEXPORT void JNICALL 2219 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetLibraryState 2220 (JNIEnv *env, 2221 jobject this, 2222 jlong ptr) { 2223 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2224 j_decompress_ptr cinfo; 2225 2226 if (data == NULL) { 2227 JNU_ThrowByName(env, 2228 "java/lang/IllegalStateException", 2229 "Attempting to use reader after dispose()"); 2230 return; 2231 } 2232 2233 cinfo = (j_decompress_ptr) data->jpegObj; 2234 2235 jpeg_abort_decompress(cinfo); 2236 } 2237 2238 2239 JNIEXPORT void JNICALL 2240 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetReader 2241 (JNIEnv *env, 2242 jobject this, 2243 jlong ptr) { 2244 2245 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2246 j_decompress_ptr cinfo; 2247 sun_jpeg_error_ptr jerr; 2248 2249 if (data == NULL) { 2250 JNU_ThrowByName(env, 2251 "java/lang/IllegalStateException", 2252 "Attempting to use reader after dispose()"); 2253 return; 2254 } 2255 2256 cinfo = (j_decompress_ptr) data->jpegObj; 2257 2258 jerr = (sun_jpeg_error_ptr) cinfo->err; 2259 2260 imageio_reset(env, (j_common_ptr) cinfo, data); 2261 2262 /* 2263 * The tables have not been reset, and there is no way to do so 2264 * in IJG without leaking memory. The only situation in which 2265 * this will cause a problem is if an image-only stream is read 2266 * with this object without initializing the correct tables first. 2267 * This situation, which should cause an error, might work but 2268 * produce garbage instead. If the huffman tables are wrong, 2269 * it will fail during the decode. If the q tables are wrong, it 2270 * will look strange. This is very unlikely, so don't worry about 2271 * it. To be really robust, we would keep a flag for table state 2272 * and consult it to catch exceptional situations. 2273 */ 2274 2275 /* above does not clean up the source, so we have to */ 2276 2277 /* 2278 We need to explicitly initialize exception handler or we may 2279 longjump to random address from the term_source() 2280 */ 2281 2282 if (setjmp(jerr->setjmp_buffer)) { 2283 2284 /* 2285 We may get IOException from pushBack() here. 2286 2287 However it could be legal if original input stream was closed 2288 earlier (for example because network connection was closed). 2289 Unfortunately, image inputstream API has no way to check whether 2290 stream is already closed or IOException was thrown because of some 2291 other IO problem, 2292 And we can not avoid call to pushBack() on closed stream for the 2293 same reason. 2294 2295 So, for now we will silently eat this exception. 2296 2297 NB: this may be changed in future when ImageInputStream API will 2298 become more flexible. 2299 */ 2300 2301 if ((*env)->ExceptionOccurred(env)) { 2302 (*env)->ExceptionClear(env); 2303 } 2304 } else { 2305 cinfo->src->term_source(cinfo); 2306 } 2307 2308 cinfo->src->bytes_in_buffer = 0; 2309 cinfo->src->next_input_byte = NULL; 2310 } 2311 2312 JNIEXPORT void JNICALL 2313 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_disposeReader 2314 (JNIEnv *env, 2315 jclass reader, 2316 jlong ptr) { 2317 2318 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2319 j_common_ptr info = destroyImageioData(env, data); 2320 2321 imageio_dispose(info); 2322 } 2323 2324 /********************** end of Reader *************************/ 2325 2326 /********************** Writer Support ************************/ 2327 2328 /********************** Destination Manager *******************/ 2329 2330 METHODDEF(void) 2331 /* 2332 * Initialize destination --- called by jpeg_start_compress 2333 * before any data is actually written. The data arrays 2334 * must be pinned before this is called. 2335 */ 2336 imageio_init_destination (j_compress_ptr cinfo) 2337 { 2338 struct jpeg_destination_mgr *dest = cinfo->dest; 2339 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 2340 streamBufferPtr sb = &data->streamBuf; 2341 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 2342 2343 if (sb->buf == NULL) { 2344 // We forgot to pin the array 2345 (*env)->FatalError(env, "Output buffer not pinned!"); 2346 } 2347 2348 dest->next_output_byte = sb->buf; 2349 dest->free_in_buffer = sb->bufferLength; 2350 } 2351 2352 /* 2353 * Empty the output buffer --- called whenever buffer fills up. 2354 * 2355 * This routine writes the entire output buffer 2356 * (ignoring the current state of next_output_byte & free_in_buffer), 2357 * resets the pointer & count to the start of the buffer, and returns TRUE 2358 * indicating that the buffer has been dumped. 2359 */ 2360 2361 METHODDEF(boolean) 2362 imageio_empty_output_buffer (j_compress_ptr cinfo) 2363 { 2364 struct jpeg_destination_mgr *dest = cinfo->dest; 2365 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 2366 streamBufferPtr sb = &data->streamBuf; 2367 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 2368 jobject output = NULL; 2369 2370 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 2371 2372 GET_IO_REF(output); 2373 2374 (*env)->CallVoidMethod(env, 2375 output, 2376 JPEGImageWriter_writeOutputDataID, 2377 sb->hstreamBuffer, 2378 0, 2379 sb->bufferLength); 2380 if ((*env)->ExceptionOccurred(env) 2381 || !GET_ARRAYS(env, data, 2382 (const JOCTET **)(&dest->next_output_byte))) { 2383 cinfo->err->error_exit((j_common_ptr) cinfo); 2384 } 2385 2386 dest->next_output_byte = sb->buf; 2387 dest->free_in_buffer = sb->bufferLength; 2388 2389 return TRUE; 2390 } 2391 2392 /* 2393 * After all of the data has been encoded there may still be some 2394 * more left over in some of the working buffers. Now is the 2395 * time to clear them out. 2396 */ 2397 METHODDEF(void) 2398 imageio_term_destination (j_compress_ptr cinfo) 2399 { 2400 struct jpeg_destination_mgr *dest = cinfo->dest; 2401 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 2402 streamBufferPtr sb = &data->streamBuf; 2403 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 2404 2405 /* find out how much needs to be written */ 2406 /* this conversion from size_t to jint is safe, because the lenght of the buffer is limited by jint */ 2407 jint datacount = (jint)(sb->bufferLength - dest->free_in_buffer); 2408 2409 if (datacount != 0) { 2410 jobject output = NULL; 2411 2412 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 2413 2414 GET_IO_REF(output); 2415 2416 (*env)->CallVoidMethod(env, 2417 output, 2418 JPEGImageWriter_writeOutputDataID, 2419 sb->hstreamBuffer, 2420 0, 2421 datacount); 2422 2423 if ((*env)->ExceptionOccurred(env) 2424 || !GET_ARRAYS(env, data, 2425 (const JOCTET **)(&dest->next_output_byte))) { 2426 cinfo->err->error_exit((j_common_ptr) cinfo); 2427 } 2428 } 2429 2430 dest->next_output_byte = NULL; 2431 dest->free_in_buffer = 0; 2432 2433 } 2434 2435 /* 2436 * Flush the destination buffer. This is not called by the library, 2437 * but by our code below. This is the simplest implementation, though 2438 * certainly not the most efficient. 2439 */ 2440 METHODDEF(void) 2441 imageio_flush_destination(j_compress_ptr cinfo) 2442 { 2443 imageio_term_destination(cinfo); 2444 imageio_init_destination(cinfo); 2445 } 2446 2447 /********************** end of destination manager ************/ 2448 2449 /********************** Writer JNI calls **********************/ 2450 2451 2452 JNIEXPORT void JNICALL 2453 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs 2454 (JNIEnv *env, 2455 jclass cls, 2456 jclass qTableClass, 2457 jclass huffClass) { 2458 2459 CHECK_NULL(JPEGImageWriter_writeOutputDataID = (*env)->GetMethodID(env, 2460 cls, 2461 "writeOutputData", 2462 "([BII)V")); 2463 CHECK_NULL(JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env, 2464 cls, 2465 "warningOccurred", 2466 "(I)V")); 2467 CHECK_NULL(JPEGImageWriter_warningWithMessageID = 2468 (*env)->GetMethodID(env, 2469 cls, 2470 "warningWithMessage", 2471 "(Ljava/lang/String;)V")); 2472 CHECK_NULL(JPEGImageWriter_writeMetadataID = (*env)->GetMethodID(env, 2473 cls, 2474 "writeMetadata", 2475 "()V")); 2476 CHECK_NULL(JPEGImageWriter_grabPixelsID = (*env)->GetMethodID(env, 2477 cls, 2478 "grabPixels", 2479 "(I)V")); 2480 CHECK_NULL(JPEGQTable_tableID = (*env)->GetFieldID(env, 2481 qTableClass, 2482 "qTable", 2483 "[I")); 2484 CHECK_NULL(JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env, 2485 huffClass, 2486 "lengths", 2487 "[S")); 2488 CHECK_NULL(JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env, 2489 huffClass, 2490 "values", 2491 "[S")); 2492 } 2493 2494 JNIEXPORT jlong JNICALL 2495 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter 2496 (JNIEnv *env, 2497 jobject this) { 2498 2499 imageIODataPtr ret; 2500 struct sun_jpeg_error_mgr *jerr; 2501 struct jpeg_destination_mgr *dest; 2502 2503 /* This struct contains the JPEG compression parameters and pointers to 2504 * working space (which is allocated as needed by the JPEG library). 2505 */ 2506 struct jpeg_compress_struct *cinfo = 2507 malloc(sizeof(struct jpeg_compress_struct)); 2508 if (cinfo == NULL) { 2509 JNU_ThrowByName( env, 2510 "java/lang/OutOfMemoryError", 2511 "Initializing Writer"); 2512 return 0; 2513 } 2514 2515 /* We use our private extension JPEG error handler. 2516 */ 2517 jerr = malloc (sizeof(struct sun_jpeg_error_mgr)); 2518 if (jerr == NULL) { 2519 JNU_ThrowByName( env, 2520 "java/lang/OutOfMemoryError", 2521 "Initializing Writer"); 2522 free(cinfo); 2523 return 0; 2524 } 2525 2526 /* We set up the normal JPEG error routines, then override error_exit. */ 2527 cinfo->err = jpeg_std_error(&(jerr->pub)); 2528 jerr->pub.error_exit = sun_jpeg_error_exit; 2529 /* We need to setup our own print routines */ 2530 jerr->pub.output_message = sun_jpeg_output_message; 2531 /* Now we can setjmp before every call to the library */ 2532 2533 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 2534 if (setjmp(jerr->setjmp_buffer)) { 2535 /* If we get here, the JPEG code has signaled an error. */ 2536 char buffer[JMSG_LENGTH_MAX]; 2537 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 2538 buffer); 2539 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 2540 return 0; 2541 } 2542 2543 /* Perform library initialization */ 2544 jpeg_create_compress(cinfo); 2545 2546 /* Now set up the destination */ 2547 dest = malloc(sizeof(struct jpeg_destination_mgr)); 2548 if (dest == NULL) { 2549 JNU_ThrowByName( env, 2550 "java/lang/OutOfMemoryError", 2551 "Initializing Writer"); 2552 imageio_dispose((j_common_ptr)cinfo); 2553 return 0; 2554 } 2555 2556 dest->init_destination = imageio_init_destination; 2557 dest->empty_output_buffer = imageio_empty_output_buffer; 2558 dest->term_destination = imageio_term_destination; 2559 dest->next_output_byte = NULL; 2560 dest->free_in_buffer = 0; 2561 2562 cinfo->dest = dest; 2563 2564 /* set up the association to persist for future calls */ 2565 ret = initImageioData(env, (j_common_ptr) cinfo, this); 2566 if (ret == NULL) { 2567 (*env)->ExceptionClear(env); 2568 JNU_ThrowByName( env, 2569 "java/lang/OutOfMemoryError", 2570 "Initializing Writer"); 2571 imageio_dispose((j_common_ptr)cinfo); 2572 return 0; 2573 } 2574 return ptr_to_jlong(ret); 2575 } 2576 2577 JNIEXPORT void JNICALL 2578 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest 2579 (JNIEnv *env, 2580 jobject this, 2581 jlong ptr) { 2582 2583 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2584 j_compress_ptr cinfo; 2585 2586 if (data == NULL) { 2587 JNU_ThrowByName(env, 2588 "java/lang/IllegalStateException", 2589 "Attempting to use writer after dispose()"); 2590 return; 2591 } 2592 2593 cinfo = (j_compress_ptr) data->jpegObj; 2594 2595 imageio_set_stream(env, data->jpegObj, data, this); 2596 2597 2598 // Don't call the init method, as that depends on pinned arrays 2599 cinfo->dest->next_output_byte = NULL; 2600 cinfo->dest->free_in_buffer = 0; 2601 } 2602 2603 JNIEXPORT void JNICALL 2604 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables 2605 (JNIEnv *env, 2606 jobject this, 2607 jlong ptr, 2608 jobjectArray qtables, 2609 jobjectArray DCHuffmanTables, 2610 jobjectArray ACHuffmanTables) { 2611 2612 struct jpeg_destination_mgr *dest; 2613 sun_jpeg_error_ptr jerr; 2614 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2615 j_compress_ptr cinfo; 2616 2617 if (data == NULL) { 2618 JNU_ThrowByName(env, 2619 "java/lang/IllegalStateException", 2620 "Attempting to use writer after dispose()"); 2621 return; 2622 } 2623 2624 cinfo = (j_compress_ptr) data->jpegObj; 2625 dest = cinfo->dest; 2626 2627 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 2628 jerr = (sun_jpeg_error_ptr) cinfo->err; 2629 2630 if (setjmp(jerr->setjmp_buffer)) { 2631 /* If we get here, the JPEG code has signaled an error 2632 while writing. */ 2633 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 2634 if (!(*env)->ExceptionOccurred(env)) { 2635 char buffer[JMSG_LENGTH_MAX]; 2636 (*cinfo->err->format_message) ((j_common_ptr) cinfo, 2637 buffer); 2638 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 2639 } 2640 return; 2641 } 2642 2643 if (GET_ARRAYS(env, data, 2644 (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) { 2645 (*env)->ExceptionClear(env); 2646 JNU_ThrowByName(env, 2647 "javax/imageio/IIOException", 2648 "Array pin failed"); 2649 return; 2650 } 2651 2652 jpeg_suppress_tables(cinfo, TRUE); // Suppress writing of any current 2653 2654 data->streamBuf.suspendable = FALSE; 2655 if (qtables != NULL) { 2656 #ifdef DEBUG_IIO_JPEG 2657 printf("in writeTables: qtables not NULL\n"); 2658 #endif 2659 setQTables(env, (j_common_ptr) cinfo, qtables, TRUE); 2660 } 2661 2662 if (DCHuffmanTables != NULL) { 2663 setHTables(env, (j_common_ptr) cinfo, 2664 DCHuffmanTables, ACHuffmanTables, TRUE); 2665 } 2666 2667 jpeg_write_tables(cinfo); // Flushes the buffer for you 2668 RELEASE_ARRAYS(env, data, NULL); 2669 } 2670 2671 static void freeArray(UINT8** arr, jint size) { 2672 int i; 2673 if (arr != NULL) { 2674 for (i = 0; i < size; i++) { 2675 if (arr[i] != NULL) { 2676 free(arr[i]); 2677 } 2678 } 2679 free(arr); 2680 } 2681 } 2682 2683 JNIEXPORT jboolean JNICALL 2684 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage 2685 (JNIEnv *env, 2686 jobject this, 2687 jlong ptr, 2688 jbyteArray buffer, 2689 jint inCs, jint outCs, 2690 jint numBands, 2691 jintArray bandSizes, 2692 jint srcWidth, 2693 jint destWidth, jint destHeight, 2694 jint stepX, jint stepY, 2695 jobjectArray qtables, 2696 jboolean writeDQT, 2697 jobjectArray DCHuffmanTables, 2698 jobjectArray ACHuffmanTables, 2699 jboolean writeDHT, 2700 jboolean optimize, 2701 jboolean progressive, 2702 jint numScans, 2703 jintArray scanInfo, 2704 jintArray componentIds, 2705 jintArray HsamplingFactors, 2706 jintArray VsamplingFactors, 2707 jintArray QtableSelectors, 2708 jboolean haveMetadata, 2709 jint restartInterval) { 2710 2711 struct jpeg_destination_mgr *dest; 2712 JSAMPROW scanLinePtr; 2713 int i, j; 2714 int pixelStride; 2715 unsigned char *in, *out, *pixelLimit, *scanLineLimit; 2716 unsigned int scanLineSize, pixelBufferSize; 2717 int targetLine; 2718 pixelBufferPtr pb; 2719 sun_jpeg_error_ptr jerr; 2720 jint *ids, *hfactors, *vfactors, *qsels; 2721 jsize qlen, hlen; 2722 int *scanptr; 2723 jint *scanData; 2724 jint *bandSize; 2725 int maxBandValue, halfMaxBandValue; 2726 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 2727 j_compress_ptr cinfo; 2728 UINT8** scale = NULL; 2729 boolean success = TRUE; 2730 2731 2732 /* verify the inputs */ 2733 2734 if (data == NULL) { 2735 JNU_ThrowByName(env, 2736 "java/lang/IllegalStateException", 2737 "Attempting to use writer after dispose()"); 2738 return JNI_FALSE; 2739 } 2740 2741 if ((buffer == NULL) || 2742 (qtables == NULL) || 2743 // H tables can be null if optimizing 2744 (componentIds == NULL) || 2745 (HsamplingFactors == NULL) || (VsamplingFactors == NULL) || 2746 (QtableSelectors == NULL) || 2747 ((numScans != 0) && (scanInfo != NULL))) { 2748 2749 JNU_ThrowNullPointerException(env, 0); 2750 return JNI_FALSE; 2751 2752 } 2753 2754 scanLineSize = destWidth * numBands; 2755 if ((inCs < 0) || (inCs > JCS_YCCK) || 2756 (outCs < 0) || (outCs > JCS_YCCK) || 2757 (numBands < 1) || (numBands > MAX_BANDS) || 2758 (srcWidth < 0) || 2759 (destWidth < 0) || (destWidth > srcWidth) || 2760 (destHeight < 0) || 2761 (stepX < 0) || (stepY < 0) || 2762 ((INT_MAX / numBands) < destWidth)) /* destWidth causes an integer overflow */ 2763 { 2764 JNU_ThrowByName(env, "javax/imageio/IIOException", 2765 "Invalid argument to native writeImage"); 2766 return JNI_FALSE; 2767 } 2768 2769 if (stepX > srcWidth) { 2770 stepX = srcWidth; 2771 } 2772 2773 bandSize = (*env)->GetIntArrayElements(env, bandSizes, NULL); 2774 CHECK_NULL_RETURN(bandSize, JNI_FALSE); 2775 2776 for (i = 0; i < numBands; i++) { 2777 if (bandSize[i] <= 0 || bandSize[i] > JPEG_BAND_SIZE) { 2778 (*env)->ReleaseIntArrayElements(env, bandSizes, 2779 bandSize, JNI_ABORT); 2780 JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid Image"); 2781 return JNI_FALSE; 2782 } 2783 } 2784 2785 for (i = 0; i < numBands; i++) { 2786 if (bandSize[i] != JPEG_BAND_SIZE) { 2787 if (scale == NULL) { 2788 scale = (UINT8**) calloc(numBands, sizeof(UINT8*)); 2789 2790 if (scale == NULL) { 2791 (*env)->ReleaseIntArrayElements(env, bandSizes, 2792 bandSize, JNI_ABORT); 2793 JNU_ThrowByName( env, "java/lang/OutOfMemoryError", 2794 "Writing JPEG Stream"); 2795 return JNI_FALSE; 2796 } 2797 } 2798 2799 maxBandValue = (1 << bandSize[i]) - 1; 2800 2801 scale[i] = (UINT8*) malloc((maxBandValue + 1) * sizeof(UINT8)); 2802 2803 if (scale[i] == NULL) { 2804 // Cleanup before throwing an out of memory exception 2805 for (j = 0; j < i; j++) { 2806 free(scale[j]); 2807 } 2808 free(scale); 2809 (*env)->ReleaseIntArrayElements(env, bandSizes, 2810 bandSize, JNI_ABORT); 2811 JNU_ThrowByName( env, "java/lang/OutOfMemoryError", 2812 "Writing JPEG Stream"); 2813 return JNI_FALSE; 2814 } 2815 2816 halfMaxBandValue = maxBandValue >> 1; 2817 2818 for (j = 0; j <= maxBandValue; j++) { 2819 scale[i][j] = (UINT8) 2820 ((j*MAX_JPEG_BAND_VALUE + halfMaxBandValue)/maxBandValue); 2821 } 2822 } 2823 } 2824 2825 (*env)->ReleaseIntArrayElements(env, bandSizes, 2826 bandSize, JNI_ABORT); 2827 2828 cinfo = (j_compress_ptr) data->jpegObj; 2829 dest = cinfo->dest; 2830 2831 /* Set the buffer as our PixelBuffer */ 2832 pb = &data->pixelBuf; 2833 2834 if (setPixelBuffer(env, pb, buffer) == NOT_OK) { 2835 freeArray(scale, numBands); 2836 return data->abortFlag; // We already threw an out of memory exception 2837 } 2838 2839 // Allocate a 1-scanline buffer 2840 scanLinePtr = (JSAMPROW)malloc(scanLineSize); 2841 if (scanLinePtr == NULL) { 2842 freeArray(scale, numBands); 2843 JNU_ThrowByName( env, 2844 "java/lang/OutOfMemoryError", 2845 "Writing JPEG Stream"); 2846 return data->abortFlag; 2847 } 2848 scanLineLimit = scanLinePtr + scanLineSize; 2849 2850 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 2851 jerr = (sun_jpeg_error_ptr) cinfo->err; 2852 2853 if (setjmp(jerr->setjmp_buffer)) { 2854 /* If we get here, the JPEG code has signaled an error 2855 while writing. */ 2856 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 2857 if (!(*env)->ExceptionOccurred(env)) { 2858 char buffer[JMSG_LENGTH_MAX]; 2859 (*cinfo->err->format_message) ((j_common_ptr) cinfo, 2860 buffer); 2861 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer); 2862 } 2863 2864 freeArray(scale, numBands); 2865 free(scanLinePtr); 2866 return data->abortFlag; 2867 } 2868 2869 // set up parameters 2870 cinfo->image_width = destWidth; 2871 cinfo->image_height = destHeight; 2872 cinfo->input_components = numBands; 2873 cinfo->in_color_space = inCs; 2874 2875 jpeg_set_defaults(cinfo); 2876 2877 jpeg_set_colorspace(cinfo, outCs); 2878 2879 cinfo->optimize_coding = optimize; 2880 2881 cinfo->write_JFIF_header = FALSE; 2882 cinfo->write_Adobe_marker = FALSE; 2883 // copy componentIds 2884 ids = (*env)->GetIntArrayElements(env, componentIds, NULL); 2885 hfactors = (*env)->GetIntArrayElements(env, HsamplingFactors, NULL); 2886 vfactors = (*env)->GetIntArrayElements(env, VsamplingFactors, NULL); 2887 qsels = (*env)->GetIntArrayElements(env, QtableSelectors, NULL); 2888 2889 if (ids && hfactors && vfactors && qsels) { 2890 for (i = 0; i < numBands; i++) { 2891 cinfo->comp_info[i].component_id = ids[i]; 2892 cinfo->comp_info[i].h_samp_factor = hfactors[i]; 2893 cinfo->comp_info[i].v_samp_factor = vfactors[i]; 2894 cinfo->comp_info[i].quant_tbl_no = qsels[i]; 2895 } 2896 } else { 2897 success = FALSE; 2898 } 2899 2900 if (ids) { 2901 (*env)->ReleaseIntArrayElements(env, componentIds, ids, JNI_ABORT); 2902 } 2903 if (hfactors) { 2904 (*env)->ReleaseIntArrayElements(env, HsamplingFactors, hfactors, JNI_ABORT); 2905 } 2906 if (vfactors) { 2907 (*env)->ReleaseIntArrayElements(env, VsamplingFactors, vfactors, JNI_ABORT); 2908 } 2909 if (qsels) { 2910 (*env)->ReleaseIntArrayElements(env, QtableSelectors, qsels, JNI_ABORT); 2911 } 2912 if (!success) { 2913 freeArray(scale, numBands); 2914 free(scanLinePtr); 2915 return data->abortFlag; 2916 } 2917 2918 jpeg_suppress_tables(cinfo, TRUE); // Disable writing any current 2919 2920 qlen = setQTables(env, (j_common_ptr) cinfo, qtables, writeDQT); 2921 2922 if (!optimize) { 2923 // Set the h tables 2924 hlen = setHTables(env, 2925 (j_common_ptr) cinfo, 2926 DCHuffmanTables, 2927 ACHuffmanTables, 2928 writeDHT); 2929 } 2930 2931 if (GET_ARRAYS(env, data, 2932 (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) { 2933 (*env)->ExceptionClear(env); 2934 freeArray(scale, numBands); 2935 free(scanLinePtr); 2936 JNU_ThrowByName(env, 2937 "javax/imageio/IIOException", 2938 "Array pin failed"); 2939 return data->abortFlag; 2940 } 2941 2942 data->streamBuf.suspendable = FALSE; 2943 2944 if (progressive) { 2945 if (numScans == 0) { // then use default scans 2946 jpeg_simple_progression(cinfo); 2947 } else { 2948 cinfo->num_scans = numScans; 2949 // Copy the scanInfo to a local array 2950 // The following is copied from jpeg_simple_progression: 2951 /* Allocate space for script. 2952 * We need to put it in the permanent pool in case the application performs 2953 * multiple compressions without changing the settings. To avoid a memory 2954 * leak if jpeg_simple_progression is called repeatedly for the same JPEG 2955 * object, we try to re-use previously allocated space, and we allocate 2956 * enough space to handle YCbCr even if initially asked for grayscale. 2957 */ 2958 if (cinfo->script_space == NULL 2959 || cinfo->script_space_size < numScans) { 2960 cinfo->script_space_size = MAX(numScans, 10); 2961 cinfo->script_space = (jpeg_scan_info *) 2962 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, 2963 JPOOL_PERMANENT, 2964 cinfo->script_space_size 2965 * sizeof(jpeg_scan_info)); 2966 } 2967 cinfo->scan_info = cinfo->script_space; 2968 scanptr = (int *) cinfo->script_space; 2969 scanData = (*env)->GetIntArrayElements(env, scanInfo, NULL); 2970 if (scanData == NULL) { 2971 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 2972 freeArray(scale, numBands); 2973 free(scanLinePtr); 2974 return data->abortFlag; 2975 } 2976 // number of jints per scan is 9 2977 // We avoid a memcpy to handle different size ints 2978 for (i = 0; i < numScans*9; i++) { 2979 scanptr[i] = scanData[i]; 2980 } 2981 (*env)->ReleaseIntArrayElements(env, scanInfo, 2982 scanData, JNI_ABORT); 2983 2984 } 2985 } 2986 2987 cinfo->restart_interval = restartInterval; 2988 2989 #ifdef DEBUG_IIO_JPEG 2990 printf("writer setup complete, starting compressor\n"); 2991 #endif 2992 2993 // start the compressor; tables must already be set 2994 jpeg_start_compress(cinfo, FALSE); // Leaves sent_table alone 2995 2996 if (haveMetadata) { 2997 // Flush the buffer 2998 imageio_flush_destination(cinfo); 2999 // Call Java to write the metadata 3000 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 3001 (*env)->CallVoidMethod(env, 3002 this, 3003 JPEGImageWriter_writeMetadataID); 3004 if ((*env)->ExceptionOccurred(env) 3005 || !GET_ARRAYS(env, data, 3006 (const JOCTET **)(&dest->next_output_byte))) { 3007 cinfo->err->error_exit((j_common_ptr) cinfo); 3008 } 3009 } 3010 3011 targetLine = 0; 3012 pixelBufferSize = srcWidth * numBands; 3013 pixelStride = numBands * stepX; 3014 3015 // for each line in destHeight 3016 while ((data->abortFlag == JNI_FALSE) 3017 && (cinfo->next_scanline < cinfo->image_height)) { 3018 // get the line from Java 3019 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); 3020 (*env)->CallVoidMethod(env, 3021 this, 3022 JPEGImageWriter_grabPixelsID, 3023 targetLine); 3024 if ((*env)->ExceptionOccurred(env) 3025 || !GET_ARRAYS(env, data, 3026 (const JOCTET **)(&dest->next_output_byte))) { 3027 cinfo->err->error_exit((j_common_ptr) cinfo); 3028 } 3029 3030 // subsample it into our buffer 3031 3032 in = data->pixelBuf.buf.bp; 3033 out = scanLinePtr; 3034 pixelLimit = in + ((pixelBufferSize > data->pixelBuf.byteBufferLength) ? 3035 data->pixelBuf.byteBufferLength : pixelBufferSize); 3036 for (; (in < pixelLimit) && (out < scanLineLimit); in += pixelStride) { 3037 for (i = 0; i < numBands; i++) { 3038 if (scale !=NULL && scale[i] != NULL) { 3039 *out++ = scale[i][*(in+i)]; 3040 #ifdef DEBUG_IIO_JPEG 3041 if (in == data->pixelBuf.buf.bp){ // Just the first pixel 3042 printf("in %d -> out %d, ", *(in+i), *(out-i-1)); 3043 } 3044 #endif 3045 3046 #ifdef DEBUG_IIO_JPEG 3047 if (in == data->pixelBuf.buf.bp){ // Just the first pixel 3048 printf("\n"); 3049 } 3050 #endif 3051 } else { 3052 *out++ = *(in+i); 3053 } 3054 } 3055 } 3056 // write it out 3057 jpeg_write_scanlines(cinfo, (JSAMPARRAY)&scanLinePtr, 1); 3058 targetLine += stepY; 3059 } 3060 3061 /* 3062 * We are done, but we might not have done all the lines, 3063 * so use jpeg_abort instead of jpeg_finish_compress. 3064 */ 3065 if (cinfo->next_scanline == cinfo->image_height) { 3066 jpeg_finish_compress(cinfo); // Flushes buffer with term_dest 3067 } else { 3068 jpeg_abort((j_common_ptr)cinfo); 3069 } 3070 3071 freeArray(scale, numBands); 3072 free(scanLinePtr); 3073 RELEASE_ARRAYS(env, data, NULL); 3074 return data->abortFlag; 3075 } 3076 3077 JNIEXPORT void JNICALL 3078 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_abortWrite 3079 (JNIEnv *env, 3080 jobject this, 3081 jlong ptr) { 3082 3083 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 3084 3085 if (data == NULL) { 3086 JNU_ThrowByName(env, 3087 "java/lang/IllegalStateException", 3088 "Attempting to use writer after dispose()"); 3089 return; 3090 } 3091 3092 imageio_abort(env, this, data); 3093 } 3094 3095 JNIEXPORT void JNICALL 3096 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_resetWriter 3097 (JNIEnv *env, 3098 jobject this, 3099 jlong ptr) { 3100 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 3101 j_compress_ptr cinfo; 3102 3103 if (data == NULL) { 3104 JNU_ThrowByName(env, 3105 "java/lang/IllegalStateException", 3106 "Attempting to use writer after dispose()"); 3107 return; 3108 } 3109 3110 cinfo = (j_compress_ptr) data->jpegObj; 3111 3112 imageio_reset(env, (j_common_ptr) cinfo, data); 3113 3114 /* 3115 * The tables have not been reset, and there is no way to do so 3116 * in IJG without leaking memory. The only situation in which 3117 * this will cause a problem is if an image-only stream is written 3118 * with this object without initializing the correct tables first, 3119 * which should not be possible. 3120 */ 3121 3122 cinfo->dest->next_output_byte = NULL; 3123 cinfo->dest->free_in_buffer = 0; 3124 } 3125 3126 JNIEXPORT void JNICALL 3127 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_disposeWriter 3128 (JNIEnv *env, 3129 jclass writer, 3130 jlong ptr) { 3131 3132 imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); 3133 j_common_ptr info = destroyImageioData(env, data); 3134 3135 imageio_dispose(info); 3136 }