Excel 操作 转图片,转pdf等

news2025/6/3 9:07:14

方式一 spire.xls.free(没找设置分辨率的方法)

macOs开发Java GUI程序提示缺少字体问题解决 

 Spire.XLS:一款Excel处理神器_spire.xls免费版和收费版的区别-CSDN博客

官方文档 

Spire.XLS for Java 中文教程

        <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.xls.free</artifactId>
            <version>5.1.0</version>
        </dependency>


      <repositories>
        <repository>
            <id>e-iceblue</id>
            <name>e-iceblue</name>
            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
      </repositories>
/**
     * 功能描述: 处理将Excel文件转换为图片并提供下载的请求。
     * 参数说明:
     *   excelFilePath: 存储在服务器上的Excel文件的绝对路径。
     * 返回值说明: ResponseEntity 包含图片文件流,供浏览器下载。
     * 使用示例:
     *   GET /downloadExcelAsImage?excelFilePath=/path/to/your/excel.xlsx
     */
    @GetMapping( "/downloadImage/{id}")
    public ResponseEntity<InputStreamResource> downloadExcelAsImage(@PathVariable("id") String id) throws IOException {
        // 调用服务层方法将Excel转换为图片
        File imageFile = resultHistoryService.convertFromFilePath(id);
        // 设置HTTP头,用于文件下载
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + imageFile.getName());
        headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
        headers.add(HttpHeaders.PRAGMA, "no-cache");
        headers.add(HttpHeaders.EXPIRES, "0");
        InputStreamResource resource = new InputStreamResource(new FileInputStream(imageFile));
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(imageFile.length())
                // 或者根据实际生成的图片类型调整 MediaType.IMAGE_JPEG 等
                .contentType(MediaType.IMAGE_PNG)
                .body(resource);

    }
public File convertFromFilePath(String id) throws IOException {
        ResultHistoryDO resultHistoryDO = resultHistoryDao.get(id);
        String uploadPath = bootdoConfig.getUploadPath();
        String fileurl = resultHistoryDO.getFileurl();
        String[] split = fileurl.split("/files/");
        String fileName =uploadPath+ split[1] ;
        Workbook workbook = new Workbook();
        // 加载Excel文档
        workbook.loadFromFile(fileName);
        // 获取第一个工作表 (您可以根据需要选择特定的工作表)
        Worksheet sheet = workbook.getWorksheets().get(0);

        // 定义输出图片的文件名和路径 (这里我们将其保存在临时目录)
        // 您可以根据需要更改保存路径和文件名逻辑
        File outputFile = File.createTempFile("excel_image_", ".png");
        // 将工作表保存为图片
        sheet.saveToImage(outputFile.getAbsolutePath());

        return outputFile;

    }

方式二aspose-cells(推荐设置分辨率转出的图片更清晰)

 

<dependency>
            <groupId>com.luhuiguo</groupId>
            <artifactId>aspose-cells</artifactId>
            <version>23.1</version>
        </dependency>

 

package com.charsming.common.domain;

/**
 * 功能描述: 用于封装图片数据及其元数据的包装类。
 */
public class ImageDataWrapper {
    // 图片的字节数组
    private byte[] data;
    // 建议的下载文件名
    private String fileName;
    // 图片的MIME类型 (例如 "image/png")
    private String contentType;

    /**
     * 功能描述: ImageDataWrapper的构造函数。
     * 参数: data - 图片的字节数组。
     * 参数: fileName - 建议的下载文件名。
     * 参数: contentType - 图片的MIME类型。
     */
    public ImageDataWrapper(byte[] data, String fileName, String contentType) {
        this.data = data;
        this.fileName = fileName;
        this.contentType = contentType;
    }

    // Getter 方法
    public byte[] getData() {
        return data;
    }

    public String getFileName() {
        return fileName;
    }

    public String getContentType() {
        return contentType;
    }
}
@GetMapping("/downloadImage/{id}")
    public ResponseEntity<InputStreamResource> downloadExcelAsImage(@PathVariable("id") String id, HttpServletResponse response) throws Exception {
        try {
            // logger.info("请求下载图片,ID: {}", id); // 日志记录
            ImageDataWrapper imageData = resultHistoryService.convertExcelToImageData(id);
            HttpHeaders headers = new HttpHeaders();
            // 设置Content-Disposition,提示浏览器下载并指定文件名
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + imageData.getFileName() + "\"");
            // 其他缓存控制相关的头信息 (可选,但推荐)
            headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
            headers.add(HttpHeaders.PRAGMA, "no-cache");
            headers.add(HttpHeaders.EXPIRES, "0");
            InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(imageData.getData()));
            // logger.info("成功生成图片: {}, 大小: {} bytes", imageData.getFileName(), imageData.getData().length); // 日志记录
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(imageData.getData().length)
                    .contentType(MediaType.parseMediaType(imageData.getContentType()))
                    .body(resource);

        } catch (Exception e) {
            // logger.error("下载图片失败,ID: {}. 错误: {}", id, e.getMessage(), e); // 记录异常堆栈
            // 在发生错误时,返回一个带有错误信息的ResponseEntity
            // 您可以根据需要定制错误响应的格式,例如返回一个JSON对象
            String errorMessage = "下载图片失败: " + e.getMessage();
            InputStreamResource errorResource = new InputStreamResource(
                    new ByteArrayInputStream(errorMessage.getBytes(java.nio.charset.StandardCharsets.UTF_8))
            );
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .contentType(MediaType.TEXT_PLAIN)
                    .body(errorResource);
        }
