原來蚜退,這才是html+css導出word最佳方式!

轉(zhuǎn)個word很難嗎彪笼?

對于任何一個在線富文本寫作產(chǎn)品钻注,導出功能是必不可少的,其中導出word是其中最常見的選項配猫,但是很多產(chǎn)品導出的word幅恋,比如說Jira,格式就有不同程度的失真.

仔細分析下來泵肄,解決這個思路的主要有兩種:

  • 硬轉(zhuǎn):使用OpenXml的SDK捆交,逐一匹配html標簽和樣式css,相當于用OpenXml實現(xiàn)了一個html+css的渲染層腐巢。
  • 偷懶:想辦法把html+css的內(nèi)容當成word的一部分品追,相當于用web視圖打開。

當時冯丙,我花了一定的時間肉瓦,在兩個方向上分別做了調(diào)研。

硬轉(zhuǎn)的思路,直覺上工作量就極大泞莉,而且很容易出Bug哪雕,畢竟那么多組合情況需要考慮。值得參考的項目是html2openxml鲫趁,1W多行只能實現(xiàn)html的轉(zhuǎn)換斯嚎,還不包括css。

不是沒想過饮寞,限制輸出html的排版孝扛,比如用固定的id代表固定的部分,css樣式也只支持特定的幾種幽崩,但后來討論下來苦始,覺得這種方法,需要前后端確定好規(guī)則慌申,而在當時快速迭代的時期陌选,這無疑會增加開發(fā)成本。

偷懶這條路蹄溉,能夠搜索到項目咨油,都是借用了word中altchunks的特性,比如:html-docx-js柒爵、html2docx役电。

問題也很明顯,

  • 不支持float之類的樣式棉胀,對圖片的支持也需要自己寫代碼轉(zhuǎn)base64法瑟,然后嵌進標簽里。這些雖然麻煩些唁奢,但是還是可以tweak霎挟。
  • 最麻煩的是,這種格式的word麻掸,兼容性很差酥夭,在微信中、mac上打不開脊奋。

于是熬北,我一度卡在這里很久,直到我發(fā)現(xiàn)……

原來诚隙,word才是轉(zhuǎn)word的最佳工具

轉(zhuǎn)機來的也很突然讶隐,就是我發(fā)現(xiàn)用word打開一個帶html+css的文件后,再另存成word最楷,不僅格式得到了保留整份,圖片也在,而且兼容性也還不錯籽孙!真是

踏破鐵鞋無覓處烈评,得來全不費工夫。

問題來了犯建,怎么把這一步程序化呢讲冠?

這下終于可以用上過去.net的開發(fā)經(jīng)驗了,C#是可以通過com組件的方式操作word适瓦,但前提是運行程序的機器上必須裝word才行竿开。

核心代碼,也是非常的簡單:

首先引用Microsoft.Office.Interop.Word玻熙,調(diào)用的代碼如下:

var word = new Application {Visible = false};
var doc = word.Documents.Open(htmlFilePath, Format: WdOpenFormat.wdOpenFormatWebPages, ReadOnly: false);
doc.SaveAs2000(wordFilePath, WdSaveFormat.wdFormatDocumentDefault, ReadOnlyRecommended: false);
doc.Close();
word.quit()

是不是很簡單呢否彩?

而這里唯一還需要處理的就是圖片,如果不做處理嗦随,圖片還是以鏈接的方式存儲的列荔。

一方面,每次打開的時候需要重復下載枚尼,好處是word文件比較小贴浙,但缺點是受限于網(wǎng)速,可能會出現(xiàn)圖片加載不出來的情況;

另一方面時署恍,如果圖片沒有指定寬度和高度崎溃,當圖片的尺寸大于文檔的尺寸時,顯示的效果就很差盯质。

估化的思路很簡單袁串,即強行把圖片的尺寸拉伸到一頁可以顯示下,同時將圖片鏈接轉(zhuǎn)成內(nèi)嵌的圖片唤殴。

foreach (InlineShape s in doc.InlineShapes)
{
    var inlineShape = s;
    
    if (inlineShape.Type != WdInlineShapeType.wdInlineShapePicture &&
        inlineShape.Type != WdInlineShapeType.wdInlineShapeLinkedPicture)
    {
        continue;
    }

    if (inlineShape.Type == WdInlineShapeType.wdInlineShapeLinkedPicture)
    {
        inlineShape.LinkFormat.SavePictureWithDocument = true;
        inlineShape.LinkFormat.BreakLink();
    }

    if (inlineShape.Width > this._documentWidth)
    {
        inlineShape.LockAspectRatio = MsoTriState.msoTrue;
        inlineShape.Width = this._documentWidth;
    }

    if (inlineShape.Height > this._documentHeight)
    {
        inlineShape.LockAspectRatio = MsoTriState.msoTrue;
        inlineShape.Height = this._documentHeight;
    }
}

到此般婆,核心的轉(zhuǎn)換代碼就已經(jīng)完成。(需要提醒各位看官的是朵逝,這種方法是不支持float和flex的css樣式的蔚袍。

剩下的工作

請注意:上述代碼是基于.net framework寫的,運行的機器上還必須有word配名。

如果要對外提供服務的話啤咽,考慮到跨語言跨平臺,最好的方式即提供http接口渠脉。

而這對一個不熟悉.net的人宇整,那要學習的東西還是不少的。

樓主我就好人做到底芋膘,在上述的核心代碼上用WCF的webHttpBinding實現(xiàn)了一個的http服務鳞青,同時使用log4net實現(xiàn)了日志功能霸饲。

最終的程序的workflow是

  • 用戶發(fā)送html+css內(nèi)容到http服務
  • 先把html+css存成文件
  • 讀取html文件,然后另存為word文件
  • 返回下載鏈接
  • 使用nginx映射目錄中的文件臂拓,實現(xiàn)下載功能

所有代碼開源在HtmlToWord厚脉,如果它對你有用,歡迎點個star.

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胶惰,一起剝皮案震驚了整個濱河市傻工,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孵滞,老刑警劉巖中捆,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坊饶,居然都是意外死亡泄伪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門匿级,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臂容,“玉大人,你說我怎么就攤上這事根蟹∨迹” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵简逮,是天一觀的道長球散。 經(jīng)常有香客問我,道長散庶,這世上最難降的妖魔是什么蕉堰? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮悲龟,結(jié)果婚禮上屋讶,老公的妹妹穿的比我還像新娘。我一直安慰自己须教,他們只是感情好皿渗,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著轻腺,像睡著了一般乐疆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贬养,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天挤土,我揣著相機與錄音,去河邊找鬼误算。 笑死仰美,一個胖子當著我的面吹牛迷殿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咖杂,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼贪庙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翰苫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤这橙,失蹤者是張志新(化名)和其女友劉穎奏窑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屈扎,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡埃唯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹰晨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墨叛。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖模蜡,靈堂內(nèi)的尸體忽然破棺而出漠趁,到底是詐尸還是另有隱情,我是刑警寧澤忍疾,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布闯传,位于F島的核電站,受9級特大地震影響卤妒,放射性物質(zhì)發(fā)生泄漏甥绿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一则披、第九天 我趴在偏房一處隱蔽的房頂上張望共缕。 院中可真熱鬧,春花似錦士复、人聲如沸图谷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜓萄。三九已至,卻和暖如春澄峰,著一層夾襖步出監(jiān)牢的瞬間嫉沽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工俏竞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绸硕,地道東北人堂竟。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像玻佩,于是被迫代替她去往敵國和親出嘹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容