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
    }
相关推荐
JulyYu13 分钟前
Android系统保存重名文件后引发的异常解决
android·操作系统·源码
叽哥16 分钟前
Kotlin学习第 2 课:Kotlin 基础语法:掌握变量、数据类型与运算符
android·kotlin·app
tangweiguo0305198720 分钟前
Android原生(Kotlin)与Flutter混合开发 - 设备控制与状态同步解决方案
android·flutter
安卓开发者2 小时前
驾驭复杂表单:用 RxJava 实现响应式表单处理
android·rxjava
一笑的小酒馆2 小时前
Android使用Compose实现简单微信朋友圈
android
xiangxiongfly9153 小时前
Android 圆形和圆角矩形总结
android·圆形·圆角·imageview
幻雨様9 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端11 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.12 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton12 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack