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