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