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