🎨 PDF export supports setting footer template https://github.com/siyuan-note/siyuan/issues/7478

This commit is contained in:
Liang Ding 2023-03-31 20:51:32 +08:00
parent 780668eacc
commit 7b259bb05d
No known key found for this signature in database
GPG key ID: 136F30F901A2231D
9 changed files with 55 additions and 15 deletions

View file

@ -740,6 +740,8 @@
"export18": "After enabling, insert the document title as a heading 1 at the beginning",
"export19": "Path to Pandoc executable",
"export20": "Exporting Word .docx files requires format conversion using <a href=\"https://pandoc.org\" target=\"_blank\">Pandoc</a>",
"export21": "Export PDF footer template",
"export22": "<code class='fn__code'>%page</code> is the current page number, <code class='fn__code'>%pages</code> is the total page number, and supports Sprig template functions",
"export23": "Export Markdown wit YFM",
"export24": "After enabling, add some general metadata information at the beginning of the exported Markdown file",
"blockRef": "Ref Block",

View file

@ -740,6 +740,8 @@
"export18": "Después de habilitar, inserte el título del documento como encabezado 1 al principio",
"export19": "Ruta de acceso al ejecutable de Pandoc",
"export20": "La exportación de archivos Word .docx requiere la conversión del formato mediante <a href=\"https://pandoc.org\" target=\"_blank\">Pandoc</a>",
"export21": "Exportar plantilla de pie de página PDF",
"export22": "<code class='fn__code'>%page</code> es el número de página actual, <code class='fn__code'>%pages</code> es el número de página total y es compatible con las funciones de plantilla de Sprig ",
"export23": "Exportar descuento con YFM",
"export24": "Después de habilitar, agregue información general de metadatos al comienzo del archivo Markdown exportado",
"blockRef": "Bloque de referencia",

View file

@ -740,6 +740,8 @@
"export18": "Après activation, insérez le titre du document comme titre 1 au début",
"export19": "Chemin vers l'exécutable Pandoc",
"export20": "L'exportation de fichiers Word .docx nécessite une conversion de format à l'aide de <a href=\"https://pandoc.org\" target=\"_blank\">Pandoc</a>",
"export21": "Exporter le modèle de pied de page PDF",
"export22": "<code class='fn__code'>%page</code> est le numéro de page actuel, <code class='fn__code'>%pages</code> est le numéro de page total et prend en charge les fonctions de modèle Sprig ",
"export23": "Exporter Markdown avec YFM",
"export24": "Après l'activation, ajoutez des informations générales sur les métadonnées au début du fichier Markdown exporté",
"blockRef": "Bloc Réf",

View file

@ -740,6 +740,8 @@
"export18": "啟用後將文檔標題以一級標題的形式插入到開頭",
"export19": "Pandoc 可執行文件路徑",
"export20": "導出 Word .docx 文件需要使用 <a href=\"https://pandoc.org\" target=\"_blank\">Pandoc</a> 進行格式轉換",
"export21": "導出 PDF 頁腳模板",
"export22": "<code class='fn__code'>%page</code> 為當前頁碼,<code class='fn__code'>%pages</code> 為總頁碼,支持 Sprig 模板函數",
"export23": "導出 Markdown 添加 YFM",
"export24": "啟用後在導出的 Markdown 文件開頭處添加一些較為通用的元數據信息",
"blockRef": "引用塊",

View file

@ -740,6 +740,8 @@
"export18": "启用后将文档标题以一级标题的形式插入到开头",
"export19": "Pandoc 可执行文件路径",
"export20": "导出 Word .docx 文件需要使用 <a href=\"https://pandoc.org\" target=\"_blank\">Pandoc</a> 进行格式转换",
"export21": "导出 PDF 页脚模板",
"export22": "<code class='fn__code'>%page</code> 为当前页码,<code class='fn__code'>%pages</code> 为总页码,支持 Sprig 模板函数",
"export23": "导出 Markdown 添加 YFM",
"export24": "启用后在导出的 Markdown 文件开头处添加一些较为通用的元数据信息",
"blockRef": "引用块",

View file

