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