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