feiyu02
2024-08-15 196bb14112448857a885e32dc4149e308e00b01a
src/main/kotlin/cn/flightfeather/supervision/common/pdf/PdfUtil.kt
@@ -1,82 +1,96 @@
package cn.flightfeather.supervision.common.pdf
import org.apache.poi.util.Units
import org.apache.poi.xwpf.usermodel.XWPFDocument
import org.apache.poi.xwpf.usermodel.XWPFParagraph
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import com.itextpdf.html2pdf.ConverterProperties
import com.itextpdf.html2pdf.HtmlConverter
import com.itextpdf.layout.font.FontProvider
import com.itextpdf.text.Element
import com.itextpdf.text.Font
import com.itextpdf.text.FontFactory
import com.itextpdf.text.pdf.BaseFont
import com.itextpdf.text.pdf.PdfReader
import com.itextpdf.text.pdf.PdfStamper
import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.rendering.PDFRenderer
import org.fit.pdfdom.PDFDomTree
import org.fit.pdfdom.PDFDomTreeConfig
import org.xhtmlrenderer.pdf.ITextRenderer
import java.io.*
import javax.imageio.ImageIO
import javax.xml.parsers.ParserConfigurationException
object PdfUtil {
    fun generateContract(dynamicParam: DynamicParam): String {
        val src = dynamicParam.templatePath+dynamicParam.templateName
        val out = dynamicParam.outPath + dynamicParam.outName
    private const val FONT1 = "/font/STSONG.TTF"
    private const val FONT2 = "font/msyhbd.ttc"
    private const val FONT3 = "font/msyhl.ttc"
        val inputStream = FileInputStream(File(src))
        val xwpfDocument = XWPFDocument(inputStream)
        replace(xwpfDocument, dynamicParam.param)
        output(xwpfDocument, out)
        return out
    @Throws(IOException::class, ParserConfigurationException::class)
    fun parseWithPdfDomTree(`is`: InputStream?, startPage: Int, endPage: Int, config: PDFDomTreeConfig?): String? {
        val pdf: PDDocument = PDDocument.load(`is`)
        val parser = PDFDomTree(config)
        parser.startPage = startPage
        parser.endPage = endPage
        val output: Writer = StringWriter()
        parser.writeText(pdf, output)
        pdf.close()
        return output.toString()
    }
    /**
     * 替换段落中指定的文本
     */
    fun replace(doc:XWPFDocument, params:Map<String, Any>) {
        try {
            setContent(doc.paragraphs, params)
    fun htmlToPdf(content: String): ByteArray {
            for (tab in doc.tables) {
                for (row in tab.rows) {
                    for (cell in row.tableCells) {
                        //注意,getParagraphs一定不能漏掉
                        //因为一个表格里面可能会有多个需要替换的文字
                        //如果没有这个步骤那么文字会替换不了
                        setContent(cell.paragraphs, params)
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        val p = ConverterProperties()
        p.fontProvider = FontProvider().apply {
            addFont(FONT1)
        }
    }
        val outputStream = ByteArrayOutputStream()
        HtmlConverter.convertToPdf(content, outputStream, p)
        val inputStream = ByteArrayInputStream(outputStream.toByteArray())
        val reader = PdfReader(inputStream)
        val output = ByteArrayOutputStream()
        val stamper = PdfStamper(reader, output)
    private fun setContent(paragraphs: List<XWPFParagraph>, params: Map<String, Any>) {
        for (p in paragraphs) {
            for (r in p.runs) {
                //需要替换的文本
                val text = r.getText(0)
                //替换指定的文本
                for (key in params.keys) {
                    if (text != null && text == key) {
                        //替换的时候要注意,setText是有两个参数的
                        //第一个是替换的文本,第二个是从哪里开始替换
                        //0是替换全部,如果不设置那么默认就是从原文字
                        //结尾开始追加
                        val v = params[key]
                        when (v) {
                            is String -> r.setText(v, 0)
                            is File -> {
                                val input = FileInputStream(v)
                                val pic = r.addPicture(input, XWPFDocument.PICTURE_TYPE_JPEG, v.name, Units.toEMU(40.0), Units.toEMU(40.0))
        val totalPages = reader.numberOfPages
        val font = BaseFont.createFont(FONT1, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED)
        for (i in 1..totalPages) {
            // 读取第i页内容
            val page = stamper.getOverContent(i)
                                input.close()
                            }
                        }
                    }
                }
            val pageSize = reader.getPageSize(i)
            page.run {
                beginText()
                setFontAndSize(font, 12F)
                showTextAligned(Element.ALIGN_CENTER, "第 ${i} 页", pageSize.width / 2, 20F, 0F)
                endText()
            }
        }
        stamper.close()
        reader.close()
//        val render = ITextRenderer()
//        render.fontResolver.adF
        return output.toByteArray()
    }
    fun output(doc: XWPFDocument, outSrc: String) {
        doc.write(FileOutputStream(outSrc))
    fun pdfToPic(bytes: ByteArray): List<ByteArray> {
        val picOutput = mutableListOf<ByteArrayOutputStream>()
        val doc = PDDocument.load(bytes)
        val renderer = PDFRenderer(doc)
        val pageCount = doc.numberOfPages
        for (i in 0 until pageCount) {
            val output = ByteArrayOutputStream()
            picOutput.add(output)
            // dpi,图片像素点,dpi越高图片体积越大,216很清晰,105体积稳定
            val image = renderer.renderImageWithDPI(i, 216f)
            // 格式为JPG
            ImageIO.write(image, "jpg", output)
        }
        doc.close()
        return picOutput.map { it.toByteArray() }
    }
}