office文檔轉換成mht文檔

要實現office文檔轉換成MHTML文檔,首先會將office文檔轉換成HTML格式的文檔,而後將HTML文檔轉換成MHTML文檔。要將 office文檔轉成HTML須要使用Microsoft.HtmlTrans.Interface的程序集。這個程序集須要安裝「HTML 轉換服務器」。HTML 轉換服務器是 Windows SharePoint Services 服務器場的可選組件。你能夠在微軟網站上找到該服務器的安裝文件。按照下面的步驟安裝:

解壓縮下載的文件,裏面有文件:

eng11probypass.mst
htmltrbackend.msi
HTML Viewer WhitePaper文檔

若是已經安裝了office,請先卸載,而後安裝支持HTML Viewer Services的Office:

在Office安裝路徑下,找到Setup文件所在路徑;
將eng11probypass.mst文件拷貝到該路徑下;
在命令提示符下輸入:Setup transforms= eng11probypass.mst來安裝支持HTML Viewer的Office;
安裝HTML Viewer Server:運行htmltrbackend.msi;
安 裝好之後,找到Microsoft.HtmlTrans.Interface.dll文件並把它copy到項目文件夾中。在項目中引用該文件。因爲將用到 命名空間Microsoft.HtmlTrans中的htmlTrLoadBalancer和htmlTrLauncher兩個Romoting對象將 office文檔轉換爲HTML文件。

不過須要注意:

Document types not supported are:
Master documents in Word (see Word Help for an explanation of Master document)
Password protected documents, workbooks, and presentations (encrypted)
Word documents that use framesets
Files that contain Excel 4.0 macros
WordPerfect files
For files with embedded objects, VBA, scripts, etc, the following rules apply:
VBA is ignored and not executed; However, the VBA project (source code, dialog definitions, etc) is retained
Embedded and linked objects are converted to graphic p_w_picpaths and displayed in the approximate location where they were in the source file
Linked or embedded objects with password protection are not converted

   在實現中另一個難點就是如何將HTML轉換成MHTML。MHTML是 MIME Encapsulation of Aggregate HTML的縮寫,它是一種網絡編碼格式,是用來定義在電子郵件正文中如何傳送html內容的MIME標準。通俗點說,就是一個HTML文件和包括其中的. css文件、.js文件、圖片等等一切的資源文件都整合在一個MHTL文件中。如下是一個典型的MHTML文件(;後爲解釋部分):

Mime-Version: 1.0
; Content-Location爲主文件地址,能夠隨意設定
Content-Location: [url]http://www.ietf.cnri.reston.va.us/[/url]
; Content-Type爲MTHML文件的類型,這裏表示MHTML文件中包含多種文件類型
;boundary定義文件之間的分隔符,可隨意定義
;type爲主文件格式
Content-Type: multipart/related; boundary="boundary-example";type="text/html"
;在前面加」--」字符表示一個文件開始
--boundary-example
;如下是文件頭
; text/html 表示該文件的文件類型;charset表示使用的字符集
Content-Type: text/html; charset="ISO-8859-1"
; Content-Transfer-Encoding:表示的是該文件的編碼類型;
;通常有兩種:一種是文本類型的通常使用」QUOTED-PRINTABLE」;
;另外一種是二進制文件通常使用」BASE64」
Content-Transfer-Encoding: QUOTED-PRINTABLE
;如下是正文
... text of the HTML document, which might contain URIs
referencing resources in other body parts, for example through
statements such as:
<IMG SRC="p_w_picpaths/ietflogo1.gif" ALT="IETF logo1">
<IMG SRC="p_w_picpaths/ietflogo2.gif" ALT="IETF logo2">
<IMG SRC="p_w_picpaths/ietflogo3.gif" ALT="IETF logo3">
Example of a copyright sign encoded with Quoted-Printable: =A9
Example of a copyright sign mapped onto HTML markup: ¨
--boundary-example
; Content-Location:該文件的地址,能夠是絕對地址或相對主文件的相對地址
;這裏是絕對地址
Content-Location:[url]http://www.ietf.cnri.reston.va.us/p_w_picpaths/ietflogo1.gif[/url]
Content-Type: IMAGE/GIF
;二進制文件,使用BASE64編碼
Content-Transfer-Encoding: BASE64
R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
etc...
--boundary-example
;這裏是相對地址
Content-Location: p_w_picpaths/ietflogo2.gif
Content-Transfer-Encoding: BASE64
R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
etc...
--boundary-example
Content-Location:[url]http://www.ietf.cnri.reston.va.us/p_w_picpaths/ietflogo3.gif[/url]
Content-Transfer-Encoding: BASE64
R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
etc...
;注意這裏是結束標記,表示MHTML文件已經結束了.在定義的分隔符先後都加上」--」
--boundary-example—

