kmp desktop实现excel预览

先将excel转paf

https://blog.csdn.net/qq_42761569/article/details/121699594

Kotlin 复制代码
package util

import com.aspose.cells.License
import com.aspose.cells.PdfSaveOptions
import com.aspose.cells.Workbook
import com.geolo.desktop.common.utils.LogUtils
import java.io.FileOutputStream

object ExcelUtils {
    /**
     * excel 转 pdf
     *
     * @param excelFilePath excel文件路径
     * @param convertSheets 需要转换的sheet
     */
    fun excel2pdf(excelFilePath: String, convertSheets: IntArray?) {
        excel2pdf(excelFilePath, null, convertSheets)
    }

    /**
     * excel 转 pdf
     *
     * @param excelFilePath excel文件路径
     * @param pdfFilePath   pdf文件路径
     * @param convertSheets 需要转换的sheet
     */
    /**
     * excel 转 pdf
     *
     * @param excelFilePath excel文件路径
     */
    /**
     * excel 转 pdf
     *
     * @param excelFilePath excel文件路径
     * @param pdfFilePath   pdf文件路径
     */
    @JvmOverloads
    fun excel2pdf(
        excelFilePath: String,
        pdfFilePath: String? = null,
        convertSheets: IntArray? = null
    ) {
        var pdfFilePath = pdfFilePath
        try {
            pdfFilePath = pdfFilePath ?: getPdfFilePath(excelFilePath)
            // 验证 License
            license
            val wb = Workbook(excelFilePath)
            val fileOS = FileOutputStream(pdfFilePath)
            val pdfSaveOptions = PdfSaveOptions()
            pdfSaveOptions.onePagePerSheet = true
            if (null != convertSheets) {
                printSheetPage(wb, convertSheets)
            }
            wb.save(fileOS, pdfSaveOptions)
            fileOS.flush()
            fileOS.close()
            LogUtils.d("Excel convert success")
        } catch (e: Exception) {
            LogUtils.d("Excel convert failed")
            e.printStackTrace()
        }
    }

    /**
     * 获取 生成的 pdf 文件路径,默认与源文件同一目录
     *
     * @param excelFilePath excel文件
     * @return 生成的 pdf 文件
     */
    private fun getPdfFilePath(excelFilePath: String): String {
        return excelFilePath.split(".".toRegex()).dropLastWhile { it.isEmpty() }
            .toTypedArray()[0] + ".pdf"
    }

    private val license: Unit
        /**
         * 获取 license 去除水印
         * 若不验证则转化出的pdf文档会有水印产生
         */
        get() {
            val licenseFilePath = "excel-license.xml"
            try {
                val `is` = ExcelUtils::class.java.classLoader.getResourceAsStream(licenseFilePath)
                val license = License()
                license.setLicense(`is`)
            } catch (e: Exception) {
                LogUtils.d("license verify failed")
                e.printStackTrace()
            }
        }

    /**
     * 隐藏workbook中不需要的sheet页。
     *
     * @param sheets 显示页的sheet数组
     */
    private fun printSheetPage(wb: Workbook, sheets: IntArray?) {
        for (i in 1 until wb.worksheets.count) {
            wb.worksheets[i].isVisible = false
        }
        if (null == sheets || sheets.size == 0) {
            wb.worksheets[0].isVisible = true
        } else {
            for (i in sheets.indices) {
                wb.worksheets[i].isVisible = true
            }
        }
    }
}

适用于window平台的desktop应用破的 pff预览view

https://github.com/Patr1ick/fxPDF?tab=readme-ov-file

预览控件

Kotlin 复制代码
package ui.pdfpreview

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.SwingPanel
import com.geolo.desktop.common.utils.LogUtils
import eu.patrickgeiger.fxpdf.util.PDF
import eu.patrickgeiger.fxpdf.viewer.MinimalViewer
import javafx.application.Platform
import javafx.embed.swing.JFXPanel
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import java.io.File

@Composable
fun PdfPreview(
    state: PdfPreviewState,
    modifier: Modifier = Modifier,
    onCreated: (MinimalViewer) -> Unit = {},
    onDispose: (MinimalViewer) -> Unit = {},
) {
    var minimalViewer by remember { mutableStateOf<MinimalViewer?>(null) }
    val currentOnDispose by rememberUpdatedState(onDispose)

    minimalViewer?.let {
        DisposableEffect(it) {
            onDispose {
                it.pdf.closeDocument() //关闭文档
                currentOnDispose(it)
            }
        }
    }


    SwingPanel(factory = {
        JFXPanel().also { jfxP ->
            Platform.runLater {
                val rootVewView = MinimalViewer.MinimalViewerBuilder()
                    .setPDF(PDF(File(state.filePath)))
                    .build()
                minimalViewer = rootVewView
                val root = StackPane()
                root.children.add(minimalViewer)
                val scene = Scene(root)
                onCreated.invoke(rootVewView)
                jfxP.scene = scene
                Platform.enterNestedEventLoop("main") //退出后可重新进入
            }
        }

    }, modifier = modifier) {jfxpannel->
    }


}

class PdfPreviewState(
    val filePath: String
)
相关推荐
程序员敲代码吗9 小时前
在Excel中快速进行精确数据查找的方法
excel
黄大帅@lz9 小时前
openai提示词学习
windows·学习
MyY_DO9 小时前
十四课 易语言核心逆向
windows·od
AI袋鼠帝20 小时前
Claude4.5+Gemini3 接管电脑桌面,这回是真无敌了..
人工智能·windows·aigc
獨枭21 小时前
Windows 下安装与使用 Miniconda 完整指南
windows
CodeToGym1 天前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel
JMchen1231 天前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
命里有定数1 天前
保姆级教程:在 Windows (WSL2) 下本地部署 Qwen3-ASR
windows
儿歌八万首1 天前
硬核春节:用 Compose 打造“赛博鞭炮”
android·kotlin·compose·春节
lucky67071 天前
Windows 上彻底卸载 Node.js
windows·node.js