|
|
/***********************************************************************
* * JPEG decompression utility functions * * Implement (1) JPEG memory data source * (2) JPEG error manager using setjmp/longjmp * * Author : Indy Zhu [indyz] * Date : 5/20/98 * ***********************************************************************/
#include <stdio.h>
// #include <stdlib.h>
#include <setjmp.h>
// Workaround for redefinition of INT32
#define XMD_H 1
extern "C" { // Header file for JPEG library
#include "jpeglib.h"
}
#include <windows.h>
#include "jpegutil.h"
//
// Buf source manager definition
//
typedef struct _buf_source_mgr { struct jpeg_source_mgr pub; // Fields specific to buf_source_mgr
LPBYTE pJPEGBlob; DWORD dwSize; } buf_source_mgr;
//
// Jump error manager definition
//
typedef struct _jmp_error_mgr { struct jpeg_error_mgr pub;
// Private fields for jump error manager
jmp_buf stackContext; } jmp_error_mgr;
/******************************************************************************\
* * init_source() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static void init_source(j_decompress_ptr pDecompInfo) { // No working necessary here
}
/******************************************************************************\
* * fill_input_buffer() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static boolean fill_input_buffer(j_decompress_ptr pDecompInfo) { buf_source_mgr *pBufSrcMgr;
// Recover buf source manager itself
pBufSrcMgr = (buf_source_mgr *)pDecompInfo->src;
// buf_source_mgr can only fire one shot
pBufSrcMgr->pub.next_input_byte = pBufSrcMgr->pJPEGBlob; pBufSrcMgr->pub.bytes_in_buffer = pBufSrcMgr->dwSize; return(TRUE); }
/******************************************************************************\
* * skip_input_data() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static void skip_input_data(j_decompress_ptr pDecompInfo, long lBytes) { buf_source_mgr *pBufSrcMgr;
// For buf source manager, it is very easy to implement
if (lBytes > 0) {
pBufSrcMgr = (buf_source_mgr *)pDecompInfo->src; pBufSrcMgr->pub.next_input_byte += lBytes; pBufSrcMgr->pub.bytes_in_buffer -= lBytes; } }
/******************************************************************************\
* * term_source() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static void term_source(j_decompress_ptr pDecompInfo) { }
/******************************************************************************\
* * jpeg_buf_src() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static void jpeg_buf_src(j_decompress_ptr pDecompInfo, LPBYTE pJPEGBlob, DWORD dwSize) { buf_source_mgr *pBufSrcMgr;
// Allocate memory for the buf source manager
pBufSrcMgr = (buf_source_mgr *) (pDecompInfo->mem->alloc_small)((j_common_ptr)pDecompInfo, JPOOL_PERMANENT, sizeof(buf_source_mgr)); // Record the pJPEGBlob
pBufSrcMgr->pJPEGBlob = pJPEGBlob; pBufSrcMgr->dwSize = dwSize;
// Fill in the function pointers
pBufSrcMgr->pub.init_source = init_source; pBufSrcMgr->pub.fill_input_buffer = fill_input_buffer; pBufSrcMgr->pub.skip_input_data = skip_input_data; pBufSrcMgr->pub.resync_to_restart = jpeg_resync_to_restart; pBufSrcMgr->pub.term_source = term_source;
// Initialize the pointer into the buffer
pBufSrcMgr->pub.bytes_in_buffer = 0; pBufSrcMgr->pub.next_input_byte = NULL;
// Ask the decompression context to remember it
pDecompInfo->src = (struct jpeg_source_mgr *)pBufSrcMgr; }
/******************************************************************************\
* * jmp_error_exit() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
static void jmp_error_exit(j_common_ptr pDecompInfo) { jmp_error_mgr *pJmpErrorMgr;
// Get the jump error manager back
pJmpErrorMgr = (jmp_error_mgr *)pDecompInfo->err;
// Display the error message
#ifdef _DEBUG
(pDecompInfo->err->output_message)(pDecompInfo); #endif
// Recover the original stack
longjmp(pJmpErrorMgr->stackContext, 1); }
/******************************************************************************\
* * jpeg_jmp_error() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
struct jpeg_error_mgr *jpeg_jmp_error(jmp_error_mgr *pJmpErrorMgr) { // Initialize the public part
jpeg_std_error(&pJmpErrorMgr->pub);
// Set up jump error manager exit method
pJmpErrorMgr->pub.error_exit = jmp_error_exit;
return((jpeg_error_mgr *)pJmpErrorMgr); }
/******************************************************************************\
* * GetJPEGDimensions() * * Arguments: * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
int GetJPEGDimensions(LPBYTE pJPEGBlob, DWORD dwSize, LONG *pWidth, LONG *pHeight, WORD *pChannel) { int ret; struct jpeg_decompress_struct decompInfo; jmp_error_mgr jpegErrMgr;
// Step 1 : Initialize JPEG session data-structure
decompInfo.err = jpeg_jmp_error(&jpegErrMgr); jpeg_create_decompress(&decompInfo); // Reserve the state of the current stack
if (setjmp(jpegErrMgr.stackContext)) {
// JPEG lib will longjump here when there is an error
jpeg_destroy_decompress(&decompInfo);
return(JPEGERR_INTERNAL_ERROR); }
// Step 2 : Specify the source of the compressed data
jpeg_buf_src(&decompInfo, pJPEGBlob, dwSize);
// Step 3 : Read JPEG file header information
ret = jpeg_read_header(&decompInfo, TRUE);
// Release the decompression context
jpeg_destroy_decompress(&decompInfo);
// Fill in the dimension info for the caller
*pWidth = decompInfo.image_width; *pHeight = decompInfo.image_height; *pChannel = decompInfo.num_components;
if (ret != JPEG_HEADER_OK) { return(JPEGERR_INTERNAL_ERROR); }
return(JPEGERR_NO_ERROR); }
/******************************************************************************\
* * DecompProgressJPEG() * * Arguments: * * Assumption : The JPEG is 24bits. * pDIBPixel is the pixel buffer of a DIB * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
short __stdcall DecompProgressJPEG( LPBYTE pJPEGBlob, DWORD dwSize, LPBYTE pDIBPixel, DWORD dwBytesPerScanLine, JPEGCallbackProc pProgressCB, PVOID pCBContext) { struct jpeg_decompress_struct decompInfo; jmp_error_mgr jpegErrMgr; LPBYTE pCurScanBuf; JSAMPLE sampleTemp; LPBYTE pCurPixel; DWORD i; //
// Callback related variables
//
ULONG ulImageSize; ULONG ulOffset; ULONG ulNewScanlines; ULONG ulCBInterval; BOOL bRet = FALSE;
// Step 1 : Initialize JPEG session data-structure
decompInfo.err = jpeg_jmp_error(&jpegErrMgr); jpeg_create_decompress(&decompInfo); // Reserve the state of the current stack
if (setjmp(jpegErrMgr.stackContext)) {
// JPEG lib will longjump here when there is an error
jpeg_destroy_decompress(&decompInfo);
return(JPEGERR_INTERNAL_ERROR); }
// Step 2 : Specify the source of the compressed data
jpeg_buf_src(&decompInfo, pJPEGBlob, dwSize);
// Step 3 : Read JPEG file header information
if (jpeg_read_header(&decompInfo, TRUE) != JPEG_HEADER_OK) {
jpeg_destroy_decompress(&decompInfo); return(JPEGERR_INTERNAL_ERROR); } // Step 4 : Set parameter for decompression
// Defaults are OK for this occasssion
// Step 5 : Start the real action
jpeg_start_decompress(&decompInfo);
//
// Prepare for the final decompression
//
pCurScanBuf = pDIBPixel + (decompInfo.image_height - 1) * dwBytesPerScanLine; if (pProgressCB) {
ulImageSize = decompInfo.image_height * dwBytesPerScanLine; ulCBInterval = decompInfo.image_height / 10; ulOffset = 0; ulNewScanlines = 0; }
// Step 6 : Acquire the scan line
while (decompInfo.output_scanline < decompInfo.output_height) {
jpeg_read_scanlines(&decompInfo, &pCurScanBuf, 1);
// Famous swapping for the unique format of Windows
pCurPixel = pCurScanBuf; for (i = 0; i < decompInfo.image_width; i++, pCurPixel += decompInfo.num_components) {
sampleTemp = *pCurPixel; *pCurPixel = *(pCurPixel + 2); *(pCurPixel + 2) = sampleTemp; } pCurScanBuf -= dwBytesPerScanLine;
//
// Fire the callback when possible and necessary
//
if (pProgressCB) {
ulNewScanlines++; ulOffset += dwBytesPerScanLine;
if ((ulNewScanlines == ulCBInterval) || (decompInfo.output_scanline == decompInfo.output_height)) {
bRet = pProgressCB( ulImageSize, ulNewScanlines, ulNewScanlines * dwBytesPerScanLine, pDIBPixel, pCBContext);
if (! bRet) { break; } } } }
// Step 7 : Finish the job
jpeg_finish_decompress(&decompInfo);
// Step 8 : Garbage collection
jpeg_destroy_decompress(&decompInfo);
if (bRet) { return(JPEGERR_NO_ERROR); } else { return(JPEGERR_CALLBACK_ERROR); } }
/******************************************************************************\
* * DecompTransferJPEG() * * Arguments: * * ppDIBPixel - *ppDIBPixel will change between callback if multiple buffer is * used, but dwBufSize is assumed to be constant. * * Return Value: * * Status * * History: * * 1/20/1999 Original Version * \******************************************************************************/
short __stdcall DecompTransferJPEG( LPBYTE pJPEGBlob, DWORD dwSize, LPBYTE *ppDIBPixel, DWORD dwBufSize, DWORD dwBytesPerScanLine, JPEGCallbackProc pProgressCB, PVOID pCBContext) { struct jpeg_decompress_struct decompInfo; jmp_error_mgr jpegErrMgr; LPBYTE pCurScanLine; JSAMPLE sampleTemp; LPBYTE pCurPixel; DWORD i; //
// Callback related variables
//
ULONG ulImageSize; ULONG ulOffset = 0; ULONG ulBufferLeft; BOOL bRet = FALSE;
//
// Parameter checking
//
if ((! ppDIBPixel) || (! *ppDIBPixel) || (! pProgressCB)) { return (JPEGERR_INTERNAL_ERROR); }
// Step 1 : Initialize JPEG session data-structure
decompInfo.err = jpeg_jmp_error(&jpegErrMgr); jpeg_create_decompress(&decompInfo); // Reserve the state of the current stack
if (setjmp(jpegErrMgr.stackContext)) {
// JPEG lib will longjump here when there is an error
jpeg_destroy_decompress(&decompInfo);
return(JPEGERR_INTERNAL_ERROR); }
// Step 2 : Specify the source of the compressed data
jpeg_buf_src(&decompInfo, pJPEGBlob, dwSize);
// Step 3 : Read JPEG file header information
if (jpeg_read_header(&decompInfo, TRUE) != JPEG_HEADER_OK) {
jpeg_destroy_decompress(&decompInfo); return(JPEGERR_INTERNAL_ERROR); }
// Step 4 : Set parameter for decompression
// Defaults are OK for this occasssion
// Step 5 : Start the real action
jpeg_start_decompress(&decompInfo);
//
// Prepare for the final decompression
//
ulImageSize = decompInfo.image_height * dwBytesPerScanLine; ulBufferLeft = dwBufSize; pCurScanLine = *ppDIBPixel;
// Step 6 : Acquire the scan line
while (decompInfo.output_scanline < decompInfo.output_height) {
jpeg_read_scanlines(&decompInfo, &pCurScanLine, 1);
// Famous swapping for the unique format of Windows
pCurPixel = pCurScanLine; for (i = 0; i < decompInfo.image_width; i++, pCurPixel += decompInfo.num_components) {
sampleTemp = *pCurPixel; *pCurPixel = *(pCurPixel + 2); *(pCurPixel + 2) = sampleTemp; }
pCurScanLine += dwBytesPerScanLine; ulBufferLeft -= dwBytesPerScanLine;
//
// Fire the callback when possible and necessary
//
if ((ulBufferLeft < dwBytesPerScanLine) || (decompInfo.output_scanline == decompInfo.output_height)) {
bRet = pProgressCB( ulImageSize, ulOffset, dwBufSize - ulBufferLeft, *ppDIBPixel, pCBContext);
if (! bRet) { break; }
//
// Reset the buffer, which may have been switched by the callback
//
ulBufferLeft = dwBufSize; pCurScanLine = *ppDIBPixel;
ulOffset = decompInfo.output_scanline * dwBytesPerScanLine; } }
// Step 7 : Finish the job
jpeg_finish_decompress(&decompInfo);
// Step 8 : Garbage collection
jpeg_destroy_decompress(&decompInfo);
if (bRet) { return(JPEGERR_NO_ERROR); } else { return(JPEGERR_CALLBACK_ERROR); } }
/******************************************************************************\
* * DecompJPEG() * * Arguments: * * Assumption : The JPEG is 24bits. * pDIBPixel is the pixel buffer of a DIB * * Return Value: * * Status * * History: * * 11/4/1998 Original Version * \******************************************************************************/
SHORT __stdcall DecompJPEG( LPBYTE pJPEGBlob, DWORD dwSize, LPBYTE pDIBPixel, DWORD dwBytesPerScanLine) { struct jpeg_decompress_struct decompInfo; jmp_error_mgr jpegErrMgr; LPBYTE pCurScanBuf; JSAMPLE sampleTemp; LPBYTE pCurPixel; DWORD i;
// Step 1 : Initialize JPEG session data-structure
decompInfo.err = jpeg_jmp_error(&jpegErrMgr); jpeg_create_decompress(&decompInfo); // Reserve the state of the current stack
if (setjmp(jpegErrMgr.stackContext)) {
// JPEG lib will longjump here when there is an error
jpeg_destroy_decompress(&decompInfo);
return(-1); }
// Step 2 : Specify the source of the compressed data
jpeg_buf_src(&decompInfo, pJPEGBlob, dwSize);
// Step 3 : Read JPEG file header information
if (jpeg_read_header(&decompInfo, TRUE) != JPEG_HEADER_OK) {
jpeg_destroy_decompress(&decompInfo); return(-1); }
// Step 4 : Set parameter for decompression
// Defaults are OK for this occasssion
// Step 5 : Start the real action
jpeg_start_decompress(&decompInfo);
pCurScanBuf = pDIBPixel + (decompInfo.image_height - 1) * dwBytesPerScanLine; // Step 6 : Acquire the scan line
while (decompInfo.output_scanline < decompInfo.output_height) {
jpeg_read_scanlines(&decompInfo, &pCurScanBuf, 1);
// Famous swapping for the unique format of Windows
pCurPixel = pCurScanBuf; for (i = 0; i < decompInfo.image_width; i++, pCurPixel += decompInfo.num_components) {
sampleTemp = *pCurPixel; *pCurPixel = *(pCurPixel + 2); *(pCurPixel + 2) = sampleTemp; }
pCurScanBuf -= dwBytesPerScanLine; }
// Step 7 : Finish the job
jpeg_finish_decompress(&decompInfo);
// Step 8 : Garbage collection
jpeg_destroy_decompress(&decompInfo);
return(0); }
|