上面是標準的MHTML文件格式,可是按上面的標準是沒法在IE裏面正確瀏覽的。還須要注意如下幾點:

1.凡是文本類型的文件全部的」=」替換成」=3D」,例如

<IMG SRC="p_w_picpaths/ietflogo3.gif" ALT="IETF logo3">
要替換成
<IMG SRC=3D"p_w_picpaths/ietflogo3.gif" ALT=3D"IETF logo3">

2. 全部的BASE64編碼的文件必需要換行;

3. 每一個文件開頭的分隔符要在前加上」--」,而最後一個分隔符要在先後加上」--」;

4. 正文與文件頭和下一個文件的分割符都要有換行符。

  廢話就說這麼說了。接下來仍是看看具體實現的代碼。

  雖然代碼比較多,可是能夠直接編譯使用的代碼。建議copy下來放到工程項目中使用VS.NET來閱讀代碼。也能夠按照上面說的步驟安裝好之後,直接使用該類。若是不能編譯的話,請確實安裝是否成功,是否在工程項目中引用



using System;
using Microsoft.HtmlTrans;
using System.Text;
using System.IO;
using System.Collections;

namespace OfficeDocConvertMHTML
{
   public class Conversion
   {
     // 字符串的編碼
     protected static Encoding encoding = Encoding.Default;
     // 用於建立IHtmlTrLoadBalancerremoting對象的url
     protected static string strServiceUrl = "http://localhost:8093/HtmlTrLoadBalancer";
     public static void ConvertMHT(string inputfile, string outputfile)
     {
       // 經過url(strServiceUrl)獲取一個IHtmlTrLoadBalancerremoting對象
       IHtmlTrLoadBalancer htmlTrLoadBalancer =
          (IHtmlTrLoadBalancer)System.Activator.GetObject(
          typeof(IHtmlTrLoadBalancer),strServiceUrl);
       // 用輸入文件名(inputfile)做爲一個任務的任務標示(strTask)
       string strTask = inputfile;

       // 根據任務標示(strTask)新建一個任務並獲取任務的url(strLauncherUri)
       string strLauncherUri = htmlTrLoadBalancer.StrGetLauncher(strTask);

       // 經過任務的url(strLauncherUri)獲取一個IHtmlTrLauncherremoting對象(htmlTrLauncher),
       // 並用這個對象來執行該任務
       IHtmlTrLauncher htmlTrLauncher =
          (IHtmlTrLauncher)System.Activator.GetObject(typeof(IHtmlTrLauncher),strLauncherUri);

       // 接下來是把輸入文件(inputfile)的內容讀入一個byte數組(bFile)
       byte[] bFile = null;
       FileStream fsInputMht = null;
       BinaryReader bwInputMht = null;
       try
       {
          fsInputMht = new FileStream(inputfile, FileMode.Open);
          bwInputMht = new BinaryReader(fsInputMht, encoding);
          bFile = new byte[fsInputMht.Length];
          for(long i = 0; i < bFile.LongLength; i++)
            bFile[i] = bwInputMht.ReadByte();
          bwInputMht.Close();
          fsInputMht.Close();

       }
       catch(Exception ex)
       {
          bwInputMht.Close();
          fsInputMht.Close();
          throw ex;
       }

       //CHICreateHtml 經過office文檔建立HTML文件及其附件
       //CHICreateHtml(
       //string strLauncherUri,         任務的url
        //byte[] rgbFile,             office 文檔的二進制內容
       //Microsoft.HtmlTrans.BrowserType bt, 使用瀏覽類型,該參數是一個枚舉類型
       //string strReqFile,           office 文檔的路徑/url
       //string strTaskName,           任務標示名,HTML轉換服務器根據其跟蹤該請求
       //int timeout,                 轉換超時時間,若是網絡情況較差,建議值設大點
       //bool fReturnFileBits          是否返回二進制內容,分別保存在CreateHtmlInforgbMainFile屬性和rgrgbThicketFiles屬性中
       //);
       CreateHtmlInfo chi = htmlTrLauncher.CHICreateHtml(strLauncherUri, bFile,
          BrowserType.BT_IE4, inputfile, strTask, 120, true);

       // 結束轉換任務
       htmlTrLoadBalancer.LauncherTaskCompleted(strLauncherUri, strTask);

       // 在轉換HTML文件的過程當中沒有錯誤,而且存在主文件,執行如下代碼
       if(chi.ce == CreationErrorType.CE_NONE && chi.fHasMainFile)
       {
          FileStream fsOutputMht = null;
          BinaryWriter bwOutputMht = null;
          try
          {
           fsOutputMht = new FileStream(outputfile, FileMode.Create);
            bwOutputMht = new BinaryWriter(fsOutputMht, encoding);
            // HTML文件及其附件轉換爲MHTML文件
            byte[] bMHTMLBody = CreateMHTMLBody(chi);
            bwOutputMht.Write(bMHTMLBody);
            bwOutputMht.Close();
            fsOutputMht.Close();
            return;
          }
          catch(Exception ex)
          {
            bwOutputMht.Close();
            fsOutputMht.Close();
            throw ex;
          }
       }
       return;
     }

