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 + -
显示快捷键?