Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
41152 views
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 */
66
static jmethodID JPEGImageReader_readInputDataID;
67
static jmethodID JPEGImageReader_skipInputBytesID;
68
static jmethodID JPEGImageReader_warningOccurredID;
69
static jmethodID JPEGImageReader_warningWithMessageID;
70
static jmethodID JPEGImageReader_setImageDataID;
71
static jmethodID JPEGImageReader_acceptPixelsID;
72
static jmethodID JPEGImageReader_pushBackID;
73
static jmethodID JPEGImageReader_passStartedID;
74
static jmethodID JPEGImageReader_passCompleteID;
75
static jmethodID JPEGImageReader_skipPastImageID;
76
static jmethodID JPEGImageWriter_writeOutputDataID;
77
static jmethodID JPEGImageWriter_warningOccurredID;
78
static jmethodID JPEGImageWriter_warningWithMessageID;
79
static jmethodID JPEGImageWriter_writeMetadataID;
80
static jmethodID JPEGImageWriter_grabPixelsID;
81
static jfieldID JPEGQTable_tableID;
82
static jfieldID JPEGHuffmanTable_lengthsID;
83
static jfieldID JPEGHuffmanTable_valuesID;
84
85
/*
86
* Defined in jpegdecoder.c. Copy code from there if and
87
* when that disappears. */
88
extern JavaVM *the_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
115
typedef 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
151
static 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
*/
159
static 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
*/
193
static 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
201
static 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
*/
210
static 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
*/
225
static 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
*/
247
static 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
*/
268
static void clearStreamBuffer(streamBufferPtr sb) {
269
sb->bufferOffset = NO_DATA;
270
}
271
272
/*************************** end StreamBuffer definition *************/
273
274
/*************************** Pixel Buffer definition ******************/
275
276
typedef 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
*/
289
static 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
*/
299
static 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
312
static 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
*/
319
static 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
*/
331
static 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
*/
346
static 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
*/
391
typedef 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
*/
406
static 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
*/
443
static 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
*/
457
static 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
*/
489
static 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
*/
500
static 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
523
struct sun_jpeg_error_mgr {
524
struct jpeg_error_mgr pub; /* "public" fields */
525
526
jmp_buf setjmp_buffer; /* for return to caller */
527
};
528
529
typedef 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
535
METHODDEF(void)
536
sun_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
554
METHODDEF(void)
555
sun_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(the_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
602
static 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
641
static 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
666
static 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
685
static void imageio_abort(JNIEnv *env, jobject this,
686
imageIODataPtr data) {
687
data->abortFlag = JNI_TRUE;
688
}
689
690
static 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
745
static 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
802
static 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
897
GLOBAL(void)
898
imageio_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
925
GLOBAL(boolean)
926
imageio_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(the_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
1018
GLOBAL(void)
1019
imageio_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(the_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
1119
GLOBAL(void)
1120
imageio_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(the_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
1204
GLOBAL(void)
1205
imageio_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(the_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
* <[email protected]> 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
1263
static boolean
1264
marker_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
1293
jbyteArray
1294
read_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
1431
JNIEXPORT void JNICALL
1432
Java_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
1496
JNIEXPORT jlong JNICALL
1497
Java_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
1588
JNIEXPORT void JNICALL
1589
Java_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
1621
JNIEXPORT jboolean JNICALL
1622
Java_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
1829
JNIEXPORT void JNICALL
1830
Java_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
1852
JNIEXPORT jboolean JNICALL
1853
Java_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
2211
JNIEXPORT void JNICALL
2212
Java_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
2230
JNIEXPORT void JNICALL
2231
Java_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
2249
JNIEXPORT void JNICALL
2250
Java_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
2270
JNIEXPORT void JNICALL
2271
Java_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
2343
JNIEXPORT void JNICALL
2344
Java_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
2361
METHODDEF(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
*/
2367
imageio_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(the_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
2392
METHODDEF(boolean)
2393
imageio_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(the_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
*/
2428
METHODDEF(void)
2429
imageio_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(the_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
*/
2471
METHODDEF(void)
2472
imageio_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
2483
JNIEXPORT void JNICALL
2484
Java_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
2525
JNIEXPORT jlong JNICALL
2526
Java_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
2608
JNIEXPORT void JNICALL
2609
Java_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
2634
JNIEXPORT void JNICALL
2635
Java_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
2702
static 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
2714
JNIEXPORT jboolean JNICALL
2715
Java_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
3108
JNIEXPORT void JNICALL
3109
Java_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
3126
JNIEXPORT void JNICALL
3127
Java_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
3157
JNIEXPORT void JNICALL
3158
Java_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
3169