     //MHTML 文件頭信息
     protected static string MIME   =
       "MIME-Version: 1.0" + Environment.NewLine +
       "Content-Type: multipart/related; boundary=\"{0}\"" + Environment.NewLine +
       Environment.NewLine;
     //MHTML 各個文件的頭信息
     protected static string HEADER  = 
       Environment.NewLine + "--{0}" + Environment.NewLine +
       "Content-Location: {1}" + Environment.NewLine +
       "Content-Transfer-Encoding: {2}" + Environment.NewLine +
       "Content-Type: {3}" + Environment.NewLine +
       Environment.NewLine;
     // 定義MHTML中各文件之間的分隔符
     protected static string BOUNDARY =  "Define_It_Youself";
     //MHTML 主文件的URL
     protected static string LOCATION =  "http://MySiteUrl/";

     private static byte[] CreateMHTMLBody(CreateHtmlInfo creatHtmlInfo)
     {
       // 將回車換行符進行編碼並存儲在字節數組中
       byte[] bNewLine = Encoding.UTF8.GetBytes(Environment.NewLine);
       // 3D進行編碼並存儲在字節數組中
       byte[] bAfterEquals = encoding.GetBytes("3D");
       //'=' byte值爲61
       byte bEquals = 61;
       //MHTML 文件的長度
       long lMHTMLBodyLength = 0;
       // 從零開始的字節偏移量
       long lOffset = 0;
       // 根據BOUNDARY的定義造成MTHML文件的頭信息
       string strMIME = string.Format(MIME, BOUNDARY);
       // 將頭信息進行編碼並存儲在字節數組中
       byte[] bMIME = encoding.GetBytes(strMIME);
       //MHTML 文件的長度增長bMIME.LongLength
       lMHTMLBodyLength += bMIME.LongLength;

       // 根據信息定義主文件的頭信息
       string strMainHeader = string.Format(HEADER,
          BOUNDARY,
          LOCATION + creatHtmlInfo.strMainFileName,
          TransferEncoding.QUOTED_PRINTABLE,
          ContentType.TEXT_HTML);
       byte[] bMainHeader = encoding.GetBytes(strMainHeader);
       lMHTMLBodyLength += bMainHeader.LongLength;

       // 創建一個動態臨時數組
       ArrayList alTempArray = new ArrayList();
      
       // 主文件的正文部分全部的"="替換成"=3D"
       for(int i = 0; i < creatHtmlInfo.rgbMainFile.Length; i ++)
       {
          alTempArray.Add(creatHtmlInfo.rgbMainFile[i]);
          if(creatHtmlInfo.rgbMainFile[i] == bEquals)
          {
            alTempArray.Add(bAfterEquals[0]);
            alTempArray.Add(bAfterEquals[1]);
          }
       }
       // 獲取新的主文件的正文部分並存儲在字節數組中
       byte[] bMainBody = new byte[alTempArray.Count];
       alTempArray.CopyTo(bMainBody);
       lMHTMLBodyLength += bMainBody.LongLength;
       alTempArray.Clear();
      
       // 申明存儲MHTML附件的正文內容字節數組,該數組爲一個二維數組
       byte[][] bThicketContent = null;
       // 申明存儲MHTML附件的頭信息字節數組
       string[] strThicketHeaders = null;
       // 若是MHTML存在附件則執行如下代碼
       if(creatHtmlInfo.fHasThicket)
       {
          bThicketContent = new byte[creatHtmlInfo.rgrgbThicketFiles.Length][];
          strThicketHeaders = new string[creatHtmlInfo.rgrgbThicketFiles.Length];
          for(int i = 0; i < strThicketHeaders.Length; i++)
          {
            // 定義附件的頭信息
            string strLocation = LOCATION +
              creatHtmlInfo.strThicketFolderName + "/" +
              creatHtmlInfo.rgstrThicketFileNames[i];
            string strTransferEncoding = TransferEncoding.GetTransferEncodingByFileName
              (creatHtmlInfo.rgstrThicketFileNames[i]);
            string strContentType = ContentType.GetContentTypeByFileName
              (creatHtmlInfo.rgstrThicketFileNames[i]);
            strThicketHeaders[i] = string.Format(HEADER,
              BOUNDARY,
              strLocation,
              strTransferEncoding,
              strContentType);
            byte[] bThicketHeader = encoding.GetBytes(strThicketHeaders[i]);
         
            StringBuilder strBase64ThicketBody = new StringBuilder();
            byte[] bThicketBody = null;
            // 若是附件二進制文件,那麼用BASE64編碼
            if(strTransferEncoding ==
              TransferEncoding.BASE64)
            {
              // 首先將字節數組裏的內容轉換爲Base64編碼的字符串
              strBase64ThicketBody.Append(
                 Convert.ToBase64String(creatHtmlInfo.rgrgbThicketFiles[i]));
              // 而後將字符串進行編碼存儲在新的字節數組中
              bThicketBody = encoding.GetBytes(strBase64ThicketBody.ToString());
              // 76個字節,加入一個換行符
              int BUFFER_SIZE = 76;
              for(int j = 0; j < bThicketBody.Length; j++)
              {
                 alTempArray.Add(bThicketBody[j]);
                 if(j % BUFFER_SIZE == BUFFER_SIZE - 1)
                 {
                   alTempArray.Add(bNewLine[0]);
                   alTempArray.Add(bNewLine[1]);
                 }
              }
              bThicketBody = new byte[alTempArray.Count];
              alTempArray.CopyTo(bThicketBody);
              alTempArray.Clear();
            }
              // 若是附件是以明文編碼,那麼明文編碼,並將附件正文部分全部的"="替換成"=3D"
            else
            {
              for(int j = 0; j < creatHtmlInfo.rgrgbThicketFiles[i].Length; j++)
              {
                 alTempArray.Add(creatHtmlInfo.rgrgbThicketFiles[i][j]);
                 if(creatHtmlInfo.rgrgbThicketFiles[i][j] == bEquals)
                 {
                   alTempArray.Add(bAfterEquals[0]);
                   alTempArray.Add(bAfterEquals[1]);
                 }
              }
              bThicketBody = new byte[alTempArray.Count];
              alTempArray.CopyTo(bThicketBody);
              alTempArray.Clear();
            }
           
            // 將附件中的頭信息字節數組和正文的字節數組合並存儲在bThicketContent[i],
            // 並在lMHTMLBodyLength增長相應的長度
            bThicketContent[i] = new byte[bThicketHeader.LongLength + bThicketBody.LongLength + bNewLine.LongLength];
            Array.Copy(
              bThicketHeader,
              0,
              bThicketContent[i],
              0,
              bThicketHeader.LongLength);
            Array.Copy(
              bThicketBody,
              0,
              bThicketContent[i],
              bThicketHeader.LongLength,
              bThicketBody.LongLength);
            Array.Copy(
              bNewLine,
              0,
              bThicketContent[i],
              bThicketHeader.LongLength + bThicketBody.LongLength,
              bNewLine.LongLength);
            lMHTMLBodyLength += bThicketContent[i].LongLength;
          }
       }
       //MHTML 文件結束分割符的存儲在字節數組中
       byte[] bEndBoundary = encoding.GetBytes(
          Environment.NewLine + "--" + BOUNDARY + "--" +Environment.NewLine);
       lMHTMLBodyLength += bEndBoundary.LongLength;

        // 新建一個數組,該數組用於存儲MHTML文件的全部內容
       byte[] bMHTMLBody = new byte[lMHTMLBodyLength];
       // 將全部的內容所有合併,並存儲在數組bMHTMLBody
       Array.Copy(bMIME, 0, bMHTMLBody, lOffset, bMIME.LongLength);
       lOffset += bMIME.LongLength;
       Array.Copy(bMainHeader, 0, bMHTMLBody, lOffset, bMainHeader.LongLength);
       lOffset += bMainHeader.LongLength;
       Array.Copy(bMainBody, 0, bMHTMLBody, lOffset, bMainBody.LongLength);
       lOffset += bMainBody.LongLength;
       if(bThicketContent != null)
          for(int i = 0; i < bThicketContent.Length; i++)
          {
            Array.Copy(
              bThicketContent[i],
              0,
              bMHTMLBody,
              lOffset,
              bThicketContent[i].LongLength);
            lOffset += bThicketContent[i].LongLength;
          }
       Array.Copy(bEndBoundary, 0, bMHTMLBody, lOffset, bEndBoundary.LongLength);
  
       return bMHTMLBody;
     }
   }
   // 根據不一樣的文件後綴名定義編碼方式
   class TransferEncoding
   {
     public const string QUOTED_PRINTABLE =  "quoted-printable";
     public const string BASE64        =  "base64";

