利用 PdfDocument 生成 PDF 文件

Android 中的 android.graphics.pdf.PdfDocument 类用来生成 pdf 文件,文档中列出了简单的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// create a new document
PdfDocument document = new PdfDocument();

// crate a page description
PageInfo pageInfo = new PageInfo.Builder(new Rect(0, 0, 100, 100), 1).create();

// start a page
Page page = document.startPage(pageInfo);

// draw something on the page
View content = getContentView();
content.draw(page.getCanvas());

// finish the page
document.finishPage(page);
. . .
// add more pages
. . .
// write the document content
document.writeTo(getOutputStream());

// close the document
document.close();

步骤就是生成页面,然后拿到 canvas ,在页面中画文字画图形,下面演示一下生成图文混排的 pdf 文件。A4 纸文件是 595×842。大概逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
拿到图文的内容 list
渲染开始:
创建一个新的页面
for item in list:
if item is txt:
计算要画的文字高度
if 页面剩下的高度画不完:
计算能画几行,并且 canvas.drawText 能画下的一部分
item 的文字内容置为剩下的部分
创建一个新界面
else
canvas.drawText
elseif item is image:
计算图片高度
if 页面剩下的高度画不完 && 不是新页面:
创建一个新界面
else
canvas.drawImage
渲染结束

难点在于如何计算要渲染的文字高度,答案是 StaticLayout, 首先设置文字的行高,计算行数,然后判断能画到第几行,然后将文字进行分割。
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val myStaticLayout = StaticLayout(content, textPaint, (w - paddingLR - paddingLR).toInt(), Layout.Alignment.ALIGN_NORMAL, 0f, lineHeight, false)
var totalCount = myStaticLayout.lineCount
while (totalCount * lineHeight > h - paddingTB - offsetY) {
totalCount--
}
if (totalCount < myStaticLayout.lineCount) { //渲染不完
val lineEnd = try {
myStaticLayout.getLineEnd(totalCount)
} catch (e: Exception) {
myStaticLayout.getLineEnd(myStaticLayout.lineCount - 1)
}
val subLayout = StaticLayout(content.substring(0, lineEnd), textPaint, (w - paddingLR - paddingLR).toInt(), Layout.Alignment.ALIGN_NORMAL, 0f, lineHeight, false)
subLayout.draw(canvas) //画文字

//创建新界面..
//....
} else {
myStaticLayout.draw(canvas)
}

下图为生成的 pdf 渲染结果:

生成的 pdf

文章来自: https://hanks.pub