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