@Override
    public ImageDataWrapper convertExcelToImageData(String id) throws Exception {
        ResultHistoryDO resultHistoryDO = resultHistoryDao.get(id);
        if (resultHistoryDO == null || resultHistoryDO.getFileurl() == null) {
            throw new Exception("未找到ID为 " + id + " 的结果历史记录或文件路径为空。");
        }
        String uploadPath = bootdoConfig.getUploadPath();
        String fileurl = resultHistoryDO.getFileurl();
        // 注意:此处的分割逻辑可能需要根据您的实际fileurl格式调整
        String[] split = fileurl.split("/files/");
        if (split.length < 2) {
            throw new Exception("文件路径格式不正确,无法提取文件名: " + fileurl);
        }
        String excelFilePath = uploadPath + split[1];
        Workbook workbook = null;
        // 使用try-with-resources确保baos关闭
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            workbook = new Workbook(excelFilePath);
            Worksheet worksheet = workbook.getWorksheets().get(0);

            // --- 全局修改默认字体 开始 ---
            Style defaultStyle = workbook.getDefaultStyle();
            Font defaultFont = defaultStyle.getFont();
            defaultFont.setName("Times New Roman"); // 设置全局默认字体名称
            defaultFont.setSize(11);   // 设置全局默认字体大小
            // defaultFont.setBold(false); // 根据需要设置其他属性
            workbook.setDefaultStyle(defaultStyle); // 应用修改后的默认样式到整个工作簿

            ImageOrPrintOptions imgOptions = new ImageOrPrintOptions();
            imgOptions.setImageType(ImageType.PNG);
            imgOptions.setHorizontalResolution(800);
            imgOptions.setVerticalResolution(800);
            SheetRender sr = new SheetRender(worksheet, imgOptions);
            if (sr.getPageCount() > 0) {
                // 渲染第一页
                int pageIndexToRender = 0;
                sr.toImage(pageIndexToRender, baos);
                // baos.flush(); // ByteArrayOutputStream的flush是空操作,可以省略
                byte[] imageBytes = baos.toByteArray();
                String originalFileName = new File(excelFilePath).getName();
                String baseName = originalFileName.contains(".") ? originalFileName.substring(0, originalFileName.lastIndexOf('.')) : originalFileName;
                String suggestedFileName = baseName  + (pageIndexToRender + 1) + ".png";
                String contentType = "image/png";
                return new ImageDataWrapper(imageBytes, suggestedFileName, contentType);
            } else {
                throw new Exception("Excel工作表 " + excelFilePath + " 为空或无法渲染成图片。");
            }
        } finally {
            if (workbook != null) {
                // 根据Aspose.Cells文档,Workbook类实现了IDisposable接口,
                // 在.NET中通常用using语句处理。在Java中,如果它有close()或dispose()方法,应在此调用。
                // 查阅文档,Aspose.Cells for Java 通常不需要显式调用 workbook.dispose(),垃圾回收器会处理。
                // 但如果遇到内存问题,可以检查是否有相关API。
            }
        }
    }
