使用wkhtmltoimage实现生成长图分享
需求
用户可以选择以长图的形式分享本网页
方法
- wkhtmltopdf
- wkhtmltopdf url file
- wkhtmltoimage url file
- java
- Runtime.getRuntime().exec()
下载
直接去官网下载对应的版本:官网
命令行使用WK
> wkhtmltopdf https://www.nowcoder.com /opt/project/java/mycommunity-pdfs/1.pdf
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done> wkhtmltoimage https://www.nowcoder.com /opt/project/java/mycommunity-images/1.png
Loading page (1/2)
Rendering (2/2)
Done// 上面那条命令生成的长图太大了,可以使用下面这条:以75%的质量输出
> wkhtmltoimage --quality 75 https://www.nowcoder.com /opt/project/java/mycommunity-images/1.png
Loading page (1/2)
Rendering (2/2)
Done
在java中调用
application.properties:
mycommunity.path.domain=http://localhost:8080
server.servlet.context-path=/myCommunity
# WK
wk.image.command=/usr/local/bin/wkhtmltoimage
wk.image.storage=/opt/project/java/mycommunity-images/
WK配置类,在每次程序开始运行时自动生成存放图像的文件夹
@Configuration
public class WkConfig {private static final Logger logger = LoggerFactory.getLogger(WkConfig.class);@Value("${wk.image.storage}")private String wkImageStorage;@PostConstructpublic void init(){// create the dic about WKimageFile file = new File(wkImageStorage);if(!file.exists()){file.mkdir();logger.info("create the dictionary of WKimage: " + wkImageStorage);}}
}
调用WK的控制层,因为生成长图比较耗时,所以使用异步操作,在用户操作时调用Kafka的生产者生成事件,通知消费者:
@Controller
public class ShareController implements CommunityConstant {private static final Logger logger = LoggerFactory.getLogger(ShareController.class);@Autowiredprivate EventProducer eventProducer;@Value("${mycommunity.path.domain}")private String domain;@Value("${server.servlet.context-path}")private String contextPath;@Value("${wk.image.storage}")private String wkImageStorage;@GetMapping(path = "/share")@ResponseBodypublic String share(String htmlUrl){// generate the file nameString fileName = CommunityUtil.generateUUID();// Asynchronous generation long picEvent event = new Event().setTopic(TOPIC_SHARE).setData("htmlUrl", htmlUrl).setData("fileName", fileName).setData("suffix", ".png");eventProducer.fireEvent(event);Map<String, Object> map = new HashMap<>();map.put("shareUrl", domain + contextPath + "/share/image" + fileName);return CommunityUtil.getJSONString(0, null, map);}//@GetMapping(path = "/share/image/{fileName}")public void getShareImage(@PathVariable("fileName") String fileName, HttpServletResponse response){if(StringUtils.isBlank(fileName)){throw new IllegalStateException("the file name cannot be blank");}response.setContentType("image/png");File file = new File(wkImageStorage + "/" + fileName + ".png");try {OutputStream os = response.getOutputStream();FileInputStream fis = new FileInputStream(file);byte[] data = new byte[1024];int len = 0;while ((len = fis.read(data)) != -1) {os.write(data, 0, len);}} catch (IOException e) {logger.error("querty the long image failed: ", e.getMessage());}}
}
Kafka的消费者,定义如何消费生成长图的事件:
@Component
public class EventConsumer implements CommunityConstant {@Autowiredprivate static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);@Value("${wk.image.storage}")private String wkImageStorage;@Value("${wk.image.command}")private String wkImageCommand;@KafkaListener(topics = {TOPIC_SHARE})public void handleShareMessage(ConsumerRecord record) {if (record == null || record.value() == null) {logger.error("the content of the message is empty");return;}Event event = JSONObject.parseObject(record.value().toString(), Event.class);if (event == null) {logger.error("message format error");return;}String htmlUrl = (String) event.getData().get("htmlUrl");String fileName = (String) event.getData().get("fileName");String suffix = (String) event.getData().get("suffix");String cmd = wkImageCommand + " --quality 75 " + htmlUrl + " " + wkImageStorage + "/" + fileName + suffix;try {Runtime.getRuntime().exec(cmd);logger.info("generate long image successfully: " + cmd);} catch (IOException e) {logger.info("generate long image fail: " + e.getMessage());}}
}
测试
相关文章:

使用wkhtmltoimage实现生成长图分享
需求 用户可以选择以长图的形式分享本网页 方法 wkhtmltopdf wkhtmltopdf url filewkhtmltoimage url file java Runtime.getRuntime().exec() 下载 直接去官网下载对应的版本:官网 命令行使用WK > wkhtmltopdf https://www.nowcoder.com /opt/project/…...

新风机未来什么样?
新风机在未来将会有许多令人期待的发展和改进,让我们一起来看一看吧!以下是新风机未来的一些可能性: 智能化和智能家居:新风机将更多地与智能家居系统整合,通过物联网和人工智能技术,实现智能控制和智能调节…...
python的几种数据类型的花样玩法(一)
Python是一种动态类型语言,这意味着在Python中,你可以操作多种不同的数据类型,而且这些数据类型可以自动转换。以下是一些Python数据类型的花样玩法: 数字: 整数 (1, 100, -786 等) 浮点数 (1.1, -78.4, 3.14159 等)…...

python回调函数之获取jenkins构建结果
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 需求背景: 现在用jenkins构建自动化测试(2个job),公司现将自动化纳入到发布系统 要求每次构建成功之后&am…...
Docker底层实现
Docker采用c/s架构,Docker守护进程( Daemon )作为服务端,接受来自客户端(命令行)的请求,并处理这些请求(创建、运行、分发容器) 。客户端和服务端既可以运行在一个机器上…...

PY32F003F18之RS485通讯
PY32F003F18将USART2连接到RS485芯片,和其它RS485设备实现串口接收后再转发的功能。 一、测试电路 二、测试程序 #include "USART2.h" #include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf() #include "…...

概率论与数理统计学习笔记(7)——全概率公式与贝叶斯公式
目录 1. 背景2. 全概率公式3. 贝叶斯公式 1. 背景 下图是本文的背景内容,小B休闲时间有80%的概率玩手机游戏,有20%的概率玩电脑游戏。这两个游戏都有抽卡环节,其中手游抽到金卡的概率为5%,端游抽到金卡的概率为15%。已知小B这天抽…...

深入了解 Axios 的 put 请求:使用技巧与最佳实践
在前端开发中,我们经常需要与后端服务器进行数据交互。其中,PUT 请求是一种常用的方法,用于向服务器发送更新或修改数据的请求。通过发送 PUT 请求,我们可以更新服务器上的资源状态。 Axios 是一个流行的 JavaScript 库࿰…...

浅谈Http协议、TCP协议(转载)
TCP标志位,有6种标示:SYN(synchronous建立联机) ,ACK(acknowledgement 确认) ,PSH(push传送),FIN(finish结束) ,RST(reset重置), URG(urgent紧急) Sequence number(顺序号码) ,Acknowledge num…...
flatten-maven-plugin使用
这篇文章主要介绍了flatten-maven-plugin使用,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 − 目录 一、简介 1.1 作用1.2 goal介绍二、使用总结 一、简介 1.1 作用 将pom工程父子pom的版…...

Vue3中快速简单使用CKEditor 5富文本编辑器
Vue3简单使用CKEditor 5 前言准备定制基础配置富文本配置目录当前文章demo目录结构 快速使用demo 前言 CKEditor 5就是内嵌在网页中的一个富文本编辑器工具 CKEditor 5开发文档(英文):https://ckeditor.com/docs/ckeditor5/latest/index.htm…...

qt简易网络聊天室 数据库的练习
qt网络聊天室 服务器: 配置文件.pro QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exac…...

Navicat连接mysql8.0:提示无法加载身份验证插件“caching_sha2_password”
Navicat连接mysql时,提示:Unable to load authentication plugin ‘caching_sha2_password‘. 原因:mysql 8.0 默认使用 caching_sha2_password 身份验证机制。 D:\MySQL8.0\install\bin>mysql -uroot -p123456789 #登录 mysql: [War…...

手写签名到背景上合为1张图
手写签名到背景上合为1张图 package.json中 "signature_pad": "3.0.0-beta.3"<template><div class"home"><canvas id"canvas" width"500" height"300"></canvas><button click"…...

华为认证系统学习大纲及课程
前言 任何学习过程都需要一个科学合理的学习路线,才能够有条不紊的完成我们的学习目标。华为认证网络工程师所需学习的内容纷繁复杂,难度较大,所以今天特别为大家整理了一个全面的华为认证网络工程师学习大纲及课程,帮大家理清思…...

某米ax3000路由器组网解析
我们使用某米k60手机与某米ax3000 wifi6路由器组网,来分析和学习网络速率与瓶颈限制。 某米 AX3000 路由器简介 某米 AX3000 路由器是一款支持 WiFi 6 的双频路由器,它的 MIMO 是 22,也就是两根天线。MIMO 是 Multiple Input Multiple Outpu…...

【leetcode 力扣刷题】数学题之除法:哈希表解决商的循环节➕快速乘求解商
两道和除法相关的力扣题目 166. 分数到小数29. 两数相除快速乘解法一:快速乘变种解法二: 二分查找 快速乘 166. 分数到小数 题目链接:166. 分数到小数 题目内容: 题目是要我们把一个分数变成一个小数,并以字符串的形…...
Union类型和集合的union()方法-set.union()
Union类型和集合的Union 方法 一、Union类型1.Union类型由来2.Union类型的语法3.Union类型的使用4.一些等价写法 二、Set.union()union() 语法示例代码 一、Union类型 1.Union类型由来 Python中的Union类型是 3.10版本引入的新功能之一。它是一种特殊的类型注释,用…...

简明SQL别名指南:掌握AS实现列名更名
在 SQL 查询中,使用 {原始字段名} as {别名} 的语法来为查询结果的列赋予更直观的名称,以提高查询结果的可读性和可理解性。 以下是用到的表。 用AS更名 例如,查询表1的name字段,并将其更名为"名字",同时查…...
基于量子密钥分发和区块链技术的新一代加密通信系统
量子通信与区块链构建下一代加密通信基础设施 量子技术和区块链技术是国家信息安全和国家数字化转型的重要组成部分,在国家战略中具有重要地位。“十四五”规划纲要将“加快数字发展建设数字中国”作为独立篇章,指出要进一步明确发展云计算、大数据、物联…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...