1 /* 2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This file was based upon the example.c stub file included in the 28 * release 6 of the Independent JPEG Group's free JPEG software. 29 * It has been updated to conform to release 6b. 30 */ 31 32 /* First, if system header files define "boolean" map it to "system_boolean" */ 33 #define boolean system_boolean 34 35 #include <stdio.h> 36 #include <setjmp.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <assert.h> 40 41 #include "jni.h" 42 #include "jni_util.h" 43 44 /* undo "system_boolean" hack and undef FAR since we don't use it anyway */ 45 #undef boolean 46 #undef FAR 47 #include <jpeglib.h> 48 #include "jerror.h" 49 50 #ifdef __APPLE__ 51 /* use setjmp/longjmp versions that do not save/restore the signal mask */ 52 #define setjmp _setjmp 53 #define longjmp _longjmp 54 #endif 55 56 /* The method IDs we cache. Note that the last two belongs to the 57 * java.io.InputStream class. 58 */ 59 static jmethodID sendHeaderInfoID; 60 static jmethodID sendPixelsByteID; 61 static jmethodID sendPixelsIntID; 62 static jmethodID InputStream_readID; 63 static jmethodID InputStream_availableID; 64 65 /* Initialize the Java VM instance variable when the library is 66 first loaded */ 67 JavaVM *jvm; 68 69 JNIEXPORT jint JNICALL 70 JNI_OnLoad(JavaVM *vm, void *reserved) 71 { 72 jvm = vm; 73 return JNI_VERSION_1_2; 74 } 75 76 /* 77 * ERROR HANDLING: 78 * 79 * The JPEG library's standard error handler (jerror.c) is divided into 80 * several "methods" which you can override individually. This lets you 81 * adjust the behavior without duplicating a lot of code, which you might 82 * have to update with each future release. 83 * 84 * Our example here shows how to override the "error_exit" method so that 85 * control is returned to the library's caller when a fatal error occurs, 86 * rather than calling exit() as the standard error_exit method does. 87 * 88 * We use C's setjmp/longjmp facility to return control. This means that the 89 * routine which calls the JPEG library must first execute a setjmp() call to 90 * establish the return point. We want the replacement error_exit to do a 91 * longjmp(). But we need to make the setjmp buffer accessible to the 92 * error_exit routine. To do this, we make a private extension of the 93 * standard JPEG error handler object. (If we were using C++, we'd say we 94 * were making a subclass of the regular error handler.) 95 * 96 * Here's the extended error handler struct: 97 */ 98 99 struct sun_jpeg_error_mgr { 100 struct jpeg_error_mgr pub; /* "public" fields */ 101 102 jmp_buf setjmp_buffer; /* for return to caller */ 103 }; 104 105 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr; 106 107 /* 108 * Here's the routine that will replace the standard error_exit method: 109 */ 110 111 METHODDEF(void) 112 sun_jpeg_error_exit (j_common_ptr cinfo) 113 { 114 /* cinfo->err really points to a sun_jpeg_error_mgr struct */ 115 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err; 116 117 /* Always display the message. */ 118 /* We could postpone this until after returning, if we chose. */ 119 /* (*cinfo->err->output_message) (cinfo); */ 120 /* For Java, we will format the message and put it in the error we throw. */ 121 122 /* Return control to the setjmp point */ 123 longjmp(myerr->setjmp_buffer, 1); 124 } 125 126 /* 127 * Error Message handling 128 * 129 * This overrides the output_message method to send JPEG messages 130 * 131 */ 132 133 METHODDEF(void) 134 sun_jpeg_output_message (j_common_ptr cinfo) 135 { 136 char buffer[JMSG_LENGTH_MAX]; 137 138 /* Create the message */ 139 (*cinfo->err->format_message) (cinfo, buffer); 140 141 /* Send it to stderr, adding a newline */ 142 fprintf(stderr, "%s\n", buffer); 143 } 144 145 146 147 148 /* 149 * INPUT HANDLING: 150 * 151 * The JPEG library's input management is defined by the jpeg_source_mgr 152 * structure which contains two fields to convey the information in the 153 * buffer and 5 methods which perform all buffer management. The library 154 * defines a standard input manager that uses stdio for obtaining compressed 155 * jpeg data, but here we need to use Java to get our data. 156 * 157 * We need to make the Java class information accessible to the source_mgr 158 * input routines. We also need to store a pointer to the start of the 159 * Java array being used as an input buffer so that it is not moved or 160 * garbage collected while the JPEG library is using it. To store these 161 * things, we make a private extension of the standard JPEG jpeg_source_mgr 162 * object. 163 * 164 * Here's the extended source manager struct: 165 */ 166 167 struct sun_jpeg_source_mgr { 168 struct jpeg_source_mgr pub; /* "public" fields */ 169 170 jobject hInputStream; 171 int suspendable; 172 unsigned long remaining_skip; 173 174 JOCTET *inbuf; 175 jbyteArray hInputBuffer; 176 size_t inbufoffset; 177 178 /* More stuff */ 179 union pixptr { 180 int *ip; 181 unsigned char *bp; 182 } outbuf; 183 jobject hOutputBuffer; 184 }; 185 186 typedef struct sun_jpeg_source_mgr * sun_jpeg_source_ptr; 187 188 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid 189 * the need to copy buffer elements. 190 * 191 * MAKE SURE TO: 192 * 193 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around 194 * callbacks to Java. 195 * - call RELEASE_ARRAYS before returning to Java. 196 * 197 * Otherwise things will go horribly wrong. There may be memory leaks, 198 * excessive pinning, or even VM crashes! 199 * 200 * Note that GetPrimitiveArrayCritical may fail! 201 */ 202 static void RELEASE_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src) 203 { 204 if (src->inbuf) { 205 if (src->pub.next_input_byte == 0) { 206 src->inbufoffset = -1; 207 } else { 208 src->inbufoffset = src->pub.next_input_byte - src->inbuf; 209 } 210 (*env)->ReleasePrimitiveArrayCritical(env, src->hInputBuffer, 211 src->inbuf, 0); 212 src->inbuf = 0; 213 } 214 if (src->outbuf.ip) { 215 (*env)->ReleasePrimitiveArrayCritical(env, src->hOutputBuffer, 216 src->outbuf.ip, 0); 217 src->outbuf.ip = 0; 218 } 219 } 220 221 static int GET_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src) 222 { 223 if (src->hInputBuffer) { 224 assert(src->inbuf == 0); 225 src->inbuf = (JOCTET *)(*env)->GetPrimitiveArrayCritical 226 (env, src->hInputBuffer, 0); 227 if (src->inbuf == 0) { 228 return 0; 229 } 230 if ((int)(src->inbufoffset) >= 0) { 231 src->pub.next_input_byte = src->inbuf + src->inbufoffset; 232 } 233 } 234 if (src->hOutputBuffer) { 235 assert(src->outbuf.ip == 0); 236 src->outbuf.ip = (int *)(*env)->GetPrimitiveArrayCritical 237 (env, src->hOutputBuffer, 0); 238 if (src->outbuf.ip == 0) { 239 RELEASE_ARRAYS(env, src); 240 return 0; 241 } 242 } 243 return 1; 244 } 245 246 /* 247 * Initialize source. This is called by jpeg_read_header() before any 248 * data is actually read. Unlike init_destination(), it may leave 249 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call 250 * will occur immediately). 251 */ 252 253 GLOBAL(void) 254 sun_jpeg_init_source(j_decompress_ptr cinfo) 255 { 256 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 257 src->pub.next_input_byte = 0; 258 src->pub.bytes_in_buffer = 0; 259 } 260 261 /* 262 * This is called whenever bytes_in_buffer has reached zero and more 263 * data is wanted. In typical applications, it should read fresh data 264 * into the buffer (ignoring the current state of next_input_byte and 265 * bytes_in_buffer), reset the pointer & count to the start of the 266 * buffer, and return TRUE indicating that the buffer has been reloaded. 267 * It is not necessary to fill the buffer entirely, only to obtain at 268 * least one more byte. bytes_in_buffer MUST be set to a positive value 269 * if TRUE is returned. A FALSE return should only be used when I/O 270 * suspension is desired (this mode is discussed in the next section). 271 */ 272 /* 273 * Note that with I/O suspension turned on, this procedure should not 274 * do any work since the JPEG library has a very simple backtracking 275 * mechanism which relies on the fact that the buffer will be filled 276 * only when it has backed out to the top application level. When 277 * suspendable is turned on, the sun_jpeg_fill_suspended_buffer will 278 * do the actual work of filling the buffer. 279 */ 280 281 GLOBAL(boolean) 282 sun_jpeg_fill_input_buffer(j_decompress_ptr cinfo) 283 { 284 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 285 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 286 int ret, buflen; 287 288 if (src->suspendable) { 289 return FALSE; 290 } 291 if (src->remaining_skip) { 292 src->pub.skip_input_data(cinfo, 0); 293 } 294 RELEASE_ARRAYS(env, src); 295 buflen = (*env)->GetArrayLength(env, src->hInputBuffer); 296 ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, 297 src->hInputBuffer, 0, buflen); 298 if (ret > buflen) ret = buflen; 299 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 300 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 301 } 302 if (ret <= 0) { 303 /* Silently accept truncated JPEG files */ 304 WARNMS(cinfo, JWRN_JPEG_EOF); 305 src->inbuf[0] = (JOCTET) 0xFF; 306 src->inbuf[1] = (JOCTET) JPEG_EOI; 307 ret = 2; 308 } 309 310 src->pub.next_input_byte = src->inbuf; 311 src->pub.bytes_in_buffer = ret; 312 313 return TRUE; 314 } 315 316 /* 317 * Note that with I/O suspension turned on, the JPEG library requires 318 * that all buffer filling be done at the top application level. Due 319 * to the way that backtracking works, this procedure should save all 320 * of the data that was left in the buffer when suspension occurred and 321 * only read new data at the end. 322 */ 323 324 GLOBAL(void) 325 sun_jpeg_fill_suspended_buffer(j_decompress_ptr cinfo) 326 { 327 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 328 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 329 size_t offset, buflen; 330 int ret; 331 332 RELEASE_ARRAYS(env, src); 333 ret = (*env)->CallIntMethod(env, src->hInputStream, 334 InputStream_availableID); 335 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 336 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 337 } 338 if (ret < 0 || (unsigned int)ret <= src->remaining_skip) { 339 return; 340 } 341 if (src->remaining_skip) { 342 src->pub.skip_input_data(cinfo, 0); 343 } 344 /* Save the data currently in the buffer */ 345 offset = src->pub.bytes_in_buffer; 346 if (src->pub.next_input_byte > src->inbuf) { 347 memmove(src->inbuf, src->pub.next_input_byte, offset); 348 } 349 RELEASE_ARRAYS(env, src); 350 buflen = (*env)->GetArrayLength(env, src->hInputBuffer) - offset; 351 if (buflen <= 0) { 352 if (!GET_ARRAYS(env, src)) { 353 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 354 } 355 return; 356 } 357 ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, 358 src->hInputBuffer, offset, buflen); 359 if ((ret > 0) && ((unsigned int)ret > buflen)) ret = buflen; 360 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 361 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 362 } 363 if (ret <= 0) { 364 /* Silently accept truncated JPEG files */ 365 WARNMS(cinfo, JWRN_JPEG_EOF); 366 src->inbuf[offset] = (JOCTET) 0xFF; 367 src->inbuf[offset + 1] = (JOCTET) JPEG_EOI; 368 ret = 2; 369 } 370 371 src->pub.next_input_byte = src->inbuf; 372 src->pub.bytes_in_buffer = ret + offset; 373 374 return; 375 } 376 377 /* 378 * Skip num_bytes worth of data. The buffer pointer and count should 379 * be advanced over num_bytes input bytes, refilling the buffer as 380 * needed. This is used to skip over a potentially large amount of 381 * uninteresting data (such as an APPn marker). In some applications 382 * it may be possible to optimize away the reading of the skipped data, 383 * but it's not clear that being smart is worth much trouble; large 384 * skips are uncommon. bytes_in_buffer may be zero on return. 385 * A zero or negative skip count should be treated as a no-op. 386 */ 387 /* 388 * Note that with I/O suspension turned on, this procedure should not 389 * do any I/O since the JPEG library has a very simple backtracking 390 * mechanism which relies on the fact that the buffer will be filled 391 * only when it has backed out to the top application level. 392 */ 393 394 GLOBAL(void) 395 sun_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 396 { 397 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 398 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 399 int ret; 400 int buflen; 401 402 403 if (num_bytes < 0) { 404 return; 405 } 406 num_bytes += src->remaining_skip; 407 src->remaining_skip = 0; 408 ret = (int)src->pub.bytes_in_buffer; /* this conversion is safe, because capacity of the buffer is limited by jnit */ 409 if (ret >= num_bytes) { 410 src->pub.next_input_byte += num_bytes; 411 src->pub.bytes_in_buffer -= num_bytes; 412 return; 413 } 414 num_bytes -= ret; 415 if (src->suspendable) { 416 src->remaining_skip = num_bytes; 417 src->pub.bytes_in_buffer = 0; 418 src->pub.next_input_byte = src->inbuf; 419 return; 420 } 421 422 /* Note that the signature for the method indicates that it takes 423 * and returns a long. Casting the int num_bytes to a long on 424 * the input should work well enough, and if we assume that the 425 * return value for this particular method should always be less 426 * than the argument value (or -1), then the return value coerced 427 * to an int should return us the information we need... 428 */ 429 RELEASE_ARRAYS(env, src); 430 buflen = (*env)->GetArrayLength(env, src->hInputBuffer); 431 while (num_bytes > 0) { 432 ret = (*env)->CallIntMethod(env, src->hInputStream, 433 InputStream_readID, 434 src->hInputBuffer, 0, buflen); 435 if (ret > buflen) ret = buflen; 436 if ((*env)->ExceptionOccurred(env)) { 437 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 438 } 439 if (ret < 0) { 440 break; 441 } 442 num_bytes -= ret; 443 } 444 if (!GET_ARRAYS(env, src)) { 445 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 446 } 447 if (num_bytes > 0) { 448 /* Silently accept truncated JPEG files */ 449 WARNMS(cinfo, JWRN_JPEG_EOF); 450 src->inbuf[0] = (JOCTET) 0xFF; 451 src->inbuf[1] = (JOCTET) JPEG_EOI; 452 src->pub.bytes_in_buffer = 2; 453 src->pub.next_input_byte = src->inbuf; 454 } else { 455 src->pub.bytes_in_buffer = -num_bytes; 456 src->pub.next_input_byte = src->inbuf + ret + num_bytes; 457 } 458 } 459 460 /* 461 * Terminate source --- called by jpeg_finish_decompress() after all 462 * data has been read. Often a no-op. 463 */ 464 465 GLOBAL(void) 466 sun_jpeg_term_source(j_decompress_ptr cinfo) 467 { 468 } 469 470 JNIEXPORT void JNICALL 471 Java_sun_awt_image_JPEGImageDecoder_initIDs(JNIEnv *env, jclass cls, 472 jclass InputStreamClass) 473 { 474 CHECK_NULL(sendHeaderInfoID = (*env)->GetMethodID(env, cls, "sendHeaderInfo", 475 "(IIZZZ)Z")); 476 CHECK_NULL(sendPixelsByteID = (*env)->GetMethodID(env, cls, "sendPixels", "([BI)Z")); 477 CHECK_NULL(sendPixelsIntID = (*env)->GetMethodID(env, cls, "sendPixels", "([II)Z")); 478 CHECK_NULL(InputStream_readID = (*env)->GetMethodID(env, InputStreamClass, 479 "read", "([BII)I")); 480 CHECK_NULL(InputStream_availableID = (*env)->GetMethodID(env, InputStreamClass, 481 "available", "()I")); 482 } 483 484 485 /* 486 * The Windows Itanium Aug 2002 SDK generates bad code 487 * for this routine. Disable optimization for now. 488 */ 489 #ifdef _M_IA64 490 #pragma optimize ("", off) 491 #endif 492 493 JNIEXPORT void JNICALL 494 Java_sun_awt_image_JPEGImageDecoder_readImage(JNIEnv *env, 495 jobject this, 496 jobject hInputStream, 497 jbyteArray hInputBuffer) 498 { 499 /* This struct contains the JPEG decompression parameters and pointers to 500 * working space (which is allocated as needed by the JPEG library). 501 */ 502 struct jpeg_decompress_struct cinfo; 503 /* We use our private extension JPEG error handler. 504 * Note that this struct must live as long as the main JPEG parameter 505 * struct, to avoid dangling-pointer problems. 506 */ 507 struct sun_jpeg_error_mgr jerr; 508 struct sun_jpeg_source_mgr jsrc; 509 510 int ret; 511 unsigned char *bp; 512 int *ip, pixel; 513 int grayscale; 514 int hasalpha; 515 int buffered_mode; 516 int final_pass; 517 518 /* Step 0: verify the inputs. */ 519 520 if (hInputBuffer == 0 || hInputStream == 0) { 521 JNU_ThrowNullPointerException(env, 0); 522 return; 523 } 524 525 jsrc.outbuf.ip = 0; 526 jsrc.inbuf = 0; 527 528 /* Step 1: allocate and initialize JPEG decompression object */ 529 530 /* We set up the normal JPEG error routines, then override error_exit. */ 531 cinfo.err = jpeg_std_error(&jerr.pub); 532 jerr.pub.error_exit = sun_jpeg_error_exit; 533 534 /* We need to setup our own print routines */ 535 jerr.pub.output_message = sun_jpeg_output_message; 536 537 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 538 if (setjmp(jerr.setjmp_buffer)) { 539 /* If we get here, the JPEG code has signaled an error. 540 * We need to clean up the JPEG object, close the input file, and return. 541 */ 542 jpeg_destroy_decompress(&cinfo); 543 RELEASE_ARRAYS(env, &jsrc); 544 if (!(*env)->ExceptionOccurred(env)) { 545 char buffer[JMSG_LENGTH_MAX]; 546 (*cinfo.err->format_message) ((struct jpeg_common_struct *) &cinfo, 547 buffer); 548 JNU_ThrowByName(env, "sun/awt/image/ImageFormatException", buffer); 549 } 550 return; 551 } 552 /* Now we can initialize the JPEG decompression object. */ 553 jpeg_create_decompress(&cinfo); 554 555 /* Step 2: specify data source (eg, a file) */ 556 557 cinfo.src = &jsrc.pub; 558 jsrc.hInputStream = hInputStream; 559 jsrc.hInputBuffer = hInputBuffer; 560 jsrc.hOutputBuffer = 0; 561 jsrc.suspendable = FALSE; 562 jsrc.remaining_skip = 0; 563 jsrc.inbufoffset = -1; 564 jsrc.pub.init_source = sun_jpeg_init_source; 565 jsrc.pub.fill_input_buffer = sun_jpeg_fill_input_buffer; 566 jsrc.pub.skip_input_data = sun_jpeg_skip_input_data; 567 jsrc.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ 568 jsrc.pub.term_source = sun_jpeg_term_source; 569 if (!GET_ARRAYS(env, &jsrc)) { 570 jpeg_destroy_decompress(&cinfo); 571 return; 572 } 573 /* Step 3: read file parameters with jpeg_read_header() */ 574 575 (void) jpeg_read_header(&cinfo, TRUE); 576 /* select buffered-image mode if it is a progressive JPEG only */ 577 buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scans(&cinfo); 578 grayscale = (cinfo.out_color_space == JCS_GRAYSCALE); 579 #ifdef YCCALPHA 580 hasalpha = (cinfo.out_color_space == JCS_RGBA); 581 #else 582 hasalpha = 0; 583 #endif 584 /* We can ignore the return value from jpeg_read_header since 585 * (a) suspension is not possible with the stdio data source, and 586 * (nor with the Java input source) 587 * (b) we passed TRUE to reject a tables-only JPEG file as an error. 588 * See libjpeg.doc for more info. 589 */ 590 RELEASE_ARRAYS(env, &jsrc); 591 ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID, 592 cinfo.image_width, cinfo.image_height, 593 grayscale, hasalpha, buffered_mode); 594 if ((*env)->ExceptionOccurred(env) || !ret) { 595 /* No more interest in this image... */ 596 jpeg_destroy_decompress(&cinfo); 597 return; 598 } 599 /* Make a one-row-high sample array with enough room to expand to ints */ 600 if (grayscale) { 601 jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width); 602 } else { 603 jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width); 604 } 605 606 if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) { 607 jpeg_destroy_decompress(&cinfo); 608 return; 609 } 610 611 /* Step 4: set parameters for decompression */ 612 613 /* In this example, we don't need to change any of the defaults set by 614 * jpeg_read_header(), so we do nothing here. 615 */ 616 /* For the first pass for Java, we want to deal with RGB for simplicity */ 617 /* Unfortunately, the JPEG code does not automatically convert Grayscale */ 618 /* to RGB, so we have to deal with Grayscale explicitly. */ 619 if (!grayscale && !hasalpha) { 620 cinfo.out_color_space = JCS_RGB; 621 } 622 623 /* Step 5: Start decompressor */ 624 625 jpeg_start_decompress(&cinfo); 626 627 /* We may need to do some setup of our own at this point before reading 628 * the data. After jpeg_start_decompress() we have the correct scaled 629 * output image dimensions available, as well as the output colormap 630 * if we asked for color quantization. 631 */ 632 633 /* Step 6: while (scan lines remain to be read) */ 634 /* jpeg_read_scanlines(...); */ 635 636 /* Here we use the library's state variable cinfo.output_scanline as the 637 * loop counter, so that we don't have to keep track ourselves. 638 */ 639 if (buffered_mode) { 640 final_pass = FALSE; 641 cinfo.dct_method = JDCT_IFAST; 642 } else { 643 final_pass = TRUE; 644 } 645 do { 646 if (buffered_mode) { 647 do { 648 sun_jpeg_fill_suspended_buffer(&cinfo); 649 jsrc.suspendable = TRUE; 650 ret = jpeg_consume_input(&cinfo); 651 jsrc.suspendable = FALSE; 652 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 653 if (ret == JPEG_REACHED_EOI) { 654 final_pass = TRUE; 655 cinfo.dct_method = JDCT_ISLOW; 656 } 657 jpeg_start_output(&cinfo, cinfo.input_scan_number); 658 } 659 while (cinfo.output_scanline < cinfo.output_height) { 660 if (! final_pass) { 661 do { 662 sun_jpeg_fill_suspended_buffer(&cinfo); 663 jsrc.suspendable = TRUE; 664 ret = jpeg_consume_input(&cinfo); 665 jsrc.suspendable = FALSE; 666 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 667 if (ret == JPEG_REACHED_EOI) { 668 break; 669 } 670 } 671 (void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1); 672 673 if (grayscale) { 674 RELEASE_ARRAYS(env, &jsrc); 675 ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID, 676 jsrc.hOutputBuffer, 677 cinfo.output_scanline - 1); 678 } else { 679 if (hasalpha) { 680 ip = jsrc.outbuf.ip + cinfo.image_width; 681 bp = jsrc.outbuf.bp + cinfo.image_width * 4; 682 while (ip > jsrc.outbuf.ip) { 683 pixel = (*--bp) << 24; 684 pixel |= (*--bp); 685 pixel |= (*--bp) << 8; 686 pixel |= (*--bp) << 16; 687 *--ip = pixel; 688 } 689 } else { 690 ip = jsrc.outbuf.ip + cinfo.image_width; 691 bp = jsrc.outbuf.bp + cinfo.image_width * 3; 692 while (ip > jsrc.outbuf.ip) { 693 pixel = (*--bp); 694 pixel |= (*--bp) << 8; 695 pixel |= (*--bp) << 16; 696 *--ip = pixel; 697 } 698 } 699 RELEASE_ARRAYS(env, &jsrc); 700 ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID, 701 jsrc.hOutputBuffer, 702 cinfo.output_scanline - 1); 703 } 704 if ((*env)->ExceptionOccurred(env) || !ret || 705 !GET_ARRAYS(env, &jsrc)) { 706 /* No more interest in this image... */ 707 jpeg_destroy_decompress(&cinfo); 708 return; 709 } 710 } 711 if (buffered_mode) { 712 jpeg_finish_output(&cinfo); 713 } 714 } while (! final_pass); 715 716 /* Step 7: Finish decompression */ 717 718 (void) jpeg_finish_decompress(&cinfo); 719 /* We can ignore the return value since suspension is not possible 720 * with the stdio data source. 721 * (nor with the Java data source) 722 */ 723 724 /* Step 8: Release JPEG decompression object */ 725 726 /* This is an important step since it will release a good deal of memory. */ 727 jpeg_destroy_decompress(&cinfo); 728 729 /* After finish_decompress, we can close the input file. 730 * Here we postpone it until after no more JPEG errors are possible, 731 * so as to simplify the setjmp error logic above. (Actually, I don't 732 * think that jpeg_destroy can do an error exit, but why assume anything...) 733 */ 734 /* Not needed for Java - the Java code will close the file */ 735 /* fclose(infile); */ 736 737 /* At this point you may want to check to see whether any corrupt-data 738 * warnings occurred (test whether jerr.pub.num_warnings is nonzero). 739 */ 740 741 /* And we're done! */ 742 743 RELEASE_ARRAYS(env, &jsrc); 744 return; 745 } 746 #ifdef _M_IA64 747 #pragma optimize ("", on) 748 #endif 749 750 751 /* 752 * SOME FINE POINTS: 753 * 754 * In the above code, we ignored the return value of jpeg_read_scanlines, 755 * which is the number of scanlines actually read. We could get away with 756 * this because we asked for only one line at a time and we weren't using 757 * a suspending data source. See libjpeg.doc for more info. 758 * 759 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); 760 * we should have done it beforehand to ensure that the space would be 761 * counted against the JPEG max_memory setting. In some systems the above 762 * code would risk an out-of-memory error. However, in general we don't 763 * know the output image dimensions before jpeg_start_decompress(), unless we 764 * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. 765 * 766 * Scanlines are returned in the same order as they appear in the JPEG file, 767 * which is standardly top-to-bottom. If you must emit data bottom-to-top, 768 * you can use one of the virtual arrays provided by the JPEG memory manager 769 * to invert the data. See wrbmp.c for an example. 770 * 771 * As with compression, some operating modes may require temporary files. 772 * On some systems you may need to set up a signal handler to ensure that 773 * temporary files are deleted if the program is interrupted. See libjpeg.doc. 774 */