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