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