async function downloadImage(imageId) {
    // 构建下载文件的 URL
    const downloadUrl = `${prefix}/downloadImage/${imageId}`;
    let loadingIndex; // 用于存储 Layui 加载层的索引
    try {
        loadingIndex = layer.load(1);
        // 使用 fetch API 发送 GET 请求
        const response = await fetch(downloadUrl, {
            method: 'GET', // 后端是 @GetMapping,所以前端也用 GET
            cache: 'no-cache', // 根据你的后端设置,这里也禁用缓存
        });
        // 检查响应是否成功
        if (!response.ok) {
            // 如果服务器返回错误状态 (如 404, 500)
            // 你可以根据 response.status 和 response.statusText 来处理不同类型的错误
            const errorText = await response.text(); // 尝试获取错误信息文本
            throw new Error(`服务器错误: ${response.status} ${response.statusText}. ${errorText}`);
        }
        // 从响应头中获取文件名
        // 后端设置了 Content-Disposition: attachment; filename=...
        const contentDisposition = response.headers.get('content-disposition');
        let filename = `image_${imageId}.png`; // 默认文件名,如果无法从头部获取
        if (contentDisposition) {
            const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;"\n]*)/i);
            if (filenameMatch && filenameMatch[1]) {
                filename = decodeURIComponent(filenameMatch[1]);
            }
        }
        // 将响应体转换为 Blob 对象
        const blob = await response.blob();
        // 创建一个指向 Blob 的 URL
        const objectUrl = window.URL.createObjectURL(blob);
        // 创建一个临时的 <a> 标签用于触发下载
        const link = document.createElement('a');
        link.href = objectUrl;
        link.setAttribute('download', filename); // 设置下载的文件名
        document.body.appendChild(link);
        // 触发点击
        link.click();
        // 清理:移除 <a> 标签并释放 Object URL
        document.body.removeChild(link);
        window.URL.revokeObjectURL(objectUrl);
        // 如果你使用了 parent.layer.alert,可以在这里提示成功
        if (parent && parent.layer) {
            parent.layer.alert("图片下载成功!");
        }

    } catch (error) {
        console.error('下载图片时发生错误:', error);
        // 如果你使用了 parent.layer.alert,可以在这里提示错误
        if (parent && parent.layer) {
            parent.layer.alert(`连接或下载错误: ${error.message}`);
        }
        throw error; // 重新抛出错误,以便调用者可以进一步处理
    }
    finally {
            layer.close(loadingIndex);
    }
}


// 如果你仍然想在类似 $.ajax 的结构中使用,可以这样包装:
function triggerDownloadWithAjaxLikeStructure(imageId) {
    // 这里不再需要 $('#signupForm').serialize(),因为 ID 是直接传递的
    // 也不再需要 type: "POST",因为下载是 GET
    // async: false 非常不推荐,fetch 默认就是异步的,应该使用 Promise 处理

    downloadImage(imageId)
        .then(() => {
            // 成功回调,提示已经在 downloadImage 函数内部处理
            // 你可以在这里添加额外的成功逻辑
            console.log('图片下载流程成功完成。');
        })
        .catch(error => {
            // 错误回调,提示已经在 downloadImage 函数内部处理
            // 你可以在这里添加额外的错误处理逻辑
            console.error('图片下载流程发生错误。', error);
        });
}
 triggerDownloadWithAjaxLikeStructure(id)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python分配方案数 2023年信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析

python分配方案数 2023全国青少年信息素养大赛Python编程挑战赛复赛真题解析 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】1、Python比赛 信息素养大赛Python编程挑战赛 蓝桥杯python选拔赛真题详解

《信号与系统》第 5 章 离散时间傅里叶变换

5.0 引言 这一章将介绍并研究离散时间傅里叶变换&#xff0c;这样就完整地建立了傅里叶分析方法。 5.1 非周期信号的表示&#xff1a;离散时间傅里叶变换 5.1.1 离散时间傅里叶变换的导出 在第4章看到&#xff1a;一个连续时间周期方波的傅里叶级数可以看成一个包络函数的采…

动态IP与区块链:重构网络信任的底层革命

在数字经济蓬勃发展的今天&#xff0c;网络安全与数据隐私正面临前所未有的挑战。动态IP技术与区块链的深度融合&#xff0c;正在构建一个去中心化、高可信的网络基础设施&#xff0c;为Web3.0时代的到来奠定基础。 一、技术碰撞&#xff1a;动态IP与区块链的天然契合 动态I…

uniapp使用Canvas生成电子名片

uniapp使用Canvas生成电子名片 工作中有生成电子名片的一个需求&#xff0c;刚刚好弄了发一下分享分享 文章目录 uniapp使用Canvas生成电子名片前言一、上代码&#xff1f;总结 前言 先看效果 一、上代码&#xff1f; 不对不对应该是上才艺&#xff0c;哈哈哈 <template…

世冠科技亮相中汽中心科技周MBDE会议,共探汽车研发数字化转型新路径

近日&#xff0c;中汽中心2025年科技周MBDE前沿应用主题会议在天津成功举办。本次会议以“智汇津门共探MBDE前沿应用新征程”为主题&#xff0c;聚焦基于模型的数字工程&#xff08;MBDE&#xff09;方法论在汽车复杂系统研发中的创新实践与跨领域协同&#xff0c;旨在推动行业…

Linux笔记---线程

1. 线程的介绍 1.1 线程的概念 基本定义&#xff1a; 线程&#xff08;Thread&#xff09;是操作系统能够进行运算调度的最小单位。它被包含在进程&#xff08;Process&#xff09;之中&#xff08;或者说是进程的一部分、对进程的划分&#xff09;&#xff0c;是进程中的实际…

