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