在数字化办公日益普及的今天,无纸化办公成为了提高工作效率和节省资源的有效途径。本文将介绍如何利用Microsoft Office软件,特别是Office 2003和Office 2007版本,实现文档的扫描、OCR识别、多TIFF文件处理以及Outlook邮件导出等功能,从而构建一个高效的无纸化办公环境。
在开始之前,需要确保计算机上安装了Office 2003或Office 2007,因为这些功能需要MODI库的支持。Office XP版本不包含MODI,无法实现这些功能。此外,为了实现邮件导出功能,还需要安装MS Outlook 2003或MS Outlook 2007。
应用程序的界面与Microsoft Imaging Viewer相似,但增加了邮件导出功能,使得文档存储更加便捷。从技术角度来看,应用程序基于MODI、TWAIN和Outlook-Interop三种技术。这些技术的整合需要进行一些修改和增强,本文将详细介绍这些过程。
作者选择了TWAIN支持而不是现代的WIA标准,因为作者拥有的扫描仪仅支持TWAIN。基于优秀的代码示例,作者创建了TwainControl来封装扫描功能。与控件的交互通过三个方法和一个事件来实现。
twainControl1.Init(this.Handle);
twainControl1.Release();
TWAIN库提供了一个设备选择对话框,可以通过调用以下方法显示:
twainControl1.SelectDevice();
开始扫描的方法有两个参数,UI和modal。设置UI为false可以不显示扫描仪的配置对话框,modal标志控制扫描对话框的模态状态。
twainControl1.StartScanning(UI, modal);
扫描完成后,会触发FinishScanning事件,主应用程序作为监听器。
private void twainControl1_FinishScanning(object sender, Util.TwainLib.FinishScanningEventArgs e)
{
if (e.scanned)
{
ArrayList images = twainControl1.PopImages();
AppendScannedImages(images);
SaveFile();
}
}
如果想通过按下扫描仪硬件按钮来打开应用程序,可以添加应用程序路径到注册表。注册表键在HKEY_LOCAL_MACHINE下,键值为:
Software\Microsoft\Windows\CurrentVersion\StillImage\Registered Applications
键值应该是:
[Path\]MartinsPaperlessDesktop.exe /StiDevice:%1 /StiEvent:%2
第一版包含了作者自己编写的TIFF处理代码,但通过整合MODI库,处理多TIFF文件变得非常简单和快速。
一个有价值的功能是'append'功能,它将页面添加到多TIFF文档中。如果扫描设备仅支持单页扫描,这可能会很有帮助。
private void AppendImage(string source)
{
if (_MODIDocument == null)
return;
try
{
MODI.Document document = new MODI.Document();
document.Create(source);
_changed = true;
// iterate through all image pages of the source document
for (int i = 0; i < document.Images.Count; i++)
{
_MODIDocument.Images.Add(document.Images[i], null);
}
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
SetImage("", false);
}
}
如果在扫描过程中顺序混乱,可以移动文档中的单页,以获得想要的顺序。
private void MoveImage(int pageNumber, bool up)
{
if (_MODIDocument == null)
return;
MODI.Image img = (MODI.Image)_MODIDocument.Images[pageNumber];
if (up)
{
if (pageNumber - 1 >= 0)
{
MODI.Image prevImg = (MODI.Image)_MODIDocument.Images[pageNumber - 1];
// the add method needs the "beforeImage" as second argument
_MODIDocument.Images.Add(img, prevImg);
MODI.Image removeImg = (MODI.Image)_MODIDocument.Images[pageNumber + 1];
_MODIDocument.Images.Remove(removeImg);
axMiDocView1.PageNum = pageNumber - 1;
}
}
else
{
if (pageNumber + 1 < axMiDocView1.NumPages)
{
MODI.Image nextImg = null;
if (pageNumber + 2 < _MODIDocument.Images.Count)
{
nextImg = (MODI.Image)_MODIDocument.Images[pageNumber + 2];
}
// if the second argument is NULL,
// the page is appended at the end of the image
_MODIDocument.Images.Add(img, nextImg);
MODI.Image removeImg = (MODI.Image)_MODIDocument.Images[pageNumber];
_MODIDocument.Images.Remove(removeImg);
axMiDocView1.PageNum = pageNumber + 1;
}
}
// this action causes a change notification
_changed = true;
ShowStatus();
}
布局处理的主要目标是保持原始文档的布局。OCR来自MODI.Document.OCR()方法。作者使用了文档模型从Document Processing Part II来获得比MODI提供的更好的布局序列化。由于将导出文档的文本到基于HTML的电子邮件,进行了非常基础的HTML转换。
private string GetDocumentText()
{
Model.Document doc = Model.Document.CreateByMODI(_MODIDocument);
string c = doc.GetText();
// very trivial converting to HTML
c = c.Replace("\r\n", "<\br\>");
return c;
}
现在,工作都完成了,导出变得非常简单。源代码位于DocumentMailer类中。构造方法打开与MSOutlook的连接。
private Microsoft.Office.Interop.Outlook.Application oApp;
private Microsoft.Office.Interop.Outlook._NameSpace oNameSpace;
private Microsoft.Office.Interop.Outlook.MAPIFolder oOutboxFolder;
public DocumentMailer()
{
oApp = new Outlook.Application();
oNameSpace = oApp.GetNamespace("MAPI");
oNameSpace.Logon(null, null, true, true);
oOutboxFolder = oNameSpace.GetDefaultFolder(OlDefaultFolders.olFolderOutbox);
}
打开Outlook连接后,AddToOutBox方法完成了所有工作。
Outlook._MailItem oMailItem = (Outlook._MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMailItem.To = toValue;
oMailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
oMailItem.Subject = subjectValue;
oMailItem.HTMLBody = bodyValue;
oMailItem.SaveSentMessageFolder = oOutboxFolder;
// .. attachments
oMailItem.Save();
oMailItem.Display(null);
为了避免每次都选择个人设置,作者添加了一个小配置类。代码位于一个实例的Configuration中,该实例在初始化期间加载。
public static Configuration LoadFromFile(string path)
{
IFormatter formatter = new BinaryFormatter();
Stream streamS = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
object o = formatter.Deserialize(streamS);
Configuration solution = (Configuration)o;
streamS.Close();
return solution;
}
public bool SaveToFile(string path)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, this);
stream.Close();
return true;
}
在所有这些技术内容之后,可以稍微分心一下。偶然间,作者设计了一个令人着迷的过程导向的冒险。
玩家:
游戏说明: