[转老马的文章]MODI中的OCR模块
作者:马健
邮箱:stronghorse_mj@hotmail.com
发布:2012.07.02
更新:
2012.07.09
补充非简体中文版内容
自从基于MODI的DjVuToy、FreePic2Pdf、Pdg2Pic发布后,很多人就在问同一个问题:能不能在不装Office 2003/2007或SharePoint Designer 2007的情况下,让基于MODI的软件正常OCR?毕竟对于简体中文来说,就算只装SharePoint Designer 2007中的MODI,也要近650 MB,装Office 2007的MODI则更夸张,要近1 GB。
想解决这个问题,需要从MODI中OCR模块的来历说起。在《用MODI OCR 21种语言》一文中已经说过,MODI其实只是封装了ScanSoft API,而google(注意我说的是google,不是baidu)一下关键词“ScanSoft API”,可以发现两个网页:
http://www.corrupteddatarecovery.com/Products/ScanSoft-API.asp
http://www.corrupteddatarecovery.com/Products/Asian-OCR-for-ScanSoft-API.asp
从这两个帖子及其他一些相关信息推断,ScanSoft API封装了清华文通以支持亚洲语言,而MODI又在ScanSoft API上封装出MODI接口,并在此基础上提供MODI应用(MSPVIEW.EXE),整个层次结构应该如下图所示:
—————— MSPVIEW.EXE
应用层 ┃
—————— MODI接口
接口层 ┃
ScanSoft API
┏━━━━━┻━━━━━┓
┃ ScanSoft API亚洲语言支持(清华文通)
—————— ┃ ┃
数据层 西欧11国、东欧3国、 亚洲语言文件
俄、希、土语言文件 (简、繁、日、朝)
从上图看,如果只想调用MODI接口,不需要应用层的支持,可以有以下选择:
- 直接调用ScanSoft API。这个比较有难度,至少我到目前为止还找不到相关文档。
- 还是调用MODI接口,至少这个的文档是公开的。
所以上面的问题就转换成了:能否抽取出支持MODI接口的最小集合,实现OCR接口功能?
身为资深技术人员,对于这种问题的回答当然不能胡言乱语,而应该以实验为基础:
1、搞一个干净的XP SP3虚拟机,再复制一份,姑且命名为“虚拟机A”、“虚拟机B”。
2、在虚拟机A中安装InstallRite 2.5,用它监视安装SharePoint Designer 2007中的MODI。
3、安装完成后,用InstallRite导出安装后新的注册表,命名为aaa.reg。
4、将虚拟机A中的两个文件夹
C:\Program Files\Common Files\Microsoft Shared\MODI
C:\Program Files\Common Files\Microsoft Shared\OFFICE12
复制到虚拟机B,并将aaa.reg导入虚拟机B。毕竟MODI接口是COM接口,与注册表无关的COM接口是不存在的。
5、运行DjVuToy、FreePic2Pdf或Pdg2Pic,可以验证在虚拟机B中能够用第三方软件正常OCR,只不过每OCR一页都要自动安装一次文件,似乎注册表中掺入了垃圾。
以上可行性实验清楚表明:
1、在不安装Office或SharePoint Designer的情况下,可以通过复制相关文件和注册表项,为第三方软件提供OCR支持。
2、对于简体中文来说,单独安装Office 2007中的MODI需要约1 GB硬盘空间,单独安装SharePoint Designer 2007中的MODI则需约650 MB,而上面两个文件夹加起来也只有约76 MB,何况中间还有水分可挤,空间的节省还是很可观的,所以这笔买卖做得过。
无聊但又必不可少的理论扯完了,下面开始进入实战:哪些文件和注册表项才是必不可少的?
先说文件。上面两个URL中的内容,其实已经说明了接口层中ScanSoft API所需的文件,剩下需要解决的就是MODI接口部分的文件。
在第三方软件中调用MODI接口的初始化代码为:
IDocument doc;
doc.CreateDispatch(_T("MODI.Document"));
在注册表中搜索字符串“MODI.Document”,可以知道此COM对象对应的DLL是MODI安装文件夹下的MDIVWCTL.DLL。再看一眼VC++的Debug窗口,可以知道在调用此DLL后,还接着调用了同文件夹下的MSPGIMME.DLL、MSPCORE.DLL,及OFFICE12文件夹下的MSO.DLL等。从文件属性看,这些文件都是微软鼓捣出来的,因此可以认为是接口层中MODI接口部分的东西。
从VC++的Debug窗口输出信息看,除了上述DLL文件外,OCR过程中还加载了MODI安装文件夹下的XOCR3.PSP、THOCR.PSP、XFILE.PSP。这3个文件虽然扩展名是PSP,但其实是DLL文件,从文件属性看属于ScanSoft API的范畴,可以看作是对上面两个URL中内容的补充。
另外VC++的Debug窗口中还记录到OCR过程调用了OFFICE12文件夹下的OGL.DLL、MSORES.DLL、2052\MSOINTL.DLL,但在后来的回归性测试中证明,在对注册表项进行简化后,这几个文件没有也没关系。
结合上面分析,及《用MODI OCR 21种语言》中的相关信息,可知要OCR简体中文、英语,至少需要的文件如下表所示,加一起也就约30 MB。其中“说明”部分的英文是从DLL文件的文件属性中复制过来的,中文是我自己加的;数据层的数据文件是用文件监视器抓取的。
层次 | 文件名 | 说明 | |
接口层 | MODI | MDIVWCTL.DLL | Microsoft Office Document Imaging Viewer Control |
MSPCORE.DLL | Microsoft® Office Document Imaging Object Library | ||
MSPGIMME.DLL | Microsoft® Gimme library | ||
OFFICE12\MSO.DLL | 2007 Microsoft Office component | ||
ScanSpft API |
BINDER.DLL | XDoc Binder module for the ScanSoft SDK | |
PSOM.DLL | Component Management Module for PefectScan API | ||
XIMAGE3B.DLL | Image Processing Module for the ScanSoft SDK | ||
XPAGE3C.DLL | Page Management Module for ScanSoft SDK | ||
XOCR3.PSP | OCR Module for ScanSoft SDK | ||
XFILE.PSP | Asian OCR Module for ScanSoft SDK | ||
THOCR.PSP | Asian OCR Module for ScanSoft SDK | ||
ScanSoft API亚洲 语言 |
FORM.DLL | Table Recognition for Asian OCR | |
REVERSE.DLL | Reverse Video Detection for Asian OCR | ||
THOCRAPI.DLL | Asian OCR API | ||
TWCUTCHR.DLL | Character Segmentation for Asian OCR | ||
TWCUTLIN.DLL | Line Segmentation for Asian OCR | ||
TWLAY32.DLL | Layout Analysis for Asian OCR | ||
TWORIENT.DLL | Orientataion Detection for Asian OCR | ||
TWRECC.DLL | Chinese Recognition for Asian OCR | ||
TWRECE.DLL | English Recognition for Asian OCR | ||
TWRECS.DLL | Punctuation Recognition for Asian OCR | ||
TWSTRUCT.DLL | Document Structure Processing for Asian OCR | ||
数据层 | 英文 | LATIN1.SHP | 西欧11国(含英文)通用特征库 |
CharSetTable.chr | 字符编码转换表,文本文件 | ||
ENGLISH.LNG | 英文语言文件 | ||
简体中文 | ENGDIC.DAT | 清华文通的英文字典文件,貌似它也支持中、英文 | |
ENGIDX.DAT | 清华文通的英文索引 | ||
JFONT.DAT | |||
LOOKUP.DAT | |||
OCRHC.DAT | |||
OCRVC.DAT | |||
TWGB32.DLL | Simplified Chinese code Conversion | ||
SCCODE.UNI | |||
SCPRINT.DAT | |||
SCPRINT2.DAT | |||
SCSERHT.DAT | |||
SCTREE.DAT | |||
TW_GU.DAT | |||
TW_UG.DAT |
如果还想增加对其他语言的OCR能力,可以参阅《用MODI OCR 21种语言》,增加相关语言对应的文件。
另外在上表中,在PSOM.DLL文件描述中出现了一个新的名字:PefectScan API。google了一下,找到其官网http://perfectscan.com/,从介绍上看是做图像处理的:
PerfectScan is an image processing program that automatically analyzes an image, then makes adjustments to that image rendering a black and white image that contains all viewable data as if it were a gray scale scan, only at 15% of the size of a gray scale image.
看来MODI还真是一个大杂烩。不过PefectScan官网上的一句话,感觉道尽了程序员的悲凉:
We built the software after 10 years of hard work, now all we have to do is build the website...OOPS!!
言归正传。搞定文件后,还需要搞定注册表项才行。与MODI相关的注册表项包括两个部分:COM相关与Office相关。
COM相关就是与MODI的COM组件相关的注册表项,这个直接用regsvr32导入即可:启动命令行,进入MODI安装文件夹,执行下面的命令:
regsvr32 MDIVWCTL.DLL
regsvr32 MSPCORE.DLL
即可完成MODI COM组件的注册。
但与Office相关的注册表项就没那么好搞定了。我曾经试过用注册表监视器对OCR过程进行监视,结果发现真相淹没在了细节的海洋里。最终不得不采用了一个笨办法:专门写了一套测试软件,在前面的可行性实验中搭建的虚拟机B里猛跑,逐一尝试删除从aaa.reg中导入的注册表项,每删除一项就检查一下对OCR会不会造成影响。最终试出来约20个注册表项是必不可少的,其中近一半与前面用regsvr32注册COM组件时自动插入的注册表项重复。
最终经过手工调整后,确认在上面表格所列文件及COM注册基础上,再增加下列注册表项即可正常用第三方软件在简体中文环境下OCR简体中文、英文:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"2052"=hex(7):76,00,55,00,70,00,41,00,56,00,53,00,2e,00,7d,00,58,00,25,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,32,00,30,00,35,00,32,00,3c,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F10040800000000000F01FEC]
"OCR_2052"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F10040800000000000F01FEC\Features]
"OCR_2052"="%mEMae,7q9*DXdU@EPi="
[HKEY_CLASSES_ROOT\Installer\Products\00002109710000000000000000F01FEC]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\3F745FF6A76FF2F4797DB74FC7B3FD8B]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\XPAGE3C.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\4080B9FA1A0BBF34FB7813E87159FC64]
"00002109F10040800000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\SCCODE.UNI"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\48AD0082D02B3D24C9A56FA50728CCAB]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\MSPCORE.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\D94C8360B8BB1DC41B1950E0F8237563]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109710000000000000000F01FEC\InstallProperties]
"WindowsInstaller"=dword:00000001
前三项的语言编码2052对应简体中文,但只要文件不缺,OCR中文、英文或其他语言都没有问题。不过在面对其他国家的用户时,解释采用简体中文的语言编码还是有点费劲,所以仍然需要继续尝试其他语言编码。
把两个虚拟机复原,重复上面可行性实验步骤:在虚拟机A中监视安装英文版SharePoint Designer 2007(安装后支持英、法、西班牙语),导出安装后的注册表和文件到虚拟机B,用同一套测试软件进行检查,出来的是不是与英文语言编码1033相关的注册表项呢?错,大错特错,跑出来不能删的是与法语(语言编码1036)相关的注册表项:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"1036"=hex(7):76,00,55,00,70,00,41,00,56,00,57,00,3f,00,57,00,41,00,24,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,31,00,30,00,33,00,36,00,3c,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F100C0400000000000F01FEC]
"OCR_1036"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F100C0400000000000F01FEC\Features]
"OCR_1036"=")aEMae,7q9*DXdU@EPi="
[HKEY_CLASSES_ROOT\Installer\Products\00002109710000000000000000F01FEC]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\3F745FF6A76FF2F4797DB74FC7B3FD8B]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\XPAGE3C.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\48AD0082D02B3D24C9A56FA50728CCAB]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\MSPCORE.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\C040B9FA1A0BBF34FB7813E87159FC64]
"00002109F100C0400000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\FRENCH.LNG"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\D94C8360B8BB1DC41B1950E0F8237563]
"00002109710000000000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109710000000000000000F01FEC\InstallProperties]
"WindowsInstaller"=dword:00000001
对比两个结果,可以看出:
- 与语言相关的注册表项共4项,其他注册表项都是相同的。
- 与语言相关的注册表项前3项直接用语言编码标识,第4项用语言文件标识,简体中文的文件是SCCODE.UNI,法语是FRENCH.LNG。
- 与语言相关的注册表项键值不是随便乱起的,是在产品基本键值(SharePoint Designer的基本键值是00002109710000000000000000F01FEC)的基础上,叠加相关语言编码(简体中文语言编码2052,十六进制0804,Intel表示为0408;法语语言编码1036,Intel表示为0C04)。敢这么玩GUID的我就见过这么一个,别人似乎都没这胆子。
- 不管采用什么语言,都可以只有一种语言,但这种语言不能是英语(语言编码1033)。
为了验证第4点,我从虚拟机A中手工导出英语相关注册表项,在虚拟机B中把与法语相关的注册表项全部换成英语的,结果OCR失败。与英语相关的4个注册表项为:
[HKEY_CLASSES_ROOT\Installer\Components\61BA386016BD0C340BBEAC273D84FD5F]
"1033"=hex(7):76,00,55,00,70,00,41,00,56,00,54,00,28,00,38,00,41,00,24,00,21,\
00,21,00,21,00,21,00,21,00,4d,00,4b,00,4b,00,53,00,6b,00,4f,00,43,00,52,00,\
5f,00,31,00,30,00,33,00,33,00,3e,00,26,00,61,00,45,00,4d,00,61,00,65,00,2c,\
00,37,00,71,00,39,00,2a,00,44,00,58,00,64,00,55,00,40,00,45,00,50,00,69,00,\
3d,00,00,00,00,00
[HKEY_CLASSES_ROOT\Installer\Features\00002109F10090400000000000F01FEC]
"OCR_1033"=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\00002109F10090400000000000F01FEC\Features]
"OCR_1033"="&aEMae,7q9*DXdU@EPi=OFu[`t.WO9zoh+x^{BHE"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\9040B9FA1A0BBF34FB7813E87159FC64]
"00002109F10090400000000000F01FEC"="C:\\Program Files\\Common Files\\Microsoft Shared\\MODI\\12.0\\ENGLISH.LNG"
因此对于国内的用户,直接上简体中文的注册表项就好;对于国外的用户,如果对简体中文解释起来比较麻烦,就上法语或其他语言的注册表项吧 。但注意一次只能上一种语言,而且不能是英语。如果在上了一种语言的注册表项的基础上,再画蛇添足上英语的注册表项,会有问题:由于前面对文件和注册表项进行了精简,在OCR时MODI组件如果发现有英文的注册表项, 就会尝试恢复被精简的文件,造成OCR速度缓慢。
当然不论是哪一种语言,在导入x64 Windows时,都要注意x64下32位软件对应的Program Files文件夹多了一个后缀,改叫Program Files (x86)了。另外在理论上Program Files文件夹也是可以不在C盘上的,所以最保险的方法是通过环境变量CommonProgramFiles、CommonProgramFiles(x86),或SHGetFolderPath等SDK函数获取实际文件夹名称。
另外一个容易被问到的问题是:貌似导入的注册表项中包含了文件路径,那么能不能通过改注册表项的方法,改变MODI的安装路径,不装到CommonProgramFiles文件夹下?答案是:不行。事实上,InstallRite 2.5导出的aaa.reg文件中的原始注册表项里,路径名中是含有非法字符(问号)的,但并不影响使用,所以我怀疑文件夹是被写死在MODI代码里的。
总之,上面说的都是在没有安装Office 2003/2007的情况下的不得已方法,如果已经装了,不仅节省不了多少空间,而且可能会出现文件或注册表项的冲突。
(完)