blob: 8c30b5ce69e4215a67d91388d4ecc6b9e5459107 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26/*
27 * This file contains the code to link the Java Image I/O JPEG plug-in
28 * to the IJG library used to read and write JPEG files. Much of it has
29 * been copied, updated, and annotated from the jpegdecoder.c AWT JPEG
30 * decoder. Where that code was unclear, the present author has either
31 * rewritten the relevant section or commented it for the sake of future
32 * maintainers.
33 *
34 * In particular, the way the AWT code handled progressive JPEGs seems
35 * to me to be only accidentally correct and somewhat inefficient. The
36 * scheme used here represents the way I think it should work. (REV 11/00)
37 */
38
39#include <stdlib.h>
40#include <setjmp.h>
41#include <assert.h>
42#include <string.h>
43
44
45/* java native interface headers */
46#include "jni.h"
47#include "jni_util.h"
48
49#include "com_sun_imageio_plugins_jpeg_JPEGImageReader.h"
50#include "com_sun_imageio_plugins_jpeg_JPEGImageWriter.h"
51
52/* headers from the JPEG library */
53#include <jpeglib.h>
54#include "jerror.h"
55
56#undef MAX
57#define MAX(a,b) ((a) > (b) ? (a) : (b))
58
59/* Cached Java method ids */
60static jmethodID ImageInputStream_readID;
61static jmethodID ImageInputStream_skipBytesID;
62static jmethodID JPEGImageReader_warningOccurredID;
63static jmethodID JPEGImageReader_warningWithMessageID;
64static jmethodID JPEGImageReader_setImageDataID;
65static jmethodID JPEGImageReader_acceptPixelsID;
66static jmethodID JPEGImageReader_pushBackID;
67static jmethodID JPEGImageReader_passStartedID;
68static jmethodID JPEGImageReader_passCompleteID;
69static jmethodID ImageOutputStream_writeID;
70static jmethodID JPEGImageWriter_warningOccurredID;
71static jmethodID JPEGImageWriter_warningWithMessageID;
72static jmethodID JPEGImageWriter_writeMetadataID;
73static jmethodID JPEGImageWriter_grabPixelsID;
74static jfieldID JPEGQTable_tableID;
75static jfieldID JPEGHuffmanTable_lengthsID;
76static jfieldID JPEGHuffmanTable_valuesID;
77
78/*
79 * Defined in jpegdecoder.c. Copy code from there if and
80 * when that disappears. */
81extern JavaVM *jvm;
82
83/*
84 * The following sets of defines must match the warning messages in the
85 * Java code.
86 */
87
88/* Reader warnings */
89#define READ_NO_EOI 0
90
91/* Writer warnings */
92
93/* Return codes for various ops */
94#define OK 1
95#define NOT_OK 0
96
97/*
98 * First we define two objects, one for the stream and buffer and one
99 * for pixels. Both contain references to Java objects and pointers to
100 * pinned arrays. These objects can be used for either input or
101 * output. Pixels can be accessed as either INT32s or bytes.
102 * Every I/O operation will have one of each these objects, one for
103 * the stream and the other to hold pixels, regardless of the I/O direction.
104 */
105
106/******************** StreamBuffer definition ************************/
107
108typedef struct streamBufferStruct {
109 jobject stream; // ImageInputStream or ImageOutputStream
110 jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream
111 JOCTET *buf; // Pinned buffer pointer */
112 int bufferOffset; // holds offset between unpin and the next pin
113 int bufferLength; // Allocated, nut just used
114 int suspendable; // Set to true to suspend input
115 long remaining_skip; // Used only on input
116} streamBuffer, *streamBufferPtr;
117
118/*
119 * This buffer size was set to 64K in the old classes, 4K by default in the
120 * IJG library, with the comment "an efficiently freadable size", and 1K
121 * in AWT.
122 * Unlike in the other Java designs, these objects will persist, so 64K
123 * seems too big and 1K seems too small. If 4K was good enough for the
124 * IJG folks, it's good enough for me.
125 */
126#define STREAMBUF_SIZE 4096
127
128/*
129 * Used to signal that no data need be restored from an unpin to a pin.
130 * I.e. the buffer is empty.
131 */
132#define NO_DATA -1
133
134// Forward reference
135static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb);
136
137/*
138 * Initialize a freshly allocated StreamBuffer object. The stream is left
139 * null, as it will be set from Java by setSource, but the buffer object
140 * is created and a global reference kept. Returns OK on success, NOT_OK
141 * if allocating the buffer or getting a global reference for it failed.
142 */
143static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
144 /* Initialize a new buffer */
145 jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE);
146 if (hInputBuffer == NULL) {
147 JNU_ThrowByName( env,
148 "java/lang/OutOfMemoryError",
149 "Initializing Reader");
150 return NOT_OK;
151 }
152 sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer);
153 sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer);
154 if (sb->hstreamBuffer == NULL) {
155 JNU_ThrowByName( env,
156 "java/lang/OutOfMemoryError",
157 "Initializing Reader");
158 return NOT_OK;
159 }
160
161
162 sb->stream = NULL;
163
164 sb->buf = NULL;
165
166 resetStreamBuffer(env, sb);
167
168 return OK;
169}
170
171/*
172 * Free all resources associated with this streamBuffer. This must
173 * be called to dispose the object to avoid leaking global references, as
174 * resetStreamBuffer does not release the buffer reference.
175 */
176static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
177 resetStreamBuffer(env, sb);
178 if (sb->hstreamBuffer != NULL) {
179 (*env)->DeleteGlobalRef(env, sb->hstreamBuffer);
180 }
181}
182
183// Forward reference
184static void unpinStreamBuffer(JNIEnv *env,
185 streamBufferPtr sb,
186 const JOCTET *next_byte);
187/*
188 * Resets the state of a streamBuffer object that has been in use.
189 * The global reference to the stream is released, but the reference
190 * to the buffer is retained. The buffer is unpinned if it was pinned.
191 * All other state is reset.
192 */
193static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
194 if (sb->stream != NULL) {
195 (*env)->DeleteGlobalRef(env, sb->stream);
196 sb->stream = NULL;
197 }
198 unpinStreamBuffer(env, sb, NULL);
199 sb->bufferOffset = NO_DATA;
200 sb->suspendable = FALSE;
201 sb->remaining_skip = 0;
202}
203
204/*
205 * Pins the data buffer associated with this stream. Returns OK on
206 * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail.
207 */
208static int pinStreamBuffer(JNIEnv *env,
209 streamBufferPtr sb,
210 const JOCTET **next_byte) {
211 if (sb->hstreamBuffer != NULL) {
212 assert(sb->buf == NULL);
213 sb->buf =
214 (JOCTET *)(*env)->GetPrimitiveArrayCritical(env,
215 sb->hstreamBuffer,
216 NULL);
217 if (sb->buf == NULL) {
218 return NOT_OK;
219 }
220 if (sb->bufferOffset != NO_DATA) {
221 *next_byte = sb->buf + sb->bufferOffset;
222 }
223 }
224 return OK;
225}
226
227/*
228 * Unpins the data buffer associated with this stream.
229 */
230static void unpinStreamBuffer(JNIEnv *env,
231 streamBufferPtr sb,
232 const JOCTET *next_byte) {
233 if (sb->buf != NULL) {
234 assert(sb->hstreamBuffer != NULL);
235 if (next_byte == NULL) {
236 sb->bufferOffset = NO_DATA;
237 } else {
238 sb->bufferOffset = next_byte - sb->buf;
239 }
240 (*env)->ReleasePrimitiveArrayCritical(env,
241 sb->hstreamBuffer,
242 sb->buf,
243 0);
244 sb->buf = NULL;
245 }
246}
247
248/*
249 * Clear out the streamBuffer. This just invalidates the data in the buffer.
250 */
251static void clearStreamBuffer(streamBufferPtr sb) {
252 sb->bufferOffset = NO_DATA;
253}
254
255/*************************** end StreamBuffer definition *************/
256
257/*************************** Pixel Buffer definition ******************/
258
259typedef struct pixelBufferStruct {
260 jobject hpixelObject; // Usually a DataBuffer bank as a byte array
261 union pixptr {
262 INT32 *ip; // Pinned buffer pointer, as 32-bit ints
263 unsigned char *bp; // Pinned buffer pointer, as bytes
264 } buf;
265} pixelBuffer, *pixelBufferPtr;
266
267/*
268 * Initialize a freshly allocated PixelBuffer. All fields are simply
269 * set to NULL, as we have no idea what size buffer we will need.
270 */
271static void initPixelBuffer(pixelBufferPtr pb) {
272 pb->hpixelObject = NULL;
273 pb->buf.ip = NULL;
274}
275
276/*
277 * Set the pixelBuffer to use the given buffer, acquiring a new global
278 * reference for it. Returns OK on success, NOT_OK on failure.
279 */
280static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) {
281 pb->hpixelObject = (*env)->NewGlobalRef(env, obj);
282
283 if (pb->hpixelObject == NULL) {
284 JNU_ThrowByName( env,
285 "java/lang/OutOfMemoryError",
286 "Setting Pixel Buffer");
287 return NOT_OK;
288 }
289 return OK;
290}
291
292// Forward reference
293static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb);
294
295/*
296 * Resets a pixel buffer to its initial state. Unpins any pixel buffer,
297 * releases the global reference, and resets fields to NULL. Use this
298 * method to dispose the object as well (there is no destroyPixelBuffer).
299 */
300static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
301 if (pb->hpixelObject != NULL) {
302 unpinPixelBuffer(env, pb);
303 (*env)->DeleteGlobalRef(env, pb->hpixelObject);
304 pb->hpixelObject = NULL;
305 }
306}
307
308/*
309 * Pins the data buffer. Returns OK on success, NOT_OK on failure.
310 */
311static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
312 if (pb->hpixelObject != NULL) {
313 assert(pb->buf.ip == NULL);
314 pb->buf.bp = (unsigned char *)(*env)->GetPrimitiveArrayCritical
315 (env, pb->hpixelObject, NULL);
316 if (pb->buf.bp == NULL) {
317 return NOT_OK;
318 }
319 }
320 return OK;
321}
322
323/*
324 * Unpins the data buffer.
325 */
326static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
327
328 if (pb->buf.ip != NULL) {
329 assert(pb->hpixelObject != NULL);
330 (*env)->ReleasePrimitiveArrayCritical(env,
331 pb->hpixelObject,
332 pb->buf.ip,
333 0);
334 pb->buf.ip = NULL;
335 }
336}
337
338/********************* end PixelBuffer definition *******************/
339
340/********************* ImageIOData definition ***********************/
341
342#define MAX_BANDS 4
343#define JPEG_BAND_SIZE 8
344#define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE)
345#define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1)
346#define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1)
347
348/* The number of possible incoming values to be scaled. */
349#define NUM_INPUT_VALUES (1 << 16)
350
351/*
352 * The principal imageioData object, opaque to I/O direction.
353 * Each JPEGImageReader will have associated with it a
354 * jpeg_decompress_struct, and similarly each JPEGImageWriter will
355 * have associated with it a jpeg_compress_struct. In order to
356 * ensure that these associations persist from one native call to
357 * the next, and to provide a central locus of imageio-specific
358 * data, we define an imageioData struct containing references
359 * to the Java object and the IJG structs. The functions
360 * that manipulate these objects know whether input or output is being
361 * performed and therefore know how to manipulate the contents correctly.
362 * If for some reason they don't, the direction can be determined by
363 * checking the is_decompressor field of the jpegObj.
364 * In order for lower level code to determine a
365 * Java object given an IJG struct, such as for dispatching warnings,
366 * we use the client_data field of the jpeg object to store a pointer
367 * to the imageIOData object. Maintenance of this pointer is performed
368 * exclusively within the following access functions. If you
369 * change that, you run the risk of dangling pointers.
370 */
371typedef struct imageIODataStruct {
372 j_common_ptr jpegObj; // Either struct is fine
373 jobject imageIOobj; // A JPEGImageReader or a JPEGImageWriter
374
375 streamBuffer streamBuf; // Buffer for the stream
376 pixelBuffer pixelBuf; // Buffer for pixels
377
378 jboolean abortFlag; // Passed down from Java abort method
379} imageIOData, *imageIODataPtr;
380
381/*
382 * Allocate and initialize a new imageIOData object to associate the
383 * jpeg object and the Java object. Returns a pointer to the new object
384 * on success, NULL on failure.
385 */
386static imageIODataPtr initImageioData (JNIEnv *env,
387 j_common_ptr cinfo,
388 jobject obj) {
389 int i, j;
390
391 imageIODataPtr data = (imageIODataPtr) malloc (sizeof(imageIOData));
392 if (data == NULL) {
393 return NULL;
394 }
395
396 data->jpegObj = cinfo;
397 cinfo->client_data = data;
398
399#ifdef DEBUG
400 printf("new structures: data is %p, cinfo is %p\n", data, cinfo);
401#endif
402
403 data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj);
404 if (data->imageIOobj == NULL) {
405 free (data);
406 return NULL;
407 }
408 if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) {
409 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
410 free (data);
411 return NULL;
412 }
413 initPixelBuffer(&data->pixelBuf);
414
415 data->abortFlag = JNI_FALSE;
416
417 return data;
418}
419
420/*
421 * Resets the imageIOData object to its initial state, as though
422 * it had just been allocated and initialized.
423 */
424static void resetImageIOData(JNIEnv *env, imageIODataPtr data) {
425 resetStreamBuffer(env, &data->streamBuf);
426 resetPixelBuffer(env, &data->pixelBuf);
427 data->abortFlag = JNI_FALSE;
428}
429
430/*
431 * Releases all resources held by this object and its subobjects,
432 * frees the object, and returns the jpeg object. This method must
433 * be called to avoid leaking global references.
434 * Note that the jpeg object is not freed or destroyed, as that is
435 * the client's responsibility, although the client_data field is
436 * cleared.
437 */
438static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) {
439 j_common_ptr ret = data->jpegObj;
440 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
441 destroyStreamBuffer(env, &data->streamBuf);
442 resetPixelBuffer(env, &data->pixelBuf);
443 ret->client_data = NULL;
444 free(data);
445 return ret;
446}
447
448/******************** end ImageIOData definition ***********************/
449
450/******************** Java array pinning and unpinning *****************/
451
452/* We use Get/ReleasePrimitiveArrayCritical functions to avoid
453 * the need to copy array elements for the above two objects.
454 *
455 * MAKE SURE TO:
456 *
457 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
458 * callbacks to Java.
459 * - call RELEASE_ARRAYS before returning to Java.
460 *
461 * Otherwise things will go horribly wrong. There may be memory leaks,
462 * excessive pinning, or even VM crashes!
463 *
464 * Note that GetPrimitiveArrayCritical may fail!
465 */
466
467/*
468 * Release (unpin) all the arrays in use during a read.
469 */
470static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte)
471{
472 unpinStreamBuffer(env, &data->streamBuf, next_byte);
473
474 unpinPixelBuffer(env, &data->pixelBuf);
475
476}
477
478/*
479 * Get (pin) all the arrays in use during a read.
480 */
481static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) {
482 if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) {
483 return NOT_OK;
484 }
485
486 if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) {
487 RELEASE_ARRAYS(env, data, *next_byte);
488 return NOT_OK;
489 }
490 return OK;
491}
492
493/****** end of Java array pinning and unpinning ***********/
494
495/****** Error Handling *******/
496
497/*
498 * Set up error handling to use setjmp/longjmp. This is the third such
499 * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes
500 * setup thier own. Ultimately these should be integrated, as they all
501 * do pretty much the same thing.
502 */
503
504struct sun_jpeg_error_mgr {
505 struct jpeg_error_mgr pub; /* "public" fields */
506
507 jmp_buf setjmp_buffer; /* for return to caller */
508};
509
510typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr;
511
512/*
513 * Here's the routine that will replace the standard error_exit method:
514 */
515
516METHODDEF(void)
517sun_jpeg_error_exit (j_common_ptr cinfo)
518{
519 /* cinfo->err really points to a sun_jpeg_error_mgr struct */
520 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err;
521
522 /* For Java, we will format the message and put it in the error we throw. */
523
524 /* Return control to the setjmp point */
525 longjmp(myerr->setjmp_buffer, 1);
526}
527
528/*
529 * Error Message handling
530 *
531 * This overrides the output_message method to send JPEG messages
532 *
533 */
534
535METHODDEF(void)
536sun_jpeg_output_message (j_common_ptr cinfo)
537{
538 char buffer[JMSG_LENGTH_MAX];
539 jstring string;
540 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
541 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
542 jobject theObject;
543
544 /* Create the message */
545 (*cinfo->err->format_message) (cinfo, buffer);
546
547 // Create a new java string from the message
548 string = (*env)->NewStringUTF(env, buffer);
549
550 theObject = data->imageIOobj;
551
552 if (cinfo->is_decompressor) {
553 (*env)->CallVoidMethod(env, theObject,
554 JPEGImageReader_warningWithMessageID,
555 string);
556 } else {
557 (*env)->CallVoidMethod(env, theObject,
558 JPEGImageWriter_warningWithMessageID,
559 string);
560 }
561}
562
563/* End of verbatim copy from jpegdecoder.c */
564
565/*************** end of error handling *********************/
566
567/*************** Shared utility code ***********************/
568
569static void imageio_set_stream(JNIEnv *env,
570 j_common_ptr cinfo,
571 imageIODataPtr data,
572 jobject stream){
573 streamBufferPtr sb;
574 sun_jpeg_error_ptr jerr;
575
576 sb = &data->streamBuf;
577
578 resetStreamBuffer(env, sb); // Removes any old stream
579
580 /* Now we need a new global reference for the stream */
581 if (stream != NULL) { // Fix for 4411955
582 sb->stream = (*env)->NewGlobalRef(env, stream);
583 if (sb->stream == NULL) {
584 JNU_ThrowByName(env,
585 "java/lang/OutOfMemoryError",
586 "Setting Stream");
587 return;
588 }
589 }
590
591 /* And finally reset state */
592 data->abortFlag = JNI_FALSE;
593
594 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
595 jerr = (sun_jpeg_error_ptr) cinfo->err;
596
597 if (setjmp(jerr->setjmp_buffer)) {
598 /* If we get here, the JPEG code has signaled an error
599 while aborting. */
600 if (!(*env)->ExceptionOccurred(env)) {
601 char buffer[JMSG_LENGTH_MAX];
602 (*cinfo->err->format_message) (cinfo,
603 buffer);
604 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
605 }
606 return;
607 }
608
609 jpeg_abort(cinfo); // Frees any markers, but not tables
610
611}
612
613static void imageio_reset(JNIEnv *env,
614 j_common_ptr cinfo,
615 imageIODataPtr data) {
616 sun_jpeg_error_ptr jerr;
617
618 resetImageIOData(env, data); // Mapping to jpeg object is retained.
619
620 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
621 jerr = (sun_jpeg_error_ptr) cinfo->err;
622
623 if (setjmp(jerr->setjmp_buffer)) {
624 /* If we get here, the JPEG code has signaled an error
625 while aborting. */
626 if (!(*env)->ExceptionOccurred(env)) {
627 char buffer[JMSG_LENGTH_MAX];
628 (*cinfo->err->format_message) (cinfo, buffer);
629 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
630 }
631 return;
632 }
633
634 jpeg_abort(cinfo); // Does not reset tables
635
636}
637
638static void imageio_dispose(j_common_ptr info) {
639
640 if (info != NULL) {
641 free(info->err);
642 info->err = NULL;
643 if (info->is_decompressor) {
644 j_decompress_ptr dinfo = (j_decompress_ptr) info;
645 free(dinfo->src);
646 dinfo->src = NULL;
647 } else {
648 j_compress_ptr cinfo = (j_compress_ptr) info;
649 free(cinfo->dest);
650 cinfo->dest = NULL;
651 }
652 jpeg_destroy(info);
653 free(info);
654 }
655}
656
657static void imageio_abort(JNIEnv *env, jobject this,
658 imageIODataPtr data) {
659 data->abortFlag = JNI_TRUE;
660}
661
662static int setQTables(JNIEnv *env,
663 j_common_ptr cinfo,
664 jobjectArray qtables,
665 boolean write) {
666 jsize qlen;
667 jobject table;
668 jintArray qdata;
669 jint *qdataBody;
670 JQUANT_TBL *quant_ptr;
671 int i, j;
672 j_compress_ptr comp;
673 j_decompress_ptr decomp;
674
675 qlen = (*env)->GetArrayLength(env, qtables);
676#ifdef DEBUG
677 printf("in setQTables, qlen = %d, write is %d\n", qlen, write);
678#endif
679 for (i = 0; i < qlen; i++) {
680 table = (*env)->GetObjectArrayElement(env, qtables, i);
681 qdata = (*env)->GetObjectField(env, table, JPEGQTable_tableID);
682 qdataBody = (*env)->GetPrimitiveArrayCritical(env, qdata, NULL);
683
684 if (cinfo->is_decompressor) {
685 decomp = (j_decompress_ptr) cinfo;
686 if (decomp->quant_tbl_ptrs[i] == NULL) {
687 decomp->quant_tbl_ptrs[i] =
688 jpeg_alloc_quant_table(cinfo);
689 }
690 quant_ptr = decomp->quant_tbl_ptrs[i];
691 } else {
692 comp = (j_compress_ptr) cinfo;
693 if (comp->quant_tbl_ptrs[i] == NULL) {
694 comp->quant_tbl_ptrs[i] =
695 jpeg_alloc_quant_table(cinfo);
696 }
697 quant_ptr = comp->quant_tbl_ptrs[i];
698 }
699
700 for (j = 0; j < 64; j++) {
701 quant_ptr->quantval[j] = (UINT16)qdataBody[j];
702 }
703 quant_ptr->sent_table = !write;
704 (*env)->ReleasePrimitiveArrayCritical(env,
705 qdata,
706 qdataBody,
707 0);
708 }
709 return qlen;
710}
711
712static void setHuffTable(JNIEnv *env,
713 JHUFF_TBL *huff_ptr,
714 jobject table) {
715
716 jshortArray huffLens;
717 jshortArray huffValues;
718 jshort *hlensBody, *hvalsBody;
719 jsize hlensLen, hvalsLen;
720 int i;
721
722 // lengths
723 huffLens = (*env)->GetObjectField(env,
724 table,
725 JPEGHuffmanTable_lengthsID);
726 hlensLen = (*env)->GetArrayLength(env, huffLens);
727 hlensBody = (*env)->GetShortArrayElements(env,
728 huffLens,
729 NULL);
730 for (i = 1; i <= hlensLen; i++) {
731 huff_ptr->bits[i] = (UINT8)hlensBody[i-1];
732 }
733 (*env)->ReleaseShortArrayElements(env,
734 huffLens,
735 hlensBody,
736 JNI_ABORT);
737 // values
738 huffValues = (*env)->GetObjectField(env,
739 table,
740 JPEGHuffmanTable_valuesID);
741 hvalsLen = (*env)->GetArrayLength(env, huffValues);
742 hvalsBody = (*env)->GetShortArrayElements(env,
743 huffValues,
744 NULL);
745
746 for (i = 0; i < hvalsLen; i++) {
747 huff_ptr->huffval[i] = (UINT8)hvalsBody[i];
748 }
749 (*env)->ReleaseShortArrayElements(env,
750 huffValues,
751 hvalsBody,
752 JNI_ABORT);
753}
754
755static int setHTables(JNIEnv *env,
756 j_common_ptr cinfo,
757 jobjectArray DCHuffmanTables,
758 jobjectArray ACHuffmanTables,
759 boolean write) {
760 int i;
761 jobject table;
762 JHUFF_TBL *huff_ptr;
763 j_compress_ptr comp;
764 j_decompress_ptr decomp;
765 jsize hlen = (*env)->GetArrayLength(env, DCHuffmanTables);
766 for (i = 0; i < hlen; i++) {
767 if (cinfo->is_decompressor) {
768 decomp = (j_decompress_ptr) cinfo;
769 if (decomp->dc_huff_tbl_ptrs[i] == NULL) {
770 decomp->dc_huff_tbl_ptrs[i] =
771 jpeg_alloc_huff_table(cinfo);
772 }
773 huff_ptr = decomp->dc_huff_tbl_ptrs[i];
774 } else {
775 comp = (j_compress_ptr) cinfo;
776 if (comp->dc_huff_tbl_ptrs[i] == NULL) {
777 comp->dc_huff_tbl_ptrs[i] =
778 jpeg_alloc_huff_table(cinfo);
779 }
780 huff_ptr = comp->dc_huff_tbl_ptrs[i];
781 }
782 table = (*env)->GetObjectArrayElement(env, DCHuffmanTables, i);
783 setHuffTable(env, huff_ptr, table);
784 huff_ptr->sent_table = !write;
785 }
786 hlen = (*env)->GetArrayLength(env, ACHuffmanTables);
787 for (i = 0; i < hlen; i++) {
788 if (cinfo->is_decompressor) {
789 decomp = (j_decompress_ptr) cinfo;
790 if (decomp->ac_huff_tbl_ptrs[i] == NULL) {
791 decomp->ac_huff_tbl_ptrs[i] =
792 jpeg_alloc_huff_table(cinfo);
793 }
794 huff_ptr = decomp->ac_huff_tbl_ptrs[i];
795 } else {
796 comp = (j_compress_ptr) cinfo;
797 if (comp->ac_huff_tbl_ptrs[i] == NULL) {
798 comp->ac_huff_tbl_ptrs[i] =
799 jpeg_alloc_huff_table(cinfo);
800 }
801 huff_ptr = comp->ac_huff_tbl_ptrs[i];
802 }
803 table = (*env)->GetObjectArrayElement(env, ACHuffmanTables, i);
804 setHuffTable(env, huff_ptr, table);
805 huff_ptr->sent_table = !write;
806 }
807 return hlen;
808}
809
810
811/*************** end of shared utility code ****************/
812
813/********************** Reader Support **************************/
814
815/********************** Source Management ***********************/
816
817/*
818 * INPUT HANDLING:
819 *
820 * The JPEG library's input management is defined by the jpeg_source_mgr
821 * structure which contains two fields to convey the information in the
822 * buffer and 5 methods which perform all buffer management. The library
823 * defines a standard input manager that uses stdio for obtaining compressed
824 * jpeg data, but here we need to use Java to get our data.
825 *
826 * We use the library jpeg_source_mgr but our own routines that access
827 * imageio-specific information in the imageIOData structure.
828 */
829
830/*
831 * Initialize source. This is called by jpeg_read_header() before any
832 * data is actually read. Unlike init_destination(), it may leave
833 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
834 * will occur immediately).
835 */
836
837GLOBAL(void)
838imageio_init_source(j_decompress_ptr cinfo)
839{
840 struct jpeg_source_mgr *src = cinfo->src;
841 src->next_input_byte = NULL;
842 src->bytes_in_buffer = 0;
843}
844
845/*
846 * This is called whenever bytes_in_buffer has reached zero and more
847 * data is wanted. In typical applications, it should read fresh data
848 * into the buffer (ignoring the current state of next_input_byte and
849 * bytes_in_buffer), reset the pointer & count to the start of the
850 * buffer, and return TRUE indicating that the buffer has been reloaded.
851 * It is not necessary to fill the buffer entirely, only to obtain at
852 * least one more byte. bytes_in_buffer MUST be set to a positive value
853 * if TRUE is returned. A FALSE return should only be used when I/O
854 * suspension is desired (this mode is discussed in the next section).
855 */
856/*
857 * Note that with I/O suspension turned on, this procedure should not
858 * do any work since the JPEG library has a very simple backtracking
859 * mechanism which relies on the fact that the buffer will be filled
860 * only when it has backed out to the top application level. When
861 * suspendable is turned on, imageio_fill_suspended_buffer will
862 * do the actual work of filling the buffer.
863 */
864
865GLOBAL(boolean)
866imageio_fill_input_buffer(j_decompress_ptr cinfo)
867{
868 struct jpeg_source_mgr *src = cinfo->src;
869 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
870 streamBufferPtr sb = &data->streamBuf;
871 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
872 int ret;
873
874 /* This is where input suspends */
875 if (sb->suspendable) {
876 return FALSE;
877 }
878
879#ifdef DEBUG
880 printf("Filling input buffer, remaining skip is %ld, ",
881 sb->remaining_skip);
882 printf("Buffer length is %d\n", sb->bufferLength);
883#endif
884
885 /*
886 * Definitively skips. Could be left over if we tried to skip
887 * more than a buffer's worth but suspended when getting the next
888 * buffer. Now we aren't suspended, so we can catch up.
889 */
890 if (sb->remaining_skip) {
891 src->skip_input_data(cinfo, 0);
892 }
893
894 /*
895 * Now fill a complete buffer, or as much of one as the stream
896 * will give us if we are near the end.
897 */
898 RELEASE_ARRAYS(env, data, src->next_input_byte);
899 ret = (*env)->CallIntMethod(env,
900 sb->stream,
901 ImageInputStream_readID,
902 sb->hstreamBuffer, 0,
903 sb->bufferLength);
904 if ((*env)->ExceptionOccurred(env)
905 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
906 cinfo->err->error_exit((j_common_ptr) cinfo);
907 }
908
909#ifdef DEBUG
910 printf("Buffer filled. ret = %d\n", ret);
911#endif
912 /*
913 * If we have reached the end of the stream, then the EOI marker
914 * is missing. We accept such streams but generate a warning.
915 * The image is likely to be corrupted, though everything through
916 * the end of the last complete MCU should be usable.
917 */
918 if (ret <= 0) {
919 jobject reader = data->imageIOobj;
920#ifdef DEBUG
921 printf("YO! Early EOI! ret = %d\n", ret);
922#endif
923 RELEASE_ARRAYS(env, data, src->next_input_byte);
924 (*env)->CallVoidMethod(env, reader,
925 JPEGImageReader_warningOccurredID,
926 READ_NO_EOI);
927 if ((*env)->ExceptionOccurred(env)
928 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
929 cinfo->err->error_exit((j_common_ptr) cinfo);
930 }
931
932 sb->buf[0] = (JOCTET) 0xFF;
933 sb->buf[1] = (JOCTET) JPEG_EOI;
934 ret = 2;
935 }
936
937 src->next_input_byte = sb->buf;
938 src->bytes_in_buffer = ret;
939
940 return TRUE;
941}
942
943/*
944 * With I/O suspension turned on, the JPEG library requires that all
945 * buffer filling be done at the top application level, using this
946 * function. Due to the way that backtracking works, this procedure
947 * saves all of the data that was left in the buffer when suspension
948 * occured and read new data only at the end.
949 */
950
951GLOBAL(void)
952imageio_fill_suspended_buffer(j_decompress_ptr cinfo)
953{
954 struct jpeg_source_mgr *src = cinfo->src;
955 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
956 streamBufferPtr sb = &data->streamBuf;
957 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
958 jint ret;
959 int offset, buflen;
960
961 /*
962 * The original (jpegdecoder.c) had code here that called
963 * InputStream.available and just returned if the number of bytes
964 * available was less than any remaining skip. Presumably this was
965 * to avoid blocking, although the benefit was unclear, as no more
966 * decompression can take place until more data is available, so
967 * the code would block on input a little further along anyway.
968 * ImageInputStreams don't have an available method, so we'll just
969 * block in the skip if we have to.
970 */
971
972 if (sb->remaining_skip) {
973 src->skip_input_data(cinfo, 0);
974 }
975
976 /* Save the data currently in the buffer */
977 offset = src->bytes_in_buffer;
978 if (src->next_input_byte > sb->buf) {
979 memcpy(sb->buf, src->next_input_byte, offset);
980 }
981 RELEASE_ARRAYS(env, data, src->next_input_byte);
982 buflen = sb->bufferLength - offset;
983 if (buflen <= 0) {
984 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
985 cinfo->err->error_exit((j_common_ptr) cinfo);
986 }
987 return;
988 }
989
990 ret = (*env)->CallIntMethod(env, sb->stream,
991 ImageInputStream_readID,
992 sb->hstreamBuffer,
993 offset, buflen);
994 if ((*env)->ExceptionOccurred(env)
995 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
996 cinfo->err->error_exit((j_common_ptr) cinfo);
997 }
998 /*
999 * If we have reached the end of the stream, then the EOI marker
1000 * is missing. We accept such streams but generate a warning.
1001 * The image is likely to be corrupted, though everything through
1002 * the end of the last complete MCU should be usable.
1003 */
1004 if (ret <= 0) {
1005 jobject reader = data->imageIOobj;
1006 RELEASE_ARRAYS(env, data, src->next_input_byte);
1007 (*env)->CallVoidMethod(env, reader,
1008 JPEGImageReader_warningOccurredID,
1009 READ_NO_EOI);
1010 if ((*env)->ExceptionOccurred(env)
1011 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1012 cinfo->err->error_exit((j_common_ptr) cinfo);
1013 }
1014
1015 sb->buf[offset] = (JOCTET) 0xFF;
1016 sb->buf[offset + 1] = (JOCTET) JPEG_EOI;
1017 ret = 2;
1018 }
1019
1020 src->next_input_byte = sb->buf;
1021 src->bytes_in_buffer = ret + offset;
1022
1023 return;
1024}
1025
1026/*
1027 * Skip num_bytes worth of data. The buffer pointer and count are
1028 * advanced over num_bytes input bytes, using the input stream
1029 * skipBytes method if the skip is greater than the number of bytes
1030 * in the buffer. This is used to skip over a potentially large amount of
1031 * uninteresting data (such as an APPn marker). bytes_in_buffer will be
1032 * zero on return if the skip is larger than the current contents of the
1033 * buffer.
1034 *
1035 * A negative skip count is treated as a no-op. A zero skip count
1036 * skips any remaining skip from a previous skip while suspended.
1037 *
1038 * Note that with I/O suspension turned on, this procedure does not
1039 * call skipBytes since the JPEG library has a very simple backtracking
1040 * mechanism which relies on the fact that the application level has
1041 * exclusive control over actual I/O.
1042 */
1043
1044GLOBAL(void)
1045imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
1046{
1047 struct jpeg_source_mgr *src = cinfo->src;
1048 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1049 streamBufferPtr sb = &data->streamBuf;
1050 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1051 jlong ret;
1052 jobject reader;
1053
1054 if (num_bytes < 0) {
1055 return;
1056 }
1057 num_bytes += sb->remaining_skip;
1058 sb->remaining_skip = 0;
1059
1060 /* First the easy case where we are skipping <= the current contents. */
1061 ret = src->bytes_in_buffer;
1062 if (ret >= num_bytes) {
1063 src->next_input_byte += num_bytes;
1064 src->bytes_in_buffer -= num_bytes;
1065 return;
1066 }
1067
1068 /*
1069 * We are skipping more than is in the buffer. We empty the buffer and,
1070 * if we aren't suspended, call the Java skipBytes method. We always
1071 * leave the buffer empty, to be filled by either fill method above.
1072 */
1073 src->bytes_in_buffer = 0;
1074 src->next_input_byte = sb->buf;
1075
1076 num_bytes -= (long)ret;
1077 if (sb->suspendable) {
1078 sb->remaining_skip = num_bytes;
1079 return;
1080 }
1081
1082 RELEASE_ARRAYS(env, data, src->next_input_byte);
1083 ret = (*env)->CallLongMethod(env,
1084 sb->stream,
1085 ImageInputStream_skipBytesID,
1086 (jlong) num_bytes);
1087 if ((*env)->ExceptionOccurred(env)
1088 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1089 cinfo->err->error_exit((j_common_ptr) cinfo);
1090 }
1091
1092 /*
1093 * If we have reached the end of the stream, then the EOI marker
1094 * is missing. We accept such streams but generate a warning.
1095 * The image is likely to be corrupted, though everything through
1096 * the end of the last complete MCU should be usable.
1097 */
1098 if (ret <= 0) {
1099 reader = data->imageIOobj;
1100 RELEASE_ARRAYS(env, data, src->next_input_byte);
1101 (*env)->CallVoidMethod(env,
1102 reader,
1103 JPEGImageReader_warningOccurredID,
1104 READ_NO_EOI);
1105
1106 if ((*env)->ExceptionOccurred(env)
1107 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1108 cinfo->err->error_exit((j_common_ptr) cinfo);
1109 }
1110 sb->buf[0] = (JOCTET) 0xFF;
1111 sb->buf[1] = (JOCTET) JPEG_EOI;
1112 src->bytes_in_buffer = 2;
1113 src->next_input_byte = sb->buf;
1114 }
1115}
1116
1117/*
1118 * Terminate source --- called by jpeg_finish_decompress() after all
1119 * data for an image has been read. In our case pushes back any
1120 * remaining data, as it will be for another image and must be available
1121 * for java to find out that there is another image. Also called if
1122 * reseting state after reading a tables-only image.
1123 */
1124
1125GLOBAL(void)
1126imageio_term_source(j_decompress_ptr cinfo)
1127{
1128 // To pushback, just seek back by src->bytes_in_buffer
1129 struct jpeg_source_mgr *src = cinfo->src;
1130 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1131 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1132 jobject reader = data->imageIOobj;
1133 if (src->bytes_in_buffer > 0) {
1134 RELEASE_ARRAYS(env, data, src->next_input_byte);
1135 (*env)->CallVoidMethod(env,
1136 reader,
1137 JPEGImageReader_pushBackID,
1138 src->bytes_in_buffer);
1139
1140 if ((*env)->ExceptionOccurred(env)
1141 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1142 cinfo->err->error_exit((j_common_ptr) cinfo);
1143 }
1144 src->bytes_in_buffer = 0;
1145 //src->next_input_byte = sb->buf;
1146 }
1147}
1148
1149/********************* end of source manager ******************/
1150
1151/********************* ICC profile support ********************/
1152/*
1153 * The following routines are modified versions of the ICC
1154 * profile support routines available from the IJG website.
1155 * The originals were written by Todd Newman
1156 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for
1157 * the IJG. They are further modified to fit in the context
1158 * of the imageio JPEG plug-in.
1159 */
1160
1161/*
1162 * Since an ICC profile can be larger than the maximum size of a JPEG marker
1163 * (64K), we need provisions to split it into multiple markers. The format
1164 * defined by the ICC specifies one or more APP2 markers containing the
1165 * following data:
1166 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
1167 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
1168 * Number of markers Total number of APP2's used (1 byte)
1169 * Profile data (remainder of APP2 data)
1170 * Decoders should use the marker sequence numbers to reassemble the profile,
1171 * rather than assuming that the APP2 markers appear in the correct sequence.
1172 */
1173
1174#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
1175#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
1176#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
1177#define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
1178
1179
1180/*
1181 * Handy subroutine to test whether a saved marker is an ICC profile marker.
1182 */
1183
1184static boolean
1185marker_is_icc (jpeg_saved_marker_ptr marker)
1186{
1187 return
1188 marker->marker == ICC_MARKER &&
1189 marker->data_length >= ICC_OVERHEAD_LEN &&
1190 /* verify the identifying string */
1191 GETJOCTET(marker->data[0]) == 0x49 &&
1192 GETJOCTET(marker->data[1]) == 0x43 &&
1193 GETJOCTET(marker->data[2]) == 0x43 &&
1194 GETJOCTET(marker->data[3]) == 0x5F &&
1195 GETJOCTET(marker->data[4]) == 0x50 &&
1196 GETJOCTET(marker->data[5]) == 0x52 &&
1197 GETJOCTET(marker->data[6]) == 0x4F &&
1198 GETJOCTET(marker->data[7]) == 0x46 &&
1199 GETJOCTET(marker->data[8]) == 0x49 &&
1200 GETJOCTET(marker->data[9]) == 0x4C &&
1201 GETJOCTET(marker->data[10]) == 0x45 &&
1202 GETJOCTET(marker->data[11]) == 0x0;
1203}
1204
1205/*
1206 * See if there was an ICC profile in the JPEG file being read;
1207 * if so, reassemble and return the profile data as a new Java byte array.
1208 * If there was no ICC profile, return NULL.
1209 *
1210 * If the file contains invalid ICC APP2 markers, we throw an IIOException
1211 * with an appropriate message.
1212 */
1213
1214jbyteArray
1215read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo)
1216{
1217 jpeg_saved_marker_ptr marker;
1218 int num_markers = 0;
1219 int seq_no;
1220 JOCTET *icc_data;
1221 unsigned int total_length;
1222#define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes
1223 char marker_present[MAX_SEQ_NO+1]; // 1 if marker found
1224 unsigned int data_length[MAX_SEQ_NO+1]; // size of profile data in marker
1225 unsigned int data_offset[MAX_SEQ_NO+1]; // offset for data in marker
1226 jbyteArray data = NULL;
1227
1228 /* This first pass over the saved markers discovers whether there are
1229 * any ICC markers and verifies the consistency of the marker numbering.
1230 */
1231
1232 for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
1233 marker_present[seq_no] = 0;
1234
1235 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
1236 if (marker_is_icc(marker)) {
1237 if (num_markers == 0)
1238 num_markers = GETJOCTET(marker->data[13]);
1239 else if (num_markers != GETJOCTET(marker->data[13])) {
1240 JNU_ThrowByName(env, "javax/imageio/IIOException",
1241 "Invalid icc profile: inconsistent num_markers fields");
1242 return NULL;
1243 }
1244 seq_no = GETJOCTET(marker->data[12]);
1245 if (seq_no <= 0 || seq_no > num_markers) {
1246 JNU_ThrowByName(env, "javax/imageio/IIOException",
1247 "Invalid icc profile: bad sequence number");
1248 return NULL;
1249 }
1250 if (marker_present[seq_no]) {
1251 JNU_ThrowByName(env, "javax/imageio/IIOException",
1252 "Invalid icc profile: duplicate sequence numbers");
1253 return NULL;
1254 }
1255 marker_present[seq_no] = 1;
1256 data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
1257 }
1258 }
1259
1260 if (num_markers == 0)
1261 return NULL; // There is no profile
1262
1263 /* Check for missing markers, count total space needed,
1264 * compute offset of each marker's part of the data.
1265 */
1266
1267 total_length = 0;
1268 for (seq_no = 1; seq_no <= num_markers; seq_no++) {
1269 if (marker_present[seq_no] == 0) {
1270 JNU_ThrowByName(env, "javax/imageio/IIOException",
1271 "Invalid icc profile: missing sequence number");
1272 return NULL;
1273 }
1274 data_offset[seq_no] = total_length;
1275 total_length += data_length[seq_no];
1276 }
1277
1278 if (total_length <= 0) {
1279 JNU_ThrowByName(env, "javax/imageio/IIOException",
1280 "Invalid icc profile: found only empty markers");
1281 return NULL;
1282 }
1283
1284 /* Allocate a Java byte array for assembled data */
1285
1286 data = (*env)->NewByteArray(env, total_length);
1287 if (data == NULL) {
1288 JNU_ThrowByName(env,
1289 "java/lang/OutOfMemoryError",
1290 "Reading ICC profile");
1291 return NULL;
1292 }
1293
1294 icc_data = (JOCTET *)(*env)->GetPrimitiveArrayCritical(env,
1295 data,
1296 NULL);
1297 if (icc_data == NULL) {
1298 JNU_ThrowByName(env, "javax/imageio/IIOException",
1299 "Unable to pin icc profile data array");
1300 return NULL;
1301 }
1302
1303 /* and fill it in */
1304 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
1305 if (marker_is_icc(marker)) {
1306 JOCTET FAR *src_ptr;
1307 JOCTET *dst_ptr;
1308 unsigned int length;
1309 seq_no = GETJOCTET(marker->data[12]);
1310 dst_ptr = icc_data + data_offset[seq_no];
1311 src_ptr = marker->data + ICC_OVERHEAD_LEN;
1312 length = data_length[seq_no];
1313 while (length--) {
1314 *dst_ptr++ = *src_ptr++;
1315 }
1316 }
1317 }
1318
1319 /* finally, unpin the array */
1320 (*env)->ReleasePrimitiveArrayCritical(env,
1321 data,
1322 icc_data,
1323 0);
1324
1325
1326 return data;
1327}
1328
1329/********************* end of ICC profile support *************/
1330
1331/********************* Reader JNI calls ***********************/
1332
1333JNIEXPORT void JNICALL
1334Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initReaderIDs
1335 (JNIEnv *env,
1336 jclass cls,
1337 jclass ImageInputStreamClass,
1338 jclass qTableClass,
1339 jclass huffClass) {
1340
1341 ImageInputStream_readID = (*env)->GetMethodID(env,
1342 ImageInputStreamClass,
1343 "read",
1344 "([BII)I");
1345 ImageInputStream_skipBytesID = (*env)->GetMethodID(env,
1346 ImageInputStreamClass,
1347 "skipBytes",
1348 "(J)J");
1349 JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env,
1350 cls,
1351 "warningOccurred",
1352 "(I)V");
1353 JPEGImageReader_warningWithMessageID =
1354 (*env)->GetMethodID(env,
1355 cls,
1356 "warningWithMessage",
1357 "(Ljava/lang/String;)V");
1358 JPEGImageReader_setImageDataID = (*env)->GetMethodID(env,
1359 cls,
1360 "setImageData",
1361 "(IIIII[B)V");
1362 JPEGImageReader_acceptPixelsID = (*env)->GetMethodID(env,
1363 cls,
1364 "acceptPixels",
1365 "(IZ)V");
1366 JPEGImageReader_passStartedID = (*env)->GetMethodID(env,
1367 cls,
1368 "passStarted",
1369 "(I)V");
1370 JPEGImageReader_passCompleteID = (*env)->GetMethodID(env,
1371 cls,
1372 "passComplete",
1373 "()V");
1374 JPEGImageReader_pushBackID = (*env)->GetMethodID(env,
1375 cls,
1376 "pushBack",
1377 "(I)V");
1378 JPEGQTable_tableID = (*env)->GetFieldID(env,
1379 qTableClass,
1380 "qTable",
1381 "[I");
1382
1383 JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env,
1384 huffClass,
1385 "lengths",
1386 "[S");
1387
1388 JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env,
1389 huffClass,
1390 "values",
1391 "[S");
1392}
1393
1394JNIEXPORT jlong JNICALL
1395Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader
1396 (JNIEnv *env,
1397 jobject this) {
1398
1399 imageIODataPtr ret;
1400 struct sun_jpeg_error_mgr *jerr;
1401
1402 /* This struct contains the JPEG decompression parameters and pointers to
1403 * working space (which is allocated as needed by the JPEG library).
1404 */
1405 struct jpeg_decompress_struct *cinfo =
1406 malloc(sizeof(struct jpeg_decompress_struct));
1407 if (cinfo == NULL) {
1408 JNU_ThrowByName( env,
1409 "java/lang/OutOfMemoryError",
1410 "Initializing Reader");
1411 return 0;
1412 }
1413
1414 /* We use our private extension JPEG error handler.
1415 */
1416 jerr = malloc (sizeof(struct sun_jpeg_error_mgr));
1417 if (jerr == NULL) {
1418 JNU_ThrowByName( env,
1419 "java/lang/OutOfMemoryError",
1420 "Initializing Reader");
1421 return 0;
1422 }
1423
1424 /* We set up the normal JPEG error routines, then override error_exit. */
1425 cinfo->err = jpeg_std_error(&(jerr->pub));
1426 jerr->pub.error_exit = sun_jpeg_error_exit;
1427 /* We need to setup our own print routines */
1428 jerr->pub.output_message = sun_jpeg_output_message;
1429 /* Now we can setjmp before every call to the library */
1430
1431 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1432 if (setjmp(jerr->setjmp_buffer)) {
1433 /* If we get here, the JPEG code has signaled an error. */
1434 char buffer[JMSG_LENGTH_MAX];
1435 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1436 buffer);
1437 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1438 return 0;
1439 }
1440
1441 /* Perform library initialization */
1442 jpeg_create_decompress(cinfo);
1443
1444 // Set up to keep any APP2 markers, as these might contain ICC profile
1445 // data
1446 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1447
1448 /*
1449 * Now set up our source.
1450 */
1451 cinfo->src =
1452 (struct jpeg_source_mgr *) malloc (sizeof(struct jpeg_source_mgr));
1453 if (cinfo->src == NULL) {
1454 JNU_ThrowByName(env,
1455 "java/lang/OutOfMemoryError",
1456 "Initializing Reader");
1457 return 0;
1458 }
1459 cinfo->src->bytes_in_buffer = 0;
1460 cinfo->src->next_input_byte = NULL;
1461 cinfo->src->init_source = imageio_init_source;
1462 cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1463 cinfo->src->skip_input_data = imageio_skip_input_data;
1464 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1465 cinfo->src->term_source = imageio_term_source;
1466
1467 /* set up the association to persist for future calls */
1468 ret = initImageioData(env, (j_common_ptr) cinfo, this);
1469 if (ret == NULL) {
1470 JNU_ThrowByName( env,
1471 "java/lang/OutOfMemoryError",
1472 "Initializing Reader");
1473 return 0;
1474 }
1475 return (jlong) ret;
1476}
1477
1478/*
1479 * When we set a source from Java, we set up the stream in the streamBuf
1480 * object. If there was an old one, it is released first.
1481 */
1482
1483JNIEXPORT void JNICALL
1484Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource
1485 (JNIEnv *env,
1486 jobject this,
1487 jlong ptr,
1488 jobject source) {
1489
1490 imageIODataPtr data = (imageIODataPtr) ptr;
1491 j_common_ptr cinfo;
1492
1493 if (data == NULL) {
1494 JNU_ThrowByName(env,
1495 "java/lang/IllegalStateException",
1496 "Attempting to use reader after dispose()");
1497 return;
1498 }
1499
1500 cinfo = data->jpegObj;
1501
1502 imageio_set_stream(env, cinfo, data, source);
1503
1504 imageio_init_source((j_decompress_ptr) cinfo);
1505}
1506
1507#define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */
1508
1509/*
1510 * For EXIF images, the APP1 will appear immediately after the SOI,
1511 * so it's safe to only look at the first marker in the list.
1512 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1513 */
1514#define IS_EXIF(c) \
1515 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1516
1517JNIEXPORT jboolean JNICALL
1518Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
1519 (JNIEnv *env,
1520 jobject this,
1521 jlong ptr,
1522 jboolean clearFirst,
1523 jboolean reset) {
1524
1525 int ret;
1526 int h_samp0, h_samp1, h_samp2;
1527 int v_samp0, v_samp1, v_samp2;
1528 jboolean retval = JNI_FALSE;
1529 imageIODataPtr data = (imageIODataPtr) ptr;
1530 j_decompress_ptr cinfo;
1531 struct jpeg_source_mgr *src;
1532 sun_jpeg_error_ptr jerr;
1533
1534 if (data == NULL) {
1535 JNU_ThrowByName(env,
1536 "java/lang/IllegalStateException",
1537 "Attempting to use reader after dispose()");
1538 return JNI_FALSE;
1539 }
1540
1541 cinfo = (j_decompress_ptr) data->jpegObj;
1542 src = cinfo->src;
1543
1544 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1545 jerr = (sun_jpeg_error_ptr) cinfo->err;
1546
1547 if (setjmp(jerr->setjmp_buffer)) {
1548 /* If we get here, the JPEG code has signaled an error
1549 while reading the header. */
1550 RELEASE_ARRAYS(env, data, src->next_input_byte);
1551 if (!(*env)->ExceptionOccurred(env)) {
1552 char buffer[JMSG_LENGTH_MAX];
1553 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1554 buffer);
1555 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1556 }
1557 return retval;
1558 }
1559
1560#ifdef DEBUG
1561 printf("In readImageHeader, data is %p cinfo is %p\n", data, cinfo);
1562 printf("clearFirst is %d\n", clearFirst);
1563#endif
1564
1565 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1566 JNU_ThrowByName(env,
1567 "javax/imageio/IIOException",
1568 "Array pin failed");
1569 return retval;
1570 }
1571
1572 /*
1573 * Now clear the input buffer if the Java code has done a seek
1574 * on the stream since the last call, invalidating any buffer contents.
1575 */
1576 if (clearFirst) {
1577 clearStreamBuffer(&data->streamBuf);
1578 src->next_input_byte = NULL;
1579 src->bytes_in_buffer = 0;
1580 }
1581
1582 ret = jpeg_read_header(cinfo, FALSE);
1583
1584 if (ret == JPEG_HEADER_TABLES_ONLY) {
1585 retval = JNI_TRUE;
1586 imageio_term_source(cinfo); // Pushback remaining buffer contents
1587#ifdef DEBUG
1588 printf("just read tables-only image; q table 0 at %p\n",
1589 cinfo->quant_tbl_ptrs[0]);
1590#endif
1591 RELEASE_ARRAYS(env, data, src->next_input_byte);
1592 } else {
1593 /*
1594 * Now adjust the jpeg_color_space variable, which was set in
1595 * default_decompress_parms, to reflect our differences from IJG
1596 */
1597
1598 switch (cinfo->jpeg_color_space) {
1599 default :
1600 break;
1601 case JCS_YCbCr:
1602
1603 /*
1604 * There are several possibilities:
1605 * - we got image with embeded colorspace
1606 * Use it. User knows what he is doing.
1607 * - we got JFIF image
1608 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2)
1609 * - we got EXIF image
1610 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63)
1611 * - something else
1612 * Apply heuristical rules to identify actual colorspace.
1613 */
1614
1615 if (cinfo->saw_Adobe_marker) {
1616 if (cinfo->Adobe_transform != 1) {
1617 /*
1618 * IJG guesses this is YCbCr and emits a warning
1619 * We would rather not guess. Then the user knows
1620 * To read this as a Raster if at all
1621 */
1622 cinfo->jpeg_color_space = JCS_UNKNOWN;
1623 cinfo->out_color_space = JCS_UNKNOWN;
1624 }
1625 } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) {
1626 /*
1627 * IJG assumes all unidentified 3-channels are YCbCr.
1628 * We assume that only if the second two channels are
1629 * subsampled (either horizontally or vertically). If not,
1630 * we assume RGB.
1631 *
1632 * 4776576: Some digital cameras output YCbCr JPEG images
1633 * that do not contain a JFIF APP0 marker but are only
1634 * vertically subsampled (no horizontal subsampling).
1635 * We should only assume this is RGB data if the subsampling
1636 * factors for the second two channels are the same as the
1637 * first (check both horizontal and vertical factors).
1638 */
1639 h_samp0 = cinfo->comp_info[0].h_samp_factor;
1640 h_samp1 = cinfo->comp_info[1].h_samp_factor;
1641 h_samp2 = cinfo->comp_info[2].h_samp_factor;
1642
1643 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1644 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1645 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1646
1647 if ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) &&
1648 (v_samp1 == v_samp0) && (v_samp2 == v_samp0))
1649 {
1650 cinfo->jpeg_color_space = JCS_RGB;
1651 /* output is already RGB, so it stays the same */
1652 }
1653 }
1654 break;
1655#ifdef YCCALPHA
1656 case JCS_YCC:
1657 cinfo->out_color_space = JCS_YCC;
1658 break;
1659#endif
1660 case JCS_YCCK:
1661 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) {
1662 /*
1663 * IJG guesses this is YCCK and emits a warning
1664 * We would rather not guess. Then the user knows
1665 * To read this as a Raster if at all
1666 */
1667 cinfo->jpeg_color_space = JCS_UNKNOWN;
1668 cinfo->out_color_space = JCS_UNKNOWN;
1669 }
1670 break;
1671 case JCS_CMYK:
1672 /*
1673 * IJG assumes all unidentified 4-channels are CMYK.
1674 * We assume that only if the second two channels are
1675 * not subsampled (either horizontally or vertically).
1676 * If they are, we assume YCCK.
1677 */
1678 h_samp0 = cinfo->comp_info[0].h_samp_factor;
1679 h_samp1 = cinfo->comp_info[1].h_samp_factor;
1680 h_samp2 = cinfo->comp_info[2].h_samp_factor;
1681
1682 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1683 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1684 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1685
1686 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1687 (v_samp1 > v_samp0) && (v_samp2 > v_samp0))
1688 {
1689 cinfo->jpeg_color_space = JCS_YCCK;
1690 /* Leave the output space as CMYK */
1691 }
1692 }
1693 RELEASE_ARRAYS(env, data, src->next_input_byte);
1694 (*env)->CallVoidMethod(env, this,
1695 JPEGImageReader_setImageDataID,
1696 cinfo->image_width,
1697 cinfo->image_height,
1698 cinfo->jpeg_color_space,
1699 cinfo->out_color_space,
1700 cinfo->num_components,
1701 read_icc_profile(env, cinfo));
1702 if (reset) {
1703 jpeg_abort_decompress(cinfo);
1704 }
1705 }
1706
1707 return retval;
1708}
1709
1710
1711JNIEXPORT void JNICALL
1712Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setOutColorSpace
1713 (JNIEnv *env,
1714 jobject this,
1715 jlong ptr,
1716 jint code) {
1717
1718 imageIODataPtr data = (imageIODataPtr) ptr;
1719 j_decompress_ptr cinfo;
1720
1721 if (data == NULL) {
1722 JNU_ThrowByName(env,
1723 "java/lang/IllegalStateException",
1724 "Attempting to use reader after dispose()");
1725 return;
1726 }
1727
1728 cinfo = (j_decompress_ptr) data->jpegObj;
1729
1730 cinfo->out_color_space = code;
1731
1732}
1733
1734JNIEXPORT jboolean JNICALL
1735Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
1736 (JNIEnv *env,
1737 jobject this,
1738 jlong ptr,
1739 jbyteArray buffer,
1740 jint numBands,
1741 jintArray srcBands,
1742 jintArray bandSizes,
1743 jint sourceXStart,
1744 jint sourceYStart,
1745 jint sourceWidth,
1746 jint sourceHeight,
1747 jint stepX,
1748 jint stepY,
1749 jobjectArray qtables,
1750 jobjectArray DCHuffmanTables,
1751 jobjectArray ACHuffmanTables,
1752 jint minProgressivePass, // Counts from 0
1753 jint maxProgressivePass,
1754 jboolean wantUpdates) {
1755
1756
1757 struct jpeg_source_mgr *src;
1758 JSAMPROW scanLinePtr;
1759 jint bands[MAX_BANDS];
1760 int i, j;
1761 jint *body;
1762 int scanlineLimit;
1763 int pixelStride;
1764 unsigned char *in, *out, *pixelLimit;
1765 int targetLine;
1766 int skipLines, linesLeft;
1767 pixelBufferPtr pb;
1768 sun_jpeg_error_ptr jerr;
1769 boolean done;
1770 jint *bandSize;
1771 int maxBandValue, halfMaxBandValue;
1772 boolean mustScale = FALSE;
1773 boolean progressive = FALSE;
1774 boolean orderedBands = TRUE;
1775 imageIODataPtr data = (imageIODataPtr) ptr;
1776 j_decompress_ptr cinfo;
1777
1778 /* verify the inputs */
1779
1780 if (data == NULL) {
1781 JNU_ThrowByName(env,
1782 "java/lang/IllegalStateException",
1783 "Attempting to use reader after dispose()");
1784 return JNI_FALSE;
1785 }
1786
1787 if ((buffer == NULL) || (srcBands == NULL)) {
1788 JNU_ThrowNullPointerException(env, 0);
1789 return JNI_FALSE;
1790 }
1791
1792 cinfo = (j_decompress_ptr) data->jpegObj;
1793
1794 if ((numBands < 1) || (numBands > cinfo->num_components) ||
1795 (sourceXStart < 0) || (sourceXStart >= (jint)cinfo->image_width) ||
1796 (sourceYStart < 0) || (sourceYStart >= (jint)cinfo->image_height) ||
1797 (sourceWidth < 1) || (sourceWidth > (jint)cinfo->image_width) ||
1798 (sourceHeight < 1) || (sourceHeight > (jint)cinfo->image_height) ||
1799 (stepX < 1) || (stepY < 1) ||
1800 (minProgressivePass < 0) ||
1801 (maxProgressivePass < minProgressivePass))
1802 {
1803 JNU_ThrowByName(env, "javax/imageio/IIOException",
1804 "Invalid argument to native readImage");
1805 return JNI_FALSE;
1806 }
1807
1808 /*
1809 * First get the source bands array and copy it to our local array
1810 * so we don't have to worry about pinning and unpinning it again.
1811 */
1812
1813 body = (*env)->GetIntArrayElements(env, srcBands, NULL);
1814 if (body == NULL) {
1815 JNU_ThrowByName( env,
1816 "java/lang/OutOfMemoryError",
1817 "Initializing Read");
1818 return JNI_FALSE;
1819 }
1820
1821 for (i = 0; i < numBands; i++) {
1822 bands[i] = body[i];
1823 if (orderedBands && (bands[i] != i)) {
1824 orderedBands = FALSE;
1825 }
1826 }
1827
1828 (*env)->ReleaseIntArrayElements(env, srcBands, body, JNI_ABORT);
1829
1830#ifdef DEBUG
1831 printf("---- in reader.read ----\n");
1832 printf("numBands is %d\n", numBands);
1833 printf("bands array: ");
1834 for (i = 0; i < numBands; i++) {
1835 printf("%d ", bands[i]);
1836 }
1837 printf("\n");
1838 printf("jq table 0 at %p\n",
1839 cinfo->quant_tbl_ptrs[0]);
1840#endif
1841
1842 data = (imageIODataPtr) cinfo->client_data;
1843 src = cinfo->src;
1844
1845 /* Set the buffer as our PixelBuffer */
1846 pb = &data->pixelBuf;
1847
1848 if (setPixelBuffer(env, pb, buffer) == NOT_OK) {
1849 return data->abortFlag; // We already threw an out of memory exception
1850 }
1851
1852 // Allocate a 1-scanline buffer
1853 scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->num_components);
1854 if (scanLinePtr == NULL) {
1855 RELEASE_ARRAYS(env, data, src->next_input_byte);
1856 JNU_ThrowByName( env,
1857 "java/lang/OutOfMemoryError",
1858 "Reading JPEG Stream");
1859 return data->abortFlag;
1860 }
1861
1862 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1863 jerr = (sun_jpeg_error_ptr) cinfo->err;
1864
1865 if (setjmp(jerr->setjmp_buffer)) {
1866 /* If we get here, the JPEG code has signaled an error
1867 while reading. */
1868 RELEASE_ARRAYS(env, data, src->next_input_byte);
1869 if (!(*env)->ExceptionOccurred(env)) {
1870 char buffer[JMSG_LENGTH_MAX];
1871 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1872 buffer);
1873 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1874 }
1875 free(scanLinePtr);
1876 return data->abortFlag;
1877 }
1878
1879 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1880 JNU_ThrowByName(env,
1881 "javax/imageio/IIOException",
1882 "Array pin failed");
1883 return data->abortFlag;
1884 }
1885
1886 // If there are no tables in our structure and table arguments aren't
1887 // NULL, use the table arguments.
1888 if ((qtables != NULL) && (cinfo->quant_tbl_ptrs[0] == NULL)) {
1889 (void) setQTables(env, (j_common_ptr) cinfo, qtables, TRUE);
1890 }
1891
1892 if ((DCHuffmanTables != NULL) && (cinfo->dc_huff_tbl_ptrs[0] == NULL)) {
1893 setHTables(env, (j_common_ptr) cinfo,
1894 DCHuffmanTables,
1895 ACHuffmanTables,
1896 TRUE);
1897 }
1898
1899 progressive = jpeg_has_multiple_scans(cinfo);
1900 if (progressive) {
1901 cinfo->buffered_image = TRUE;
1902 cinfo->input_scan_number = minProgressivePass+1; // Java count from 0
1903#define MAX_JAVA_INT 2147483647 // XXX Is this defined in JNI somewhere?
1904 if (maxProgressivePass < MAX_JAVA_INT) {
1905 maxProgressivePass++; // For testing
1906 }
1907 }
1908
1909 data->streamBuf.suspendable = FALSE;
1910
1911 jpeg_start_decompress(cinfo);
1912
1913 // loop over progressive passes
1914 done = FALSE;
1915 while (!done) {
1916 if (progressive) {
1917 // initialize the next pass. Note that this skips up to
1918 // the first interesting pass.
1919 jpeg_start_output(cinfo, cinfo->input_scan_number);
1920 if (wantUpdates) {
1921 (*env)->CallVoidMethod(env, this,
1922 JPEGImageReader_passStartedID,
1923 cinfo->input_scan_number-1);
1924 }
1925 } else if (wantUpdates) {
1926 (*env)->CallVoidMethod(env, this,
1927 JPEGImageReader_passStartedID,
1928 0);
1929
1930 }
1931
1932 // Skip until the first interesting line
1933 while ((data->abortFlag == JNI_FALSE)
1934 && ((jint)cinfo->output_scanline < sourceYStart)) {
1935 jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
1936 }
1937
1938 scanlineLimit = sourceYStart+sourceHeight;
1939 pixelLimit = scanLinePtr
1940 +(sourceXStart+sourceWidth)*cinfo->num_components;
1941
1942 pixelStride = stepX*cinfo->num_components;
1943 targetLine = 0;
1944
1945 while ((data->abortFlag == JNI_FALSE)
1946 && ((jint)cinfo->output_scanline < scanlineLimit)) {
1947
1948 jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
1949
1950 // Now mangle it into our buffer
1951 out = data->pixelBuf.buf.bp;
1952
1953 if (orderedBands && (pixelStride == numBands)) {
1954 // Optimization: The component bands are ordered sequentially,
1955 // so we can simply use memcpy() to copy the intermediate
1956 // scanline buffer into the raster.
1957 in = scanLinePtr + (sourceXStart * cinfo->num_components);
1958 if (pixelLimit > in) {
1959 memcpy(out, in, pixelLimit - in);
1960 }
1961 } else {
1962 for (in = scanLinePtr+sourceXStart*cinfo->num_components;
1963 in < pixelLimit;
1964 in += pixelStride) {
1965 for (i = 0; i < numBands; i++) {
1966 *out++ = *(in+bands[i]);
1967 }
1968 }
1969 }
1970
1971 // And call it back to Java
1972 RELEASE_ARRAYS(env, data, src->next_input_byte);
1973 (*env)->CallVoidMethod(env,
1974 this,
1975 JPEGImageReader_acceptPixelsID,
1976 targetLine++,
1977 progressive);
1978
1979 if ((*env)->ExceptionOccurred(env)
1980 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1981 cinfo->err->error_exit((j_common_ptr) cinfo);
1982 }
1983
1984 // And skip over uninteresting lines to the next subsampled line
1985 // Ensure we don't go past the end of the image
1986
1987 // Lines to skip based on subsampling
1988 skipLines = stepY - 1;
1989 // Lines left in the image
1990 linesLeft = scanlineLimit - cinfo->output_scanline;
1991 // Take the minimum
1992 if (skipLines > linesLeft) {
1993 skipLines = linesLeft;
1994 }
1995 for(i = 0; i < skipLines; i++) {
1996 jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
1997 }
1998 }
1999 if (progressive) {
2000 jpeg_finish_output(cinfo); // Increments pass counter
2001 // Call Java to notify pass complete
2002 if (jpeg_input_complete(cinfo)
2003 || (cinfo->input_scan_number > maxProgressivePass)) {
2004 done = TRUE;
2005 }
2006 } else {
2007 done = TRUE;
2008 }
2009 if (wantUpdates) {
2010 (*env)->CallVoidMethod(env, this,
2011 JPEGImageReader_passCompleteID);
2012 }
2013
2014 }
2015 /*
2016 * We are done, but we might not have read all the lines, or all
2017 * the passes, so use jpeg_abort instead of jpeg_finish_decompress.
2018 */
2019 if (cinfo->output_scanline == cinfo->output_height) {
2020 // if ((cinfo->output_scanline == cinfo->output_height) &&
2021 //(jpeg_input_complete(cinfo))) { // We read the whole file
2022 jpeg_finish_decompress(cinfo);
2023 } else {
2024 jpeg_abort_decompress(cinfo);
2025 }
2026
2027 free(scanLinePtr);
2028
2029 RELEASE_ARRAYS(env, data, src->next_input_byte);
2030
2031 return data->abortFlag;
2032}
2033
2034JNIEXPORT void JNICALL
2035Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_abortRead
2036 (JNIEnv *env,
2037 jobject this,
2038 jlong ptr) {
2039
2040 imageIODataPtr data = (imageIODataPtr) ptr;
2041
2042 if (data == NULL) {
2043 JNU_ThrowByName(env,
2044 "java/lang/IllegalStateException",
2045 "Attempting to use reader after dispose()");
2046 return;
2047 }
2048
2049 imageio_abort(env, this, data);
2050
2051}
2052
2053JNIEXPORT void JNICALL
2054Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetLibraryState
2055 (JNIEnv *env,
2056 jobject this,
2057 jlong ptr) {
2058 imageIODataPtr data = (imageIODataPtr) ptr;
2059 j_decompress_ptr cinfo;
2060
2061 if (data == NULL) {
2062 JNU_ThrowByName(env,
2063 "java/lang/IllegalStateException",
2064 "Attempting to use reader after dispose()");
2065 return;
2066 }
2067
2068 cinfo = (j_decompress_ptr) data->jpegObj;
2069
2070 jpeg_abort_decompress(cinfo);
2071}
2072
2073
2074JNIEXPORT void JNICALL
2075Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetReader
2076 (JNIEnv *env,
2077 jobject this,
2078 jlong ptr) {
2079
2080 imageIODataPtr data = (imageIODataPtr) ptr;
2081 j_decompress_ptr cinfo;
2082 sun_jpeg_error_ptr jerr;
2083
2084 if (data == NULL) {
2085 JNU_ThrowByName(env,
2086 "java/lang/IllegalStateException",
2087 "Attempting to use reader after dispose()");
2088 return;
2089 }
2090
2091 cinfo = (j_decompress_ptr) data->jpegObj;
2092
2093 jerr = (sun_jpeg_error_ptr) cinfo->err;
2094
2095 imageio_reset(env, (j_common_ptr) cinfo, data);
2096
2097 /*
2098 * The tables have not been reset, and there is no way to do so
2099 * in IJG without leaking memory. The only situation in which
2100 * this will cause a problem is if an image-only stream is read
2101 * with this object without initializing the correct tables first.
2102 * This situation, which should cause an error, might work but
2103 * produce garbage instead. If the huffman tables are wrong,
2104 * it will fail during the decode. If the q tables are wrong, it
2105 * will look strange. This is very unlikely, so don't worry about
2106 * it. To be really robust, we would keep a flag for table state
2107 * and consult it to catch exceptional situations.
2108 */
2109
2110 /* above does not clean up the source, so we have to */
2111
2112 /*
2113 We need to explicitly initialize exception handler or we may
2114 longjump to random address from the term_source()
2115 */
2116
2117 if (setjmp(jerr->setjmp_buffer)) {
2118
2119 /*
2120 We may get IOException from pushBack() here.
2121
2122 However it could be legal if original input stream was closed
2123 earlier (for example because network connection was closed).
2124 Unfortunately, image inputstream API has no way to check whether
2125 stream is already closed or IOException was thrown because of some
2126 other IO problem,
2127 And we can not avoid call to pushBack() on closed stream for the
2128 same reason.
2129
2130 So, for now we will silently eat this exception.
2131
2132 NB: this may be changed in future when ImageInputStream API will
2133 become more flexible.
2134 */
2135
2136 if ((*env)->ExceptionOccurred(env)) {
2137 (*env)->ExceptionClear(env);
2138 }
2139 } else {
2140 cinfo->src->term_source(cinfo);
2141 }
2142
2143 cinfo->src->bytes_in_buffer = 0;
2144 cinfo->src->next_input_byte = NULL;
2145}
2146
2147JNIEXPORT void JNICALL
2148Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_disposeReader
2149 (JNIEnv *env,
2150 jclass reader,
2151 jlong ptr) {
2152
2153 imageIODataPtr data = (imageIODataPtr) ptr;
2154 j_common_ptr info = destroyImageioData(env, data);
2155
2156 imageio_dispose(info);
2157}
2158
2159/********************** end of Reader *************************/
2160
2161/********************** Writer Support ************************/
2162
2163/********************** Destination Manager *******************/
2164
2165METHODDEF(void)
2166/*
2167 * Initialize destination --- called by jpeg_start_compress
2168 * before any data is actually written. The data arrays
2169 * must be pinned before this is called.
2170 */
2171imageio_init_destination (j_compress_ptr cinfo)
2172{
2173 struct jpeg_destination_mgr *dest = cinfo->dest;
2174 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2175 streamBufferPtr sb = &data->streamBuf;
2176 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2177
2178 if (sb->buf == NULL) {
2179 // We forgot to pin the array
2180 (*env)->FatalError(env, "Output buffer not pinned!");
2181 }
2182
2183 dest->next_output_byte = sb->buf;
2184 dest->free_in_buffer = sb->bufferLength;
2185}
2186
2187/*
2188 * Empty the output buffer --- called whenever buffer fills up.
2189 *
2190 * This routine writes the entire output buffer
2191 * (ignoring the current state of next_output_byte & free_in_buffer),
2192 * resets the pointer & count to the start of the buffer, and returns TRUE
2193 * indicating that the buffer has been dumped.
2194 */
2195
2196METHODDEF(boolean)
2197imageio_empty_output_buffer (j_compress_ptr cinfo)
2198{
2199 struct jpeg_destination_mgr *dest = cinfo->dest;
2200 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2201 streamBufferPtr sb = &data->streamBuf;
2202 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2203
2204 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2205
2206 (*env)->CallVoidMethod(env,
2207 sb->stream,
2208 ImageOutputStream_writeID,
2209 sb->hstreamBuffer,
2210 0,
2211 sb->bufferLength);
2212 if ((*env)->ExceptionOccurred(env)
2213 || !GET_ARRAYS(env, data,
2214 (const JOCTET **)(&dest->next_output_byte))) {
2215 cinfo->err->error_exit((j_common_ptr) cinfo);
2216 }
2217
2218 dest->next_output_byte = sb->buf;
2219 dest->free_in_buffer = sb->bufferLength;
2220
2221 return TRUE;
2222}
2223
2224/*
2225 * After all of the data has been encoded there may still be some
2226 * more left over in some of the working buffers. Now is the
2227 * time to clear them out.
2228 */
2229METHODDEF(void)
2230imageio_term_destination (j_compress_ptr cinfo)
2231{
2232 struct jpeg_destination_mgr *dest = cinfo->dest;
2233 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2234 streamBufferPtr sb = &data->streamBuf;
2235 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2236
2237 /* find out how much needs to be written */
2238 jint datacount = sb->bufferLength - dest->free_in_buffer;
2239
2240 if (datacount != 0) {
2241 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2242
2243 (*env)->CallVoidMethod(env,
2244 sb->stream,
2245 ImageOutputStream_writeID,
2246 sb->hstreamBuffer,
2247 0,
2248 datacount);
2249
2250 if ((*env)->ExceptionOccurred(env)
2251 || !GET_ARRAYS(env, data,
2252 (const JOCTET **)(&dest->next_output_byte))) {
2253 cinfo->err->error_exit((j_common_ptr) cinfo);
2254 }
2255 }
2256
2257 dest->next_output_byte = NULL;
2258 dest->free_in_buffer = 0;
2259
2260}
2261
2262/*
2263 * Flush the destination buffer. This is not called by the library,
2264 * but by our code below. This is the simplest implementation, though
2265 * certainly not the most efficient.
2266 */
2267METHODDEF(void)
2268imageio_flush_destination(j_compress_ptr cinfo)
2269{
2270 imageio_term_destination(cinfo);
2271 imageio_init_destination(cinfo);
2272}
2273
2274/********************** end of destination manager ************/
2275
2276/********************** Writer JNI calls **********************/
2277
2278
2279JNIEXPORT void JNICALL
2280Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs
2281 (JNIEnv *env,
2282 jclass cls,
2283 jclass IOSClass,
2284 jclass qTableClass,
2285 jclass huffClass) {
2286
2287 ImageOutputStream_writeID = (*env)->GetMethodID(env,
2288 IOSClass,
2289 "write",
2290 "([BII)V");
2291
2292 JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env,
2293 cls,
2294 "warningOccurred",
2295 "(I)V");
2296 JPEGImageWriter_warningWithMessageID =
2297 (*env)->GetMethodID(env,
2298 cls,
2299 "warningWithMessage",
2300 "(Ljava/lang/String;)V");
2301
2302 JPEGImageWriter_writeMetadataID = (*env)->GetMethodID(env,
2303 cls,
2304 "writeMetadata",
2305 "()V");
2306 JPEGImageWriter_grabPixelsID = (*env)->GetMethodID(env,
2307 cls,
2308 "grabPixels",
2309 "(I)V");
2310
2311 JPEGQTable_tableID = (*env)->GetFieldID(env,
2312 qTableClass,
2313 "qTable",
2314 "[I");
2315
2316 JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env,
2317 huffClass,
2318 "lengths",
2319 "[S");
2320
2321 JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env,
2322 huffClass,
2323 "values",
2324 "[S");
2325}
2326
2327JNIEXPORT jlong JNICALL
2328Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter
2329 (JNIEnv *env,
2330 jobject this) {
2331
2332 imageIODataPtr ret;
2333 struct sun_jpeg_error_mgr *jerr;
2334 struct jpeg_destination_mgr *dest;
2335
2336 /* This struct contains the JPEG compression parameters and pointers to
2337 * working space (which is allocated as needed by the JPEG library).
2338 */
2339 struct jpeg_compress_struct *cinfo =
2340 malloc(sizeof(struct jpeg_compress_struct));
2341 if (cinfo == NULL) {
2342 JNU_ThrowByName( env,
2343 "java/lang/OutOfMemoryError",
2344 "Initializing Writer");
2345 return 0;
2346 }
2347
2348 /* We use our private extension JPEG error handler.
2349 */
2350 jerr = malloc (sizeof(struct sun_jpeg_error_mgr));
2351 if (jerr == NULL) {
2352 JNU_ThrowByName( env,
2353 "java/lang/OutOfMemoryError",
2354 "Initializing Writer");
2355 free(cinfo);
2356 return 0;
2357 }
2358
2359 /* We set up the normal JPEG error routines, then override error_exit. */
2360 cinfo->err = jpeg_std_error(&(jerr->pub));
2361 jerr->pub.error_exit = sun_jpeg_error_exit;
2362 /* We need to setup our own print routines */
2363 jerr->pub.output_message = sun_jpeg_output_message;
2364 /* Now we can setjmp before every call to the library */
2365
2366 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2367 if (setjmp(jerr->setjmp_buffer)) {
2368 /* If we get here, the JPEG code has signaled an error. */
2369 char buffer[JMSG_LENGTH_MAX];
2370 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
2371 buffer);
2372 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2373 return 0;
2374 }
2375
2376 /* Perform library initialization */
2377 jpeg_create_compress(cinfo);
2378
2379 /* Now set up the destination */
2380 dest = malloc(sizeof(struct jpeg_destination_mgr));
2381 if (dest == NULL) {
2382 JNU_ThrowByName( env,
2383 "java/lang/OutOfMemoryError",
2384 "Initializing Writer");
2385 free(cinfo);
2386 free(jerr);
2387 return 0;
2388 }
2389
2390 dest->init_destination = imageio_init_destination;
2391 dest->empty_output_buffer = imageio_empty_output_buffer;
2392 dest->term_destination = imageio_term_destination;
2393 dest->next_output_byte = NULL;
2394 dest->free_in_buffer = 0;
2395
2396 cinfo->dest = dest;
2397
2398 /* set up the association to persist for future calls */
2399 ret = initImageioData(env, (j_common_ptr) cinfo, this);
2400 if (ret == NULL) {
2401 JNU_ThrowByName( env,
2402 "java/lang/OutOfMemoryError",
2403 "Initializing Writer");
2404 free(cinfo);
2405 free(jerr);
2406 return 0;
2407 }
2408 return (jlong) ret;
2409}
2410
2411JNIEXPORT void JNICALL
2412Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest
2413 (JNIEnv *env,
2414 jobject this,
2415 jlong ptr,
2416 jobject destination) {
2417
2418 imageIODataPtr data = (imageIODataPtr) ptr;
2419 j_compress_ptr cinfo;
2420
2421 if (data == NULL) {
2422 JNU_ThrowByName(env,
2423 "java/lang/IllegalStateException",
2424 "Attempting to use writer after dispose()");
2425 return;
2426 }
2427
2428 cinfo = (j_compress_ptr) data->jpegObj;
2429
2430 imageio_set_stream(env, data->jpegObj, data, destination);
2431
2432
2433 // Don't call the init method, as that depends on pinned arrays
2434 cinfo->dest->next_output_byte = NULL;
2435 cinfo->dest->free_in_buffer = 0;
2436}
2437
2438JNIEXPORT void JNICALL
2439Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables
2440 (JNIEnv *env,
2441 jobject this,
2442 jlong ptr,
2443 jobjectArray qtables,
2444 jobjectArray DCHuffmanTables,
2445 jobjectArray ACHuffmanTables) {
2446
2447 struct jpeg_destination_mgr *dest;
2448 sun_jpeg_error_ptr jerr;
2449 imageIODataPtr data = (imageIODataPtr) ptr;
2450 j_compress_ptr cinfo;
2451
2452 if (data == NULL) {
2453 JNU_ThrowByName(env,
2454 "java/lang/IllegalStateException",
2455 "Attempting to use writer after dispose()");
2456 return;
2457 }
2458
2459 cinfo = (j_compress_ptr) data->jpegObj;
2460 dest = cinfo->dest;
2461
2462 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2463 jerr = (sun_jpeg_error_ptr) cinfo->err;
2464
2465 if (setjmp(jerr->setjmp_buffer)) {
2466 /* If we get here, the JPEG code has signaled an error
2467 while writing. */
2468 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2469 if (!(*env)->ExceptionOccurred(env)) {
2470 char buffer[JMSG_LENGTH_MAX];
2471 (*cinfo->err->format_message) ((j_common_ptr) cinfo,
2472 buffer);
2473 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2474 }
2475 return;
2476 }
2477
2478 if (GET_ARRAYS(env, data,
2479 (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) {
2480 JNU_ThrowByName(env,
2481 "javax/imageio/IIOException",
2482 "Array pin failed");
2483 return;
2484 }
2485
2486 jpeg_suppress_tables(cinfo, TRUE); // Suppress writing of any current
2487
2488 data->streamBuf.suspendable = FALSE;
2489 if (qtables != NULL) {
2490#ifdef DEBUG
2491 printf("in writeTables: qtables not NULL\n");
2492#endif
2493 setQTables(env, (j_common_ptr) cinfo, qtables, TRUE);
2494 }
2495
2496 if (DCHuffmanTables != NULL) {
2497 setHTables(env, (j_common_ptr) cinfo,
2498 DCHuffmanTables, ACHuffmanTables, TRUE);
2499 }
2500
2501 jpeg_write_tables(cinfo); // Flushes the buffer for you
2502 RELEASE_ARRAYS(env, data, NULL);
2503}
2504
2505JNIEXPORT jboolean JNICALL
2506Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
2507 (JNIEnv *env,
2508 jobject this,
2509 jlong ptr,
2510 jbyteArray buffer,
2511 jint inCs, jint outCs,
2512 jint numBands,
2513 jintArray bandSizes,
2514 jint srcWidth,
2515 jint destWidth, jint destHeight,
2516 jint stepX, jint stepY,
2517 jobjectArray qtables,
2518 jboolean writeDQT,
2519 jobjectArray DCHuffmanTables,
2520 jobjectArray ACHuffmanTables,
2521 jboolean writeDHT,
2522 jboolean optimize,
2523 jboolean progressive,
2524 jint numScans,
2525 jintArray scanInfo,
2526 jintArray componentIds,
2527 jintArray HsamplingFactors,
2528 jintArray VsamplingFactors,
2529 jintArray QtableSelectors,
2530 jboolean haveMetadata,
2531 jint restartInterval) {
2532
2533 struct jpeg_destination_mgr *dest;
2534 JSAMPROW scanLinePtr;
2535 int i, j;
2536 int pixelStride;
2537 unsigned char *in, *out, *pixelLimit;
2538 int targetLine;
2539 pixelBufferPtr pb;
2540 sun_jpeg_error_ptr jerr;
2541 jint *ids, *hfactors, *vfactors, *qsels;
2542 jsize qlen, hlen;
2543 int *scanptr;
2544 jint *scanData;
2545 jint *bandSize;
2546 int maxBandValue, halfMaxBandValue;
2547 imageIODataPtr data = (imageIODataPtr) ptr;
2548 j_compress_ptr cinfo;
2549 UINT8** scale = NULL;
2550
2551 /* verify the inputs */
2552
2553 if (data == NULL) {
2554 JNU_ThrowByName(env,
2555 "java/lang/IllegalStateException",
2556 "Attempting to use writer after dispose()");
2557 return JNI_FALSE;
2558 }
2559
2560 if ((buffer == NULL) ||
2561 (qtables == NULL) ||
2562 // H tables can be null if optimizing
2563 (componentIds == NULL) ||
2564 (HsamplingFactors == NULL) || (VsamplingFactors == NULL) ||
2565 (QtableSelectors == NULL) ||
2566 ((numScans != 0) && (scanInfo != NULL))) {
2567
2568 JNU_ThrowNullPointerException(env, 0);
2569 return JNI_FALSE;
2570
2571 }
2572
2573 if ((inCs < 0) || (inCs > JCS_YCCK) ||
2574 (outCs < 0) || (outCs > JCS_YCCK) ||
2575 (numBands < 1) || (numBands > MAX_BANDS) ||
2576 (srcWidth < 0) ||
2577 (destWidth < 0) || (destWidth > srcWidth) ||
2578 (destHeight < 0) ||
2579 (stepX < 0) || (stepY < 0))
2580 {
2581 JNU_ThrowByName(env, "javax/imageio/IIOException",
2582 "Invalid argument to native writeImage");
2583 return JNI_FALSE;
2584 }
2585
2586 bandSize = (*env)->GetIntArrayElements(env, bandSizes, NULL);
2587
2588 for (i = 0; i < numBands; i++) {
2589 if (bandSize[i] != JPEG_BAND_SIZE) {
2590 if (scale == NULL) {
2591 scale = (UINT8**) calloc(numBands, sizeof(UINT8*));
2592
2593 if (scale == NULL) {
2594 JNU_ThrowByName( env, "java/lang/OutOfMemoryError",
2595 "Writing JPEG Stream");
2596 return JNI_FALSE;
2597 }
2598 }
2599
2600 maxBandValue = (1 << bandSize[i]) - 1;
2601
2602 scale[i] = (UINT8*) malloc((maxBandValue + 1) * sizeof(UINT8));
2603
2604 if (scale[i] == NULL) {
2605 JNU_ThrowByName( env, "java/lang/OutOfMemoryError",
2606 "Writing JPEG Stream");
2607 return JNI_FALSE;
2608 }
2609
2610 halfMaxBandValue = maxBandValue >> 1;
2611
2612 for (j = 0; j <= maxBandValue; j++) {
2613 scale[i][j] = (UINT8)
2614 ((j*MAX_JPEG_BAND_VALUE + halfMaxBandValue)/maxBandValue);
2615 }
2616 }
2617 }
2618
2619 (*env)->ReleaseIntArrayElements(env, bandSizes,
2620 bandSize, JNI_ABORT);
2621
2622 cinfo = (j_compress_ptr) data->jpegObj;
2623 dest = cinfo->dest;
2624
2625 /* Set the buffer as our PixelBuffer */
2626 pb = &data->pixelBuf;
2627
2628 if (setPixelBuffer(env, pb, buffer) == NOT_OK) {
2629 return data->abortFlag; // We already threw an out of memory exception
2630 }
2631
2632 // Allocate a 1-scanline buffer
2633 scanLinePtr = (JSAMPROW)malloc(destWidth*numBands);
2634 if (scanLinePtr == NULL) {
2635 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2636 JNU_ThrowByName( env,
2637 "java/lang/OutOfMemoryError",
2638 "Writing JPEG Stream");
2639 return data->abortFlag;
2640 }
2641
2642 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2643 jerr = (sun_jpeg_error_ptr) cinfo->err;
2644
2645 if (setjmp(jerr->setjmp_buffer)) {
2646 /* If we get here, the JPEG code has signaled an error
2647 while writing. */
2648 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2649 if (!(*env)->ExceptionOccurred(env)) {
2650 char buffer[JMSG_LENGTH_MAX];
2651 (*cinfo->err->format_message) ((j_common_ptr) cinfo,
2652 buffer);
2653 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2654 }
2655 free(scanLinePtr);
2656 return data->abortFlag;
2657 }
2658
2659 // set up parameters
2660 cinfo->image_width = destWidth;
2661 cinfo->image_height = destHeight;
2662 cinfo->input_components = numBands;
2663 cinfo->in_color_space = inCs;
2664
2665 jpeg_set_defaults(cinfo);
2666
2667 jpeg_set_colorspace(cinfo, outCs);
2668
2669 cinfo->optimize_coding = optimize;
2670
2671 cinfo->write_JFIF_header = FALSE;
2672 cinfo->write_Adobe_marker = FALSE;
2673 // copy componentIds
2674 ids = (*env)->GetIntArrayElements(env, componentIds, NULL);
2675 hfactors = (*env)->GetIntArrayElements(env, HsamplingFactors, NULL);
2676 vfactors = (*env)->GetIntArrayElements(env, VsamplingFactors, NULL);
2677 qsels = (*env)->GetIntArrayElements(env, QtableSelectors, NULL);
2678
2679 if ((ids == NULL) ||
2680 (hfactors == NULL) || (vfactors == NULL) ||
2681 (qsels == NULL)) {
2682 JNU_ThrowByName( env,
2683 "java/lang/OutOfMemoryError",
2684 "Writing JPEG");
2685 return JNI_FALSE;
2686 }
2687
2688 for (i = 0; i < numBands; i++) {
2689 cinfo->comp_info[i].component_id = ids[i];
2690 cinfo->comp_info[i].h_samp_factor = hfactors[i];
2691 cinfo->comp_info[i].v_samp_factor = vfactors[i];
2692 cinfo->comp_info[i].quant_tbl_no = qsels[i];
2693 }
2694
2695 (*env)->ReleaseIntArrayElements(env, componentIds,
2696 ids, JNI_ABORT);
2697 (*env)->ReleaseIntArrayElements(env, HsamplingFactors,
2698 hfactors, JNI_ABORT);
2699 (*env)->ReleaseIntArrayElements(env, VsamplingFactors,
2700 vfactors, JNI_ABORT);
2701 (*env)->ReleaseIntArrayElements(env, QtableSelectors,
2702 qsels, JNI_ABORT);
2703
2704 jpeg_suppress_tables(cinfo, TRUE); // Disable writing any current
2705
2706 qlen = setQTables(env, (j_common_ptr) cinfo, qtables, writeDQT);
2707
2708 if (!optimize) {
2709 // Set the h tables
2710 hlen = setHTables(env,
2711 (j_common_ptr) cinfo,
2712 DCHuffmanTables,
2713 ACHuffmanTables,
2714 writeDHT);
2715 }
2716
2717 if (GET_ARRAYS(env, data,
2718 (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) {
2719 JNU_ThrowByName(env,
2720 "javax/imageio/IIOException",
2721 "Array pin failed");
2722 return data->abortFlag;
2723 }
2724
2725 data->streamBuf.suspendable = FALSE;
2726
2727 if (progressive) {
2728 if (numScans == 0) { // then use default scans
2729 jpeg_simple_progression(cinfo);
2730 } else {
2731 cinfo->num_scans = numScans;
2732 // Copy the scanInfo to a local array
2733 // The following is copied from jpeg_simple_progression:
2734 /* Allocate space for script.
2735 * We need to put it in the permanent pool in case the application performs
2736 * multiple compressions without changing the settings. To avoid a memory
2737 * leak if jpeg_simple_progression is called repeatedly for the same JPEG
2738 * object, we try to re-use previously allocated space, and we allocate
2739 * enough space to handle YCbCr even if initially asked for grayscale.
2740 */
2741 if (cinfo->script_space == NULL
2742 || cinfo->script_space_size < numScans) {
2743 cinfo->script_space_size = MAX(numScans, 10);
2744 cinfo->script_space = (jpeg_scan_info *)
2745 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
2746 JPOOL_PERMANENT,
2747 cinfo->script_space_size
2748 * sizeof(jpeg_scan_info));
2749 }
2750 cinfo->scan_info = cinfo->script_space;
2751 scanptr = (int *) cinfo->script_space;
2752 scanData = (*env)->GetIntArrayElements(env, scanInfo, NULL);
2753 // number of jints per scan is 9
2754 // We avoid a memcpy to handle different size ints
2755 for (i = 0; i < numScans*9; i++) {
2756 scanptr[i] = scanData[i];
2757 }
2758 (*env)->ReleaseIntArrayElements(env, scanInfo,
2759 scanData, JNI_ABORT);
2760
2761 }
2762 }
2763
2764 cinfo->restart_interval = restartInterval;
2765
2766#ifdef DEBUG
2767 printf("writer setup complete, starting compressor\n");
2768#endif
2769
2770 // start the compressor; tables must already be set
2771 jpeg_start_compress(cinfo, FALSE); // Leaves sent_table alone
2772
2773 if (haveMetadata) {
2774 // Flush the buffer
2775 imageio_flush_destination(cinfo);
2776 // Call Java to write the metadata
2777 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2778 (*env)->CallVoidMethod(env,
2779 this,
2780 JPEGImageWriter_writeMetadataID);
2781 if ((*env)->ExceptionOccurred(env)
2782 || !GET_ARRAYS(env, data,
2783 (const JOCTET **)(&dest->next_output_byte))) {
2784 cinfo->err->error_exit((j_common_ptr) cinfo);
2785 }
2786 }
2787
2788 targetLine = 0;
2789
2790 // for each line in destHeight
2791 while ((data->abortFlag == JNI_FALSE)
2792 && (cinfo->next_scanline < cinfo->image_height)) {
2793 // get the line from Java
2794 RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2795 (*env)->CallVoidMethod(env,
2796 this,
2797 JPEGImageWriter_grabPixelsID,
2798 targetLine);
2799 if ((*env)->ExceptionOccurred(env)
2800 || !GET_ARRAYS(env, data,
2801 (const JOCTET **)(&dest->next_output_byte))) {
2802 cinfo->err->error_exit((j_common_ptr) cinfo);
2803 }
2804
2805 // subsample it into our buffer
2806
2807 in = data->pixelBuf.buf.bp;
2808 out = scanLinePtr;
2809 pixelLimit = in + srcWidth*numBands;
2810 pixelStride = numBands*stepX;
2811 for (; in < pixelLimit; in += pixelStride) {
2812 for (i = 0; i < numBands; i++) {
2813 if (scale !=NULL && scale[i] != NULL) {
2814 *out++ = scale[i][*(in+i)];
2815#ifdef DEBUG
2816 if (in == data->pixelBuf.buf.bp){ // Just the first pixel
2817 printf("in %d -> out %d, ", *(in+i), *(out-i-1));
2818 }
2819#endif
2820
2821#ifdef DEBUG
2822 if (in == data->pixelBuf.buf.bp){ // Just the first pixel
2823 printf("\n");
2824 }
2825#endif
2826 } else {
2827 *out++ = *(in+i);
2828 }
2829 }
2830 }
2831 // write it out
2832 jpeg_write_scanlines(cinfo, (JSAMPARRAY)&scanLinePtr, 1);
2833 targetLine += stepY;
2834 }
2835
2836 /*
2837 * We are done, but we might not have done all the lines,
2838 * so use jpeg_abort instead of jpeg_finish_compress.
2839 */
2840 if (cinfo->next_scanline == cinfo->image_height) {
2841 jpeg_finish_compress(cinfo); // Flushes buffer with term_dest
2842 } else {
2843 jpeg_abort((j_common_ptr)cinfo);
2844 }
2845
2846 if (scale != NULL) {
2847 for (i = 0; i < numBands; i++) {
2848 if (scale[i] != NULL) {
2849 free(scale[i]);
2850 }
2851 }
2852 free(scale);
2853 }
2854
2855 free(scanLinePtr);
2856 RELEASE_ARRAYS(env, data, NULL);
2857 return data->abortFlag;
2858}
2859
2860JNIEXPORT void JNICALL
2861Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_abortWrite
2862 (JNIEnv *env,
2863 jobject this,
2864 jlong ptr) {
2865
2866 imageIODataPtr data = (imageIODataPtr) ptr;
2867
2868 if (data == NULL) {
2869 JNU_ThrowByName(env,
2870 "java/lang/IllegalStateException",
2871 "Attempting to use writer after dispose()");
2872 return;
2873 }
2874
2875 imageio_abort(env, this, data);
2876}
2877
2878JNIEXPORT void JNICALL
2879Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_resetWriter
2880 (JNIEnv *env,
2881 jobject this,
2882 jlong ptr) {
2883 imageIODataPtr data = (imageIODataPtr) ptr;
2884 j_compress_ptr cinfo;
2885
2886 if (data == NULL) {
2887 JNU_ThrowByName(env,
2888 "java/lang/IllegalStateException",
2889 "Attempting to use writer after dispose()");
2890 return;
2891 }
2892
2893 cinfo = (j_compress_ptr) data->jpegObj;
2894
2895 imageio_reset(env, (j_common_ptr) cinfo, data);
2896
2897 /*
2898 * The tables have not been reset, and there is no way to do so
2899 * in IJG without leaking memory. The only situation in which
2900 * this will cause a problem is if an image-only stream is written
2901 * with this object without initializing the correct tables first,
2902 * which should not be possible.
2903 */
2904
2905 cinfo->dest->next_output_byte = NULL;
2906 cinfo->dest->free_in_buffer = 0;
2907}
2908
2909JNIEXPORT void JNICALL
2910Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_disposeWriter
2911 (JNIEnv *env,
2912 jclass writer,
2913 jlong ptr) {
2914
2915 imageIODataPtr data = (imageIODataPtr) ptr;
2916 j_common_ptr info = destroyImageioData(env, data);
2917
2918 imageio_dispose(info);
2919}