1. 程式人生 > >Asciidoctor 與 gradle 整合生成 PDF備忘

Asciidoctor 與 gradle 整合生成 PDF備忘

緣起

簡單文件一般使用 markdown 就足夠了,尤其單頁文件,不過稍微複雜點的文件用這玩意顯然就很不方便了,就單單一個不支援 include 就很痛苦,雖然可以用 pandoc 做一些 hack 處理,不過麻煩啊,尤其還需要生成 html5pdf 的時候。

所以這時候個人傾向於使用 asciidoc 格式來寫文件。

配置

編譯 asciidochtml5pdf 的話,Asciidoctor 提供了命令列工具,不過這玩意需要通過 gem 安裝,如果額外還想生成 PDF,還需要安裝 asciidoctor-pdf,看看官方文件就知道麻煩事不少。

所以還是配合 gradle 省事,一個配置檔案搞定,尤其對於 java 程式設計師來說,gradle 應該算是標配了吧——呃,maven 使用者可能有話說。

目錄結構

gradle 專案的一個最基本的目錄結構應該如下:

.
├── build.gradle
├── data
│   ├── fonts
│   │   ├── KaiGenGothicCN-Bold-Italic.ttf
│   │   ├── KaiGenGothicCN-Bold.ttf
│   │   ├── KaiGenGothicCN-Regular-Italic.ttf
│   │   ├── KaiGenGothicCN-Regular.ttf
│   │   ├── RobotoMono-Bold.ttf
│   │   ├── RobotoMono-BoldItalic.ttf
│   │   ├── RobotoMono-Italic.ttf
│   │   └── RobotoMono-Regular.ttf
│   └── themes
│       └── basic-theme.yml
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    └── docs
        └── asciidoc
            ├── chapter
            │   └── 0010_overview.adoc
            ├── images
            │   └── keep
            └── spec.adoc

簡單說明一下:

  • src/docs/asciidoc: asciidoc 所在目錄
  • data/fonts: 用於生成 PDF 的字型檔案目錄
  • data/themes: 用於定義 PDF 的主題檔案目錄

build.gradle 配置

buildscript {
    repositories {
        maven {
            url "http://maven.aliyun.com/nexus/content/groups/public/"
        }

        jcenter()
        mavenCentral()
    }
}

plugins {
    id "org.asciidoctor.jvm.convert" version "2.3.0"
    id "org.asciidoctor.jvm.pdf" version "2.3.0"
}

wrapper {
    distributionType = Wrapper.DistributionType.ALL
}

version = '1.0.0'

asciidoctor {
    logDocuments true

    // sourceDir  file('docs')
    sources {
        include 'spec.adoc'
    }
    baseDirFollowsSourceDir()
    // outputDir  file('build/docs')

    // 強制每次都重新生成
    outputs.upToDateWhen { false }
    outputOptions {
        backends = ['html5', 'pdf']
    }

    // pdfThemes {
    //     local 'basic', {
    //         styleDir = file('data/themes/basic')
    //         styleName = 'basic'
    //     }
    // }
    attributes 'pdf-fontsdir': file('data/fonts')
    attributes 'pdf-stylesdir': file('data/themes')
    attributes 'pdf-style': 'basic'

     // 版本號
    attributes 'revnumber': project.version

    // 一些通用屬性
    attributes 'toc': 'left'
    attributes 'toclevels': 4
    attributes 'toc-title': '目錄'
    attributes 'docinfo1': ''
    attributes 'imagesdir': 'images'
    // 語法高亮,可選項有 coderay, highlightjs, prettify, pygments
    // 為保證生成的 html5 和 pdf 均有語法高亮,所以啟用 coderay
    // 使用其它幾個選項還需要做不少額外的工作,沒有必要
    attributes 'source-highlighter': 'coderay'
    attributes 'sectnums': true
    attributes 'sectanchors': true
    attributes 'sectlinks': true
    attributes 'experimental': true


    // TIP、NOTE 之類的用自體圖示顯示
    // 之所以將此屬性放置在這兒是為了避免 idea asciidoc 外掛無法正常顯示
    attributes 'icons': 'font'
}

