libjpeg库使用实例细节分析
#include <config.h>
#include <pic_operation.h>
#include <picfmt_manager.h>
#include <file.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <jpeglib.h>
typedef struct MyErrorMgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
}T_MyErrorMgr, *PT_MyErrorMgr;
static int isJPGFormat(PT_FileMap ptFileMap);
static int GetPixelDatasFrmJPG(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForJPG(PT_PixelDatas ptPixelDatas);
static T_PicFileParser g_tJPGParser = {
.name = "jpg",
.isSupport = isJPGFormat,
.GetPixelDatas = GetPixelDatasFrmJPG,
.FreePixelDatas = FreePixelDatasForJPG,
};
/**********************************************************************
* 函数名称: MyErrorExit
* 功能描述: 自定义的libjpeg库出错处理函数
* 默认的错误处理函数是让程序退出,我们当然不会使用它
* 参考libjpeg里的bmp.c编写了这个错误处理函数
* 输入参数: ptCInfo - libjpeg库抽象出来的通用结构体
* 输出参数: 无
* 返 回 值: 无
***********************************************************************/
static void MyErrorExit(j_common_ptr ptCInfo)
{
static char errStr[JMSG_LENGTH_MAX];
PT_MyErrorMgr ptMyErr = (PT_MyErrorMgr)ptCInfo->err;
/* Create the message */
(*ptCInfo->err->format_message) (ptCInfo, errStr);
DBG_PRINTF("%s\n", errStr);
longjmp(ptMyErr->setjmp_buffer, 1);
}
/**********************************************************************
* 函数名称: isJPGFormat
* 功能描述: JPG模块是否支持该文件,即该文件是否为JPG文件
* 输入参数: ptFileMap - 内含文件信息
* 输出参数: 无
* 返 回 值: 0 - 不支持, 1 - 支持
***********************************************************************/
static int isJPGFormat(PT_FileMap ptFileMap)
{
struct jpeg_decompress_struct tDInfo;
/* 默认的错误处理函数是让程序退出
* 我们参考libjpeg里的bmp.c编写自己的错误处理函数
*/
//struct jpeg_error_mgr tJErr;
T_MyErrorMgr tJerr;
int iRet;
fseek(ptFileMap->tFp, 0, SEEK_SET);
// 分配和初始化一个decompression结构体
// tDInfo.err = jpeg_std_error(&tJErr);
tDInfo.err = jpeg_std_error(&tJerr.pub);
tJerr.pub.error_exit = MyErrorExit;
if(setjmp(tJerr.setjmp_buffer))
{
/* 如果程序能运行到这里, 表示JPEG解码出错 */
jpeg_destroy_decompress(&tDInfo);
return 0;;
}
jpeg_create_decompress(&tDInfo);
// 用jpeg_read_header获得jpg信息
jpeg_stdio_src(&tDInfo, ptFileMap->tFp);
iRet = jpeg_read_header(&tDInfo, TRUE);
jpeg_abort_decompress(&tDInfo);
return (iRet == JPEG_HEADER_OK);
}
/**********************************************************************
* 函数名称: CovertOneLine
* 功能描述: 把已经从JPG文件取出的一行象素数据,转换为能在显示设备上使用的格式
* 输入参数: iWidth - 宽度,即多少个象素
* iSrcBpp - 已经从JPG文件取出的一行象素数据里面,一个象素用多少位来表示
* iDstBpp - 显示设备上一个象素用多少位来表示
* pudSrcDatas - 已经从JPG文件取出的一行象素数所存储的位置
* pudDstDatas - 转换所得数据存储的位置
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
unsigned int dwRed;
unsigned int dwGreen;
unsigned int dwBlue;
unsigned int dwColor;
unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
unsigned int *pwDstDatas32bpp = (unsigned int *)pudDstDatas;
int i;
int pos = 0;
if (iSrcBpp != 24)
{
return -1;
}
if (iDstBpp == 24)
{
memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
}
else
{
for (i = 0; i < iWidth; i++)
{
dwRed = pudSrcDatas[pos++];
dwGreen = pudSrcDatas[pos++];
dwBlue = pudSrcDatas[pos++];
if (iDstBpp == 32)
{
dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
*pwDstDatas32bpp = dwColor;
pwDstDatas32bpp++;
}
else if (iDstBpp == 16)
{
/* 565 */
dwRed = dwRed >> 3;
dwGreen = dwGreen >> 2;
dwBlue = dwBlue >> 3;
dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
*pwDstDatas16bpp = dwColor;
pwDstDatas16bpp++;
}
}
}
return 0;
}
/**********************************************************************
* 函数名称: GetPixelDatasFrmJPG
* 功能描述: 把JPG文件中的图像数据,取出并转换为能在显示设备上使用的格式
* 输入参数: ptFileMap - 内含文件信息
* 输出参数: ptPixelDatas - 内含象素数据
* ptPixelDatas->iBpp 是输入的参数, 它确定从JPG文件得到的数据要转换为该BPP
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
static int GetPixelDatasFrmJPG(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{
struct jpeg_decompress_struct tDInfo;
//struct jpeg_error_mgr tJErr;
//int iRet;
int iRowStride;
unsigned char *aucLineBuffer = NULL;
unsigned char *pucDest;
T_MyErrorMgr tJerr;
fseek(ptFileMap->tFp, 0, SEEK_SET);
// 分配和初始化一个decompression结构体
//tDInfo.err = jpeg_std_error(&tJErr);
tDInfo.err = jpeg_std_error(&tJerr.pub);
tJerr.pub.error_exit = MyErrorExit;
if(setjmp(tJerr.setjmp_buffer))
{
/* 如果程序能运行到这里, 表示JPEG解码出错 */
jpeg_destroy_decompress(&tDInfo);
if (aucLineBuffer)
{
free(aucLineBuffer);
}
if (ptPixelDatas->aucPixelDatas)
{
free(ptPixelDatas->aucPixelDatas);
}
return -1;
}
jpeg_create_decompress(&tDInfo);
// 用jpeg_read_header获得jpg信息
jpeg_stdio_src(&tDInfo, ptFileMap->tFp);
jpeg_read_header(&tDInfo, TRUE);
// 设置解压参数,比如放大、缩小
tDInfo.scale_num = tDInfo.scale_denom = 1;
// 启动解压:jpeg_start_decompress
jpeg_start_decompress(&tDInfo);
// 一行的数据长度
iRowStride = tDInfo.output_width * tDInfo.output_components;
aucLineBuffer = malloc(iRowStride);
if (NULL == aucLineBuffer)
{
return -1;
}
ptPixelDatas->iWidth = tDInfo.output_width;
ptPixelDatas->iHeight = tDInfo.output_height;
//ptPixelDatas->iBpp = iBpp;
ptPixelDatas->iLineBytes = ptPixelDatas->iWidth * ptPixelDatas->iBpp / 8;
ptPixelDatas->iTotalBytes = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes;
ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);
if (NULL == ptPixelDatas->aucPixelDatas)
{
return -1;
}
pucDest = ptPixelDatas->aucPixelDatas;
// 循环调用jpeg_read_scanlines来一行一行地获得解压的数据
while (tDInfo.output_scanline < tDInfo.output_height)
{
/* 得到一行数据,里面的颜色格式为0xRR, 0xGG, 0xBB */
(void) jpeg_read_scanlines(&tDInfo, &aucLineBuffer, 1);
// 转到ptPixelDatas去
CovertOneLine(ptPixelDatas->iWidth, 24, ptPixelDatas->iBpp, aucLineBuffer, pucDest);
pucDest += ptPixelDatas->iLineBytes;
}
free(aucLineBuffer);
jpeg_finish_decompress(&tDInfo);
jpeg_destroy_decompress(&tDInfo);
return 0;
}
/**********************************************************************
* 函数名称: FreePixelDatasForJPG
* 功能描述: GetPixelDatasFrmJPG的反函数,把象素数据所占内存释放掉
* 输入参数: ptPixelDatas - 内含象素数据
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
static int FreePixelDatasForJPG(PT_PixelDatas ptPixelDatas)
{
free(ptPixelDatas->aucPixelDatas);
return 0;
}
/**********************************************************************
* 函数名称: JPGParserInit
* 功能描述: 注册"JPG文件解析模块"
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
int JPGParserInit(void)
{
return RegisterPicFileParser(&g_tJPGParser);
}
这段代码是一个使用libjpeg库进行JPEG文件解析的模块。以下是代码的主要功能和结构:
MyErrorMgr结构体定义了自定义的错误管理器,用于处理libjpeg库的错误。
isJPGFormat函数用于判断给定的文件是否为JPEG格式。它使用libjpeg库的函数来读取文件头并检查是否为有效的JPEG文件。
CovertOneLine函数用于将从JPEG文件中提取的一行像素数据转换为可以在显示设备上使用的格式。根据输入和输出的像素位数,它将像素数据转换为24位、16位或32位的格式。
GetPixelDatasFrmJPG函数用于从JPEG文件中提取图像数据并转换为可以在显示设备上使用的格式。它使用libjpeg库来解压缩JPEG数据并将其转换为指定的像素位数。
FreePixelDatasForJPG函数用于释放从JPEG文件中提取的像素数据所占用的内存。
JPGParserInit函数用于注册JPEG文件解析模块,将其添加到系统中。
该模块提供了一组函数来解析JPEG文件并将其转换为可以在显示设备上使用的像素数据。它使用libjpeg库提供的函数来处理JPEG文件的解码和转换过程。
错误管理器结构体
typedef struct MyErrorMgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
}T_MyErrorMgr, *PT_MyErrorMgr;
这段代码定义了一个名为 MyErrorMgr 的结构体,并使用 typedef 关键字定义了两个类型别名 T_MyErrorMgr 和 PT_MyErrorMgr。
MyErrorMgr 结构体包含两个成员变量:
pub:类型为 struct jpeg_error_mgr,是 libjpeg 库中定义的错误管理器结构体。
setjmp_buffer:类型为 jmp_buf,用于实现跳转缓冲区,用于错误处理。
通过 typedef 关键字,将 MyErrorMgr 结构体类型别名为 T_MyErrorMgr,并将指向 MyErrorMgr 结构体的指针类型别名为 PT_MyErrorMgr。
这样做的目的是定义一个自定义的错误管理器结构体,继承了 libjpeg 库中的错误管理器结构体,并添加了额外的字段用于自定义的错误处理。通过使用类型别名,可以方便地在代码中使用 T_MyErrorMgr 和 PT_MyErrorMgr 来表示该结构体类型和指针类型。
libjpeg库出错处理函数
static void MyErrorExit(j_common_ptr ptCInfo)
{
static char errStr[JMSG_LENGTH_MAX];
PT_MyErrorMgr ptMyErr = (PT_MyErrorMgr)ptCInfo->err;
/* Create the message */
(*ptCInfo->err->format_message) (ptCInfo, errStr);
DBG_PRINTF("%s\n", errStr);
longjmp(ptMyErr->setjmp_buffer, 1);
}
这段代码实现了一个自定义的错误处理函数 MyErrorExit,该函数用于处理由 libjpeg 库发生的错误。以下是对该函数的逐行解析:
static void MyErrorExit(j_common_ptr ptCInfo): 函数声明,接受一个名为 ptCInfo 的 j_common_ptr 类型参数,该参数是 libjpeg 库抽象出来的通用结构体指针。
static char errStr[JMSG_LENGTH_MAX];: 定义一个静态字符数组 errStr,长度为 JMSG_LENGTH_MAX,用于存储错误消息字符串。
PT_MyErrorMgr ptMyErr = (PT_MyErrorMgr)ptCInfo->err;: 声明并初始化一个名为 ptMyErr 的指针变量,将 ptCInfo->err 强制转换为 PT_MyErrorMgr 类型,即自定义的错误管理器结构体指针。
(*ptCInfo->err->format_message) (ptCInfo, errStr);: 调用 ptCInfo->err->format_message 函数指针指向的函数,将错误消息格式化为字符串,并将其存储在 errStr 中。
DBG_PRINTF(“%s\n”, errStr);: 将错误消息打印输出到调试输出中。
longjmp(ptMyErr->setjmp_buffer, 1);: 使用 longjmp 函数跳转到 ptMyErr->setjmp_buffer 所标记的位置,同时传递参数 1。
总体而言,该函数的功能是在 libjpeg 库发生错误时,将错误消息格式化并输出到调试输出,然后通过 longjmp 函数跳转到错误处理的位置,以便进行进一步的处理或退出程序。
文件是否为JPG文件
/**********************************************************************
* 函数名称: isJPGFormat
* 功能描述: JPG模块是否支持该文件,即该文件是否为JPG文件
* 输入参数: ptFileMap - 内含文件信息
* 输出参数: 无
* 返 回 值: 0 - 不支持, 1 - 支持
***********************************************************************/
static int isJPGFormat(PT_FileMap ptFileMap)
{
struct jpeg_decompress_struct tDInfo;
/* 默认的错误处理函数是让程序退出
* 我们参考libjpeg里的bmp.c编写自己的错误处理函数
*/
//struct jpeg_error_mgr tJErr;
T_MyErrorMgr tJerr;
int iRet;
fseek(ptFileMap->tFp, 0, SEEK_SET);
// 分配和初始化一个decompression结构体
// tDInfo.err = jpeg_std_error(&tJErr);
tDInfo.err = jpeg_std_error(&tJerr.pub);
tJerr.pub.error_exit = MyErrorExit;
if(setjmp(tJerr.setjmp_buffer))
{
/* 如果程序能运行到这里, 表示JPEG解码出错 */
jpeg_destroy_decompress(&tDInfo);
return 0;;
}
jpeg_create_decompress(&tDInfo);
// 用jpeg_read_header获得jpg信息
jpeg_stdio_src(&tDInfo, ptFileMap->tFp);
iRet = jpeg_read_header(&tDInfo, TRUE);
jpeg_abort_decompress(&tDInfo);
return (iRet == JPEG_HEADER_OK);
}
这段代码实现了一个函数 isJPGFormat,用于检查给定文件是否为 JPEG 格式。以下是对该函数的逐行解析:
static int isJPGFormat(PT_FileMap ptFileMap): 函数声明,接受一个名为 ptFileMap 的 PT_FileMap 类型参数,该参数是文件映射结构体指针。
struct jpeg_decompress_struct tDInfo;: 声明一个 jpeg_decompress_struct 结构体变量 tDInfo,用于存储 JPEG 解压缩相关的信息。
T_MyErrorMgr tJerr;: 声明一个 T_MyErrorMgr 结构体变量 tJerr,用于自定义的错误管理器。
int iRet;: 声明一个 int 类型变量 iRet,用于存储函数执行结果。
fseek(ptFileMap->tFp, 0, SEEK_SET);: 将文件指针移动到文件开头位置,以便进行后续的读取操作。
tDInfo.err = jpeg_std_error(&tJerr.pub);: 将 tJerr.pub 的错误管理器结构体赋值给 tDInfo.err,用于处理 JPEG 解压缩过程中的错误。
tJerr.pub.error_exit = MyErrorExit;: 将自定义的错误处理函数 MyErrorExit 赋值给 tJerr.pub.error_exit,以便在发生错误时执行相应的错误处理。
if (setjmp(tJerr.setjmp_buffer)): 使用 setjmp 函数设置一个跳转点,并检查跳转标记是否被设置。
jpeg_destroy_decompress(&tDInfo);: 在发生错误时,释放 JPEG 解压缩结构体 tDInfo 的资源。
return 0;: 返回 0,表示给定文件不是 JPEG 格式。
jpeg_create_decompress(&tDInfo);: 创建 JPEG 解压缩对象 tDInfo。
jpeg_stdio_src(&tDInfo, ptFileMap->tFp);: 将文件指针 ptFileMap->tFp 与 JPEG 解压缩对象 tDInfo 关联,以便从文件中读取 JPEG 数据。
iRet = jpeg_read_header(&tDInfo, TRUE);: 使用 jpeg_read_header 函数读取 JPEG 数据的头信息,并将结果存储在 iRet 变量中。
jpeg_abort_decompress(&tDInfo);: 中止 JPEG 解压缩过程,释放相关资源。
return (iRet == JPEG_HEADER_OK);: 返回比较结果 (iRet == JPEG_HEADER_OK),表示给定文件是否为有效的 JPEG 格式。
总体而言,该函数通过使用 libjpeg 库的函数来判断给定文件是否为 JPEG 格式。它首先尝试解析文件头信息,如果成功解析并返回 JPEG_HEADER_OK,则表示给定文件是有效的 JPEG 格式;否则,表示给定文件不是 JPEG 格式或解析过程中发生了错误。
取出的一行象素数据,转换为能在显示设备上使用的格式
/**********************************************************************
* 函数名称: CovertOneLine
* 功能描述: 把已经从JPG文件取出的一行象素数据,转换为能在显示设备上使用的格式
* 输入参数: iWidth - 宽度,即多少个象素
* iSrcBpp - 已经从JPG文件取出的一行象素数据里面,一个象素用多少位来表示
* iDstBpp - 显示设备上一个象素用多少位来表示
* pudSrcDatas - 已经从JPG文件取出的一行象素数所存储的位置
* pudDstDatas - 转换所得数据存储的位置
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
***********************************************************************/
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
unsigned int dwRed;
unsigned int dwGreen;
unsigned int dwBlue;
unsigned int dwColor;
unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
unsigned int *pwDstDatas32bpp = (unsigned int *)pudDstDatas;
int i;
int pos = 0;
if (iSrcBpp != 24)
{
return -1;
}
if (iDstBpp == 24)
{
memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
}
else
{
for (i = 0; i < iWidth; i++)
{
dwRed = pudSrcDatas[pos++];
dwGreen = pudSrcDatas[pos++];
dwBlue = pudSrcDatas[pos++];
if (iDstBpp == 32)
{
dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
*pwDstDatas32bpp = dwColor;
pwDstDatas32bpp++;
}
else if (iDstBpp == 16)
{
/* 565 */
dwRed = dwRed >> 3;
dwGreen = dwGreen >> 2;
dwBlue = dwBlue >> 3;
dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
*pwDstDatas16bpp = dwColor;
pwDstDatas16bpp++;
}
}
}
return 0;
}