基于DeepSeek实现PDF嵌入SVG图片无损放大

1. PDF中效果图

在这里插入图片描述

2. 询问Deepseek进行代码书写,不断优化后结果

/*** SVG工具类,用于生成价格趋势的SVG图表*/
public class SvgUtils {// SVG画布尺寸private static final int WIDTH = 800;private static final int HEIGHT = 500;private static final int PADDING = 60;// 生成SVG折线图public static String generatePriceTrendSvg(List<PriceData> data, String title, String subtitle) {if (data.isEmpty()) {return "<svg xmlns='http://www.w3.org/2000/svg' width='" + WIDTH + "' height='" + HEIGHT + "'></svg>";}// 计算价格和时间的范围double minPrice = data.stream().mapToDouble(PriceData::getPrice).min().orElse(0) * 0.8;double maxPrice = data.stream().mapToDouble(PriceData::getPrice).max().orElse(1) * 1.2;// 解析最小和最大日期String minYearMonth = data.stream().map(PriceData::getYearmonth).min(String::compareTo).orElse("2024-06");String maxYearMonth = data.stream().map(PriceData::getYearmonth).max(String::compareTo).orElse("2025-01");// 构建SVG内容StringBuilder svg = new StringBuilder();svg.append(String.format("<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>", WIDTH, HEIGHT));// 画背景svg.append(String.format("<rect width='%d' height='%d' fill='#ffffff'/>", WIDTH, HEIGHT));// 添加标题和副标题(居中显示)svg.append(String.format("<text x='%d' y='%d' font-size='20' font-family='Arial' fill='#333333' font-weight='bold' text-anchor='middle'>%s</text>",WIDTH / 2, 30, title));svg.append(String.format("<text x='%d' y='%d' font-size='14' font-family='Arial' fill='#666666' text-anchor='middle'>%s</text>",WIDTH / 2, 50, subtitle));// 画虚线网格线svg.append(drawGrid(minYearMonth, maxYearMonth, minPrice, maxPrice));// 画深色坐标轴svg.append(drawAxis(minYearMonth, maxYearMonth, minPrice, maxPrice));// 画浅色平滑折线svg.append(drawSmoothLine(data, minYearMonth, maxYearMonth, minPrice, maxPrice));svg.append("</svg>");return svg.toString();}// 画虚线网格线private static String drawGrid(String minYearMonth, String maxYearMonth, double minPrice, double maxPrice) {StringBuilder grid = new StringBuilder();// 水平网格线(价格)int numHorizontalLines = 5;for (int i = 0; i <= numHorizontalLines; i++) {double price = minPrice + (maxPrice - minPrice) * i / numHorizontalLines;int y = HEIGHT - PADDING - (int) ((price - minPrice) * (HEIGHT - 2 * PADDING) / (maxPrice - minPrice));grid.append(String.format("<line x1='%d' y1='%d' x2='%d' y2='%d' stroke='#e0e0e0' stroke-width='1' stroke-dasharray='5,5'/>",PADDING, y, WIDTH - PADDING, y));}// 垂直网格线(时间)List<String> yearMonths = generateYearMonths(minYearMonth, maxYearMonth);for (String yearMonth : yearMonths) {int x = PADDING + (int) ((getMonthIndex(yearMonth) - getMonthIndex(minYearMonth)) * (WIDTH - 2 * PADDING) / (yearMonths.size() - 1));grid.append(String.format("<line x1='%d' y1='%d' x2='%d' y2='%d' stroke='#e0e0e0' stroke-width='1' stroke-dasharray='5,5'/>",x, PADDING, x, HEIGHT - PADDING));}return grid.toString();}// 画深色坐标轴private static String drawAxis(String minYearMonth, String maxYearMonth, double minPrice, double maxPrice) {StringBuilder axis = new StringBuilder();// X轴(时间)axis.append(String.format("<line x1='%d' y1='%d' x2='%d' y2='%d' stroke='#333333' stroke-width='2'/>",PADDING, HEIGHT - PADDING, WIDTH - PADDING, HEIGHT - PADDING));// Y轴(价格)axis.append(String.format("<line x1='%d' y1='%d' x2='%d' y2='%d' stroke='#333333' stroke-width='2'/>",PADDING, PADDING, PADDING, HEIGHT - PADDING));// X轴标签List<String> yearMonths = generateYearMonths(minYearMonth, maxYearMonth);for (String yearMonth : yearMonths) {int x = PADDING + (int) ((getMonthIndex(yearMonth) - getMonthIndex(minYearMonth)) * (WIDTH - 2 * PADDING) / (yearMonths.size() - 1));axis.append(String.format("<text x='%d' y='%d' font-size='12' font-family='Arial' fill='#000000' text-anchor='middle'>%s</text>",x, HEIGHT - PADDING + 20, yearMonth));}// Y轴标签int numYLabels = 5;for (int i = 0; i <= numYLabels; i++) {double price = minPrice + (maxPrice - minPrice) * i / numYLabels;int y = HEIGHT - PADDING - (int) ((price - minPrice) * (HEIGHT - 2 * PADDING) / (maxPrice - minPrice));axis.append(String.format("<text x='%d' y='%d' font-size='12' font-family='Arial' fill='#000000' text-anchor='end'>%.2f</text>",PADDING - 10, y + 5, price));}return axis.toString();}// 画浅色平滑折线private static String drawSmoothLine(List<PriceData> data, String minYearMonth, String maxYearMonth, double minPrice, double maxPrice) {if (data.size() < 2) {return "";}StringBuilder path = new StringBuilder("<path d='M");for (int i = 0; i < data.size(); i++) {PriceData point = data.get(i);int x = PADDING + (int) ((getMonthIndex(point.getYearmonth()) - getMonthIndex(minYearMonth)) * (WIDTH - 2 * PADDING) / (getMonthIndex(maxYearMonth) - getMonthIndex(minYearMonth)));int y = HEIGHT - PADDING - (int) ((point.getPrice() - minPrice) * (HEIGHT - 2 * PADDING) / (maxPrice - minPrice));if (i == 0) {path.append(x).append(",").append(y);} else {// 计算控制点以实现平滑效果PriceData prevPoint = data.get(i - 1);int prevX = PADDING + (int) ((getMonthIndex(prevPoint.getYearmonth()) - getMonthIndex(minYearMonth)) * (WIDTH - 2 * PADDING) / (getMonthIndex(maxYearMonth) - getMonthIndex(minYearMonth)));int prevY = HEIGHT - PADDING - (int) ((prevPoint.getPrice() - minPrice) * (HEIGHT - 2 * PADDING) / (maxPrice - minPrice));int ctrlX1 = (prevX + x) / 2;int ctrlY1 = prevY;int ctrlX2 = (prevX + x) / 2;int ctrlY2 = y;path.append(" C").append(ctrlX1).append(",").append(ctrlY1).append(" ").append(ctrlX2).append(",").append(ctrlY2).append(" ").append(x).append(",").append(y);}}path.append("' fill='none' stroke='#66B3FF' stroke-width='2'/>");return path.toString();}// 生成从 minYearMonth 到 maxYearMonth 的连续月份列表private static List<String> generateYearMonths(String minYearMonth, String maxYearMonth) {List<String> yearMonths = new ArrayList<>();int year = Integer.parseInt(minYearMonth.substring(0, 4));int month = Integer.parseInt(minYearMonth.substring(5));while (true) {yearMonths.add(String.format("%04d-%02d", year, month));if (yearMonths.get(yearMonths.size() - 1).equals(maxYearMonth)) {break;}month++;if (month > 12) {month = 1;year++;}}return yearMonths;}// 将 yearmonth 转换为索引(从 0 开始)private static int getMonthIndex(String yearMonth) {int year = Integer.parseInt(yearMonth.substring(0, 4));int month = Integer.parseInt(yearMonth.substring(5));return (year - 2024) * 12 + (month - 1); // 假设最小年份是 2024}public static void main(String[] args) {List<PriceData> data = PriceData.getSampleData();String title = "价格走势图";String subtitle = "2024-06 至 2025-01";String svg = SvgUtils.generatePriceTrendSvg(data, title, subtitle);System.out.println(svg);}
}
@Data
public class PriceData {private String yearmonth;private Double price;public PriceData() {}public PriceData(String yearmonth, Double price) {this.yearmonth = yearmonth;this.price = price;}public static List<PriceData> getSampleData() {List<PriceData> data = new ArrayList<>();data.add(new PriceData("2025-01", 100.0)); // 2023-01-01data.add(new PriceData("2025-02", 105.0)); // 2023-01-02data.add(new PriceData("2025-03", 102.0)); // 2023-01-03data.add(new PriceData("2025-04", 110.0)); // 2023-01-04data.add(new PriceData("2025-05", 108.0)); // 2023-01-05return data;}
}

OK, 生成的SVG嵌入到html网页中进行渲染即可

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linyu-im

linyu-mini-server&#xff1a;springboot vue mysql。一款非常漂亮的linyu-im&#xff0c;它的mini版本&#xff0c;仅使用了mysql数据库 1、数据库有sqlite和mysql&#xff0c;这里修改为mysql 2、User类的badge徽章字段中使用了JacksonTypeHandler转为字符串为List<S…

提升数据库性能与可靠性:深入解析MySQL主从复制

在当今数据驱动的世界中&#xff0c;无论是初创公司还是大型企业&#xff0c;都面临着如何高效管理和保护其宝贵数据的挑战。随着业务的增长和用户需求的增加&#xff0c;单点数据库往往难以承受日益增长的负载压力&#xff0c;这就需要一种更加灵活、可靠的解决方案来确保系统…

【CVPR2025】 EVSSM:用状态空间模型高效去模糊

Efficient Visual State Space Model for Image Deblurring 论文信息 题目&#xff1a; Efficient Visual State Space Model for Image Deblurring 用于图像去模糊的高效视觉状态空间模型 源码&#xff1a;https://github.com/kkkls/EVSSM 创新点 提出了高效视觉状态空间模型…

Ubuntu虚拟机中使用QEMU搭建ARM64环境

Ubuntu虚拟机中使用QEMU搭建ARM64环境 通过本实验学习如何编译一个 ARM64 版本的内核 image&#xff0c;并且在QEMU 上运行起来。 文章目录 Ubuntu虚拟机中使用QEMU搭建ARM64环境一、安装aarch64交叉编译工具二、安装QEMU三、制作根文件系统1、根文件系统简介2、BusyBox构建根…

SQL经典查询

查询不在表里的数据&#xff0c;一张学生表&#xff0c;一张学生的选课表&#xff0c;要求查出没有选课的学生&#xff1f; select students.student_name from students left join course_selection on students.student_idcourse_selection.student_id where course_selecti…

【神经网络】python实现神经网络(一)——数据集获取

一.概述 在文章【机器学习】一个例子带你了解神经网络是什么中&#xff0c;我们大致了解神经网络的正向信息传导、反向传导以及学习过程的大致流程&#xff0c;现在我们正式开始进行代码的实现&#xff0c;首先我们来实现第一步的运算过程模拟讲解&#xff1a;正向传导。本次代…

黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程 针对人像、静物以及户外旅拍照片&#xff0c;运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具&#xff0c;如基本参数调整、HSL&#xff08;色相、饱和度、明亮度&#xff09;调整、曲线工具等改变照片原本的色彩、明度、对比度等属性&#xff0c;将…

Kubernetes中的 iptables 规则介绍

#作者&#xff1a;邓伟 文章目录 一、Kubernetes 网络模型概述二、iptables 基础知识三、Kubernetes 中的 iptables 应用四、查看和调试 iptables 规则五、总结 在 Kubernetes 集群中&#xff0c;iptables 是一个核心组件&#xff0c; 用于实现服务发现和网络策略。iptables 通…

C语言_数据结构总结5:顺序栈

纯C语言代码&#xff0c;不涉及C 想了解链式栈的实现&#xff0c;欢迎查看这篇文章&#xff1a;C语言_数据结构总结6&#xff1a;链式栈-CSDN博客 这里分享插入一下个人觉得很有用的习惯&#xff1a; 1. 就是遇到代码哪里不理解的&#xff0c;你就问豆包&#xff0c;C知道&a…

STM32之ADC

逐次逼近式ADC&#xff1a; 左边是8路输入通道&#xff0c;左下是地址锁存和译码&#xff0c;可将通道的地址锁存进ADDA&#xff0c;ADDB&#xff0c;ADDC类似38译码器的结构&#xff0c;ALE为锁存控制键&#xff0c;通道选择开关可控制选择单路或者多路通道&#xff0c;DAC为…

Magento2根据图片文件包导入产品图片

图片包给的图片文件是子产品的图片&#xff0c;如下图&#xff1a;A104255是主产品的sku <?php/*** 根据图片包导入产品图片&#xff0c;包含子产品和主产品* 子产品是作为主图&#xff0c;主产品是作为附加图片*/use Magento\Framework\App\Bootstrap;include(../app/boot…

初学STM32之简单认识IO口配置(学习笔记)

在使用51单片机的时候基本上不需要额外的配置IO&#xff0c;不过在使用特定的IO的时候需要额外的设计外围电路&#xff0c;比如PO口它是没有内置上拉电阻的。因此若想P0输出高电平&#xff0c;它就需要外接上拉电平。&#xff08;当然这不是说它输入不需要上拉电阻&#xff0c;…

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image 文章目录 图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image主要创新点模型架构图生成器生成器源码 判别器判别器源码 损失函数需要源码讲解的私信我 S…

STM32之I2C硬件外设

注意&#xff1a;硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器&#xff0c;此时会置状态寄存器的TXE为1&#xff0c;表示发送寄存器为空&#xff0c;然后往数据控制寄存器中一位一位的移送数…

Git - 补充工作中常用的一些命令

Git - 补充工作中常用的一些命令 1 一些场景1.1 场景11.2 场景21.3 场景31.4 场景41.5 场景51.6 场景61.7 场景71.8 场景81.9 场景91.10 场景101.11 场景111.12 场景121.13 场景131.14 场景141.15 场景15 2 git cherry-pick \<commit-hash\> 和 git checkout branch \-\-…

AI 驱动的软件测试革命:从自动化到智能化的进阶之路

&#x1f680;引言&#xff1a;软件测试的智能化转型浪潮 在数字化转型加速的今天&#xff0c;软件产品的迭代速度与复杂度呈指数级增长。传统软件测试依赖人工编写用例、执行测试的模式&#xff0c;已难以应对快速交付与高质量要求的双重挑战。人工智能技术的突破为测试领域注…

Unity--Cubism Live2D模型使用

了解LIVE2D在unity的使用--前提记录 了解各个组件的作用 Live2D Manuals & Tutorials 这些文件都是重要的控制动画参数的 Cubism Editor是编辑Live2D的工具&#xff0c;而导出的数据的类型&#xff0c;需要满足以上的条件 SDK中包含的Cubism的Importer会自动生成一个Pref…

Windows 系统 Docker Desktop 入门教程:从零开始掌握容器化技术

文章目录 前言一、Docker 简介二、Docker Desktop 安装2.1 系统要求2.2 安装步骤 三、Docker 基本概念四、Docker 常用命令五、实战&#xff1a;运行你的第一个容器5.1 拉取并运行 Nginx 容器5.2 查看容器日志5.3 停止并删除容器 六、总结 前言 随着云计算和微服务架构的普及&…

Lab17_ Blind SQL injection with out-of-band data exfiltration

文章目录 前言&#xff1a;进入实验室构造 payload 前言&#xff1a; 实验室标题为&#xff1a; 带外数据泄露的 SQL 盲注 简介&#xff1a; 本实验包含一个SQL盲目注入漏洞。应用程序使用跟踪Cookie进行分析&#xff0c;并执行包含提交的Cookie值的SQL查询。 SQL查询是异…

Vue 框架深度解析:源码分析与实现原理详解

文章目录 一、Vue 核心架构设计1.1 整体架构流程图1.2 模块职责划分 二、响应式系统源码解析2.1 核心类关系图2.2 核心源码分析2.2.1 数据劫持实现2.2.2 依赖收集过程 三、虚拟DOM与Diff算法实现3.1 Diff算法流程图3.2 核心Diff源码 四、模板编译全流程剖析4.1 编译流程图4.2 编…