/*********************************************************************** * * 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 // // 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; }