1 /* 2 * Copyright (c) 1995, 2015, 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 DEF_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 size_t outbufSize; 184 jobject hOutputBuffer; 185 }; 186 187 typedef struct sun_jpeg_source_mgr * sun_jpeg_source_ptr; 188 189 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid 190 * the need to copy buffer elements. 191 * 192 * MAKE SURE TO: 193 * 194 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around 195 * callbacks to Java. 196 * - call RELEASE_ARRAYS before returning to Java. 197 * 198 * Otherwise things will go horribly wrong. There may be memory leaks, 199 * excessive pinning, or even VM crashes! 200 * 201 * Note that GetPrimitiveArrayCritical may fail! 202 */ 203 static void RELEASE_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src) 204 { 205 if (src->inbuf) { 206 if (src->pub.next_input_byte == 0) { 207 src->inbufoffset = -1; 208 } else { 209 src->inbufoffset = src->pub.next_input_byte - src->inbuf; 210 } 211 (*env)->ReleasePrimitiveArrayCritical(env, src->hInputBuffer, 212 src->inbuf, 0); 213 src->inbuf = 0; 214 } 215 if (src->outbuf.ip) { 216 (*env)->ReleasePrimitiveArrayCritical(env, src->hOutputBuffer, 217 src->outbuf.ip, 0); 218 src->outbuf.ip = 0; 219 } 220 } 221 222 static int GET_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src) 223 { 224 if (src->hInputBuffer) { 225 assert(src->inbuf == 0); 226 src->inbuf = (JOCTET *)(*env)->GetPrimitiveArrayCritical 227 (env, src->hInputBuffer, 0); 228 if (src->inbuf == 0) { 229 return 0; 230 } 231 if ((int)(src->inbufoffset) >= 0) { 232 src->pub.next_input_byte = src->inbuf + src->inbufoffset; 233 } 234 } 235 if (src->hOutputBuffer) { 236 assert(src->outbuf.ip == 0); 237 src->outbufSize = (*env)->GetArrayLength(env, src->hOutputBuffer); 238 src->outbuf.ip = (int *)(*env)->GetPrimitiveArrayCritical 239 (env, src->hOutputBuffer, 0); 240 if (src->outbuf.ip == 0) { 241 RELEASE_ARRAYS(env, src); 242 return 0; 243 } 244 } 245 return 1; 246 } 247 248 /* 249 * Initialize source. This is called by jpeg_read_header() before any 250 * data is actually read. Unlike init_destination(), it may leave 251 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call 252 * will occur immediately). 253 */ 254 255 GLOBAL(void) 256 sun_jpeg_init_source(j_decompress_ptr cinfo) 257 { 258 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 259 src->pub.next_input_byte = 0; 260 src->pub.bytes_in_buffer = 0; 261 } 262 263 /* 264 * This is called whenever bytes_in_buffer has reached zero and more 265 * data is wanted. In typical applications, it should read fresh data 266 * into the buffer (ignoring the current state of next_input_byte and 267 * bytes_in_buffer), reset the pointer & count to the start of the 268 * buffer, and return TRUE indicating that the buffer has been reloaded. 269 * It is not necessary to fill the buffer entirely, only to obtain at 270 * least one more byte. bytes_in_buffer MUST be set to a positive value 271 * if TRUE is returned. A FALSE return should only be used when I/O 272 * suspension is desired (this mode is discussed in the next section). 273 */ 274 /* 275 * Note that with I/O suspension turned on, this procedure should not 276 * do any work since the JPEG library has a very simple backtracking 277 * mechanism which relies on the fact that the buffer will be filled 278 * only when it has backed out to the top application level. When 279 * suspendable is turned on, the sun_jpeg_fill_suspended_buffer will 280 * do the actual work of filling the buffer. 281 */ 282 283 GLOBAL(boolean) 284 sun_jpeg_fill_input_buffer(j_decompress_ptr cinfo) 285 { 286 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 287 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 288 int ret, buflen; 289 290 if (src->suspendable) { 291 return FALSE; 292 } 293 if (src->remaining_skip) { 294 src->pub.skip_input_data(cinfo, 0); 295 } 296 RELEASE_ARRAYS(env, src); 297 buflen = (*env)->GetArrayLength(env, src->hInputBuffer); 298 ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, 299 src->hInputBuffer, 0, buflen); 300 if (ret > buflen) ret = buflen; 301 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 302 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 303 } 304 if (ret <= 0) { 305 /* Silently accept truncated JPEG files */ 306 WARNMS(cinfo, JWRN_JPEG_EOF); 307 src->inbuf[0] = (JOCTET) 0xFF; 308 src->inbuf[1] = (JOCTET) JPEG_EOI; 309 ret = 2; 310 } 311 312 src->pub.next_input_byte = src->inbuf; 313 src->pub.bytes_in_buffer = ret; 314 315 return TRUE; 316 } 317 318 /* 319 * Note that with I/O suspension turned on, the JPEG library requires 320 * that all buffer filling be done at the top application level. Due 321 * to the way that backtracking works, this procedure should save all 322 * of the data that was left in the buffer when suspension occurred and 323 * only read new data at the end. 324 */ 325 326 GLOBAL(void) 327 sun_jpeg_fill_suspended_buffer(j_decompress_ptr cinfo) 328 { 329 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 330 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 331 size_t offset, buflen; 332 int ret; 333 334 RELEASE_ARRAYS(env, src); 335 ret = (*env)->CallIntMethod(env, src->hInputStream, 336 InputStream_availableID); 337 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 338 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 339 } 340 if (ret < 0 || (unsigned int)ret <= src->remaining_skip) { 341 return; 342 } 343 if (src->remaining_skip) { 344 src->pub.skip_input_data(cinfo, 0); 345 } 346 /* Save the data currently in the buffer */ 347 offset = src->pub.bytes_in_buffer; 348 if (src->pub.next_input_byte > src->inbuf) { 349 memmove(src->inbuf, src->pub.next_input_byte, offset); 350 } 351 RELEASE_ARRAYS(env, src); 352 buflen = (*env)->GetArrayLength(env, src->hInputBuffer) - offset; 353 if (buflen <= 0) { 354 if (!GET_ARRAYS(env, src)) { 355 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 356 } 357 return; 358 } 359 ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, 360 src->hInputBuffer, offset, buflen); 361 if ((ret > 0) && ((unsigned int)ret > buflen)) ret = (int)buflen; 362 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { 363 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 364 } 365 if (ret <= 0) { 366 /* Silently accept truncated JPEG files */ 367 WARNMS(cinfo, JWRN_JPEG_EOF); 368 src->inbuf[offset] = (JOCTET) 0xFF; 369 src->inbuf[offset + 1] = (JOCTET) JPEG_EOI; 370 ret = 2; 371 } 372 373 src->pub.next_input_byte = src->inbuf; 374 src->pub.bytes_in_buffer = ret + offset; 375 376 return; 377 } 378 379 /* 380 * Skip num_bytes worth of data. The buffer pointer and count should 381 * be advanced over num_bytes input bytes, refilling the buffer as 382 * needed. This is used to skip over a potentially large amount of 383 * uninteresting data (such as an APPn marker). In some applications 384 * it may be possible to optimize away the reading of the skipped data, 385 * but it's not clear that being smart is worth much trouble; large 386 * skips are uncommon. bytes_in_buffer may be zero on return. 387 * A zero or negative skip count should be treated as a no-op. 388 */ 389 /* 390 * Note that with I/O suspension turned on, this procedure should not 391 * do any I/O since the JPEG library has a very simple backtracking 392 * mechanism which relies on the fact that the buffer will be filled 393 * only when it has backed out to the top application level. 394 */ 395 396 GLOBAL(void) 397 sun_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 398 { 399 sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; 400 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 401 int ret; 402 int buflen; 403 404 405 if (num_bytes < 0) { 406 return; 407 } 408 num_bytes += src->remaining_skip; 409 src->remaining_skip = 0; 410 ret = (int)src->pub.bytes_in_buffer; /* this conversion is safe, because capacity of the buffer is limited by jnit */ 411 if (ret >= num_bytes) { 412 src->pub.next_input_byte += num_bytes; 413 src->pub.bytes_in_buffer -= num_bytes; 414 return; 415 } 416 num_bytes -= ret; 417 if (src->suspendable) { 418 src->remaining_skip = num_bytes; 419 src->pub.bytes_in_buffer = 0; 420 src->pub.next_input_byte = src->inbuf; 421 return; 422 } 423 424 /* Note that the signature for the method indicates that it takes 425 * and returns a long. Casting the int num_bytes to a long on 426 * the input should work well enough, and if we assume that the 427 * return value for this particular method should always be less 428 * than the argument value (or -1), then the return value coerced 429 * to an int should return us the information we need... 430 */ 431 RELEASE_ARRAYS(env, src); 432 buflen = (*env)->GetArrayLength(env, src->hInputBuffer); 433 while (num_bytes > 0) { 434 ret = (*env)->CallIntMethod(env, src->hInputStream, 435 InputStream_readID, 436 src->hInputBuffer, 0, buflen); 437 if (ret > buflen) ret = buflen; 438 if ((*env)->ExceptionOccurred(env)) { 439 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 440 } 441 if (ret < 0) { 442 break; 443 } 444 num_bytes -= ret; 445 } 446 if (!GET_ARRAYS(env, src)) { 447 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); 448 } 449 if (num_bytes > 0) { 450 /* Silently accept truncated JPEG files */ 451 WARNMS(cinfo, JWRN_JPEG_EOF); 452 src->inbuf[0] = (JOCTET) 0xFF; 453 src->inbuf[1] = (JOCTET) JPEG_EOI; 454 src->pub.bytes_in_buffer = 2; 455 src->pub.next_input_byte = src->inbuf; 456 } else { 457 src->pub.bytes_in_buffer = -num_bytes; 458 src->pub.next_input_byte = src->inbuf + ret + num_bytes; 459 } 460 } 461 462 /* 463 * Terminate source --- called by jpeg_finish_decompress() after all 464 * data has been read. Often a no-op. 465 */ 466 467 GLOBAL(void) 468 sun_jpeg_term_source(j_decompress_ptr cinfo) 469 { 470 } 471 472 JNIEXPORT void JNICALL 473 Java_sun_awt_image_JPEGImageDecoder_initIDs(JNIEnv *env, jclass cls, 474 jclass InputStreamClass) 475 { 476 CHECK_NULL(sendHeaderInfoID = (*env)->GetMethodID(env, cls, "sendHeaderInfo", 477 "(IIZZZ)Z")); 478 CHECK_NULL(sendPixelsByteID = (*env)->GetMethodID(env, cls, "sendPixels", "([BI)Z")); 479 CHECK_NULL(sendPixelsIntID = (*env)->GetMethodID(env, cls, "sendPixels", "([II)Z")); 480 CHECK_NULL(InputStream_readID = (*env)->GetMethodID(env, InputStreamClass, 481 "read", "([BII)I")); 482 CHECK_NULL(InputStream_availableID = (*env)->GetMethodID(env, InputStreamClass, 483 "available", "()I")); 484 } 485 486 487 /* 488 * The Windows Itanium Aug 2002 SDK generates bad code 489 * for this routine. Disable optimization for now. 490 */ 491 #ifdef _M_IA64 492 #pragma optimize ("", off) 493 #endif 494 495 JNIEXPORT void JNICALL 496 Java_sun_awt_image_JPEGImageDecoder_readImage(JNIEnv *env, 497 jobject this, 498 jobject hInputStream, 499 jbyteArray hInputBuffer) 500 { 501 /* This struct contains the JPEG decompression parameters and pointers to 502 * working space (which is allocated as needed by the JPEG library). 503 */ 504 struct jpeg_decompress_struct cinfo; 505 /* We use our private extension JPEG error handler. 506 * Note that this struct must live as long as the main JPEG parameter 507 * struct, to avoid dangling-pointer problems. 508 */ 509 struct sun_jpeg_error_mgr jerr; 510 struct sun_jpeg_source_mgr jsrc; 511 512 int ret; 513 unsigned char *bp; 514 int *ip, pixel; 515 int grayscale; 516 int hasalpha; 517 int buffered_mode; 518 int final_pass; 519 520 /* Step 0: verify the inputs. */ 521 522 if (hInputBuffer == 0 || hInputStream == 0) { 523 JNU_ThrowNullPointerException(env, 0); 524 return; 525 } 526 527 jsrc.outbuf.ip = 0; 528 jsrc.inbuf = 0; 529 530 /* Step 1: allocate and initialize JPEG decompression object */ 531 532 /* We set up the normal JPEG error routines, then override error_exit. */ 533 cinfo.err = jpeg_std_error(&jerr.pub); 534 jerr.pub.error_exit = sun_jpeg_error_exit; 535 536 /* We need to setup our own print routines */ 537 jerr.pub.output_message = sun_jpeg_output_message; 538 539 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 540 if (setjmp(jerr.setjmp_buffer)) { 541 /* If we get here, the JPEG code has signaled an error. 542 * We need to clean up the JPEG object, close the input file, and return. 543 */ 544 jpeg_destroy_decompress(&cinfo); 545 RELEASE_ARRAYS(env, &jsrc); 546 if (!(*env)->ExceptionOccurred(env)) { 547 char buffer[JMSG_LENGTH_MAX]; 548 (*cinfo.err->format_message) ((struct jpeg_common_struct *) &cinfo, 549 buffer); 550 JNU_ThrowByName(env, "sun/awt/image/ImageFormatException", buffer); 551 } 552 return; 553 } 554 /* Now we can initialize the JPEG decompression object. */ 555 jpeg_create_decompress(&cinfo); 556 557 /* Step 2: specify data source (eg, a file) */ 558 559 cinfo.src = &jsrc.pub; 560 jsrc.hInputStream = hInputStream; 561 jsrc.hInputBuffer = hInputBuffer; 562 jsrc.hOutputBuffer = 0; 563 jsrc.suspendable = FALSE; 564 jsrc.remaining_skip = 0; 565 jsrc.inbufoffset = -1; 566 jsrc.pub.init_source = sun_jpeg_init_source; 567 jsrc.pub.fill_input_buffer = sun_jpeg_fill_input_buffer; 568 jsrc.pub.skip_input_data = sun_jpeg_skip_input_data; 569 jsrc.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ 570 jsrc.pub.term_source = sun_jpeg_term_source; 571 if (!GET_ARRAYS(env, &jsrc)) { 572 jpeg_destroy_decompress(&cinfo); 573 return; 574 } 575 /* Step 3: read file parameters with jpeg_read_header() */ 576 577 (void) jpeg_read_header(&cinfo, TRUE); 578 /* select buffered-image mode if it is a progressive JPEG only */ 579 buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scans(&cinfo); 580 grayscale = (cinfo.out_color_space == JCS_GRAYSCALE); 581 #ifdef YCCALPHA 582 hasalpha = (cinfo.out_color_space == JCS_RGBA); 583 #else 584 hasalpha = 0; 585 #endif 586 /* We can ignore the return value from jpeg_read_header since 587 * (a) suspension is not possible with the stdio data source, and 588 * (nor with the Java input source) 589 * (b) we passed TRUE to reject a tables-only JPEG file as an error. 590 * See libjpeg.doc for more info. 591 */ 592 RELEASE_ARRAYS(env, &jsrc); 593 ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID, 594 cinfo.image_width, cinfo.image_height, 595 grayscale, hasalpha, buffered_mode); 596 if ((*env)->ExceptionOccurred(env) || !ret) { 597 /* No more interest in this image... */ 598 jpeg_destroy_decompress(&cinfo); 599 return; 600 } 601 /* Make a one-row-high sample array with enough room to expand to ints */ 602 if (grayscale) { 603 jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width); 604 } else { 605 jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width); 606 } 607 608 if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) { 609 jpeg_destroy_decompress(&cinfo); 610 return; 611 } 612 613 /* Step 4: set parameters for decompression */ 614 615 /* In this example, we don't need to change any of the defaults set by 616 * jpeg_read_header(), so we do nothing here. 617 */ 618 /* For the first pass for Java, we want to deal with RGB for simplicity */ 619 /* Unfortunately, the JPEG code does not automatically convert Grayscale */ 620 /* to RGB, so we have to deal with Grayscale explicitly. */ 621 if (!grayscale && !hasalpha) { 622 cinfo.out_color_space = JCS_RGB; 623 } 624 625 /* Step 5: Start decompressor */ 626 627 jpeg_start_decompress(&cinfo); 628 629 /* We may need to do some setup of our own at this point before reading 630 * the data. After jpeg_start_decompress() we have the correct scaled 631 * output image dimensions available, as well as the output colormap 632 * if we asked for color quantization. 633 */ 634 635 /* Step 6: while (scan lines remain to be read) */ 636 /* jpeg_read_scanlines(...); */ 637 638 /* Here we use the library's state variable cinfo.output_scanline as the 639 * loop counter, so that we don't have to keep track ourselves. 640 */ 641 if (buffered_mode) { 642 final_pass = FALSE; 643 cinfo.dct_method = JDCT_IFAST; 644 } else { 645 final_pass = TRUE; 646 } 647 do { 648 if (buffered_mode) { 649 do { 650 sun_jpeg_fill_suspended_buffer(&cinfo); 651 jsrc.suspendable = TRUE; 652 ret = jpeg_consume_input(&cinfo); 653 jsrc.suspendable = FALSE; 654 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 655 if (ret == JPEG_REACHED_EOI) { 656 final_pass = TRUE; 657 cinfo.dct_method = JDCT_ISLOW; 658 } 659 jpeg_start_output(&cinfo, cinfo.input_scan_number); 660 } 661 while (cinfo.output_scanline < cinfo.output_height) { 662 if (! final_pass) { 663 do { 664 sun_jpeg_fill_suspended_buffer(&cinfo); 665 jsrc.suspendable = TRUE; 666 ret = jpeg_consume_input(&cinfo); 667 jsrc.suspendable = FALSE; 668 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 669 if (ret == JPEG_REACHED_EOI) { 670 break; 671 } 672 } 673 (void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1); 674 675 if (grayscale) { 676 RELEASE_ARRAYS(env, &jsrc); 677 ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID, 678 jsrc.hOutputBuffer, 679 cinfo.output_scanline - 1); 680 } else { 681 if (hasalpha) { 682 ip = jsrc.outbuf.ip + jsrc.outbufSize; 683 bp = jsrc.outbuf.bp + jsrc.outbufSize * 4; 684 while (ip > jsrc.outbuf.ip) { 685 pixel = (*--bp) << 24; 686 pixel |= (*--bp); 687 pixel |= (*--bp) << 8; 688 pixel |= (*--bp) << 16; 689 *--ip = pixel; 690 } 691 } else { 692 ip = jsrc.outbuf.ip + jsrc.outbufSize; 693 bp = jsrc.outbuf.bp + jsrc.outbufSize * 3; 694 while (ip > jsrc.outbuf.ip) { 695 pixel = (*--bp); 696 pixel |= (*--bp) << 8; 697 pixel |= (*--bp) << 16; 698 *--ip = pixel; 699 } 700 } 701 RELEASE_ARRAYS(env, &jsrc); 702 ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID, 703 jsrc.hOutputBuffer, 704 cinfo.output_scanline - 1); 705 } 706 if ((*env)->ExceptionOccurred(env) || !ret || 707 !GET_ARRAYS(env, &jsrc)) { 708 /* No more interest in this image... */ 709 jpeg_destroy_decompress(&cinfo); 710 return; 711 } 712 } 713 if (buffered_mode) { 714 jpeg_finish_output(&cinfo); 715 } 716 } while (! final_pass); 717 718 /* Step 7: Finish decompression */ 719 720 (void) jpeg_finish_decompress(&cinfo); 721 /* We can ignore the return value since suspension is not possible 722 * with the stdio data source. 723 * (nor with the Java data source) 724 */ 725 726 /* Step 8: Release JPEG decompression object */ 727 728 /* This is an important step since it will release a good deal of memory. */ 729 jpeg_destroy_decompress(&cinfo); 730 731 /* After finish_decompress, we can close the input file. 732 * Here we postpone it until after no more JPEG errors are possible, 733 * so as to simplify the setjmp error logic above. (Actually, I don't 734 * think that jpeg_destroy can do an error exit, but why assume anything...) 735 */ 736 /* Not needed for Java - the Java code will close the file */ 737 /* fclose(infile); */ 738 739 /* At this point you may want to check to see whether any corrupt-data 740 * warnings occurred (test whether jerr.pub.num_warnings is nonzero). 741 */ 742 743 /* And we're done! */ 744 745 RELEASE_ARRAYS(env, &jsrc); 746 return; 747 } 748 #ifdef _M_IA64 749 #pragma optimize ("", on) 750 #endif 751 752 753 /* 754 * SOME FINE POINTS: 755 * 756 * In the above code, we ignored the return value of jpeg_read_scanlines, 757 * which is the number of scanlines actually read. We could get away with 758 * this because we asked for only one line at a time and we weren't using 759 * a suspending data source. See libjpeg.doc for more info. 760 * 761 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); 762 * we should have done it beforehand to ensure that the space would be 763 * counted against the JPEG max_memory setting. In some systems the above 764 * code would risk an out-of-memory error. However, in general we don't 765 * know the output image dimensions before jpeg_start_decompress(), unless we 766 * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. 767 * 768 * Scanlines are returned in the same order as they appear in the JPEG file, 769 * which is standardly top-to-bottom. If you must emit data bottom-to-top, 770 * you can use one of the virtual arrays provided by the JPEG memory manager 771 * to invert the data. See wrbmp.c for an example. 772 * 773 * As with compression, some operating modes may require temporary files. 774 * On some systems you may need to set up a signal handler to ensure that 775 * temporary files are deleted if the program is interrupted. See libjpeg.doc. 776 */