You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
560 lines
12 KiB
560 lines
12 KiB
|
|
/***********************************************************************
|
|
*
|
|
* 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 "pch.h"
|
|
|
|
#include <setjmp.h>
|
|
|
|
//
|
|
// Workaround for redefinition of INT32
|
|
//
|
|
|
|
#define XMD_H 1
|
|
|
|
//
|
|
// Header file for JPEG library
|
|
//
|
|
|
|
extern "C"
|
|
{
|
|
#include "jpeglib.h"
|
|
}
|
|
#include "utils.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 __cdecl
|
|
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 __cdecl
|
|
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 __cdecl
|
|
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 __cdecl
|
|
term_source(
|
|
j_decompress_ptr pDecompInfo)
|
|
{
|
|
}
|
|
|
|
/******************************************************************************\
|
|
*
|
|
* jpeg_buf_src()
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Status
|
|
*
|
|
* History:
|
|
*
|
|
* 11/4/1998 Original Version
|
|
*
|
|
\******************************************************************************/
|
|
|
|
static void __cdecl
|
|
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 __cdecl
|
|
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:
|
|
* pJpeg -- jpeg file in memory. It could be in JFIF and EXIF
|
|
* format
|
|
* JpegSize -- the jpeg file size
|
|
* pWidth -- to return the image width in pixels
|
|
* pHeight -- to return the image height in pixels
|
|
* pBitDepth -- to return the image bit depth.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HRESULT
|
|
*
|
|
* History:
|
|
*
|
|
* 11/4/1998 Original Version
|
|
*
|
|
\******************************************************************************/
|
|
|
|
HRESULT
|
|
WINAPI
|
|
GetJpegDimensions(
|
|
BYTE *pJpeg,
|
|
UINT JpegSize,
|
|
UINT *pWidth,
|
|
UINT *pHeight,
|
|
UINT *pBitDepth
|
|
)
|
|
{
|
|
struct jpeg_decompress_struct decompInfo;
|
|
jmp_error_mgr jpegErrMgr;
|
|
int ret;
|
|
|
|
//
|
|
// 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(E_FAIL);
|
|
}
|
|
|
|
//
|
|
// Step 2 : Specify the source of the compressed data
|
|
//
|
|
|
|
jpeg_buf_src(&decompInfo, pJpeg, JpegSize);
|
|
|
|
//
|
|
// 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;
|
|
*pBitDepth = 24;
|
|
|
|
if (ret != JPEG_HEADER_OK)
|
|
{
|
|
return(E_FAIL);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// This function converts a jpeg file in memory to DIB bitmap
|
|
//
|
|
// Input:
|
|
// pJpeg -- jpeg file in memory. JFIF or EXIF are supported
|
|
// JpegSize -- the jpeg file size
|
|
// DIBBmpSize -- DIB bitmap buffer size
|
|
// pDIBBmp -- DIB bitmap buffer
|
|
// LineSize -- desitnation scanline size in bytes
|
|
// MaxLines -- maximum scanlines per transfer
|
|
//
|
|
HRESULT
|
|
WINAPI
|
|
Jpeg2DIBBitmap(
|
|
BYTE *pJpeg,
|
|
UINT JpegSize,
|
|
BYTE *pDIBBmp,
|
|
UINT DIBBmpSize,
|
|
UINT LineSize,
|
|
UINT MaxLines
|
|
)
|
|
{
|
|
struct jpeg_decompress_struct decompInfo;
|
|
jmp_error_mgr jpegErrMgr;
|
|
|
|
|
|
//
|
|
// Parameter checking
|
|
//
|
|
if (!pJpeg || !JpegSize || !DIBBmpSize || !pDIBBmp || !LineSize)
|
|
return E_INVALIDARG;
|
|
|
|
//
|
|
// 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(E_FAIL);
|
|
}
|
|
|
|
//
|
|
// Step 2 : Specify the source of the compressed data
|
|
//
|
|
|
|
jpeg_buf_src(&decompInfo, pJpeg, JpegSize);
|
|
|
|
//
|
|
// Step 3 : Read JPEG file header information
|
|
//
|
|
|
|
if (jpeg_read_header(&decompInfo, TRUE) != JPEG_HEADER_OK)
|
|
{
|
|
|
|
jpeg_destroy_decompress(&decompInfo);
|
|
return(E_FAIL);
|
|
}
|
|
|
|
//
|
|
// Step 4 : Set parameter for decompression
|
|
// Defaults are OK for this occasssion
|
|
// Specify the JCS_BGR output colorspace so that the returned
|
|
// decompressed image has the same format as DIB. Also, it forces
|
|
// the decompressor to return a 24-bits RGB colors image
|
|
//
|
|
|
|
decompInfo.out_color_space = JCS_BGR;
|
|
|
|
//
|
|
// Calculate DIB scan line size, assuming 24bits color.
|
|
//
|
|
HRESULT hr;
|
|
|
|
hr = S_OK;
|
|
|
|
//
|
|
// Step 5 : Start the real action
|
|
//
|
|
|
|
jpeg_start_decompress(&decompInfo);
|
|
|
|
//
|
|
// Step 6 : Acquire the scan line
|
|
//
|
|
|
|
while (S_OK == hr &&
|
|
decompInfo.output_scanline < decompInfo.output_height)
|
|
{
|
|
if (DIBBmpSize >= LineSize)
|
|
{
|
|
//
|
|
// Decompress line by line. Ignore the MaxLines since
|
|
// we do not do more than one line at a time.
|
|
//
|
|
jpeg_read_scanlines(&decompInfo, &pDIBBmp, 1);
|
|
pDIBBmp -= LineSize;
|
|
DIBBmpSize -= LineSize;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The provided buffer is too small.
|
|
//
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
}
|
|
//
|
|
// Step 7 : Finish the job
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
jpeg_finish_decompress(&decompInfo);
|
|
}
|
|
else
|
|
{
|
|
jpeg_abort_decompress(&decompInfo);
|
|
}
|
|
//
|
|
// Step 8 : Garbage collection
|
|
//
|
|
|
|
jpeg_destroy_decompress(&decompInfo);
|
|
return hr;
|
|
}
|