@ -44,5 +44,6 @@ func NewExport() *Export {
FileAnnotationRefMode: 0,
PandocBin: "",
MarkdownYFM: false,
PDFFooter: "%page / %pages",
}
}

View file

@ -108,6 +108,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.9.1 // indirect
github.com/pdfcpu/pdfcpu v0.4.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect

View file

@ -232,6 +232,8 @@ github.com/panjf2000/ants/v2 v2.7.1 h1:qBy5lfSdbxvrR0yUnZfaEDjf0FlCw4ufsbcsxmE7r
github.com/panjf2000/ants/v2 v2.7.1/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pdfcpu/pdfcpu v0.4.0 h1:381iGNvMeLP+GFqIAqgd0LSj36AsK3JH4UTaF6D5jRc=
github.com/pdfcpu/pdfcpu v0.4.0/go.mod h1:9NDeS6hrCheauxw6YUlzgL/q6At2+PMzUKyFcfUzLLY=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=

View file

@ -20,6 +20,7 @@ import (
"bytes"
"errors"
"fmt"
"github.com/Masterminds/sprig/v3"
"net/http"
"net/url"
"os"
@ -29,6 +30,7 @@ import (
"sort"
"strconv"
"strings"
"text/template"
"time"
"unicode/utf8"
@ -711,6 +713,7 @@ func ProcessPDF(id, p string, merge, removeAssets bool) (err error) {
processPDFBookmarks(pdfCtx, headings)
processPDFLinkEmbedAssets(pdfCtx, assetDests, removeAssets)
processPDFFooter(pdfCtx)
pdfcpu.VersionStr = "SiYuan v" + util.Ver
if writeErr := api.WriteContextFile(pdfCtx, p); nil != writeErr {
@ -970,26 +973,49 @@ func processPDFLinkEmbedAssets(pdfCtx *pdfcpu.Context, assetDests []string, remo
}
}
func annotRect(i int, w, h, d, l float64) *pdfcpu.Rectangle {
// d..distance between annotation rectangles
// l..side length of rectangle
func processPDFFooter(pdfCtx *pdfcpu.Context) {
templateContent := strings.TrimSpace(Conf.Export.PDFFooter)
if "" == templateContent {
return
}
// max number of rectangles fitting into w
xmax := int((w - d) / (l + d))
footerTpl, err := template.New("").Funcs(sprig.TxtFuncMap()).Parse(templateContent)
if nil != err {
logging.LogErrorf("parse pdf footer template failed: %s", err)
return
}
// max number of rectangles fitting into h
ymax := int((h - d) / (l + d))
buf := &bytes.Buffer{}
buf.Grow(4096)
err = footerTpl.Execute(buf, nil)
if nil != err {
logging.LogErrorf("render pdf footer template failed: %s", err)
return
}
footer := buf.String()
col := float64(i % xmax)
row := float64(i / xmax % ymax)
fontName := "Times-Roman"
pos := "bc"
dx := 10
fillCol := "#000000"
desc := fmt.Sprintf("font:%s, points:12, sc:1 abs, pos:%s, off:%d 10, fillcol:%s, rot:0", fontName, pos, dx, fillCol)
footer = strings.ReplaceAll(footer, "%pages", strconv.Itoa(pdfCtx.PageCount))
m := map[int]*pdfcpu.Watermark{}
for i := 1; i <= pdfCtx.PageCount; i++ {
text := strings.ReplaceAll(footer, "%page", strconv.Itoa(i))
wm, watermarkErr := api.TextWatermark(text, desc, true, false, pdfcpu.POINTS)
if nil != watermarkErr {
logging.LogErrorf("add pdf footer failed: %s", watermarkErr)
return
}
llx := d + col*(l+d)
lly := d + row*(l+d)
m[i] = wm
}
urx := llx + l
ury := lly + l
return pdfcpu.Rect(llx, lly, urx, ury)
if watermarkErr := pdfCtx.AddWatermarksMap(m); nil != watermarkErr {
logging.LogErrorf("add pdf footer failed: %s", watermarkErr)
return
}
}
func ExportStdMarkdown(id string) string {