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