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