主题:[原创]做了一个动态连接库(DLL),读取JPEG图像文件(附件已上传)
上次在网上看到IJG,是一个用C语言写的、跨平台的、操作JPEG的开源函数库。但是这个库比较庞大,编译后有数百k。对于普通的应用来说,通常只希望读取JPEG图象,而不会保存JPEG图象,因此很多功能也用不上。
最近我把IJG封装了一下,做成了自己的DLL,现在发出来给大家分享。提供了两种风格的接口,C语言可以直接调用函数接口,C++则推荐使用封装后的类。大家看看这个封装是否合理?希望各位能提出好的建议[em2]。
头文件、编译好的DLL和LIB文件在附件里,另外还附带了测试图片和测试用的源代码(利用OpenGL的glDrawPixels把像素绘制到屏幕上)。
单独头文件贴出,其中有大量注释,就是对各函数、类的说明了。(因字数限制,分为两部分)
[code=c]#ifndef _jpeg_H_
#define _jpeg_H_
#ifdef __cplusplus
extern "C" {
#endif
//+===========================================================================+
//| |
//| C风格的函数接口 |
//| |
//+===========================================================================+
// enum tagErrorCode
//
// 错误代码
typedef enum tagErrorCode{
EC_NO_ERROR = 0, // 正常
EC_UNKNOWN_ERROR, // 未知错误
EC_OUT_OF_MEMORY, // 内存不足
EC_BAD_ALIGN, // 错误的字节对齐数
EC_BAD_FILE, // 文件打开失败
EC_BAD_FORCE_X, // 强制设定宽度引起的失败
EC_BAD_FORCE_Y // 强制设定高度引起的失败
} ErrorCode;
// enum tagJpegImageStatusName
//
// 状态名称
typedef enum tagJpegImageStatusName {
JISN_RESERVED = 0, // 零是保留的名字
JISN_LAST_ERROR, // 错误代码,为零表示没有错误
JISN_ALIGN_BYTES, // 按字节对齐(1表示不对齐)
JISN_IS_BUTTON_TO_TOP, // 像素垂直保存方向(非零表示从上到下)
JISN_FORCE_X, // 强制指定的宽度(零表示不强制指定)
JISN_FORCE_Y // 强制指定的高度(零表示不强制指定)
} JpegImageStatusName;
// struct JpegImage
//
// 保存JPEG数据
typedef struct tagJpegImage {
int sizeX; // 图象宽度(水平方向像素数量)
int sizeY; // 图象高度(垂直方向像素数量)
int components; // 图象的颜色分量数,例如:
// RGB有红、绿、蓝三个分量
// RGBA有红、绿、蓝、alpha四个分量
int bytesInLine; // 每行像素数据所占的字节数
// 这个值至少是sizeX * components,但是可能更多
// 参见JpegImage_SetAlign函数
int isButtonToTop; // 像素的垂直保存方式
// 参见JpegImage_SetButtonToTop函数
const void* bytes; // 指向像素数据的指针
} JpegImage;
// function JpegImage_GetLastError
//
// 获得最后一次的出错信息
// 如果JpegImage_LoadXXX系列函数没有成功的读取到JPEG图象,则会设置一个错误信息
// 通过本函数可以获得该错误信息的描述文本
//
// 参数:没有
// 返回:一个错误信息文本
//
// 说明:文本数据放在静态存储区,不要调用free或delete来释放
//
const char* JpegImage_GetLastError();
// function JpegImage_SetAlignBytes
//
// 设置字节对齐
// 比如某图象宽度为30,使用RGB格式,因此一行像素总共需要30*3=90字节,
// 但是如果设置为四字节对齐,则一行像素使用92字节(92是4的倍数),
// 最后两字节闲置不使用
// 例如将JPEG转化为BMP,BMP要求四字节对齐,这里设置字节对齐后不必另行编写代码
// 注意本函数只能设置为单字节、双字节、四字节、八字节对齐
// 若设置为单字节对齐,实际上与不使用字节对齐是等效的
//
// 参数:int alignBytes -- 对齐的字节数,必须是1, 2, 4, 8这四者之一
// 返回:若成功返回非零值,若失败返回零
// 如果返回零,可以使用JpegImage_GetLastError取得错误信息
//
// 说明:如果没有使用本函数设置字节对齐,则默认为四字节对齐
//
int JpegImage_SetAlignBytes(int alignBytes);
// function JpegImage_SetButtonToTop
//
// 设置像素的垂直保存方式
// 有两种保存方式可供选择
// 从上到下的保存,
// 首先保存最上一行像素,然后依次往下,直到最下一行
// 从下到上的保存,
// 首先保存最下一行像素,然后依次往上,直到最上一行
//
// 参数:int isButtonToTop -- 如果为非零值,表示从下到上的保存
// 否则表示从上到下的保存
// 返回:没有
//
// 说明:如果没有使用本函数设置垂直保存方式,则默认为从上到下的保存
// 无论哪种方式,每一行像素都是从左到右保存的
//
void JpegImage_SetButtonToTop(int isButtonToTop);
// function JpegImage_SetForceSize
//
// 强制性的设定JPEG图象的大小
// 如果JPEG文件头中没有包含正确的高度、宽度信息,则可以使用本函数强制设定
//
// 参数:int forceX -- 强制性的设定图象宽度
// 如果这个值为零或者负数,则表示不强制性的设定
// int forceY -- 强制性的设定图象高度
// 如果这个值为零或者负数,则表示不强制性的设定
//
// 说明:某些情况下,多个JPEG图象共用一个文件头,只是文件体不同
// (参见暴雪公司游戏《魔兽争霸3》中的BLP文件格式)
// 如果这些JPEG图象本身的大小是各不相同的,文件头无法一一指定各自的大小
// 此时可以通过本函数强制设定
//
// 注意:为了确保不出现运行时错误(Runtime Error),规定
// 当强制性设定的大小大于图象本身的大小时,读取直接失败,
// 而不是妄图读取大量的数据,导致下标越界
//
void JpegImage_SetForceSize(int forceX, int forceY);
// function JpegImage_LoadFromFile
//
// 从文件读取一幅JPEG图象
//
// 参数:const char* filename -- 文件的名字
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
JpegImage* JpegImage_LoadFromFile(const char* filename);
// function JpegImage_LoadFromMemory
//
// 从内存中读取一幅JPEG图象
//
// 参数:const void* data -- 指向JPEG数据的指针
// size_t size -- JPEG数据的长度(按字节计算)
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
// 说明:如果是从网络或其它位置获得JPEG数据,而不是从文件获得,则可以使用本函数
//
// 本函数相当于
// JpegImage_LoadFromMemorySegment(1, &data, &size);
// 参见JpegImage_LoadFromMemorySegment
//
JpegImage* JpegImage_LoadFromMemory(const void* data, size_t size);
// function JpegImage_LoadFromMemorySegment
//
// 从内存中读取一幅JPEG图象
// 其中JPEG图象的数据并不是连续存放,而是被分为多段
//
// 参数:size_t iSegments -- 数据的段数
// const void* segmentData -- 一个数组
// 数组的第i个元素是指向第i段数据的指针
// size_t segmentSize -- 一个数组
// 数组的第i个元素是第i段数据的长度
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
// 说明:某些情况下,多个JPEG图象共用一个文件头,只是文件体不同
// (参见暴雪公司游戏《魔兽争霸3》中的BLP文件格式)
// 这时一个JPEG图象被分为文件头和文件体两段,可以使用本函数来读取
// 例如:pHeader, iHeaderSize, pBody, iBodySize分别表示了
// 指向文件头数据的指针、文件头数据长度、
// 指向文件体数据的指针、文件体数据长度
// 则以下代码可以读取这个JPEG图象
// const void* segmentData[] = {pHeader, pBody};
// const size_t segmentSize[] = {iHeaderSize, iBodySize};
// JpegImage* pJpegImage = JpegImage_LoadFromMemorySegment(
// 2, segmentData, segmentSize);
//
JpegImage* JpegImage_LoadFromMemorySegment(
size_t iSegments,
const void* segmentData[],
const size_t size[]);
// function JpegImage_Unload
//
// 销毁JPEG图象数据
//
// 参数:JpegImage* pJpegImage -- 指向JPEG图象数据的指针
// 返回:没有
//
// 说明:仅当JPEG图象数据不再使用时,才应该进行销毁
// 销毁后的图象数据不再能使用
void JpegImage_Unload(JpegImage* pJpegImage);
// function JpegImage_GetStatusInteger
//
// 查询当前的状态
//
// 参数:JpegImageStatusName statusName -- 要取得的状态的名字
// 返回:指定的状态的值
// 如果指定的不是一个状态,则默认返回0
//
int JpegImage_GetStatusInteger(JpegImageStatusName statusName);[/code]
最近我把IJG封装了一下,做成了自己的DLL,现在发出来给大家分享。提供了两种风格的接口,C语言可以直接调用函数接口,C++则推荐使用封装后的类。大家看看这个封装是否合理?希望各位能提出好的建议[em2]。
头文件、编译好的DLL和LIB文件在附件里,另外还附带了测试图片和测试用的源代码(利用OpenGL的glDrawPixels把像素绘制到屏幕上)。
单独头文件贴出,其中有大量注释,就是对各函数、类的说明了。(因字数限制,分为两部分)
[code=c]#ifndef _jpeg_H_
#define _jpeg_H_
#ifdef __cplusplus
extern "C" {
#endif
//+===========================================================================+
//| |
//| C风格的函数接口 |
//| |
//+===========================================================================+
// enum tagErrorCode
//
// 错误代码
typedef enum tagErrorCode{
EC_NO_ERROR = 0, // 正常
EC_UNKNOWN_ERROR, // 未知错误
EC_OUT_OF_MEMORY, // 内存不足
EC_BAD_ALIGN, // 错误的字节对齐数
EC_BAD_FILE, // 文件打开失败
EC_BAD_FORCE_X, // 强制设定宽度引起的失败
EC_BAD_FORCE_Y // 强制设定高度引起的失败
} ErrorCode;
// enum tagJpegImageStatusName
//
// 状态名称
typedef enum tagJpegImageStatusName {
JISN_RESERVED = 0, // 零是保留的名字
JISN_LAST_ERROR, // 错误代码,为零表示没有错误
JISN_ALIGN_BYTES, // 按字节对齐(1表示不对齐)
JISN_IS_BUTTON_TO_TOP, // 像素垂直保存方向(非零表示从上到下)
JISN_FORCE_X, // 强制指定的宽度(零表示不强制指定)
JISN_FORCE_Y // 强制指定的高度(零表示不强制指定)
} JpegImageStatusName;
// struct JpegImage
//
// 保存JPEG数据
typedef struct tagJpegImage {
int sizeX; // 图象宽度(水平方向像素数量)
int sizeY; // 图象高度(垂直方向像素数量)
int components; // 图象的颜色分量数,例如:
// RGB有红、绿、蓝三个分量
// RGBA有红、绿、蓝、alpha四个分量
int bytesInLine; // 每行像素数据所占的字节数
// 这个值至少是sizeX * components,但是可能更多
// 参见JpegImage_SetAlign函数
int isButtonToTop; // 像素的垂直保存方式
// 参见JpegImage_SetButtonToTop函数
const void* bytes; // 指向像素数据的指针
} JpegImage;
// function JpegImage_GetLastError
//
// 获得最后一次的出错信息
// 如果JpegImage_LoadXXX系列函数没有成功的读取到JPEG图象,则会设置一个错误信息
// 通过本函数可以获得该错误信息的描述文本
//
// 参数:没有
// 返回:一个错误信息文本
//
// 说明:文本数据放在静态存储区,不要调用free或delete来释放
//
const char* JpegImage_GetLastError();
// function JpegImage_SetAlignBytes
//
// 设置字节对齐
// 比如某图象宽度为30,使用RGB格式,因此一行像素总共需要30*3=90字节,
// 但是如果设置为四字节对齐,则一行像素使用92字节(92是4的倍数),
// 最后两字节闲置不使用
// 例如将JPEG转化为BMP,BMP要求四字节对齐,这里设置字节对齐后不必另行编写代码
// 注意本函数只能设置为单字节、双字节、四字节、八字节对齐
// 若设置为单字节对齐,实际上与不使用字节对齐是等效的
//
// 参数:int alignBytes -- 对齐的字节数,必须是1, 2, 4, 8这四者之一
// 返回:若成功返回非零值,若失败返回零
// 如果返回零,可以使用JpegImage_GetLastError取得错误信息
//
// 说明:如果没有使用本函数设置字节对齐,则默认为四字节对齐
//
int JpegImage_SetAlignBytes(int alignBytes);
// function JpegImage_SetButtonToTop
//
// 设置像素的垂直保存方式
// 有两种保存方式可供选择
// 从上到下的保存,
// 首先保存最上一行像素,然后依次往下,直到最下一行
// 从下到上的保存,
// 首先保存最下一行像素,然后依次往上,直到最上一行
//
// 参数:int isButtonToTop -- 如果为非零值,表示从下到上的保存
// 否则表示从上到下的保存
// 返回:没有
//
// 说明:如果没有使用本函数设置垂直保存方式,则默认为从上到下的保存
// 无论哪种方式,每一行像素都是从左到右保存的
//
void JpegImage_SetButtonToTop(int isButtonToTop);
// function JpegImage_SetForceSize
//
// 强制性的设定JPEG图象的大小
// 如果JPEG文件头中没有包含正确的高度、宽度信息,则可以使用本函数强制设定
//
// 参数:int forceX -- 强制性的设定图象宽度
// 如果这个值为零或者负数,则表示不强制性的设定
// int forceY -- 强制性的设定图象高度
// 如果这个值为零或者负数,则表示不强制性的设定
//
// 说明:某些情况下,多个JPEG图象共用一个文件头,只是文件体不同
// (参见暴雪公司游戏《魔兽争霸3》中的BLP文件格式)
// 如果这些JPEG图象本身的大小是各不相同的,文件头无法一一指定各自的大小
// 此时可以通过本函数强制设定
//
// 注意:为了确保不出现运行时错误(Runtime Error),规定
// 当强制性设定的大小大于图象本身的大小时,读取直接失败,
// 而不是妄图读取大量的数据,导致下标越界
//
void JpegImage_SetForceSize(int forceX, int forceY);
// function JpegImage_LoadFromFile
//
// 从文件读取一幅JPEG图象
//
// 参数:const char* filename -- 文件的名字
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
JpegImage* JpegImage_LoadFromFile(const char* filename);
// function JpegImage_LoadFromMemory
//
// 从内存中读取一幅JPEG图象
//
// 参数:const void* data -- 指向JPEG数据的指针
// size_t size -- JPEG数据的长度(按字节计算)
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
// 说明:如果是从网络或其它位置获得JPEG数据,而不是从文件获得,则可以使用本函数
//
// 本函数相当于
// JpegImage_LoadFromMemorySegment(1, &data, &size);
// 参见JpegImage_LoadFromMemorySegment
//
JpegImage* JpegImage_LoadFromMemory(const void* data, size_t size);
// function JpegImage_LoadFromMemorySegment
//
// 从内存中读取一幅JPEG图象
// 其中JPEG图象的数据并不是连续存放,而是被分为多段
//
// 参数:size_t iSegments -- 数据的段数
// const void* segmentData -- 一个数组
// 数组的第i个元素是指向第i段数据的指针
// size_t segmentSize -- 一个数组
// 数组的第i个元素是第i段数据的长度
// 返回:若读取成功,返回图象数据的指针
// 当图象数据不再需要时,可以通过JpegImage_Unload函数销毁图象数据
// 若读取失败,返回NULL指针
// 此时可以使用JpegImage_GetLastError取得错误信息
//
// 说明:某些情况下,多个JPEG图象共用一个文件头,只是文件体不同
// (参见暴雪公司游戏《魔兽争霸3》中的BLP文件格式)
// 这时一个JPEG图象被分为文件头和文件体两段,可以使用本函数来读取
// 例如:pHeader, iHeaderSize, pBody, iBodySize分别表示了
// 指向文件头数据的指针、文件头数据长度、
// 指向文件体数据的指针、文件体数据长度
// 则以下代码可以读取这个JPEG图象
// const void* segmentData[] = {pHeader, pBody};
// const size_t segmentSize[] = {iHeaderSize, iBodySize};
// JpegImage* pJpegImage = JpegImage_LoadFromMemorySegment(
// 2, segmentData, segmentSize);
//
JpegImage* JpegImage_LoadFromMemorySegment(
size_t iSegments,
const void* segmentData[],
const size_t size[]);
// function JpegImage_Unload
//
// 销毁JPEG图象数据
//
// 参数:JpegImage* pJpegImage -- 指向JPEG图象数据的指针
// 返回:没有
//
// 说明:仅当JPEG图象数据不再使用时,才应该进行销毁
// 销毁后的图象数据不再能使用
void JpegImage_Unload(JpegImage* pJpegImage);
// function JpegImage_GetStatusInteger
//
// 查询当前的状态
//
// 参数:JpegImageStatusName statusName -- 要取得的状态的名字
// 返回:指定的状态的值
// 如果指定的不是一个状态,则默认返回0
//
int JpegImage_GetStatusInteger(JpegImageStatusName statusName);[/code]