重點需要注意:

  • plugins 下的兩個 plugin 使用版本為 2.3.0,而官網是 2.4.0,但是後者在各個 maven 庫中都沒發現,估計截止當前位置尚未更新
  • asciidoctor 配置中可以不用官網文件寫的 pdfThemes,也就是上面原始碼中註釋的部分,直接採用 attributes 'pdf-fontsdir' 這種配置即可,看原始碼就知道,前者也不過就是為了達到後者的效果
  • source-highlighter 使用 coderay,這個相比其它原始碼高亮工具稍顯簡單,不過好處是不需額外配置就可以提供 PDF 高亮。

PDF 示例:

PDF 示例

入口 adoc 檔案示例

= 開發規範

:toc: left
:toc-title: 目錄
:toclevels: 3
:source-highlighter: coderay
:imagesdir: images
:icons: font
:sectnums:
:sectanchors:
:sectlinks:
:experimental:
:revnumber: v1.0

[#overview]
== 概述
include::chapter/0010_overview.adoc[]

上述檔案其實把 build.gradle 中的 attributes 又定義了一遍,之所以如此是為了在 vscode、WebStorm 之類的工具中可以直接預覽,當然這是可選項,如果不需要這種比較一致的預覽需求,完全可以把入口 adoc 中的這些配置項刪除。

PDF 中文字型的額外配置

上述配置完成之後執行 ./gradlew asciidoctor 已經可以生成 html5、pdf 了,不過開啟 pdf 的話會發現中文亂碼,中文都變成了¬,此問題可參見官方說明 Built-In (AFM) Fonts

提示如下:

The following text could not be fully converted to the Windows-1252 character set:
| <string with unknown glyph>

PDF 亂碼示例:

pdf 亂碼示例

之所以亂碼主要是 asciidoctor-pdf 預設使用的 default-theme.yml 中配置的字型檔案不支援中文,點開看看這個檔案就知道怎麼回事了。

可以去 asciidoctor-pdf-cjk-kai_gen_gothic 下載「懷源黑體」(思源黑體的 ttf 版)和「Roboto Mono」等寬字型,放置到 data/fonts 下面。

之後編寫 data/themes/basic-theme.yml

#
# 過載 https://github.com/asciidoctor/asciidoctor-pdf/blob/master/data/themes/default-theme.yml
# 使用中文字型解決 pdf 亂碼問題
#

extends: default

# 過載字型定義
font:
    catalog:
        KaiGen Gothic CN:
            normal: KaiGenGothicCN-Regular.ttf
            bold: KaiGenGothicCN-Bold.ttf
            italic: KaiGenGothicCN-Regular-Italic.ttf
            bold_italic: KaiGenGothicCN-Bold-Italic.ttf
        Roboto Mono:
            normal: RobotoMono-Regular.ttf
            bold: RobotoMono-Bold.ttf
            italic: RobotoMono-Italic.ttf
            bold_italic: RobotoMono-BoldItalic.ttf
    fallbacks:
        - KaiGen Gothic CN

# 覆蓋基礎字型
base:
    font_family: KaiGen Gothic CN

# 覆蓋等寬字型
literal:
    font_family: Roboto Mono

最後在 build.gradle 中配置:

    attributes 'pdf-fontsdir': file('data/fonts')
    attributes 'pdf-stylesdir': file('data/themes')
    attributes 'pdf-style': 'basic'

中文問題解決!

Spring REST Docs 版本要求

asciidoc 的另一個使用場景是配合 Spring REST Docs 生成 api 文件,不過需要注意的是這時候只能使用 1.5.x 版本的 org.asciidoctor.convert,因為 Spring REST Docs 暫時還不支援新版 asciidoctor

這時候需要注意 build.gradle 中一些配置需要調整,例如:

    outputOptions {
        backends = ['html5', 'pdf']
    }

需要調整為:

backends 'html5', 'pdf'

參考