MCP架构深度解析:从基础原理到核心设计

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 持续学习&#xff0c;不断…

数据库暴露--Get型注入攻击

1.背景知识 1.1Post、Get的对比 特性GET 方法POST 方法HTTP 方法类型GETPOST数据位置URL 查询字符串(?key=value)请求体(Request Body)数据可见性明文显示在 URL 和浏览器历史中不可见(除非开发者工具查看)数据长度限制受 URL 长度限制(通常约 2048 字符)无明确限制(…

AI炼丹日志-26 - crawl4ai 专为 AI 打造的爬虫爬取库 上手指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇&#xff1a; MyBatis 更新完毕目前开始更新 Spring&#xff0c;一起深入浅出&#xff01; 大数据篇 300&#xff1a; Hadoop&…

ESP32-idf学习(四)esp32C3驱动lcd

一、前言 屏幕是人机交互的重要媒介&#xff0c;而且现在我们产品升级的趋势越来越高大尚&#xff0c;不少产品都会用lcd来做界面&#xff0c;而esp32c3在一些项目上是可以替代主mcu&#xff0c;所以驱动lcd也是必须学会的啦 我新买的这块st7789&#xff0c;突然发现是带触摸…

【python】uv管理器

uv是一个速度极快的 Python 包和项目管理器&#xff0c;用 Rust 编写。 安装 安装uv之前&#xff0c;确保你的电脑不需要安装了python 在Windows下&#xff0c;可以使用官方的脚本直接安装 powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.…

戴尔AI服务器订单激增至121亿美元,但传统业务承压

戴尔科技121亿美元的AI服务器订单&#xff0c;不仅超过了公司整个2025财年的AI服务器出货量&#xff0c;更让其AI订单积压达到144亿美元的历史高位。 戴尔科技最新财报显示&#xff0c;AI服务器需求的爆炸式增长正在重塑这家老牌PC制造商的业务格局&#xff0c;但同时也暴露出…

如何手搓扫雷(待扩展)

文章目录 一、扫雷游戏分析与设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析1.2.2 文件结构设计 二、扫雷游戏的代码实现三、扫雷游戏的扩展总结 一、扫雷游戏分析与设计 扫雷游戏网页版 1.1 扫雷游戏的功能说明 使用控制台&#xff08;黑框框的程序&a…

俄军操作系统 Astra Linux 安装教程

安装 U盘制作 Rufus 写盘工具&#xff1a;https://rufus.ie/ Astra Linux ISO 镜像文件&#xff1a;https://dl.astralinux.ru/astra/stable/2.12_x86-64/iso/ 准备一个8g以上的u盘&#xff0c;打开Rufus写盘工具&#xff0c;选择下载的iso镜像&#xff0c;写入u盘&#xff…

第三方软件评测机构如何助力软件品质提升及企业发展?

第三方软件评测机构与软件开发者及使用者无直接关联&#xff0c;它们提供全方位的检测和公正的评价服务。这样的评测可以展现客观的成效&#xff0c;对提升软件的品质具有显著影响&#xff0c;且在软件产业中发挥着至关重要的角色。 评测的客观性 独立第三方机构与软件开发者…

Python打卡训练营Day40

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#x…

JS逆向案例—喜马拉雅xm-sign详情页爬取

JS逆向案例——喜马拉雅xm-sign详情页爬取 声明网站流程分析总结 声明 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&am…

STM32CubeMX定时器配置

STM32CubeMX定时器配置 一&#xff0c;Mode界面1&#xff0c;Slave Mode (从模式)2&#xff0c;Trigger Source (触发源) 三&#xff0c;Channelx&#xff08;通道模式&#xff09;1&#xff0c;Input Capture2&#xff0c;Output Compare3&#xff0c;PWM Generation4&#xf…

QNAP MEMOS 域名访问 SSL(Lucky)

注意&#xff1a;下述是通过ssh、docker-compose方式安装docker的&#xff0c;不是直接在container station中安装的哈&#xff01;&#xff01;&#xff01; 一、编辑docker-compose.yml文件 用“#”号标识的&#xff0c;在保存文件的时候建议去掉&#xff0c;不然有时候会出…

如何将多张图组合到一张图里同时保留高的分辨率(用PPT+AdobeAcrobat)

文章目录 一、用PPT排版得到一页排布了很多图片的PPT二、用AdobeAcrobat打开pdf文件三、最后得到的图片 一、用PPT排版得到一页排布了很多图片的PPT 步骤如下 ①将幻灯片大小的长设置为17.2&#xff0c;宽根据图像多少进行调整&#xff0c;我这里是10 幻灯片大小的长设置步骤&…