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 */
59static jmethodID sendHeaderInfoID;
60static jmethodID sendPixelsByteID;
61static jmethodID sendPixelsIntID;
62static jmethodID InputStream_readID;
63static jmethodID InputStream_availableID;
64
65/* Initialize the Java VM instance variable when the library is
66 first loaded */
67JavaVM *jvm;
68
69JNIEXPORT jint JNICALL
70DEF_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
99struct sun_jpeg_error_mgr {
100 struct jpeg_error_mgr pub; /* "public" fields */
101
102 jmp_buf setjmp_buffer; /* for return to caller */
103};
104
105typedef 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
111METHODDEF(void)
112sun_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
133METHODDEF(void)
134sun_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
167struct 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
187typedef 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 */
203static 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
222static 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
255GLOBAL(void)
256sun_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
283GLOBAL(boolean)
284sun_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
326GLOBAL(void)
327sun_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
396GLOBAL(void)
397sun_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
467GLOBAL(void)
468sun_jpeg_term_source(j_decompress_ptr cinfo)
469{
470}
471
472JNIEXPORT void JNICALL
473Java_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
486JNIEXPORT void JNICALL
487Java_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 hasalpha = 0;
573 /* We can ignore the return value from jpeg_read_header since
574 * (a) suspension is not possible with the stdio data source, and
575 * (nor with the Java input source)
576 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
577 * See libjpeg.doc for more info.
578 */
579 RELEASE_ARRAYS(env, &jsrc);
580 ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID,
581 cinfo.image_width, cinfo.image_height,
582 grayscale, hasalpha, buffered_mode);
583 if ((*env)->ExceptionOccurred(env) || !ret) {
584 /* No more interest in this image... */
585 jpeg_destroy_decompress(&cinfo);
586 return;
587 }
588 /* Make a one-row-high sample array with enough room to expand to ints */
589 if (grayscale) {
590 jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width);
591 } else {
592 jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width);
593 }
594
595 if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) {
596 jpeg_destroy_decompress(&cinfo);
597 return;
598 }
599
600 /* Step 4: set parameters for decompression */
601
602 /* In this example, we don't need to change any of the defaults set by
603 * jpeg_read_header(), so we do nothing here.
604 */
605 /* For the first pass for Java, we want to deal with RGB for simplicity */
606 /* Unfortunately, the JPEG code does not automatically convert Grayscale */
607 /* to RGB, so we have to deal with Grayscale explicitly. */
608 if (!grayscale && !hasalpha) {
609 cinfo.out_color_space = JCS_RGB;
610 }
611
612 /* Step 5: Start decompressor */
613
614 jpeg_start_decompress(&cinfo);
615
616 /* We may need to do some setup of our own at this point before reading
617 * the data. After jpeg_start_decompress() we have the correct scaled
618 * output image dimensions available, as well as the output colormap
619 * if we asked for color quantization.
620 */
621
622 /* Step 6: while (scan lines remain to be read) */
623 /* jpeg_read_scanlines(...); */
624
625 /* Here we use the library's state variable cinfo.output_scanline as the
626 * loop counter, so that we don't have to keep track ourselves.
627 */
628 if (buffered_mode) {
629 final_pass = FALSE;
630 cinfo.dct_method = JDCT_IFAST;
631 } else {
632 final_pass = TRUE;
633 }
634 do {
635 if (buffered_mode) {
636 do {
637 sun_jpeg_fill_suspended_buffer(&cinfo);
638 jsrc.suspendable = TRUE;
639 ret = jpeg_consume_input(&cinfo);
640 jsrc.suspendable = FALSE;
641 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI);
642 if (ret == JPEG_REACHED_EOI) {
643 final_pass = TRUE;
644 cinfo.dct_method = JDCT_ISLOW;
645 }
646 jpeg_start_output(&cinfo, cinfo.input_scan_number);
647 }
648 while (cinfo.output_scanline < cinfo.output_height) {
649 if (! final_pass) {
650 do {
651 sun_jpeg_fill_suspended_buffer(&cinfo);
652 jsrc.suspendable = TRUE;
653 ret = jpeg_consume_input(&cinfo);
654 jsrc.suspendable = FALSE;
655 } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI);
656 if (ret == JPEG_REACHED_EOI) {
657 break;
658 }
659 }
660 (void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1);
661
662 if (grayscale) {
663 RELEASE_ARRAYS(env, &jsrc);
664 ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID,
665 jsrc.hOutputBuffer,
666 cinfo.output_scanline - 1);
667 } else {
668 if (hasalpha) {
669 ip = jsrc.outbuf.ip + jsrc.outbufSize;
670 bp = jsrc.outbuf.bp + jsrc.outbufSize * 4;
671 while (ip > jsrc.outbuf.ip) {
672 pixel = (*--bp) << 24;
673 pixel |= (*--bp);
674 pixel |= (*--bp) << 8;
675 pixel |= (*--bp) << 16;
676 *--ip = pixel;
677 }
678 } else {
679 ip = jsrc.outbuf.ip + jsrc.outbufSize;
680 bp = jsrc.outbuf.bp + jsrc.outbufSize * 3;
681 while (ip > jsrc.outbuf.ip) {
682 pixel = (*--bp);
683 pixel |= (*--bp) << 8;
684 pixel |= (*--bp) << 16;
685 *--ip = pixel;
686 }
687 }
688 RELEASE_ARRAYS(env, &jsrc);
689 ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID,
690 jsrc.hOutputBuffer,
691 cinfo.output_scanline - 1);
692 }
693 if ((*env)->ExceptionOccurred(env) || !ret ||
694 !GET_ARRAYS(env, &jsrc)) {
695 /* No more interest in this image... */
696 jpeg_destroy_decompress(&cinfo);
697 return;
698 }
699 }
700 if (buffered_mode) {
701 jpeg_finish_output(&cinfo);
702 }
703 } while (! final_pass);
704
705 /* Step 7: Finish decompression */
706
707 (void) jpeg_finish_decompress(&cinfo);
708 /* We can ignore the return value since suspension is not possible
709 * with the stdio data source.
710 * (nor with the Java data source)
711 */
712
713 /* Step 8: Release JPEG decompression object */
714
715 /* This is an important step since it will release a good deal of memory. */
716 jpeg_destroy_decompress(&cinfo);
717
718 /* After finish_decompress, we can close the input file.
719 * Here we postpone it until after no more JPEG errors are possible,
720 * so as to simplify the setjmp error logic above. (Actually, I don't
721 * think that jpeg_destroy can do an error exit, but why assume anything...)
722 */
723 /* Not needed for Java - the Java code will close the file */
724 /* fclose(infile); */
725
726 /* At this point you may want to check to see whether any corrupt-data
727 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
728 */
729
730 /* And we're done! */
731
732 RELEASE_ARRAYS(env, &jsrc);
733 return;
734}
735
736/*
737 * SOME FINE POINTS:
738 *
739 * In the above code, we ignored the return value of jpeg_read_scanlines,
740 * which is the number of scanlines actually read. We could get away with
741 * this because we asked for only one line at a time and we weren't using
742 * a suspending data source. See libjpeg.doc for more info.
743 *
744 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
745 * we should have done it beforehand to ensure that the space would be
746 * counted against the JPEG max_memory setting. In some systems the above
747 * code would risk an out-of-memory error. However, in general we don't
748 * know the output image dimensions before jpeg_start_decompress(), unless we
749 * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this.
750 *
751 * Scanlines are returned in the same order as they appear in the JPEG file,
752 * which is standardly top-to-bottom. If you must emit data bottom-to-top,
753 * you can use one of the virtual arrays provided by the JPEG memory manager
754 * to invert the data. See wrbmp.c for an example.
755 *
756 * As with compression, some operating modes may require temporary files.
757 * On some systems you may need to set up a signal handler to ensure that
758 * temporary files are deleted if the program is interrupted. See libjpeg.doc.
759 */
760