     public static string GetTransferEncodingByFileName(string fileName)
     {
       string strExtension = fileName.Remove(0,fileName.LastIndexOf(".")).ToUpper();
       switch(strExtension)
       {
            // 如下文件名在MTHML文件中都將以明文的形式編碼
          default:
          case ".HTM":
          case ".HTML":
          case ".CSS":
          case ".XML":
            return TransferEncoding.QUOTED_PRINTABLE;
            // 如下文件名在MHTML文件中都將以BASE64編碼形式出現
          case ".JPG":
          case ".JEPG":
          case ".PNG":
          case ".MSO":
          case ".EMZ":
          case ".GIF":
          case ".WMF":
            return TransferEncoding.BASE64;
       }
       return string.Empty;
     }
   }
   // 根據不一樣的後綴名定義文件內容的類型
   class ContentType
   {
     public const string TEXT_HTML       =  "text/html; charset=\"us-ascii\"";
     public const string APPLICATION_XMSO =  "application/x-mso";
     public const string IMAGE_XEMZ      =  "p_w_picpath/x-emz";
     public const string IMAGE_GIF       =  "p_w_picpath/gif";
     public const string TEXT_CSS       =  "text/css";
     public const string TEXT_XML       =  "text/xml; charset=\"utf-8\"";
     public const string IMAGE_XWMF      =  "p_w_picpath/x-wmf";
     public const string IMAGE_PNG       =  "p_w_picpath/png";
     public const string IMAGE_JPEG      =  "p_w_picpath/jpeg";

