不太懂分類檢索的人可以參考 此網頁 中的資訊.
開發工具與環境:
- iTextSharp: Java 最常用於操作 PDF 的套件是 iText, 此套件也有 .Net 版, 叫做 iTextSharp. ( 下載點)
因為 iTextSharp 的功能跟 Java 版的 iText 大同小異, 所以文件的部分可參考 iText 的 document. (online版) - Visual Studio 2008
- XMP: 請參考 Adobe 的 網頁說明.
- 下載 iTextSharp 並解壓縮後, 會有一個 itextsharp.dll 檔, 記得在專案中將此 dll 加入參考.
因為本文所用到的類別與函式並不多, 所以只需要 using 以下的命名空間:using System; using System.IO; using System.Text; using System.Xml; using iTextSharp.text.pdf; using iTextSharp.text.xml.xmp;
- 首先是讀取 pdf 中的 XMP 資訊:
- 使用 PdfReader 這個類別.
- 轉換後的字串可以利用 XmlDocument 做其他利用.
- 若要對 XmlDocument 做進一步的查詢, 可參考 此篇 做 XmlNamespaceManager 的初始設定.
- 需注意有可能無法取得 pdf 中的 XMP 資訊, 此時的 Metadata 會是 null.
PdfReader pdfSourceReader = new PdfReader(@"c:\source.pdf"); XmlDocument docSource = new XmlDocument(); if (pdfSourceReader.Metadata != null) { //用UTF-8編碼, 以避免XML的亂碼 string strMetadata = Encoding.UTF8.GetString(pdfSourceReader.Metadata); //載入至XmlDocument docSource.LoadXml(strMetadata); }
- 將 XMP 資訊寫入至 pdf 檔中:
- 使用 PdfStamper 這個類別, 做 pdf 檔的複製.
- 由於分類檢索主要是 Dublin Code 的資訊, 所以利用 iTextSharp 的 DublinCoreSchema 類別進行設定.
- 利用 XmpWriter 這個類別包裝新的 XMP 資訊.
- 若要對 XmlDocument 做進一步的查詢, 又不太知道 xmlns 的設定值為何, 可參考 此篇 做 XmlNamespaceManager 的初始設定.
我在這部分寫了一個 GetNs() 函式來處理, 如下:public static XmlNamespaceManager GetNs(XmlDocument doc) { XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); XmlNodeList lstNodes = doc.SelectNodes("//child::*"); foreach (XmlNode node in lstNodes) { foreach (XmlAttribute attr in node.Attributes) { if (attr.Prefix.Equals("xmlns")) { if (!mgr.HasNamespace(attr.LocalName)) { mgr.AddNamespace(attr.LocalName, attr.Value); } } } } return mgr; }
- 要從 XmlDocumentA 複製一個 XmlNode 到 XmlDocumentB, 可參考 此網頁 的說明.
//建立一個設定分類檢索資訊的DublinCoreSchema物件 DublinCoreSchema dcSchema = new DublinCoreSchema(); dcSchema.SetProperty(DublinCoreSchema.TITLE, new LangAlt("RSS 詮釋資料基準範例")); dcSchema.SetProperty(DublinCoreSchema.CREATOR, new LangAlt("行政院研究發展考核委員會")); dcSchema.SetProperty(DublinCoreSchema.SUBJECT, new LangAlt("RSS 詮釋資料基準範例")); dcSchema.SetProperty(DublinCoreSchema.DESCRIPTION, new LangAlt("RSS 詮釋資料基準範例")); dcSchema.SetProperty(DublinCoreSchema.CONTRIBUTOR, new LangAlt("行政院研究發展考核委員會")); dcSchema.SetProperty(DublinCoreSchema.TYPE, new LangAlt("text/pdf")); dcSchema.SetProperty(DublinCoreSchema.FORMAT, new LangAlt("pdf")); dcSchema.SetProperty(DublinCoreSchema.SOURCE, new LangAlt("行政院研究發展考核委員會")); dcSchema.SetProperty(DublinCoreSchema.LANGUAGE, new LangAlt("中文")); dcSchema.SetProperty(DublinCoreSchema.COVERAGE, new LangAlt("2009-03-31~2015-12-20")); dcSchema.SetProperty(DublinCoreSchema.PUBLISHER, new LangAlt("行政院研究發展考核委員會")); dcSchema.SetProperty(DublinCoreSchema.DATE, new LangAlt("2009-03-31T15:49:18+08:00")); dcSchema.SetProperty(DublinCoreSchema.IDENTIFIER, new LangAlt("341000000A")); dcSchema.SetProperty(DublinCoreSchema.RIGHTS, new LangAlt("行政院研究發展考核委員會")); dcSchema.SetProperty("Category.Theme", new LangAlt("000")); dcSchema.SetProperty("Category.Cake", new LangAlt("000")); dcSchema.SetProperty("Category.Service", new LangAlt("I60")); //建立一個存放最後要輸出的XmlDocument物件 XmlDocument docTarget = new XmlDocument(); //利用MemoryStream做XmpWriter的輸出Stream using (MemoryStream ms = new MemoryStream()) { XmpWriter xmpWriter = new XmpWriter(ms); //將存放分類檢索資訊的DublinCoreSchema透過XmpWriter輸出到Stream xmpWriter.AddRdfDescription(dcSchema); //最後記得要呼叫Close(), 不然XMP的資訊會不完整 xmpWriter.Close(); //將XMP的資訊載入至欲輸出的XmlDocument docTarget.LoadXml(Encoding.UTF8.GetString(ms.ToArray())); } //如果要把原始pdf中的XMP資訊也append到新的pdf檔中, 可參考以下的Code: //---------- Import Start ---------- //設定原始XMP中的NamespaceManager XmlNamespaceManager mgrSource = GetNs(docSource); //取得原始XMP的<rdf:RDF> XmlNode nodeSourceRdf = docSource.SelectSingleNode("//rdf:RDF", mgrSource); //設定新XMP中的NamespaceManager XmlNamespaceManager mgrTarget = GetNs(docTarget); //取得新XMP的<rdf:RDF> XmlNode nodeTargetRdf = docTarget.SelectSingleNode("//rdf:RDF", mgrTarget); //如果有原始的XMP資訊,開始進行<rdf:Description>的複製 if (nodeSourceRdf != null) { foreach (XmlNode nodeDesc in nodeSourceRdf.ChildNodes) { nodeTargetRdf.AppendChild(nodeTargetRdf.OwnerDocument.ImportNode(nodeDesc, true)); } } //---------- Import End ---------- //設定要輸出的pdf.(第一個參數是讀取原始pdf檔的PdfReader物件) PdfStamper pdfStamper = new PdfStamper(pdfSourceReader, new FileStream(@"c:\stamped.pdf", FileMode.OpenOrCreate, FileAccess.Write)); //將新的XMP資訊設定至欲輸出的pdf檔 pdfStamper.XmpMetadata = Encoding.UTF8.GetBytes(docTarget.OuterXml); //呼叫Close(), 以完成pdf檔的輸出(複製)程序 pdfStamper.Close();
因此建議程式開發過程中要多一點錯誤判斷 (ex: try…catch), 以避免程式出錯或當掉.
補充: 網路上還有一套可讀寫 XMP 的套件 (C# XMP Toolkit), 有興趣的也可以試試.
沒有留言:
張貼留言