jpegdecoder.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 757 行 · 第 1/2 页
C
757 行
/* * * @(#)jpegdecoder.c 1.32 06/10/03 * * Portions Copyright 2000-2008 Sun Microsystems, Inc. All Rights * Reserved. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. *//* * This file was based upon the example.c stub file included in the * release 6 of the Independent JPEG Group's free JPEG software. *//* First, if system header files define "boolean" map it to "system_boolean" */#define boolean system_boolean#include <stdio.h>#include <setjmp.h>#include <string.h>#include <stdlib.h>#include <assert.h>#include "jni.h"#include "jni_util.h"/* undo "system_boolean" hack and undef FAR since we don't use it anyway */#undef boolean#undef FAR#include "jpeglib.h"#include "jerror.h"/* The cached JNI IDs we need. */struct CachedIDs{ jmethodID JPEGImageDecoder_sendHeaderInfoMID; jmethodID JPEGImageDecoder_sendPixelsByteMID; jmethodID JPEGImageDecoder_sendPixelsIntMID; jmethodID java_io_InputStream_readMID; jmethodID java_io_InputStream_availableMID; jclass java_lang_NullPointerExceptionClass; jclass sun_awt_image_ImageFormatExceptionClass;};static struct CachedIDs CachedIDs;/* Initialize the Java VM instance variable when the library is first loaded */JavaVM *jvm;JNIEXPORT void JNICALLJava_sun_awt_image_JPEGImageDecoder_initIDs(JNIEnv *env, jclass cls, jclass InputStreamClass){ /* Cache reference to Java VM. */ if ((*env)->GetJavaVM(env, &jvm) != 0) return; CachedIDs.JPEGImageDecoder_sendHeaderInfoMID = (*env)->GetMethodID(env, cls, "sendHeaderInfo", "(IIZZ)Z"); CachedIDs.JPEGImageDecoder_sendPixelsByteMID = (*env)->GetMethodID(env, cls, "sendPixels", "([BI)Z"); CachedIDs.JPEGImageDecoder_sendPixelsIntMID = (*env)->GetMethodID(env, cls, "sendPixels", "([II)Z"); CachedIDs.java_io_InputStream_readMID = (*env)->GetMethodID(env, InputStreamClass, "read", "([BII)I"); CachedIDs.java_io_InputStream_availableMID = (*env)->GetMethodID(env, InputStreamClass, "available", "()I"); cls = (*env)->FindClass(env, "java/lang/NullPointerException"); CachedIDs.java_lang_NullPointerExceptionClass = (jclass) (*env)->NewGlobalRef (env, cls); cls = (*env)->FindClass (env, "sun/awt/image/ImageFormatException"); CachedIDs.sun_awt_image_ImageFormatExceptionClass = (*env)->NewGlobalRef (env, cls);}/* * ERROR HANDLING: * * The JPEG library's standard error handler (jerror.c) is divided into * several "methods" which you can override individually. This lets you * adjust the behavior without duplicating a lot of code, which you might * have to update with each future release. * * Our example here shows how to override the "error_exit" method so that * control is returned to the library's caller when a fatal error occurs, * rather than calling exit() as the standard error_exit method does. * * We use C's setjmp/longjmp facility to return control. This means that the * routine which calls the JPEG library must first execute a setjmp() call to * establish the return point. We want the replacement error_exit to do a * longjmp(). But we need to make the setjmp buffer accessible to the * error_exit routine. To do this, we make a private extension of the * standard JPEG error handler object. (If we were using C++, we'd say we * were making a subclass of the regular error handler.) * * Here's the extended error handler struct: */struct sun_jpeg_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */};typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr;/* * Here's the routine that will replace the standard error_exit method: */METHODDEF(void)sun_jpeg_error_exit (j_common_ptr cinfo){ /* cinfo->err really points to a sun_jpeg_error_mgr struct */ sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ /* (*cinfo->err->output_message) (cinfo); */ /* For Java, we will format the message and put it in the error we throw. */ /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1);}/* * Error Message handling * * This overrides the output_message method to send JPEG messages * */METHODDEF(void)sun_jpeg_output_message (j_common_ptr cinfo){ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); /* Send it to stderr, adding a newline */ fprintf(stderr, "%s\n", buffer);}/* * INPUT HANDLING: * * The JPEG library's input management is defined by the jpeg_source_mgr * structure which contains two fields to convey the information in the * buffer and 5 methods which perform all buffer management. The library * defines a standard input manager that uses stdio for obtaining compressed * jpeg data, but here we need to use Java to get our data. * * We need to make the Java class information accessible to the source_mgr * input routines. We also need to store a pointer to the start of the * Java array being used as an input buffer so that it is not moved or * garbage collected while the JPEG library is using it. To store these * things, we make a private extension of the standard JPEG jpeg_source_mgr * object. * * Here's the extended source manager struct: */struct sun_jpeg_source_mgr { struct jpeg_source_mgr pub; /* "public" fields */ jobject hInputStream; int suspendable; long remaining_skip; JOCTET *inbuf; jbyteArray hInputBuffer; int inbufoffset; /* More stuff */ union pixptr { long *ip; unsigned char *bp; } outbuf; jobject hOutputBuffer;};typedef struct sun_jpeg_source_mgr * sun_jpeg_source_ptr;/* We use Get/ReleasePrimitiveArrayCritical functions to avoid * the need to copy buffer elements. * * MAKE SURE TO: * * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around * callbacks to Java. * - call RELEASE_ARRAYS before returning to Java. * * Otherwise things will go horribly wrong. There may be memory leaks, * excessive pinning, or even VM crashes! * * Note that GetPrimitiveArrayCritical may fail! */static void RELEASE_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src){ if (src->inbuf) { if (src->pub.next_input_byte == 0) { src->inbufoffset = -1; } else { src->inbufoffset = src->pub.next_input_byte - src->inbuf; } (*env)->ReleasePrimitiveArrayCritical(env, src->hInputBuffer, src->inbuf, 0); src->inbuf = 0; } if (src->outbuf.ip) { (*env)->ReleasePrimitiveArrayCritical(env, src->hOutputBuffer, src->outbuf.ip, 0); src->outbuf.ip = 0; }}static int GET_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src){ if (src->hInputBuffer) { assert(src->inbuf == 0); src->inbuf = (JOCTET *)(*env)->GetPrimitiveArrayCritical (env, src->hInputBuffer, 0); if (src->inbuf == 0) { return 0; } if (src->inbufoffset >= 0) { src->pub.next_input_byte = src->inbuf + src->inbufoffset; } } if (src->hOutputBuffer) { assert(src->outbuf.ip == 0); src->outbuf.ip = (long *)(*env)->GetPrimitiveArrayCritical (env, src->hOutputBuffer, 0); if (src->outbuf.ip == 0) { RELEASE_ARRAYS(env, src); return 0; } } return 1;}/* * Initialize source. This is called by jpeg_read_header() before any * data is actually read. Unlike init_destination(), it may leave * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call * will occur immediately). */GLOBAL(void)sun_jpeg_init_source(j_decompress_ptr cinfo){ sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; src->pub.next_input_byte = 0; src->pub.bytes_in_buffer = 0;}/* * This is called whenever bytes_in_buffer has reached zero and more * data is wanted. In typical applications, it should read fresh data * into the buffer (ignoring the current state of next_input_byte and * bytes_in_buffer), reset the pointer & count to the start of the * buffer, and return TRUE indicating that the buffer has been reloaded. * It is not necessary to fill the buffer entirely, only to obtain at * least one more byte. bytes_in_buffer MUST be set to a positive value * if TRUE is returned. A FALSE return should only be used when I/O * suspension is desired (this mode is discussed in the next section). *//* * Note that with I/O suspension turned on, this procedure should not * do any work since the JPEG library has a very simple backtracking * mechanism which relies on the fact that the buffer will be filled * only when it has backed out to the top application level. When * suspendable is turned on, the sun_jpeg_fill_suspended_buffer will * do the actual work of filling the buffer. */GLOBAL(boolean)sun_jpeg_fill_input_buffer(j_decompress_ptr cinfo){ sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; JNIEnv *env; int ret, buflen; (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_2); if (src->suspendable) { return FALSE; } if (src->remaining_skip) { src->pub.skip_input_data(cinfo, 0); } RELEASE_ARRAYS(env, src); buflen = (*env)->GetArrayLength(env, src->hInputBuffer); ret = (*env)->CallIntMethod(env, src->hInputStream, CachedIDs.java_io_InputStream_readMID, src->hInputBuffer, 0, buflen); if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); } if (ret <= 0) { /* Silently accept truncated JPEG files */ WARNMS(cinfo, JWRN_JPEG_EOF); src->inbuf[0] = (JOCTET) 0xFF; src->inbuf[1] = (JOCTET) JPEG_EOI; ret = 2; } src->pub.next_input_byte = src->inbuf; src->pub.bytes_in_buffer = ret; return TRUE;}/* * Note that with I/O suspension turned on, the JPEG library requires * that all buffer filling be done at the top application level. Due * to the way that backtracking works, this procedure should save all * of the data that was left in the buffer when suspension occured and * only read new data at the end. */GLOBAL(void)sun_jpeg_fill_suspended_buffer(j_decompress_ptr cinfo){ sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src; JNIEnv *env; int ret, offset, buflen; (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_2); RELEASE_ARRAYS(env, src); ret = (*env)->CallIntMethod(env, src->hInputStream, CachedIDs.java_io_InputStream_availableMID); if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); } if (ret <= src->remaining_skip) { return; } if (src->remaining_skip) { src->pub.skip_input_data(cinfo, 0); } /* Save the data currently in the buffer */ offset = src->pub.bytes_in_buffer; if (src->pub.next_input_byte > src->inbuf) { memcpy(src->inbuf, src->pub.next_input_byte, offset); } RELEASE_ARRAYS(env, src); buflen = (*env)->GetArrayLength(env, src->hInputBuffer) - offset; if (buflen <= 0) { if (!GET_ARRAYS(env, src)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?