     public static string GetContentTypeByFileName(string fileName)
     {
       string strExtension = fileName.Remove(0,fileName.LastIndexOf(".")).ToUpper();
       switch(strExtension)
       {
            // 如下文件名在MHTML文件中的類型是text/html; charset="us-ascii"
          case ".HTM":
          case ".HTML":
            return ContentType.TEXT_HTML;
            // 如下文件名在MHTML文件中的類型是application/x-mso
          case ".MSO":
            return ContentType.APPLICATION_XMSO;
           // 如下文件名在MHTML文件中的類型是p_w_picpath/x-emz
          case ".EMZ":
            return ContentType.IMAGE_XEMZ;
            // 如下文件名在MHTML文件中的類型是p_w_picpath/gif
          case ".GIF":
            return ContentType.IMAGE_GIF;
            // 如下文件名在MHTML文件中的類型是text/css
          case ".CSS":
            return ContentType.TEXT_CSS;
            // 如下文件名在MHTML文件中的類型是text/xml; charset="utf-8"
          case ".XML":
            return ContentType.TEXT_XML;
            // 如下文件名在MHTML文件中的類型是p_w_picpath/x-wmf
          case ".WMF":
            return ContentType.IMAGE_XWMF;
            // 如下文件名在MHTML文件中的類型是p_w_picpath/png
          case ".PNG":
            return ContentType.IMAGE_PNG;
            // 如下文件名在MHTML文件中的類型是p_w_picpath/jpeg
          case ".JPG":
          case ".JEPG":
            return ContentType.IMAGE_JPEG;
       }
       return string.Empty;
     }
   }
}
相關文章
相關標籤/搜索