1 /* 2 * Copyright (c) 1995, 2017, 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 JNIEXPORT void JNICALL 487 Java_sun_awt_image_JPEGImageDecoder_readImage(JNIEnv *env, 488 jobject this, 489 jobject hInputStream, 490 jbyteArray hInputBuffer) 491 { 492 /* This struct contains the JPEG decompression parameters and pointers to 493 * working space (which is allocated as needed by the JPEG library). 494 */ 495 struct jpeg_decompress_struct cinfo; 496 /* We use our private extension JPEG error handler. 497 * Note that this struct must live as long as the main JPEG parameter 498 * struct, to avoid dangling-pointer problems. 499 */ 500 struct sun_jpeg_error_mgr jerr; 501 struct sun_jpeg_source_mgr jsrc; 502 503 int ret; 504 unsigned char *bp; 505 int *ip, pixel; 506 int grayscale; 507 int hasalpha; 508 int buffered_mode; 509 int final_pass; 510 511 /* Step 0: verify the inputs. */ 512 513 if (hInputBuffer == 0 || hInputStream == 0) { 514 JNU_ThrowNullPointerException(env, 0); 515 return; 516 } 517 518 jsrc.outbuf.ip = 0; 519 jsrc.inbuf = 0; 520 521 /* Step 1: allocate and initialize JPEG decompression object */ 522 523 /* We set up the normal JPEG error routines, then override error_exit. */ 524 cinfo.err = jpeg_std_error(&jerr.pub); 525 jerr.pub.error_exit = sun_jpeg_error_exit; 526 527 /* We need to setup our own print routines */ 528 jerr.pub.output_message = sun_jpeg_output_message; 529 530 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 531 if (setjmp(jerr.setjmp_buffer)) { 532 /* If we get here, the JPEG code has signaled an error. 533 * We need to clean up the JPEG object, close the input file, and return. 534 */ 535 jpeg_destroy_decompress(&cinfo); 536 RELEASE_ARRAYS(env, &jsrc); 537 if (!(*env)->ExceptionOccurred(env)) { 538 char buffer[JMSG_LENGTH_MAX]; 539 (*cinfo.err->format_message) ((struct jpeg_common_struct *) &cinfo, 540 buffer); 541 JNU_ThrowByName(env, "sun/awt/image/ImageFormatException", buffer); 542 } 543 return; 544 } 545 /* Now we can initialize the JPEG decompression object. */ 546 jpeg_create_decompress(&cinfo); 547 548 /* Step 2: specify data source (eg, a file) */ 549 550 cinfo.src = &jsrc.pub; 551 jsrc.hInputStream = hInputStream; 552 jsrc.hInputBuffer = hInputBuffer; 553 jsrc.hOutputBuffer = 0; 554 jsrc.suspendable = FALSE; 555 jsrc.remaining_skip = 0; 556 jsrc.inbufoffset = -1; 557 jsrc.pub.init_source = sun_jpeg_init_source; 558 jsrc.pub.fill_input_buffer = sun_jpeg_fill_input_buffer; 559 jsrc.pub.skip_input_data = sun_jpeg_skip_input_data; 560 jsrc.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ 561 jsrc.pub.term_source = sun_jpeg_term_source; 562 if (!GET_ARRAYS(env, &jsrc)) { 563 jpeg_destroy_decompress(&cinfo); 564 return; 565 } 566 /* Step 3: read file parameters with jpeg_read_header() */ 567 568 (void) jpeg_read_header(&cinfo, TRUE); 569 /* select buffered-image mode if it is a progressive JPEG only */ 570 buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scans(&cinfo); 571 grayscale = (cinfo.out_color_space == JCS_GRAYSCALE); 572 #ifdef YCCALPHA 573 hasalpha = (cinfo.out_color_space == JCS_RGBA); 574 #else 575 hasalpha = 0; 576 #endif 577 /* We can ignore the return value from jpeg_read_header since 578 * (a) suspension is not possible with the stdio data source, and 579 * (nor with the Java input source) 580 * (b) we passed TRUE to reject a tables-only JPEG file as an error. 581 * See libjpeg.doc for more info. 582 */ 583 RELEASE_ARRAYS(env, &jsrc); 584 ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID, 585 cinfo.image_width, cinfo.image_height, 586 grayscale, hasalpha, buffered_mode); 587 if ((*env)->ExceptionOccurred(env) || !ret) { 588 /* No more interest in this image... */ 589 jpeg_destroy_decompress(&cinfo); 590 return; 591 } 592 /* Make a one-row-high sample array with enough room to expand to ints */ 593 if (grayscale) { 594 jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width); 595 } else { 596 jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width); 597 } 598 599 if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) { 600 jpeg_destroy_decompress(&cinfo); 601 return; 602 } 603 604 /* Step 4: set parameters for decompression */ 605 606 /* In this example, we don't need to change any of the defaults set by 607 * jpeg_read_header(), so we do nothing here. 608 */ 609 /* For the first pass for Java, we want to deal with RGB for simplicity */ 610 /* Unfortunately, the JPEG code does not automatically convert Grayscale */ 611 /* to RGB, so we have to deal with Grayscale explicitly. */ 612 if (!grayscale && !hasalpha) { 613 cinfo.out_color_space = JCS_RGB; 614 } 615 616 /* Step 5: Start decompressor */ 617 618 jpeg_start_decompress(&cinfo); 619 620 /* We may need to do some setup of our own at this point before reading 621 * the data. After jpeg_start_decompress() we have the correct scaled 622 * output image dimensions available, as well as the output colormap 623 * if we asked for color quantization. 624 */ 625 626 /* Step 6: while (scan lines remain to be read) */ 627 /* jpeg_read_scanlines(...); */ 628 629 /* Here we use the library's state variable cinfo.output_scanline as the 630 * loop counter, so that we don't have to keep track ourselves. 631 */ 632 if (buffered_mode) { 633 final_pass = FALSE; 634 cinfo.dct_method = JDCT_IFAST; 635 } else { 636 final_pass = TRUE; 637 } 638 do { 639 if (buffered_mode) { 640 do { 641 sun_jpeg_fill_suspended_buffer(&cinfo); 642 jsrc.suspendable = TRUE; 643 ret = jpeg_consume_input(&cinfo); 644 jsrc.suspendable = FALSE; 645 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 646 if (ret == JPEG_REACHED_EOI) { 647 final_pass = TRUE; 648 cinfo.dct_method = JDCT_ISLOW; 649 } 650 jpeg_start_output(&cinfo, cinfo.input_scan_number); 651 } 652 while (cinfo.output_scanline < cinfo.output_height) { 653 if (! final_pass) { 654 do { 655 sun_jpeg_fill_suspended_buffer(&cinfo); 656 jsrc.suspendable = TRUE; 657 ret = jpeg_consume_input(&cinfo); 658 jsrc.suspendable = FALSE; 659 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI); 660 if (ret == JPEG_REACHED_EOI) { 661 break; 662 } 663 } 664 (void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1); 665 666 if (grayscale) { 667 RELEASE_ARRAYS(env, &jsrc); 668 ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID, 669 jsrc.hOutputBuffer, 670 cinfo.output_scanline - 1); 671 } else { 672 if (hasalpha) { 673 ip = jsrc.outbuf.ip + jsrc.outbufSize; 674 bp = jsrc.outbuf.bp + jsrc.outbufSize * 4; 675 while (ip > jsrc.outbuf.ip) { 676 pixel = (*--bp) << 24; 677 pixel |= (*--bp); 678 pixel |= (*--bp) << 8; 679 pixel |= (*--bp) << 16; 680 *--ip = pixel; 681 } 682 } else { 683 ip = jsrc.outbuf.ip + jsrc.outbufSize; 684 bp = jsrc.outbuf.bp + jsrc.outbufSize * 3; 685 while (ip > jsrc.outbuf.ip) { 686 pixel = (*--bp); 687 pixel |= (*--bp) << 8; 688 pixel |= (*--bp) << 16; 689 *--ip = pixel; 690 } 691 } 692 RELEASE_ARRAYS(env, &jsrc); 693 ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID, 694 jsrc.hOutputBuffer, 695 cinfo.output_scanline - 1); 696 } 697 if ((*env)->ExceptionOccurred(env) || !ret || 698 !GET_ARRAYS(env, &jsrc)) { 699 /* No more interest in this image... */ 700 jpeg_destroy_decompress(&cinfo); 701 return; 702 } 703 } 704 if (buffered_mode) { 705 jpeg_finish_output(&cinfo); 706 } 707 } while (! final_pass); 708 709 /* Step 7: Finish decompression */ 710 711 (void) jpeg_finish_decompress(&cinfo); 712 /* We can ignore the return value since suspension is not possible 713 * with the stdio data source. 714 * (nor with the Java data source) 715 */ 716 717 /* Step 8: Release JPEG decompression object */ 718 719 /* This is an important step since it will release a good deal of memory. */ 720 jpeg_destroy_decompress(&cinfo); 721 722 /* After finish_decompress, we can close the input file. 723 * Here we postpone it until after no more JPEG errors are possible, 724 * so as to simplify the setjmp error logic above. (Actually, I don't 725 * think that jpeg_destroy can do an error exit, but why assume anything...) 726 */ 727 /* Not needed for Java - the Java code will close the file */ 728 /* fclose(infile); */ 729 730 /* At this point you may want to check to see whether any corrupt-data 731 * warnings occurred (test whether jerr.pub.num_warnings is nonzero). 732 */ 733 734 /* And we're done! */ 735 736 RELEASE_ARRAYS(env, &jsrc); 737 return; 738 } 739 740 /* 741 * SOME FINE POINTS: 742 * 743 * In the above code, we ignored the return value of jpeg_read_scanlines, 744 * which is the number of scanlines actually read. We could get away with 745 * this because we asked for only one line at a time and we weren't using 746 * a suspending data source. See libjpeg.doc for more info. 747 * 748 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); 749 * we should have done it beforehand to ensure that the space would be 750 * counted against the JPEG max_memory setting. In some systems the above 751 * code would risk an out-of-memory error. However, in general we don't 752 * know the output image dimensions before jpeg_start_decompress(), unless we 753 * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. 754 * 755 * Scanlines are returned in the same order as they appear in the JPEG file, 756 * which is standardly top-to-bottom. If you must emit data bottom-to-top, 757 * you can use one of the virtual arrays provided by the JPEG memory manager 758 * to invert the data. See wrbmp.c for an example. 759 * 760 * As with compression, some operating modes may require temporary files. 761 * On some systems you may need to set up a signal handler to ensure that 762 * temporary files are deleted if the program is interrupted. See libjpeg.doc. 763 */