android pdf框架-6,文本生成pdf

前文介绍如何使用图片生成pdf,这里介绍如何使用文本生成pdf

使用mupdf生成

mupdf生成的pdf略大,字体可以自定义.

生成的代码不复杂,也有好几种,以story的方式生成为例

fun createPdfFromText(sourcePath: String, destPath: String): Boolean {
        val text = EncodingDetect.readFile(sourcePath)
        val mediabox = Rect(0f, 0f, 500f, 707f) //A2
        val margin = 10f
        var writer = DocumentWriter(destPath, "PDF", "")

        var snark = "<!DOCTYPE html>" +
                "<style>" +
                "#body { font-family: \"Droid Sans\", sans-serif; }" +
                "</style>" +
                "<body>" +
                text +
                "</body></html>"
        val story = Story(snark, "", 12f)

        var more: Boolean

        do {
            val filled = Rect()
            val where = Rect(
                mediabox.x0 + margin,
                mediabox.y0 + margin,
                mediabox.x1 - margin,
                mediabox.y1 - margin
            )
            val dev: Device = writer.beginPage(mediabox)
            more = story.place(where, filled)
            story.draw(dev, Matrix.Identity())
            writer.endPage()
        } while (more)

        writer.close()
        writer.destroy()
        story.destroy()

        return true
    }

文档的读取,对于中文,可能会涉及到编码的处理.

先定义mediabox,就是纸张大小,这里是a2

然后用html生成story,最后写入就完成了

如果要自定义样式,颜色这些,api要去查如何使用.并不那么方便.

使用系统sdk生成

系统sdk是基于福昕的代码.但生成时可以使用view来设置样式,然后生成页面.样式比较容易控制,毕竟view长什么样是容易修改的.

读取文本是一样的.

val pdfDocument = PdfDocument()
        val pageWidth = PDF_PAGE_WIDTH.toInt()
        val pageHeight = PDF_PAGE_HEIGHT.toInt()
        val contentView =
            LayoutInflater.from(context).inflate(R.layout.pdf_content, parent, false) as TextView
        contentView.text = content
        val measureWidth = View.MeasureSpec.makeMeasureSpec(pageWidth, View.MeasureSpec.EXACTLY)
        val measuredHeight = View.MeasureSpec.makeMeasureSpec(pageHeight, View.MeasureSpec.EXACTLY)
        contentView.measure(measureWidth, measuredHeight)
        contentView.layout(0, 0, pageWidth, pageHeight)

建立文档对象,然后加载布局

val lineCount = contentView.lineCount
        var lineHeight = contentView.lineHeight
        if (contentView.lineSpacingMultiplier > 0) {
            lineHeight = (lineHeight * contentView.lineSpacingMultiplier).toInt()
        }
        val layout = contentView.layout
        var start = 0
        var end: Int
        var pageH = 0
        val paddingTopAndBottom: Int = Utils.dipToPixel(context, 40f)

设置边距40dp,读取行间距与行数.

因为设置了内容后,由textview自己就能计算出这些,然后根据这些信息,计算我们一页的高宽可以分成几页,然后每一页再用一个布局去生成就行了.

while (i < lineCount) {
            end = layout.getLineEnd(i)
            val line = content.substring(start, end) //指定行的内容
            start = end
            sb.append(line)
            pageH += lineHeight
            if (pageH >= pageHeight - paddingTopAndBottom) {
                Log.d(
                    "TextView",
                    String.format(
                        "============page line:%s,lh:%s,ph:%s==========",
                        i,
                        lineHeight,
                        pageHeight
                    )
                )
                createTxtPage(
                    context,
                    parent,
                    pdfDocument,
                    pageWidth,
                    pageHeight,
                    i + 1,
                    sb.toString()
                )
                pageH = 0
                sb.setLength(0)
            }
            i++
        }
        if (sb.length > 0) {
            Log.d("TextView", "last line ===")
            createTxtPage(context, parent, pdfDocument, pageWidth, pageHeight, i, sb.toString())
        }

这就是计算的过程,最后要再处理剩下的部分.

对于每一页的显示字符数处理完,接着就是对这些生成页面

private fun createTxtPage(
        context: Context?,
        parent: ViewGroup?,
        pdfDocument: PdfDocument,
        pageWidth: Int,
        pageHeight: Int,
        pageNo: Int,
        content: String?
    ) {
        val contentView =
            LayoutInflater.from(context).inflate(R.layout.pdf_content, parent, false) as TextView
        contentView.text = content
        val pageInfo: PdfDocument.PageInfo =
            PdfDocument.PageInfo.Builder(pageWidth, pageHeight, pageNo)
                .create()
        val page: PdfDocument.Page = pdfDocument.startPage(pageInfo)
        val pageCanvas: Canvas = page.getCanvas()
        val measureWidth = View.MeasureSpec.makeMeasureSpec(pageWidth, View.MeasureSpec.EXACTLY)
        val measuredHeight = View.MeasureSpec.makeMeasureSpec(pageHeight, View.MeasureSpec.EXACTLY)
        contentView.measure(measureWidth, measuredHeight)
        contentView.layout(0, 0, pageWidth, pageHeight)
        contentView.draw(pageCanvas)

        // finish the page
        pdfDocument.finishPage(page)
    }

页面同样用之前的布局,这样保持是一致的,否则高宽计算就不对了.这里因为不需要显示,所以我们要调用measure与layout再draw画出来

保存就简单了

private fun savePdf(path: String?, document: PdfDocument): Boolean {
        val outputStream = FileOutputStream(path)
        try {
            document.writeTo(outputStream)
            return true
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            document.close()
        }
        return false
    }
相关推荐
CYRUS STUDIO20 分钟前
ARM64汇编寻址、汇编指令、指令编码方式
android·汇编·arm开发·arm·arm64
weixin_449310841 小时前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
Zender Han1 小时前
Flutter自定义矩形进度条实现详解
android·flutter·ios
白乐天_n3 小时前
adb:Android调试桥
android·adb
姑苏风7 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
数据猎手小k11 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小1011 小时前
JavaWeb项目-----博客系统
android
风和先行12 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.12 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰13 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder