/java-1.7.0-openjdk/openjdk/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c

# · C · 3024 lines · 1971 code · 425 blank · 628 comment · 406 complexity · 7b7e4027d0060cc39313d97c919e9592 MD5 · raw file

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