WmfModule.cpp
上传用户:yatsl7111
上传日期:2007-01-08
资源大小:1433k
文件大小:23k
源码类别:

图形图象

开发平台:

Visual C++

  1. /********************************************************************
  2. WmfModule.cpp - ISee图像浏览器—WMF图像读写模块实现文件
  3.           
  4.     版权所有(C) 2000 VCHelp-coPathway-ISee workgroup member - YZ
  5.     这一程序是自由软件,你可以遵照自由软件基金会出版的GNU 通用公共许
  6. 可证条款来修改和重新发布这一程序。或者用许可证的第二版,或者(根
  7. 据你的选择)用任何更新的版本。
  8.     发布这一程序的目的是希望它有用,但没有任何担保。甚至没有适合特定
  9. 目地的隐含的担保。更详细的情况请参阅GNU通用公共许可证。
  10.     你应该已经和程序一起收到一份GNU通用公共许可证的副本。如果还没有,
  11. 写信给:
  12.     The Free Software Foundation, Inc.,  675  Mass Ave,  Cambridge,
  13.     MA02139,  USA
  14. 如果你在使用本软件时有什么问题或建议,用以下地址可以与我们取得联
  15. 系:
  16. http://isee.126.com
  17. http://www.vchelp.net
  18. 或:
  19. iseesoft@china.com
  20. 编写人:YZ
  21. E-Mail:yzfree@sina.com 或 yzfree@yeah.net
  22. 文件版本:
  23. Beta 1.1
  24. Build 00622
  25. Date  2000-6-22
  26. ********************************************************************/
  27. #include "stdafx.h"
  28. #include "WmfModule.h"
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34. static char ModuleProcessImgType[]="WMF"; // 本模块能处理的图像类型
  35. static char WriterList[]="YZ"; // 本模块的作者列表
  36. static char WriterMess[]="很高兴能在自由软件开发组作矢量图的工作,这使我学到了不少元文件的知识^_^"; // 作者留言
  37. //
  38. // Note!
  39. //
  40. // If this DLL is dynamically linked against the MFC
  41. // DLLs, any functions exported from this DLL which
  42. // call into MFC must have the AFX_MANAGE_STATE macro
  43. // added at the very beginning of the function.
  44. //
  45. // For example:
  46. //
  47. // extern "C" BOOL PASCAL EXPORT ExportedFunction()
  48. // {
  49. // AFX_MANAGE_STATE(AfxGetStaticModuleState());
  50. // // normal function body here
  51. // }
  52. //
  53. // It is very important that this macro appear in each
  54. // function, prior to any calls into MFC.  This means that
  55. // it must appear as the first statement within the 
  56. // function, even before any object variable declarations
  57. // as their constructors may generate calls into the MFC
  58. // DLL.
  59. //
  60. // Please see MFC Technical Notes 33 and 58 for additional
  61. // details.
  62. //
  63. /////////////////////////////////////////////////////////////////////////////
  64. // CWmfModuleApp
  65. BEGIN_MESSAGE_MAP(CWmfModuleApp, CWinApp)
  66. //{{AFX_MSG_MAP(CWmfModuleApp)
  67. // NOTE - the ClassWizard will add and remove mapping macros here.
  68. //    DO NOT EDIT what you see in these blocks of generated code!
  69. //}}AFX_MSG_MAP
  70. END_MESSAGE_MAP()
  71. /////////////////////////////////////////////////////////////////////////////
  72. // CWmfModuleApp construction
  73. CWmfModuleApp::CWmfModuleApp()
  74. {
  75. // TODO: add construction code here,
  76. // Place all significant initialization in InitInstance
  77. }
  78. /////////////////////////////////////////////////////////////////////////////
  79. // The one and only CWmfModuleApp object
  80. CWmfModuleApp theApp;
  81. // 接口函数声明 — 第一层,唯一与外界联系的接口
  82. int WINAPI AccessWMFModule(INFOSTR *pInfo)
  83. {
  84. switch(pInfo->comm)
  85. {
  86. case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
  87. _fnCMD_GETPROCTYPE(pInfo);
  88. break;
  89. case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
  90. _fnCMD_GETWRITERS(pInfo);
  91. break;
  92. case CMD_GETWRITERMESS: // 获取作者们的留言
  93. _fnCMD_GETWRITERMESS(pInfo);
  94. break;
  95. case CMD_GETBUILDID: // 获取图像模块内部版本号
  96. _fnCMD_GETBUILDID(pInfo);
  97. break;
  98. case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
  99. _fnCMD_IS_VALID_FILE(pInfo);
  100. break;
  101. case CMD_GET_FILE_INFO: // 获取指定文件的信息
  102. _fnCMD_GET_FILE_INFO(pInfo);
  103. break;
  104. case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
  105. _fnCMD_LOAD_FROM_FILE(pInfo);
  106. break;
  107. case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
  108. _fnCMD_SAVE_TO_FILE(pInfo);
  109. break;
  110. case CMD_IS_SUPPORT: // 查询某个命令是否被支持
  111. _fnCMD_IS_SUPPORT(pInfo);
  112. break;
  113. case CMD_RESIZE: // 从新获取指定尺寸的图像位数据(只适用于矢量图像)
  114. _fnCMD_RESIZE(pInfo);
  115. break;
  116. default:
  117. pInfo->result = ER_ILLCOMM; // 非法命令
  118. ASSERT(FALSE); // 调用者的程序设计有问题 :-)
  119. break;
  120. }
  121. // 执行命令成功返回1, 失败返回0
  122. return (pInfo->result==ER_SUCCESS)? 1:0;
  123. }
  124. // 命令解释函数 — 第二层解释函数
  125. //********************************************************************//
  126. // 操作命令解释函数---解释:CMD_IS_SUPPORT命令
  127. // 查询某个命令是否被支持
  128. void _fnCMD_IS_SUPPORT(INFOSTR *pInfo)
  129. {
  130. ASSERT(pInfo->result == ER_EMPTY);
  131. switch(pInfo->annexdata.cmAnnData)  
  132. {
  133. case CMD_GETPROCTYPE: // 获取本模块能处理的图像类型
  134. pInfo->result = ER_SUCCESS;
  135. break;
  136. case CMD_GETWRITERS: // 获取本模块的作者列表,多人时用逗号分隔
  137. pInfo->result = ER_SUCCESS;
  138. break;
  139. case CMD_GETWRITERMESS: // 获取作者们的留言
  140. pInfo->result = ER_SUCCESS;
  141. break;
  142. case CMD_GETBUILDID: // 获取图像模块内部版本号
  143. pInfo->result = ER_SUCCESS;
  144. break;
  145. case CMD_IS_VALID_FILE: // 判断指定文件是否是有效的WMF文件
  146. pInfo->result = ER_SUCCESS;
  147. break;
  148. case CMD_GET_FILE_INFO: // 获取指定文件的信息
  149. pInfo->result = ER_SUCCESS;
  150. break;
  151. case CMD_LOAD_FROM_FILE: // 从指定图像文件中读取数据
  152. pInfo->result = ER_SUCCESS;
  153. break;
  154. case CMD_SAVE_TO_FILE: // 将数据保存到指定文件中
  155. pInfo->result = ER_NOTSUPPORT;
  156. break;
  157. case CMD_IS_SUPPORT: // 查询某个命令是否被支持
  158. pInfo->result = ER_SUCCESS;
  159. break;
  160. case CMD_RESIZE: // 获取指定尺寸的图像(只适用于矢量图像)
  161. pInfo->result = ER_SUCCESS;
  162. break;
  163. default:
  164. pInfo->result = ER_NOTSUPPORT;
  165. break;
  166. }
  167. }
  168. // 操作命令解释函数---解释:CMD_GETPROCTYPE命令
  169. // 获取本模块能处理的图像类型,如:BMP,PCX等等
  170. void _fnCMD_GETPROCTYPE(INFOSTR *pInfo)
  171. {
  172. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  173. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  174. ASSERT(pInfo->result == ER_EMPTY);
  175. // 复制能处理的类型字符串
  176. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)ModuleProcessImgType, 
  177. sizeof(ModuleProcessImgType));
  178. pInfo->result = ER_SUCCESS;
  179. }
  180. // 操作命令解释函数---解释:CMD_GETWRITER命令
  181. // 获取本模块的作者列表,多人时用逗号分隔
  182. void _fnCMD_GETWRITERS(INFOSTR *pInfo)
  183. {
  184. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  185. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  186. ASSERT(pInfo->result == ER_EMPTY);
  187. // 复制开发者名单串
  188. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterList, 
  189. sizeof(WriterList));
  190. pInfo->result = ER_SUCCESS;
  191. }
  192. // 操作命令解释函数---解释:CMD_GETWRITERMESS命令
  193. // 获取作者们的留言
  194. void _fnCMD_GETWRITERMESS(INFOSTR *pInfo)
  195. {
  196. // 根据接口定义,此时附加数据应被清空为0,所以下此断言
  197. ASSERT(pInfo->annexdata.scAnnData[0] == 0);
  198. ASSERT(pInfo->result == ER_EMPTY);
  199. // 复制开发者们的留言字符串
  200. ::CopyMemory((PVOID)pInfo->annexdata.scAnnData, (PVOID)WriterMess, 
  201. sizeof(WriterMess));
  202. pInfo->result = ER_SUCCESS;
  203. }
  204. // 操作命令解释函数---解释:CMD_GETBUILDID命令
  205. // 获取图像模块内部版本号
  206. void _fnCMD_GETBUILDID(INFOSTR *pInfo)
  207. {
  208. // 根据接口定义,此时annexdata.dwAnnData应被设为0,所以下此断言
  209. ASSERT(pInfo->annexdata.dwAnnData == 0);
  210. ASSERT(pInfo->result == ER_EMPTY);
  211. // 填写内部版本号码
  212. pInfo->annexdata.dwAnnData = WMF_MODULE_BUILDID;
  213. pInfo->result = ER_SUCCESS;
  214. }
  215. // 操作命令解释函数---解释:CMD_IS_VALID_FILE命令
  216. // 判断指定文件是否是有效的WMF文件
  217. void _fnCMD_IS_VALID_FILE(INFOSTR *pInfo)
  218. {
  219. CFile file;
  220. DWORD dwIsAldus;
  221. DWORD dwSeekPos;
  222. DWORD dwFileSize;
  223. ALDUSMFHEADER aldusMFHeader;
  224. METAHEADER mfHeader;
  225. // 检验入口参数是否符合接口定义
  226. ASSERT(pInfo->result == ER_EMPTY);
  227. ASSERT(pInfo->annexdata.iAnnData == 0);
  228. ASSERT(::strlen(pInfo->filename));
  229. ASSERT(pInfo->state == PKST_NOTVER);
  230. // 先判断指定的文件是否存在
  231. if (!IsFileExist(pInfo->filename))
  232. pInfo->result = ER_COMMINFOERR;
  233. else
  234. {
  235. // 打开指定文件
  236. if (!file.Open(pInfo->filename, CFile::modeRead))
  237. {
  238. pInfo->result = ER_FILERWERR; // 打开文件时出错
  239. return;
  240. }
  241. dwFileSize = file.GetLength();
  242. // 用长度判断
  243. if (dwFileSize < sizeof(METAHEADER))
  244. {
  245. pInfo->result = ER_SUCCESS; // 这不是一个WMF文件
  246. pInfo->annexdata.iAnnData = 0; // WMF文件的长度起码大于
  247. file.Close(); // METAHEADER结构的长度
  248. return;
  249. }
  250. file.Seek(0, CFile::begin);
  251. // 读取文件头的四个字节。(如果是可放置元文件,该DWORD的
  252. // 内容应该是0x9AC6CDD7
  253. if (file.Read(&dwIsAldus, sizeof(DWORD)) != sizeof(DWORD))
  254. {
  255. pInfo->result = ER_FILERWERR; // 读文件时出错
  256. file.Close();
  257. return;
  258. }
  259. if (dwIsAldus == ALDUSKEY) 
  260. {
  261. // 表明该文件是一个可放置元文件
  262. if (dwFileSize < (ALDUSMFHEADERSIZE+sizeof(METAHEADER)))
  263. {
  264. pInfo->result = ER_SUCCESS; // 这可能是一个受损的WMF文件
  265. pInfo->annexdata.iAnnData = 0;
  266. file.Close();
  267. return;
  268. }
  269. // 读去文件头部的结构。
  270. file.Seek(0, CFile::begin);
  271. if (file.Read(&aldusMFHeader, ALDUSMFHEADERSIZE) != ALDUSMFHEADERSIZE)
  272. {
  273. pInfo->result = ER_FILERWERR;
  274. file.Close();
  275. return;
  276. }
  277. dwSeekPos = ALDUSMFHEADERSIZE;
  278. }
  279. else // 老式的Windows元文件
  280. dwSeekPos = 0;
  281. file.Seek(dwSeekPos, CFile::begin);
  282. // 读windows元文件头
  283. if (file.Read(&mfHeader, sizeof(METAHEADER)) != sizeof(METAHEADER))
  284. {
  285. pInfo->result = ER_FILERWERR;
  286. file.Close();
  287. return;
  288. }
  289. // 检查头部标志(0表示是内存元文件,1表示磁盘元文件)
  290. if ((mfHeader.mtType != 0)&&(mfHeader.mtType != 1))
  291. {
  292. pInfo->result = ER_SUCCESS;
  293. pInfo->annexdata.iAnnData = 0; // 这可能是一个受损的WMF文件
  294. file.Close();
  295. return;
  296. }
  297. // 到此,表明该文件是一个有效的WMF文件,iAnnData变量设为1
  298. pInfo->annexdata.iAnnData = 1;
  299. pInfo->state = PKST_PASSVER;
  300. pInfo->result = ER_SUCCESS;
  301. file.Close();
  302. }
  303. }
  304. // 操作命令解释函数---解释:CMD_GET_FILE_INFO命令
  305. // 获取指定文件的信息
  306. void _fnCMD_GET_FILE_INFO(INFOSTR *pInfo)
  307. {
  308. CFile file;
  309. DWORD dwIsAldus;
  310. ALDUSMFHEADER aldusMFHeader;
  311. // 检验入口参数是否符合接口定义
  312. ASSERT(pInfo->result == ER_EMPTY);
  313. ASSERT(::strlen(pInfo->filename));
  314. // 此时,该文件必需是一个已存在的、并且是有效的WMF文件
  315. ASSERT(pInfo->state == PKST_PASSVER);
  316. // 客户模块必需要先将imginfo清空为0
  317. ASSERT(pInfo->imginfo.imgtype == IMT_NULL);
  318. // 打开指定文件
  319. if (!file.Open(pInfo->filename, CFile::modeRead))
  320. {
  321. pInfo->result = ER_FILERWERR;
  322. return;
  323. }
  324. file.Seek(0, CFile::begin);
  325. // 读取文件头的四个字节。(如果是可放置元文件,该DWORD的
  326. // 内容应该是0x9AC6CDD7
  327. if (file.Read(&dwIsAldus, sizeof(DWORD)) != sizeof(DWORD))
  328. {
  329. file.Close();
  330. pInfo->result = ER_FILERWERR;
  331. return;
  332. }
  333. if (dwIsAldus == ALDUSKEY) 
  334. {
  335. // 表明该文件是一个可放置元文件,读文件头部的结构。
  336. file.Seek(0, CFile::begin);
  337. if (file.Read(&aldusMFHeader, ALDUSMFHEADERSIZE) != ALDUSMFHEADERSIZE)
  338. {
  339. file.Close();
  340. pInfo->result = ER_FILERWERR;
  341. return;
  342. }
  343. }
  344. HWND hWnd = ::GetDesktopWindow();
  345. HDC dc = ::GetDC(hWnd);
  346. LPIMAGEINFOSTR lpImgInfoStr = &pInfo->imginfo;
  347. // 获取文件的长度、图像的宽度、高度等信息
  348. lpImgInfoStr->imgtype = IMT_VECTORSTATIC;
  349. lpImgInfoStr->imgformat = IMF_WMF;
  350. lpImgInfoStr->filesize = file.GetLength();
  351. // 计算WMF图像的原始尺寸。其中aldusMFHeader.bbox中存放的是文件单位的
  352. // 图像尺寸,而aldusMFHeader.inch中则是一英寸等于多少文件单位的数值。
  353. // 我们先计算出该图像的以英寸为单位的尺寸,然后再除以当前显示器的每
  354. // 英寸多少像素的值(可用GetDeviceCaps()函数取得),就可以得到图像以
  355. // 像素为单位的尺寸了。(挺麻烦的:-)
  356. float fx, fy;
  357. if (dwIsAldus == ALDUSKEY)
  358. {
  359. fx = (float)(aldusMFHeader.bbox.right-aldusMFHeader.bbox.left);
  360. fy = (float)(aldusMFHeader.bbox.bottom-aldusMFHeader.bbox.top);
  361. fx = (fx/(float)aldusMFHeader.inch)*::GetDeviceCaps(dc, LOGPIXELSX)+(float)0.5; // 此处的加上0.5是四舍五入.
  362. fy = (fy/(float)aldusMFHeader.inch)*::GetDeviceCaps(dc, LOGPIXELSY)+(float)0.5;
  363. }
  364. if (dwIsAldus == ALDUSKEY)
  365. lpImgInfoStr->width = (int)fx;
  366. // 如果是可放置的元文件,则宽度等于指定的宽度.
  367. else
  368. lpImgInfoStr->width = ::GetDeviceCaps(dc, HORZRES);
  369. // 如果是老式的Windows元文件,就默认它的宽度为屏幕宽度.因为这种
  370. // 元文件中没有保存图像尺寸的数据.
  371. if (dwIsAldus == ALDUSKEY)
  372. lpImgInfoStr->height = (int)fy;
  373. else
  374. lpImgInfoStr->height = ::GetDeviceCaps(dc, VERTRES);
  375. ::ReleaseDC(hWnd, dc);
  376. // 这是个虚值,没有意义.因为元文件中没有保存颜色数据(不针对增强型元文件).
  377. lpImgInfoStr->bitcount = 24;
  378. lpImgInfoStr->compression = ICS_GDIRECORD;
  379. // 以下这个0值没有意义,该参数只对BMP图像文件有意义.
  380. lpImgInfoStr->linesize = 0;
  381. // 静态WMF文件只有一个图像,所以设为1.
  382. lpImgInfoStr->imgnumbers = 1;
  383. // 可以被编辑,因为它是静态图像。
  384. lpImgInfoStr->imgchang = 0;
  385. // 获取文件最后的修改日期(月在高字节,日在低字节)
  386. CFileStatus status;
  387. file.GetStatus(status);
  388. lpImgInfoStr->year = (WORD)status.m_mtime.GetYear();
  389. lpImgInfoStr->monday = (WORD)status.m_mtime.GetMonth();
  390. lpImgInfoStr->monday <<= 8;
  391. lpImgInfoStr->monday |= (WORD)status.m_mtime.GetDay();
  392. // 获取文件最后的修改时间(字序:最高—0, 2—时,1—分,0—秒)
  393. lpImgInfoStr->time = status.m_mtime.GetHour();
  394. lpImgInfoStr->time <<= 8;
  395. lpImgInfoStr->time |= status.m_mtime.GetMinute();
  396. lpImgInfoStr->time <<= 8;
  397. lpImgInfoStr->time |= status.m_mtime.GetSecond();
  398. lpImgInfoStr->time &= 0xffffff;
  399. // 关闭文件
  400. file.Close();
  401. // 设置出口数据
  402. pInfo->state = PKST_PASSINFO;
  403. pInfo->result = ER_SUCCESS;
  404. }
  405. // 操作命令解释函数---解释:CMD_LOAD_FROM_FILE命令
  406. // 从指定图像文件中读取数据
  407. void _fnCMD_LOAD_FROM_FILE(INFOSTR *pInfo)
  408. {
  409. // 检验入口参数是否符合接口定义
  410. ASSERT(pInfo->result == ER_EMPTY);
  411. ASSERT(::strlen(pInfo->filename));
  412. // 此时,该文件必需是一个已存在的、有效的WMF文件,并且数据包中
  413. // 含有该文件的信息(imginfo结构中)
  414. ASSERT(pInfo->state == PKST_PASSINFO);
  415. ASSERT(pInfo->imginfo.imgformat == IMF_WMF);
  416. ASSERT(pInfo->pImgInfo == NULL);
  417. // 必需设置标准图像格式信息
  418. ASSERT(pInfo->sDIBInfo.bmi.biSize == sizeof(BITMAPINFOHEADER));
  419. ASSERT(pInfo->pLineAddr != NULL);
  420. ASSERT(pInfo->_pbdata != NULL);
  421. HENHMETAFILE hEnhMeta;
  422. BYTE *pby;
  423. HBITMAP bmp, oldbmp;
  424. HWND hWnd = ::GetDesktopWindow();
  425. HDC hDC = ::GetDC(hWnd);
  426. HDC hComDC;
  427. int sizeline;
  428. ASSERT(hWnd);
  429. if (pInfo->fpProgress)
  430. {
  431. if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 6))
  432. { // 如果进度函数返回1,则说明用户想中断操作,返回。
  433. ::ReleaseDC(hWnd, hDC);
  434. pInfo->result = ER_USERBREAK;
  435. return;
  436. }
  437. }
  438. if (Read(pInfo, &hEnhMeta))
  439. {
  440. ASSERT(hEnhMeta);
  441. ASSERT(pInfo->sDIBInfo.bmi.biPlanes == 1);
  442. // 可接收三中格式的图像位数据请求:16,24,32。并且要求数据包位
  443. // 数据缓冲区是DIB格式(扫描行以4字节对齐)
  444. ASSERT((pInfo->sDIBInfo.bmi.biBitCount==16)||(pInfo->sDIBInfo.bmi.biBitCount==24)||(pInfo->sDIBInfo.bmi.biBitCount==32));
  445. // 创建用于存放图像位数据的临时缓冲区
  446. bmp = ::CreateDIBSection(hDC, (CONST BITMAPINFO*)&pInfo->sDIBInfo, 
  447. DIB_RGB_COLORS, (VOID**)&pby, NULL, 0);
  448. hComDC = ::CreateCompatibleDC(hDC);
  449. if ((bmp == NULL)||(hComDC == NULL)) // 错误检查
  450. {
  451. ASSERT(pInfo->pImgInfo);
  452. ::GlobalFree(pInfo->pImgInfo);
  453. pInfo->pImgInfo = NULL;
  454. ::DeleteEnhMetaFile(hEnhMeta);
  455. ::ReleaseDC(hWnd, hDC);
  456. if (bmp) ::DeleteObject(bmp);
  457. if (hComDC) ::DeleteDC(hComDC);
  458. pInfo->result = ER_SYSERR;
  459. return;
  460. }
  461. ASSERT(pby); // 此时pby中必然存在bmp位数据缓冲区的地址
  462. oldbmp = (HBITMAP)::SelectObject(hComDC, bmp);
  463. // 设置背景色为缺省窗口色
  464. ::FillRect(hComDC, &CRect(0,0,pInfo->sDIBInfo.bmi.biWidth, pInfo->sDIBInfo.bmi.biHeight), (HBRUSH)(COLOR_WINDOW+1));
  465. // 绘制WMF图像(由Windows元文件格式转为的EMF格式)
  466. ::PlayEnhMetaFile(hComDC, hEnhMeta, CRect(0,0,pInfo->sDIBInfo.bmi.biWidth, pInfo->sDIBInfo.bmi.biHeight));
  467. ::SelectObject(hComDC, oldbmp);
  468. ::DeleteDC(hComDC);
  469. int height = pInfo->sDIBInfo.bmi.biHeight;
  470. ASSERT(height != 0);
  471. // DIB缓冲区中每一扫描行都是4字节对齐的,所以使用了DIBSCANLINE_WIDTHBYTES宏
  472. sizeline = DIBSCANLINE_WIDTHBYTES(pInfo->sDIBInfo.bmi.biWidth*pInfo->sDIBInfo.bmi.biBitCount);
  473. // 复制图像到数据包中
  474. PBYTE lpsou = pby;
  475. ASSERT(pInfo->pLineAddr[0] != NULL); // 如果数据包中的行地址没有填写,就会引发此断言
  476. if (height < 0) // 正向DIB缓冲区(top-down)
  477. {
  478. for (int i=0;i<height;i++)
  479. {
  480. ::CopyMemory((PVOID)pInfo->pLineAddr[i], (CONST VOID *)lpsou, sizeline);
  481. lpsou += sizeline;
  482. }
  483. }
  484. else // 倒向
  485. {
  486. for (int i=0;i<height;i++)
  487. {
  488. ::CopyMemory((PVOID)pInfo->pLineAddr[height-i-1], (CONST VOID *)lpsou, sizeline);
  489. lpsou += sizeline;
  490. }
  491. }
  492. ::DeleteObject(bmp);
  493. ::DeleteEnhMetaFile(hEnhMeta);
  494. // 成功
  495. pInfo->state = PKST_INFOANDBITS;
  496. pInfo->modify = 0;
  497. pInfo->result = ER_SUCCESS;
  498. }
  499. ::ReleaseDC(hWnd, hDC);
  500. if (pInfo->fpProgress) // 结束进度条,此调用不再支持用户中断
  501. (*pInfo->fpProgress)(RWPROGRESSSIZE, RWPROGRESSSIZE);
  502. }
  503. // 操作命令解释函数---解释:CMD_SAVE_TO_FILE命令
  504. // 将数据保存到指定文件中
  505. void _fnCMD_SAVE_TO_FILE(INFOSTR *pInfo)
  506. {
  507. // WMF模块无法支持保存命令。
  508. pInfo->result = ER_NOTSUPPORT;
  509. return;
  510. }
  511. // 操作命令解释函数---解释:CMD_RESIZE命令
  512. // 重新获取指定尺寸的图像位数据(只适用于矢量图像)
  513. void _fnCMD_RESIZE(INFOSTR *pInfo)
  514. {
  515. // 指定尺寸在pInfo->sDIBInfo.bmi中指定
  516. _fnCMD_LOAD_FROM_FILE(pInfo);
  517. }
  518. /*************************************************************************
  519.  *
  520.  * IsFileExist()
  521.  * 
  522.  * 参数说明:
  523.  *
  524.  * char *lpFileName - 待判断的文件路径和名称(文件名)
  525.  *
  526.  * 返回值:
  527.  *
  528.  * BOOL - 如果指定的文件存在返回TRUE,否则返回FALSE。
  529.  * 
  530.  * 描述:
  531.  *
  532.  * 判断指定的文件是否存在
  533.  * 
  534.  * 该文件必需可以被读和写
  535.  *
  536.  ************************************************************************/
  537. BOOL IsFileExist(char *lpFileName)
  538. {
  539. CFile file;
  540. BOOL bExist = FALSE; // 文件存在是TRUE,不存在是FALSE
  541. // 确定指定的文件是否存在
  542. if (file.Open(lpFileName, CFile::modeReadWrite))
  543. {
  544. bExist = TRUE;
  545. file.Close();
  546. }
  547. return bExist;
  548. }
  549. /*************************************************************************
  550.  *
  551.  * Read()
  552.  * 
  553.  * 参数说明:
  554.  *
  555.  * INFOSTR *pInfo - 图像读写数据包
  556.  * HENHMETAFILE *pHEnhMeta  - 返回的元文件句柄(如果成功的话)
  557.  *
  558.  * 返回值:
  559.  *
  560.  * BOOL - 如果读取成功返回TRUE,否则返回FALSE。
  561.  * 
  562.  * 描述:
  563.  * 如果调用成功,该函数将修改pHEnhMeta指向的值,而且申请一块内存
  564.  * 挂接到pInfo中的pImgInfo上(此内存块由客户程序负责释放)。
  565.  *
  566.  * 读取指定元文件到数据包中
  567.  * 
  568.  ************************************************************************/
  569. BOOL Read(INFOSTR *pInfo, HENHMETAFILE *pHEnhMeta)
  570. {
  571. CFile file;
  572. DWORD    dwIsAldus;
  573. ALDUSMFHEADER m_aldusMFHeader;
  574. METAHEADER mfHeader;
  575.    DWORD     dwSize;
  576. DWORD seekpos;
  577. *pHEnhMeta = NULL;
  578. // 打开指定文件
  579. if (!file.Open(pInfo->filename, CFile::modeRead))
  580. {
  581. pInfo->result = ER_FILERWERR;
  582. return FALSE;
  583. }
  584. file.Seek(0, CFile::begin);
  585. if (file.Read(&dwIsAldus, sizeof(DWORD)) != sizeof(DWORD))
  586. {
  587. file.Close();
  588. pInfo->result = ER_FILERWERR;
  589. return FALSE;
  590. }
  591. if (dwIsAldus != ALDUSKEY) // 旧的Windows元文件.
  592. {
  593. ::ZeroMemory(&m_aldusMFHeader, sizeof(m_aldusMFHeader));
  594. seekpos = 0;
  595. }
  596. else // 可放置型元文件.
  597. {
  598. file.Seek(0, CFile::begin);
  599. // 读去头部的附加结构
  600. if (file.Read(&m_aldusMFHeader, ALDUSMFHEADERSIZE) != ALDUSMFHEADERSIZE)
  601. {
  602. file.Close();
  603. pInfo->result = ER_FILERWERR;
  604. return FALSE;
  605. }
  606. seekpos = ALDUSMFHEADERSIZE;
  607. }
  608. file.Seek(seekpos, CFile::begin);
  609. // 读Windows元文件头.
  610. if (file.Read(&mfHeader, sizeof(mfHeader)) != sizeof(mfHeader))
  611. {
  612. file.Close();
  613. pInfo->result = ER_FILERWERR;
  614. return FALSE;
  615. }
  616. // 为元文件数据分配内存.(mtSize的尺寸值单位是WORD型,所以乘2)
  617. dwSize = mfHeader.mtSize*2;
  618. BYTE* lpMFBits = (BYTE*)::GlobalAlloc(GPTR, dwSize);
  619. if (lpMFBits == NULL)
  620. {
  621. file.Close();
  622. pInfo->result = ER_MEMORYERR; // 内存不足,返回.
  623. return FALSE;
  624. }
  625. // 定位元文件位数据偏移.
  626. file.Seek(seekpos, CFile::begin);
  627. int loop = dwSize/RWBLOCKSIZE; // 读的循环次数
  628. int leavings = dwSize-(loop*RWBLOCKSIZE); // 剩余尺寸
  629. BYTE *lpTmp = lpMFBits;
  630. // 将图像数据读入内存
  631. for (int i=0;i<loop;i++)
  632. {
  633. if (file.Read(lpTmp, RWBLOCKSIZE) != RWBLOCKSIZE)
  634. {
  635. file.Close();
  636. ::GlobalFree(lpMFBits);
  637. pInfo->result = ER_FILERWERR;
  638. return FALSE;
  639. }
  640. if (pInfo->fpProgress)
  641. {
  642. if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 10+60/loop*(i+1)))
  643. { // 如果进度函数返回1,则说明用户想中断操作,返回。
  644. file.Close();
  645. ::GlobalFree(lpMFBits);
  646. pInfo->result = ER_USERBREAK;
  647. return FALSE;
  648. }
  649. }
  650. lpTmp += RWBLOCKSIZE;
  651. }
  652. if (file.Read(lpTmp, leavings) != (unsigned int)leavings)
  653. {
  654. file.Close();
  655. ::GlobalFree(lpMFBits);
  656. pInfo->result = ER_FILERWERR;
  657. return FALSE;
  658. }
  659. /* 简化代码
  660. if (file.ReadHuge(lpMFBits, dwSize) != dwSize)
  661. {
  662. file.Close();
  663. delete [] lpMFBits;
  664. pInfo->result = ER_FILERWERR;
  665. return FALSE;
  666. }
  667. */
  668. // 获得元文件句柄
  669. *pHEnhMeta = ::SetWinMetaFileBits(dwSize, lpMFBits, NULL, NULL);
  670. // 此时lpMFBits中的数据已经无用,删除.
  671. ASSERT(lpMFBits);
  672. ::GlobalFree(lpMFBits);
  673. file.Close();
  674. if (!(*pHEnhMeta))
  675. {
  676. pInfo->result = ER_SYSERR;
  677. return FALSE;
  678. }
  679. if (pInfo->fpProgress)
  680. {
  681. if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 80))
  682. { // 如果进度函数返回1,则说明用户想中断操作,返回。
  683. ::DeleteEnhMetaFile(*pHEnhMeta);
  684. *pHEnhMeta = NULL;
  685. pInfo->result = ER_USERBREAK;
  686. return FALSE;
  687. }
  688. }
  689. // 分配原始图像信息块
  690. LPWMFADDINFO lpWmfAddInfo;
  691. lpWmfAddInfo = (LPWMFADDINFO)::GlobalAlloc(GPTR, sizeof(WMFADDINFO));
  692. if (!lpWmfAddInfo)
  693. {
  694. ::DeleteEnhMetaFile(*pHEnhMeta);
  695. *pHEnhMeta = NULL;
  696. pInfo->result = ER_MEMORYERR;
  697. return FALSE;
  698. }
  699. HWND hWnd = ::GetDesktopWindow();
  700. HDC dc = ::GetDC(hWnd);
  701. if (dwIsAldus == ALDUSKEY) 
  702. {
  703. // 表明该文件是一个可放置元文件,读文件头部的结构。
  704. lpWmfAddInfo->format = 1; // 等于1表示它是可放置元文件
  705. lpWmfAddInfo->inchto = m_aldusMFHeader.inch; // 文件单位到英寸单位的转换因子
  706. lpWmfAddInfo->x1 = m_aldusMFHeader.bbox.left;
  707. lpWmfAddInfo->y1 = m_aldusMFHeader.bbox.top;
  708. lpWmfAddInfo->x2 = m_aldusMFHeader.bbox.right;
  709. lpWmfAddInfo->y2 = m_aldusMFHeader.bbox.bottom;
  710. lpWmfAddInfo->whgene = (float)(((float)lpWmfAddInfo->x2-lpWmfAddInfo->x1)/((float)lpWmfAddInfo->y2-lpWmfAddInfo->y1));
  711. }
  712. else
  713. {
  714. lpWmfAddInfo->format = 0; // 0表示老的Windows元文件
  715. lpWmfAddInfo->inchto = 0;
  716. lpWmfAddInfo->x1 = 0;
  717. lpWmfAddInfo->y1 = 0;
  718. // 此时x1,x2,y1,y2的单位就不是文件单位了,而是像素单位
  719. lpWmfAddInfo->x2 = ::GetDeviceCaps(dc, HORZRES);
  720. lpWmfAddInfo->y2 = ::GetDeviceCaps(dc, VERTRES);
  721. lpWmfAddInfo->whgene = (float)(((float)lpWmfAddInfo->x2-lpWmfAddInfo->x1)/((float)lpWmfAddInfo->y2-lpWmfAddInfo->y1));
  722. }
  723. // 置原始图像信息,此内存块由客户程序负责释放
  724. pInfo->pImgInfo = (void*)lpWmfAddInfo;
  725. ::ReleaseDC(hWnd, dc);
  726. if (pInfo->fpProgress)
  727. {
  728. if ((*pInfo->fpProgress)(RWPROGRESSSIZE, 90))
  729. { // 如果进度函数返回1,则说明用户想中断操作,返回。
  730. ::DeleteEnhMetaFile(*pHEnhMeta);
  731. *pHEnhMeta = NULL;
  732. ::GlobalFree(lpWmfAddInfo);
  733. pInfo->pImgInfo = NULL;
  734. pInfo->result = ER_USERBREAK;
  735. return FALSE;
  736. }
  737. }
  738. return TRUE;
  739. }