PngModule.cpp
上传用户:yatsl7111
上传日期:2007-01-08
资源大小:1433k
文件大小:33k
- // PngModule.cpp : Defines the initialization routines for the DLL.
- //
- #include "stdafx.h"
- #include "PngModule.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- static char ModuleProcessImgType[]="PNG"; // 本模块能处理的图像类型
- static char WriterList[]="Aurora"; // 本模块的作者列表
- static char WriterMess[]="第一版"; // 作者留言
- //
- // Note!
- //
- // If this DLL is dynamically linked against the MFC
- // DLLs, any functions exported from this DLL which
- // call into MFC must have the AFX_MANAGE_STATE macro
- // added at the very beginning of the function.
- //
- // For example:
- //
- // extern "C" BOOL PASCAL EXPORT ExportedFunction()
- // {
- // AFX_MANAGE_STATE(AfxGetStaticModuleState());
- // // normal function body here
- // }
- //
- // It is very important that this macro appear in each
- // function, prior to any calls into MFC. This means that
- // it must appear as the first statement within the
- // function, even before any object variable declarations
- // as their constructors may generate calls into the MFC
- // DLL.
- //
- // Please see MFC Technical Notes 33 and 58 for additional
- // details.
- //
- // 在图像读写模块中,如果想分配内存,请使用API函数GlobalAlloc()
- // ,如果想释放内存请使用GlobalFree()函数。不要使用诸如:new
- // 、malloc()等函数。这是为了使各模块之间可以异地释放内存。
- //
- //
- /////////////////////////////////////////////////////////////////////////////
- // CPngModuleApp
- BEGIN_MESSAGE_MAP(CPngModuleApp, CWinApp)
- //{{AFX_MSG_MAP(CPngModuleApp)
- // NOTE - the ClassWizard will add and remove mapping macros here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CPngModuleApp construction
- CPngModuleApp::CPngModuleApp()
- {
- // TODO: add construction code here,
- // Place all significant initialization in InitInstance
- }
- /////////////////////////////////////////////////////////////////////////////
- // The one and only CPngModuleApp object
- CPngModuleApp theApp;
- long WINAPI GetLong(void)
- {
- return 2L;
- }
- // 接口函数声明 — 第一层,唯一与外界联系的接口
- int WINAPI AccessPNGModule(INFOSTR *pInfo)
- {
- // 这个函数可以不作修改的使用,除非你的返回值多于两种。
- switch(pInfo->comm)
- {
- case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
- _fnCMD_GETPROCTYPE(pInfo);
- break;
- case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
- _fnCMD_GETWRITERS(pInfo);
- break;
- case CMD_GETWRITERMESS: // 获取作者们的留言
- _fnCMD_GETWRITERMESS(pInfo);
- break;
- case CMD_GETBUILDID: // 获取图像模块内部版本号
- _fnCMD_GETBUILDID(pInfo);
- break;
- case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
- _fnCMD_IS_VALID_FILE(pInfo);
- break;
- case CMD_GET_FILE_INFO: // 获取指定文件的信息
- _fnCMD_GET_FILE_INFO(pInfo);
- break;
- case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
- _fnCMD_LOAD_FROM_FILE(pInfo);
- break;
- case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
- _fnCMD_SAVE_TO_FILE(pInfo);
- break;
- case CMD_IS_SUPPORT: // 查询某个命令是否被支持
- _fnCMD_IS_SUPPORT(pInfo);
- break;
- case CMD_RESIZE: // 从新获取指定尺寸的图像位数据(只适用于矢量图像)
- _fnCMD_RESIZE(pInfo);
- break;
- default:
- pInfo->result = ER_ILLCOMM; // 非法命令
- ASSERT(FALSE); // 调用者的程序设计有问题 :-)
- break;
- }
- // 执行命令成功返回1, 失败返回0
- return (pInfo->result==ER_SUCCESS)? 1:0;
- }
- // 命令解释函数 — 第二层解释函数
- //********************************************************************//
- // 操作命令解释函数---解释:CMD_IS_SUPPORT命令
- // 查询某个命令是否被支持
- void _fnCMD_IS_SUPPORT(INFOSTR *pInfo)
- {
- // 这个函数是为客户程序查询时使用,如果你实现了对某个命令的
- // 解释,可修改相应的case中的设置,使其返回ER_SUCCESS,这就
- // 表示你的模块已经支持该命令了。同时,现在的这个文件中已包
- // 含了对前四个命令的解释,你只需向还未支持的命令函数中添加
- // 代码即可。
- ASSERT(pInfo->result == ER_EMPTY);
- switch(pInfo->annexdata.cmAnnData)
- {
- case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_GETWRITERMESS: // 获取作者们的留言
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_GETBUILDID: // 获取图像模块内部版本号
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_GET_FILE_INFO: // 获取指定文件的信息
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_IS_SUPPORT: // 查询某个命令是否被支持
- pInfo->result = ER_SUCCESS;
- break;
- case CMD_RESIZE: // 获取指定尺寸的图像(只适用于矢量图像)
- pInfo->result = ER_NOTSUPPORT;
- break;
- default:
- pInfo->result = ER_NOTSUPPORT;
- break;
- }
- }
- // 操作命令解释函数---解释:CMD_GETPROCTYPE命令
- // 获取本模块能处理的图像类型,如:BMP,PCX等等
- void _fnCMD_GETPROCTYPE(INFOSTR *pInfo)
- {
- // 这是预定义的函数代码,你可以不必修改的使用。
- // 根据接口定义,此时附加数据应被清空为0,所以下此断言
- ASSERT(pInfo->annexdata.scAnnData[0] == 0);
- ASSERT(pInfo->result == ER_EMPTY);
- // 复制能处理的类型字符串
- ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)ModuleProcessImgType,
- sizeof(ModuleProcessImgType));
- pInfo->result = ER_SUCCESS;
- }
- // 操作命令解释函数---解释:CMD_GETWRITER命令
- // 获取本模块的作者列表,多人时用逗号分隔
- void _fnCMD_GETWRITERS(INFOSTR *pInfo)
- {
- // 这是预定义的函数代码,你可以不必修改的使用。
- // 根据接口定义,此时附加数据应被清空为0,所以下此断言
- ASSERT(pInfo->annexdata.scAnnData[0] == 0);
- ASSERT(pInfo->result == ER_EMPTY);
- // 复制开发者名单串
- ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterList,
- sizeof(WriterList));
- pInfo->result = ER_SUCCESS;
- }
- // 操作命令解释函数---解释:CMD_GETWRITERMESS命令
- // 获取作者们的留言
- void _fnCMD_GETWRITERMESS(INFOSTR *pInfo)
- {
- // 这是预定义的函数代码,你可以不必修改的使用。
- // 根据接口定义,此时附加数据应被清空为0,所以下此断言
- ASSERT(pInfo->annexdata.scAnnData[0] == 0);
- ASSERT(pInfo->result == ER_EMPTY);
- // 复制开发者们的留言字符串
- ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterMess,
- sizeof(WriterMess));
- pInfo->result = ER_SUCCESS;
- }
- // 操作命令解释函数---解释:CMD_GETBUILDID命令
- // 获取图像模块内部版本号
- void _fnCMD_GETBUILDID(INFOSTR *pInfo)
- {
- // 这是预定义的函数代码,你可以不必修改的使用。
- // 根据接口定义,此时annexdata.dwAnnData应被设为0,所以下此断言
- ASSERT(pInfo->annexdata.dwAnnData == 0);
- ASSERT(pInfo->result == ER_EMPTY);
- // 填写内部版本号码
- pInfo->annexdata.dwAnnData = MODULE_BUILDID;
- pInfo->result = ER_SUCCESS;
- }
- // 操作命令解释函数---解释:CMD_IS_VALID_FILE命令
- // 判断指定文件是否是有效的WMF文件
- void _fnCMD_IS_VALID_FILE(INFOSTR *pInfo)
- {
- ASSERT(pInfo->result == ER_EMPTY);
- ASSERT(pInfo->annexdata.iAnnData == 0);
- ASSERT(::strlen(pInfo->filename));
- ASSERT(pInfo->state == PKST_NOTVER);
-
- BYTE Signature[8];
- HANDLE m_hPng;
- m_hPng = CreateFile(pInfo->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if(m_hPng == INVALID_HANDLE_VALUE)
- pInfo->result = ER_COMMINFOERR; //文件打开错
- else
- {
- DWORD dwBytes;
-
- //读出PNG文件头上的8个标志字节
- BOOL Correct = ReadFile(m_hPng, Signature, 8, &dwBytes, NULL);
- if(!Correct)
- {
- pInfo->result = ER_FILERWERR;
- TRACE("读文件错误!");
- CloseHandle(m_hPng);
- return;
- }
- pInfo->result = ER_SUCCESS;
- //判断是否PNG
- if(png_sig_cmp(Signature, 0, 8))
- pInfo->annexdata.iAnnData = 0;
- else
- {
- //合法PNG文件
- pInfo->annexdata.iAnnData = 1;
- pInfo->state = PKST_PASSVER;
- }
- CloseHandle(m_hPng);
- }
- return;
- }
- // 操作命令解释函数---解释:CMD_GET_FILE_INFO命令
- // 获取指定文件的信息
- void _fnCMD_GET_FILE_INFO(INFOSTR *pInfo)
- {
- // 检验入口参数是否符合接口定义
- ASSERT(pInfo->result == ER_EMPTY);
- ASSERT(::strlen(pInfo->filename));
- // 确认PNG文件有效且客户模块将imginfo晴空
- ASSERT(pInfo->state == PKST_PASSVER);
- ASSERT(pInfo->imginfo.imgtype == IMT_NULL);
- HANDLE m_hPng;
- png_structp pPng;
- png_infop pPngInfo;
- __try
- {
- m_hPng = ::CreateFile(pInfo->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if(m_hPng == INVALID_HANDLE_VALUE) //打开文件错误
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- LPIMAGEINFOSTR lpImgInfoStr = &pInfo->imginfo;
- // 获取文件的长度、图像的宽度、高度等信息
- lpImgInfoStr->imgtype = IMT_RESSTATIC;
- lpImgInfoStr->imgformat = IMF_PNG;
- lpImgInfoStr->filesize = ::GetFileSize(m_hPng, NULL);
- /* 读文件信息头 */
- //分配PNG结构,并初始化
- pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING,
- (png_voidp)::GetForegroundWindow(), PngErrorHandler, NULL);
- if(pPng == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
-
- //建立PNG信息头结构
- pPngInfo = png_create_info_struct(pPng);
- if(pPngInfo == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- //设置自定义读函数
- png_set_read_fn(pPng, (PVOID)m_hPng, PngRead4Win32);
- //读文件信息头(直到IDAT)
- png_read_info(pPng, pPngInfo);
- //获取图象信息
- PNGINFOHEADER pngInfoHeader;
-
- png_get_IHDR(pPng, pPngInfo, &pngInfoHeader.Width,
- &pngInfoHeader.Height, &pngInfoHeader.bit_depth,
- &pngInfoHeader.color_type, &pngInfoHeader.interlace_type,
- &pngInfoHeader.compression_type, &pngInfoHeader.filter_type);
- lpImgInfoStr->width = pngInfoHeader.Width;
- lpImgInfoStr->height = pngInfoHeader.Height;
- lpImgInfoStr->bitcount = 24; //所有格式的图形均转换为24位RGB
- lpImgInfoStr->compression = ICS_RGB;
- /** 获取图象每扫描行的字节数 **/
- /** 因为本模块准备将图形都转换为24位RGB图,所以linesize可以通过更简单的方法获得 */
- lpImgInfoStr->linesize = lpImgInfoStr->bitcount * lpImgInfoStr->width / 8;//png_get_rowbytes(pPng, pPngInfo);
- lpImgInfoStr->imgnumbers = 1; //PNG支持多幅图象,但此处暂定为1
- lpImgInfoStr->imgchang = 1; //图象显示器不允许修改图象
- //获取文件最后一次修改的时间
- FILETIME fLastWriteTime;
- SYSTEMTIME sLastWriteTime;
- if(::GetFileTime(m_hPng, NULL, NULL, &fLastWriteTime))
- {
- FileTimeToSystemTime(&fLastWriteTime, &sLastWriteTime);
- lpImgInfoStr->year = sLastWriteTime.wYear;
- lpImgInfoStr->monday = sLastWriteTime.wMonth;
- lpImgInfoStr->monday <<= 8;
- lpImgInfoStr->monday |= sLastWriteTime.wDay;
-
- // 获取文件最后的修改时间(字序:最高—0, 2—时,1—分,0—秒)
- lpImgInfoStr->time = sLastWriteTime.wHour;
- lpImgInfoStr->time <<= 8;
- lpImgInfoStr->time |= sLastWriteTime.wMinute;
- lpImgInfoStr->time <<= 8;
- lpImgInfoStr->time |= sLastWriteTime.wSecond;
- lpImgInfoStr->time &= 0xffffff;
- //读参数成功,设置state,将执行结果置为成功
- pInfo->state = PKST_PASSINFO;
- pInfo->result = ER_SUCCESS;
- }
- else
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- __finally
- {
- //清除分配单元,并且关闭文件
- if(pPng != NULL)
- png_destroy_read_struct(&pPng, &pPngInfo, (png_infopp)NULL);
- if(m_hPng != INVALID_HANDLE_VALUE)
- CloseHandle(m_hPng);
- }
-
- return;
- }
- // 操作命令解释函数---解释:CMD_LOAD_FROM_FILE命令
- // 从指定图像文件中读取数据
- void _fnCMD_LOAD_FROM_FILE(INFOSTR *pInfo)
- {
- // 检验入口参数是否符合接口定义
- ASSERT(pInfo->result == ER_EMPTY);
- ASSERT(::strlen(pInfo->filename));
- // 此时,该文件必需是一个已存在的、有效的WMF文件,并且数据包中
- // 含有该文件的信息(imginfo结构中)
- ASSERT(pInfo->state == PKST_PASSINFO);
- ASSERT(pInfo->imginfo.imgformat == IMF_PNG);
- ASSERT(pInfo->pImgInfo == NULL);
- // 必需设置标准图像格式信息
- ASSERT(pInfo->sDIBInfo.bmi.biSize == sizeof(BITMAPINFOHEADER));
- ASSERT(pInfo->pLineAddr != NULL);
- ASSERT(pInfo->_pbdata != NULL);
- HANDLE hPng;
- png_structp pPng;
- png_infop pPngInfo;
- __try
- {
- //分配PNG结构,并初始化
- pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING,
- (png_voidp)::GetForegroundWindow(), PngErrorHandler, NULL);
- if(pPng == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
-
- //建立PNG信息头结构
- pPngInfo = png_create_info_struct(pPng);
- if(pPngInfo == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- hPng = ::CreateFile(pInfo->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if(hPng == INVALID_HANDLE_VALUE) //打开文件错误
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- //设置自定义读函数
- png_set_read_fn(pPng, (PVOID)hPng, PngRead4Win32);
- if (setjmp(png_jmpbuf(pPng)))
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- //读文件信息头(直到IDAT),在读取图象数据前必须
- png_read_info(pPng, pPngInfo);
- //获取PNG图象头,以备设置读取变换时引用
- PNGINFOHEADER pngInfoHeader;
- png_get_IHDR(pPng, pPngInfo, &pngInfoHeader.Width,
- &pngInfoHeader.Height, &pngInfoHeader.bit_depth,
- &pngInfoHeader.color_type, &pngInfoHeader.interlace_type,
- &pngInfoHeader.compression_type, &pngInfoHeader.filter_type);
- /* 通知PNGLIB将16位图形削减为8位 */
- png_set_strip_16(pPng);
- /* 将1、2、4位图形由压缩状态变为每位象素用1字节表示 */
- png_set_packing(pPng);
- /* 将索引图转换为RGB图 */
- if (pngInfoHeader.color_type == PNG_COLOR_TYPE_PALETTE &&
- pngInfoHeader.bit_depth <= 8)
- png_set_palette_to_rgb(pPng);
- /* 将小于8位的灰度图转换为8位灰度 */
- if (pngInfoHeader.color_type == PNG_COLOR_TYPE_GRAY &&
- pngInfoHeader.bit_depth < 8)
- png_set_gray_1_2_4_to_8(pPng);
-
- /* 将tRNS通道转换为alpha通道 */
- if (png_get_valid(pPng, pPngInfo,PNG_INFO_tRNS))
- png_set_tRNS_to_alpha(pPng);
- /* 若读图象时使用png_set_strip_alpha()去掉alpha通道,则可以不设置背景色
- * 若读图象时未去掉alpha通道,则必须设置背景色,否则不能正确显示
- */
- png_color_16 *image_background;
- png_color_16 user_background; //使用当前背景做图形背景
- COLORREF bkColor = ::GetBkColor(::GetDC(::GetForegroundWindow()));
- user_background.index = 0;
- user_background.red = GetRValue(bkColor);
- user_background.blue = GetBValue(bkColor);
- user_background.green = GetGValue(bkColor);
- user_background.gray = 255;
- if (png_get_bKGD(pPng, pPngInfo, &image_background)) //图象自带背景
- png_set_background(pPng, image_background,
- PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
- else
- png_set_background(pPng, &user_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
- /* 调整屏幕显示的GAMMA值 */
- /* screen gamma由CRT_gamma和环境矫正gamma组成 */
- /* 暂时不实现用户指定屏幕gamma */
- double screen_gamma;
- char *gamma_str;
- if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) //获取当前环境变量的值
- {
- screen_gamma = atof(gamma_str);
- }
- else
- {
- screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly
- lit room */
- }
- /* 让LIBPNG处理gamma矫正 */
- /* 此处应支持用户输入图象gamma值 */
- int intent;
- if (png_get_sRGB(pPng, pPngInfo, &intent))
- png_set_gamma(pPng, screen_gamma, 0.45455); /* 对图象gamma的猜测 */
- else
- {
- double image_gamma;
- if (png_get_gAMA(pPng, pPngInfo, &image_gamma))
- png_set_gamma(pPng, screen_gamma, image_gamma);
- else
- png_set_gamma(pPng, screen_gamma, 0.45455);
- }
- /* 将图象数据由RGB转换为BGR */
- png_set_bgr(pPng);
- /* 将灰度图转换为RGB图 */
- if (pngInfoHeader.color_type == PNG_COLOR_TYPE_GRAY ||
- pngInfoHeader.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(pPng);
- /* 打开INTERLACE处理器(使用png_read_row读图象时必须) */
- pngInfoHeader.number_passes = png_set_interlace_handling(pPng);
- /* 调用上述变换函数后必须,更新信息结构 */
- png_read_update_info(pPng, pPngInfo);
-
- // 下面开始读图象数据
- // 存储单元以在客户模块中分配
- DWORD Height = (pInfo->imginfo).height;
- DWORD dwBytes = (pInfo->imginfo).linesize;
- //分配读文件所需的数据缓冲区及行指针(必须)
- png_bytep* row_pointers = (png_bytep*)new PBYTE[Height];
- if(row_pointers == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- PBYTE pImage = new BYTE[Height * dwBytes];
- if(pImage == NULL)
- {
- delete []row_pointers;
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- //按24位位深度设置行指针,以正确读取图象数据
- for(DWORD row = 0; row < Height; row ++)
- row_pointers[row] = (png_bytep)(pImage + row * dwBytes);
- //设置JUMPBUFFER以便PNGLIB在遇到错误时能返回这里处理错误
- if (setjmp(png_jmpbuf(pPng)))
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- int pass;
- for(pass = 0; pass < pngInfoHeader.number_passes; pass++)
- {
- //每次读取一行图象
- for (row = 0L; row < Height; row++)
- {
- //调用回调函数,处理用户中断请求
- //这里的效果可能不太好,因为要在处理完一行数据之后才响应用户请求
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, (100 * row * (pass + 1))/
- (Height * pngInfoHeader.number_passes)))
- { // 如果进度函数返回1,则说明用户想中断操作,返回。
- pInfo->result = ER_USERBREAK;
- __leave;
- }
- }
- //从文件中读取一行数据
- png_read_rows(pPng, &row_pointers[row], NULL, 1);
- }
- }
- //读取图象附加信息,包括zTxt、sTxt、tIME通道的信息
- //对这些信息暂不处理,以后可以加到pImginfo中传递给客户模块
- png_read_end(pPng, pPngInfo);
- //根据pInfo->sDIBInfo.bmi中提供的标准图象信息转换图象格式
- ASSERT(pInfo->sDIBInfo.bmi.biPlanes == 1);
- // 可接收三中格式的图像位数据请求:16,24,32。并且要求数据包位
- ASSERT((pInfo->sDIBInfo.bmi.biBitCount==16)||(pInfo->sDIBInfo.bmi.biBitCount==24)||(pInfo->sDIBInfo.bmi.biBitCount==32));
- if(pInfo->sDIBInfo.bmi.biBitCount == 16)
- {
- if(!Image24to16(pInfo, pImage, row_pointers))
- {
- //操作失败,释放内存
- delete []pImage;
- delete []row_pointers;
- __leave;
- }
- }
- else if(pInfo->sDIBInfo.bmi.biBitCount == 32)
- {
- if(!Image24to32(pInfo, pImage, row_pointers))
- {
- delete []pImage;
- delete []row_pointers;
- __leave;
- }
- }
- else
- {
- //24位倒置、对齐并且拷贝到图象缓冲区中
- if(!Image24to24(pInfo, pImage, row_pointers))
- {
- delete []pImage;
- delete []row_pointers;
- __leave;
- }
- }
- //释放图象缓冲区
- delete []row_pointers;
- delete []pImage;
- //成功!
- pInfo->state = PKST_INFOANDBITS;
- pInfo->result = ER_SUCCESS;
-
- __leave;
- }
- __finally
- {
- //关闭PNG文件
- if(hPng != INVALID_HANDLE_VALUE)
- CloseHandle(hPng);
- //清除分配单元
- if(pPng != NULL)
- png_destroy_read_struct(&pPng, &pPngInfo, (png_infopp)NULL);
- }
- return;
- }
- // 操作命令解释函数---解释:CMD_SAVE_TO_FILE命令
- // 将数据保存到指定文件中
- void _fnCMD_SAVE_TO_FILE(INFOSTR *pInfo)
- {
- // 检验入口参数是否符合接口定义
- ASSERT(pInfo->result == ER_EMPTY);
- ASSERT(::strlen(pInfo->filename));
- // 此时,该文件必需是一个已存在的、有效的WMF文件,并且数据包中
- // 含有该文件的信息(imginfo结构中)
- ASSERT(pInfo->state == PKST_INFOANDBITS);
- // 必须存在有效的图象信息
- ASSERT(pInfo->sDIBInfo.bmi.biSize == sizeof(BITMAPINFOHEADER));
- ASSERT(pInfo->pLineAddr != NULL);
- ASSERT(pInfo->_pbdata != NULL);
- //仅支持16、24、32位位图
- if(pInfo->sDIBInfo.bmi.biBitCount == 1 || pInfo->sDIBInfo.bmi.biBitCount == 4 ||
- pInfo->sDIBInfo.bmi.biBitCount == 8)
- {
- pInfo->result = ER_NOTSUPPORT;
- return;
- }
- HANDLE hPng;
- png_structp pPng;
- png_infop pPngInfo;
- __try
- {
- //分配PNG结构,并初始化
- pPng = png_create_write_struct(PNG_LIBPNG_VER_STRING,
- (png_voidp)::GetForegroundWindow(), PngErrorHandler, NULL);
- if(pPng == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
-
- //建立PNG信息头结构
- pPngInfo = png_create_info_struct(pPng);
- if(pPngInfo == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- hPng = ::CreateFile(pInfo->filename, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if(hPng == INVALID_HANDLE_VALUE) //打开文件错误
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- //设置自定义写函数
- png_set_write_fn(pPng, (PVOID)hPng, PngWrite4Win32, (png_flush_ptr)PngFlush4Win32);
- if (setjmp(png_jmpbuf(pPng)))
- {
- pInfo->result = ER_FILERWERR;
- __leave;
- }
- //设置并写文件信息头
- pngSetIHDR(pPng, pPngInfo, pInfo);
- //图象变换
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- DWORD BitCount = bmpInfo.biBitCount;
- DWORD Height = bmpInfo.biHeight;
- DWORD Width = bmpInfo.biWidth;
- PBYTE pngImage;
- PBYTE* row_pointers;
-
- pngImage = new BYTE[Height * Width * 3];
- if(pngImage == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- row_pointers = new PBYTE[Height];
- if(row_pointers == NULL)
- {
- pInfo->result = ER_MEMORYERR;
- __leave;
- }
- if(BitCount == 16)
- {
- if(!TransformImage16(pInfo, pngImage))
- {
- delete []pngImage;
- delete []row_pointers;
- __leave;
- }
- //置行指针,行指针倒置,因为PNG图象是top-down排列的
- for(DWORD i = 0; i < Height; i++)
- row_pointers[i] = pngImage + Width * 3 * (Height - i - 1);
- }
- else if(BitCount == 24)
- {
- if(!TransformImage24(pInfo, pngImage))
- {
- delete []pngImage;
- delete []row_pointers;
- __leave;
- }
- for(DWORD i = 0; i < Height; i++)
- row_pointers[i] = pngImage + Width * 3 * (Height - i - 1);
- }
- else //if(BitCount == 32)
- {
- if(!TransformImage32(pInfo, pngImage))
- {
- delete []pngImage;
- delete []row_pointers;
- __leave;
- }
- for(DWORD i = 0; i < Height; i++)
- row_pointers[i] = pngImage + Width * 3 * (Height - i - 1);
- }
- //写图象
- /* 这里用交错格式(interlaced)存储 */
- DWORD number_passes = png_set_interlace_handling(pPng);
- for (DWORD pass = 0; pass < number_passes; pass++)
- {
- /* 一次只写入一行 */
- for (DWORD y = 0; y < Height; y++)
- {
- //进度函数调用
- if(pInfo->fpProgress)
- {
- if ((*(pInfo->fpProgress))(RWPROGRESSSIZE, pass * y * 100 / (pass * Height)))
- {
- pInfo->result = ER_USERBREAK;
- __leave;
- }
- }
- png_write_rows(pPng, &row_pointers[y], 1);
- }
- }
- /* 这里可以写入tEXt, zTXt, and tIME */
- /* 写入IEND通道,必须 */
- png_write_end(pPng, pPngInfo);
- delete []pngImage;
- delete []row_pointers;
-
- /* 使用png_free释放用png_malloced分配的调色板或其他单元 */
- //png_free(pPng, palette);
- pInfo->result = ER_SUCCESS;
- }
- __finally
- {
- //关闭PNG文件
- if(hPng != INVALID_HANDLE_VALUE)
- CloseHandle(hPng);
- //清除分配单元
- if(pPng != NULL)
- png_destroy_write_struct(&pPng, &pPngInfo);
- }
- return;
- }
- // 操作命令解释函数---解释:CMD_RESIZE命令
- // 重新获取指定尺寸的图像位数据(只适用于矢量图像)
- void _fnCMD_RESIZE(INFOSTR *pInfo)
- {
- pInfo->result = ER_NOTSUPPORT;
- return;
- }
- /* ====================================================================================== */
- /* 内部处理函数 */
- /* ====================================================================================== */
- /*
- * PNG库自定义错误处理函数
- *
- */
- static void
- PngErrorHandler(png_structp png_ptr, png_const_charp message)
- {
- TRACE("错误:%s", message);
- CString ErrMsg = "错误:";
- ErrMsg += message;
-
- ::MessageBox((HWND)png_ptr->error_ptr, ErrMsg, NULL, 0);
- #ifdef PNG_SETJMP_SUPPORTED
- # ifdef USE_FAR_KEYWORD
- {
- jmp_buf jmpbuf;
- png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf));
- longjmp(jmpbuf, 1);
- }
- # else
- longjmp(png_ptr->jmpbuf, 1);
- # endif
- #else
- if (png_ptr == NULL)
- /* make compiler happy */ ;
- PNG_ABORT();
- #endif
- }
- /* ==============================
- * PNG库自定义读函数
- * 参数:
- * data — 返回数据缓冲区
- * length — 读数据长度
- */
- static void
- PngRead4Win32(png_structp png_ptr, png_bytep data, png_size_t length)
- {
- HANDLE m_hPng;
- m_hPng = (HANDLE)CVT_PTR(png_ptr->io_ptr);
- if(m_hPng != NULL)
- {
- DWORD dwBytes;
- BOOL Correct = ReadFile(m_hPng, (PVOID)data, (DWORD)length, &dwBytes, NULL);
- if(!Correct || dwBytes != (DWORD)length)
- {
- png_error(png_ptr, "Read Error");
- }
- }
- }
- /* ==============================
- * PNG库自定义写函数
- * 参数:
- * data — 数据缓冲区
- * length — 数据长度
- */
- static void
- PngWrite4Win32(png_structp png_ptr, png_bytep data, png_size_t length)
- {
- HANDLE m_hPng;
- m_hPng = (HANDLE)CVT_PTR(png_ptr->io_ptr);
- if(m_hPng != NULL)
- {
- DWORD dwBytes;
- BOOL Correct = WriteFile(m_hPng, (PVOID)data, (DWORD)length, &dwBytes, NULL);
- if(!Correct || dwBytes != (DWORD)length)
- {
- png_error(png_ptr, "Write Error");
- }
- }
- }
- /* ==============================
- * PNG库自定义FLUSH函数
- * 参数:
- * data — 数据缓冲区
- * length — 数据长度
- */
- static void
- PngFlush4Win32(png_structp png_ptr)
- {
- HANDLE m_hPng;
- m_hPng = (HANDLE)CVT_PTR(png_ptr->io_ptr);
- if (m_hPng != NULL)
- {
- BOOL Correct = FlushFileBuffers(m_hPng);
- if(!Correct)
- png_error(png_ptr, "Flush Error");
- }
- }
- /* ==========================================================================*
- * 图象的输出格式将根据用户的需要进行适当的变换
- * 下面的一组函数用于将图象由从PNG读出时的24位变换为输出格式
- * ==========================================================================*/
- /*
- * 将图象由24位转换为32位
- */
- BOOL Image24to32(INFOSTR *pInfo, PBYTE pImage, PBYTE* pLineAddr)
- {
- DWORD Height = (pInfo->imginfo).height;
- DWORD Width = (pInfo->imginfo).width;
- PBYTE p2 = pInfo->_pbdata;
- PBYTE p1;// = pImage;
- PBYTE *pLine = pLineAddr + Height - 1;
- for(DWORD y = 0L; y < Height; y++)
- {
- if(pInfo->fpProgress)
- {
- if ((*(pInfo->fpProgress))(RWPROGRESSSIZE, y * 100 / Height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- p1 = *(pLine --);
- for(DWORD i = 0L; i < Width; i ++)
- {
- *p2++ = *p1++;
- *p2++ = *p1++;
- *p2++ = *p1++;
- *p2++ = 0;
- }
- }
- return TRUE;
- }
-
- /*
- * 将位图转换为16位
- */
- BOOL Image24to16(INFOSTR *pInfo, PBYTE pImage, PBYTE* pLineAddr)
- {
- DWORD BMask = (pInfo->sDIBInfo).bmask;
- DWORD RMask = (pInfo->sDIBInfo).rmask;
- DWORD GMask = (pInfo->sDIBInfo).gmask;
-
- DWORD Height = (pInfo->imginfo).height;
- DWORD Width = (pInfo->imginfo).width;
- if(pInfo->sDIBInfo.bmi.biCompression == BI_RGB)
- {
- BMask = 0x0000001F;
- GMask = 0x000003E0;
- RMask = 0x00007C00;
- }
- PWORD p2 = (PWORD)pInfo->_pbdata;
- PBYTE p1;// = pImage;
- PBYTE *pLine = pLineAddr + Height - 1;
- WORD Red, Blue, Green;
- WORD rs;
- double Rmax24, Bmax24, Gmax24;
- double Rmax16, Bmax16, Gmax16;
- Rmax24 = Bmax24 = Gmax24 = (1 << 8) - 1;
- Rmax16 = Bmax16 = (1 << 5) - 1;
- if(GMask == 0x000003E0)
- {
- Gmax16 = (1 << 5) - 1;
- rs = 10;
- }
- else
- {
- rs = 11;
- Gmax16 = (1 << 6) - 1;
- }
- for(DWORD y = 0L; y < Height; y++)
- {
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, y * 100 / Height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- p1 = *(pLine --);
- for(DWORD i = 0; i < Width; i++)
- {
- //为保持与原图基本一致应按比例变化
- Blue = (WORD)((double)(*p1++) * Bmax16 / Bmax24) & BMask;
- Green = ((WORD)((double)(*p1++) * Gmax16 / Gmax24) << 5) & GMask;
- Red = ((WORD)((double)(*p1++) * Rmax16 / Rmax24) << rs) & RMask;
- *p2++ = Blue | Green | Red;
- }
- //考虑DWORD对齐
- if(Width % 2)
- *p2++ = 255; //边界用白色填充
- }
- return TRUE;
- }
- /*
- * 24位位图倒置,并且按DWORD边界对齐
- */
- BOOL Image24to24(INFOSTR *pInfo, PBYTE pImage, PBYTE* pLineAddr)
- {
- DWORD Height = (pInfo->imginfo).height;
- DWORD Width = (pInfo->imginfo).width * 3;
- DWORD Linesize = (Width + sizeof(DWORD) - 1) / sizeof(DWORD) * sizeof(DWORD);
- PBYTE p1;
- PBYTE p2 = pInfo->_pbdata;
- PBYTE *pLine = pLineAddr + Height - 1;
- for(DWORD y = 0L; y < Height; y++)
- {
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, y * 100 / Height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- p1 = *(pLine--);
- memcpy(p2, p1, Width);
-
- //DWORD对齐
- memset(p2 + Width, 255, Linesize - Width);
- p2 += Linesize;
- }
- return TRUE;
- }
-
- /* ===============================================================================*
- * 设置PNG头信息,并且写PNG文件头
- * ===============================================================================*/
- /*
- * 根据BMP信息头设置PNG文件信息头
- */
- void pngSetIHDR(png_structp pPng, png_infop pPngInfo, INFOSTR *pInfo)
- {
- //所有的PNG文件都保存为color type 2, bitdepth 8(24位), 无alpha通道的图形
- DWORD Height, Width;
- int color_type, bit_depth;
- int compression_type, filter_type;
- int interlace_type = PNG_INTERLACE_ADAM7; //缺省设置为ADAM7交错图象
- compression_type = PNG_COMPRESSION_TYPE_DEFAULT; //缺省压缩类型
- filter_type = PNG_FILTER_TYPE_DEFAULT; //缺省FILTER
-
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- Height = bmpInfo.biHeight; //图象真实高度
- Width = bmpInfo.biWidth; //图象真实宽度
-
- int BitCount = bmpInfo.biBitCount;
- color_type = 2; //RGB图
- bit_depth = 8;
- png_set_IHDR(pPng, pPngInfo, Width, Height, bit_depth, color_type,
- interlace_type, compression_type, filter_type);
- if(BitCount == 16)
- {
- //设置真实位数通道
- png_color_8 sig_bit;
- sig_bit.red = 5;
- sig_bit.blue = 5;
- sig_bit.green = 5;
- if(bmpInfo.biCompression == BI_BITFIELDS)
- if(pInfo->sDIBInfo.gmask == 0x07E0)
- sig_bit.green = 6;
- png_set_sBIT(pPng, pPngInfo, &sig_bit);
- }
-
- //将信息写入信息头
- png_write_info(pPng, pPngInfo);
- }
- /* ============================================================================*
- * 调用PNGLIB存储图象之前先将图象数据转换为PNG格式的数据
- * 下面的几个函数用于将图象由BMP格式转换为PNG格式
- * ============================================================================*/
- /*
- * 图象变换,将16位图象扩展为24位,并按BGR格式排列
- */
- BOOL TransformImage16(INFOSTR *pInfo, PBYTE pngImage)
- {
- PBYTE pImage = (PBYTE)pInfo->_pbdata;
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- ASSERT(bmpInfo.biBitCount == 16);
- DWORD gMask, bMask, rMask;
- bMask = 0x001F;
- gMask = 0x03E0;
- rMask = 0x7C00;
- if(bmpInfo.biCompression == BI_BITFIELDS)
- {
- bMask = pInfo->sDIBInfo.bmask;
- gMask = pInfo->sDIBInfo.gmask;
- rMask = pInfo->sDIBInfo.rmask;
- }
- int rs = 10;
- DWORD Rmax16, Gmax16, Bmax16;
- DWORD Rmax24, Gmax24, Bmax24;
- Rmax16 = Gmax16 = Bmax16 = (1 << 5) - 1;
- Rmax24 = Gmax24 = Bmax24 = (1 << 8) - 1;
- if(gMask == 0x07e0)
- {
- rs = 10;
- Gmax16 = (1 << 6) - 1;
- }
- DWORD height = bmpInfo.biHeight;
- DWORD width = bmpInfo.biWidth;
- DWORD linesize = DIBSCANLINE_WIDTHBYTES(width * bmpInfo.biBitCount);
-
- PWORD pRow = (PWORD)pImage;
- PBYTE p = pngImage;
- for(DWORD row = 0; row < height; row ++)
- {
- pRow = (WORD*)(pImage + linesize * row);
- //进度控制
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, row * 100 / height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- for(DWORD i = 0; i < width; i++)
- {
- WORD red = (*pRow) & rMask;
- WORD green = *pRow & gMask;
- *p++ = (BYTE)((double)(red >> rs) * (double)Rmax24 / (double)Rmax16); //red
- *p++ = (BYTE)((double)(green >> 5) * (double)Gmax24 / (double)Gmax16); //green
- *p++ = (BYTE)((double)(*pRow & bMask) * (double)Bmax24 / (double)Bmax16);//blue
- pRow ++;
- }
- }
- return TRUE;
- }
- /*
- * 24位图象变换,24位图象可以不用变换,直接拷贝图象即可。
- *
- * 这里去掉为DWORD对齐而增加的填充字节。
- *
- */
- BOOL TransformImage24(INFOSTR *pInfo, PBYTE pngImage)
- {
- PBYTE pImage = (PBYTE)pInfo->_pbdata;
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- ASSERT(bmpInfo.biBitCount == 24);
- DWORD height = bmpInfo.biHeight;
- DWORD width = bmpInfo.biWidth;
- DWORD linesize = DIBSCANLINE_WIDTHBYTES(width * bmpInfo.biBitCount);
-
- PBYTE pRow = pImage;
- PBYTE p = pngImage;
- for(DWORD row = 0; row < height; row ++)
- {
- pRow = pImage + row * linesize;
-
- //进度控制
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, row * 100 / height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- for(DWORD i = 0; i < width; i++)
- {
- *p++ = *(pRow + 2); //red
- *p++ = *(pRow + 1); //green
- *p++ = *(pRow); //blue
- pRow += 3;
- }
- }
- return TRUE;
- }
- /*
- * 32位图象转换,去掉最高的未用字节
- */
- BOOL TransformImage32(INFOSTR* pInfo, PBYTE pngImage)
- {
- PBYTE pImage = (PBYTE)pInfo->_pbdata;
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- ASSERT(bmpInfo.biBitCount == 32);
- DWORD height = bmpInfo.biHeight;
- DWORD width = bmpInfo.biWidth;
- DWORD linesize = DIBSCANLINE_WIDTHBYTES(width * bmpInfo.biBitCount);
-
- PBYTE pRow = pImage;
- PBYTE p = pngImage;
- for(DWORD row = 0; row < height; row ++)
- {
- pRow = pImage + row * linesize;
- //进度控制
- if(pInfo->fpProgress)
- {
- if ((*pInfo->fpProgress)(RWPROGRESSSIZE, row * 100 / height))
- {
- pInfo->result = ER_USERBREAK;
- return FALSE;
- }
- }
- for(DWORD i = 0; i < width; i++)
- {
- *p++ = *(pRow + 2); //red
- *p++ = *(pRow + 1); //green
- *p++ = *(pRow); //blue
- pRow += 4;
- }
- }
- return TRUE;
- }
- /*
- * 1、4、8位位图象转换,无需转换,直接拷贝
- */
- BOOL TransformImage1_4_8(INFOSTR* pInfo, PBYTE pngImage)
- {
- PBYTE pImage = (PBYTE)pInfo->_pbdata;
- BITMAPINFOHEADER bmpInfo = pInfo->sDIBInfo.bmi;
- DWORD height = bmpInfo.biHeight;
- DWORD linesize = DIBSCANLINE_WIDTHBYTES(bmpInfo.biWidth * bmpInfo.biBitCount);
-
- memcpy(pngImage, pImage, height * linesize);
- return TRUE;
- }