使用OneNote的COM組件,實現OCR功能。,onenoteocr
背景
在業務系統開發的過程中,很多情況下會去識別圖片中的相關信息,並且把信息錄入到系統中。現在希望通過自動化的方式錄入,就有了以下的工作。在對比了幾個OCR軟件在中文識別方面的准確率後,決定使用微軟的OneNote開發相應的功能。
准備工作
代碼實現的邏輯
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012017230332.gif)
![]()
1 public class OrcImage
2 {
3 private static readonly string tmpPath = AppDomain.CurrentDomain.BaseDirectory + "tmpPath/";
4 private static readonly int waitTime = Convert.ToInt32(ConfigurationManager.AppSettings["WaitTime"]);
5
6 private Tuple<string, int, int> GetBase64(string strImgPath)
7 {
8 return GetBase64(new FileInfo(strImgPath));
9 }
10
11 /// <summary>
12 /// 獲取圖片的Base64編碼
13 /// </summary>
14 /// <param name="file"></param>
15 /// <returns></returns>
16 private Tuple<string, int, int> GetBase64(FileInfo file)
17 {
18 using (MemoryStream ms = new MemoryStream())
19 {
20 Bitmap bp = new Bitmap(file.FullName);
21 switch (file.Extension.ToLower())
22 {
23 case ".jpg":
24 bp.Save(ms, ImageFormat.Jpeg);
25 break;
26
27 case ".jpeg":
28 bp.Save(ms, ImageFormat.Jpeg);
29 break;
30
31 case ".gif":
32 bp.Save(ms, ImageFormat.Gif);
33 break;
34
35 case ".bmp":
36 bp.Save(ms, ImageFormat.Bmp);
37 break;
38
39 case ".tiff":
40 bp.Save(ms, ImageFormat.Tiff);
41 break;
42
43 case ".png":
44 bp.Save(ms, ImageFormat.Png);
45 break;
46
47 case ".emf":
48 bp.Save(ms, ImageFormat.Emf);
49 break;
50
51 default:
52 return new Tuple<string, int, int>("不支持的圖片格式。", 0, 0);
53 }
54 byte[] buffer = ms.GetBuffer();
55 return new Tuple<string, int, int>(Convert.ToBase64String(buffer), bp.Width, bp.Height);
56 }
57 }
58
59 public string Orc_Img(FileInfo fi)
60 {
61 // 向Onenote2010中插入圖片
62 var onenoteApp = new Microsoft.Office.Interop.OneNote.Application(); //onenote提供的API
63 /***************************************************************************************/
64 string sectionID;
65 onenoteApp.OpenHierarchy(tmpPath + "newfile.one", null, out sectionID, CreateFileType.cftSection);
66 string pageID = "{A975EE72-19C3-4C80-9C0E-EDA576DAB5C6}{1}{B0}"; // 格式 {guid}{tab}{??}
67 onenoteApp.CreateNewPage(sectionID, out pageID, NewPageStyle.npsBlankPageNoTitle);
68 /********************************************************************************/
69 string notebookXml;
70 onenoteApp.GetHierarchy(null, HierarchyScope.hsPages, out notebookXml);
71 var doc = XDocument.Parse(notebookXml);
72 var ns = doc.Root.Name.Namespace;
73 var pageNode = doc.Descendants(ns + "Page").FirstOrDefault();
74 var existingPageId = pageNode.Attribute("ID").Value;
75 if (pageNode != null)
76 {
77 Tuple<string, int, int> imgInfo = this.GetBase64(fi);
78 var page = new XDocument(new XElement(ns + "Page",
79 new XElement(ns + "Outline",
80 new XElement(ns + "OEChildren",
81 new XElement(ns + "OE",
82 new XElement(ns + "Image",
83 new XAttribute("format", fi.Extension.Remove(0, 1)), new XAttribute("originalPageNumber", "0"),
84 new XElement(ns + "Position",
85 new XAttribute("x", "0"), new XAttribute("y", "0"), new XAttribute("z", "0")),
86 new XElement(ns + "Size",
87 new XAttribute("width", imgInfo.Item2), new XAttribute("height", imgInfo.Item3)),
88 new XElement(ns + "Data", imgInfo.Item1)))))));
89 page.Root.SetAttributeValue("ID", existingPageId);
90
91 onenoteApp.UpdatePageContent(page.ToString(), DateTime.MinValue);
92
93 // 線程休眠時間,單位毫秒,若圖片很大,則延長休眠時間,保證Onenote OCR完畢
94 int fileSize = Convert.ToInt32(fi.Length / 1024 / 1024); // 文件大小 單位M
95 System.Threading.Thread.Sleep(waitTime * (fileSize > 1 ? fileSize : 1)); // 小於1M的都默認1M
96
97 string pageXml;
98 onenoteApp.GetPageContent(existingPageId, out pageXml, PageInfo.piBinaryData);
99
100 /*********************************************************************************/
101
102 XmlDocument xmlDoc = new XmlDocument();
103 xmlDoc.LoadXml(pageXml);
104 XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
105 nsmgr.AddNamespace("one", ns.ToString());
106
107 XmlNode xmlNode = xmlDoc.SelectSingleNode("//one:Image//one:OCRText", nsmgr);
108 string strRet = xmlNode.InnerText;
109
110 /**********************************************************************/
111
112 onenoteApp.DeleteHierarchy(sectionID, DateTime.MinValue, true); // 摧毀原始頁面
113
114 return strRet;
115 }
116
117 return "沒有識別";
118 }
119 }
View Code
XML的格式
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012017230332.gif)
![]()
1 /*Onenote 2010 中圖片的XML格式
2 <one:Image format="" originalPageNumber="0" lastModifiedTime="" objectID="">
3 <one:Position x="" y="" z=""/>
4 <one:Size width="" height=""/>
5 <one:Data>Base64</one:Data>
6
7 //以下標簽由Onenote 2010自動生成,不要在程序中處理,目標是獲取OCRText中的內容。
8 <one:OCRData lang="en-US">
9 <one:OCRText>
10 <![CDATA[ OCR後的文字 ]]>
11 </one:OCRText>
12 <one:OCRToken startPos="0" region="0" line="0" x="4.251968383789062" y="3.685039281845092" width="31.18110275268555" height="7.370078563690185"/>
13 <one:OCRToken startPos="7" region="0" line="0" x="39.40157318115234" y="3.685039281845092" width="13.32283401489258" height="8.78740119934082"/>
14 <one:OCRToken startPos="12" region="0" line="1" x="4.251968383789062" y="17.85826683044434" width="23.52755928039551" height="6.803150177001953"/>
15 <one:OCRToken startPos="18" region="0" line="1" x="32.031494140625" y="17.85826683044434" width="41.10236358642578" height="6.803150177001953"/>
16 <one:OCRToken startPos="28" region="0" line="1" x="77.66928863525391" y="17.85826683044434" width="31.46456718444824" height="6.803150177001953"/>
17 ................
18 </one:Image>
19 */
20
21 /*ObjectID格式
22 The representation of an object to be used for identification of objects on a page. Not unique through OneNote, but unique on the page and the hierarchy.
23 <xsd:simpleType name="ObjectID" ">
24 <xsd:restriction base="xsd:string">
25 <xsd:pattern value="\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\}\{[0-9]+\}\{[A-Z][0-9]+\}" />
26 </xsd:restriction>
27 </xsd:simpleType>
28 */
View Code
目前是桌面應用程序是實現了相關功能。預期期望是:任何一個系統通過webservice接口形式就能使用OCR功能。但是改成一個web程序遇到了問題,在網上找了僅有的一點點資料,也沒有解決。我了解到,現在使用OneNote的OCR功能的程序也都是用WinForm程序,在程序運行的過程中,會在後台啟動OneNote程序。所以我猜測可能是由於這個原因,導致它只能做成桌面程序。
檢索 COM 類工廠中 CLSID 為 {D7FAC39E-7FF1-49AA-98CF-A1DDD316337E} 的組件失敗,原因是出現以下錯誤: 80070005 拒絕訪問。 (異常來自 HRESULT:0x80070005 (E_ACCESSDENIED))。
web中報這個錯誤,是權限的問題。依照配置Excel,Word這類COM來找,可是發現DCOM中,一直都找不到這個ID的組件。知道的朋友麻煩告知一下,謝謝。
程序效果圖如下:識別效果還不錯,剩下的就是根據所需要的信息,進行正則表達式的匹配就可以了。
![](https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017012017230374.jpg)