java后台生成模拟聊天截图并返回给前端

要实现前端的一些聊天记录,生成聊天记录的那种截图,效果如下:

网上看了很多,大部分都没有资源,要么就是仗着一点技术非要挣钱用,我真看不起。

而我的需求比较简单,就是前端将标题、内容、图片、联系方式等发到后端,然后后端生成截图,并返回给前端。

技术路线比较多,我的技术路线是:

前端发起请求--后端java调用python脚本利用selenium生成html的截图,裁剪--上传到七牛云--返回链接给前端。

  • 为什么不用canvas? canvas不支持很多css样式,而我前端比较菜,我真调不出来想要的样式。

  • 为什么直接用java而要用python? 因为我swing、以及java的绘图也比较菜,用起来打脑壳。

  • 为什么用selenium? 首先用html生成聊天记录页是非常简单的一件事情,然后用selenium进行页面截图也是非常简单的。

第一步,首先使用thymeleaf写一个聊天页面图

例子:

<html>
<head>
  <meta charSet="utf-8"/>
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no"/>
  <title>聊天记录生成页</title>
  <style>
    body {
      background-color: #49270a;
      margin: 0;
    }
    .container {
      width: 300px;
      min-height: 600px;
      background-color: #efdbc9;
      display: flex;
      flex-direction: column;
      align-items: center;
      font-family: "微软雅黑";
    }
    .time {
      background-color: aliceblue;
      border-radius: 20px;
      padding: 2px 10px 2px 10px;
      margin-top: 20px;
      margin-bottom: 20px;
      font-size: 12px;
    }
    .label {
      background-color: aliceblue;
      border-radius: 5px;
      padding: 2px 10px 2px 10px;
      color: blue;
      margin-right: auto;
      margin-left: 20px;
      font-size: 12px;
    }
    .title {
      margin-top: 5px !important;
    }
    .images img{
      max-width: 180px;
    }
    .public {
      margin-right: auto;
      margin-left: 20px;
      margin-top: 20px;
      background-color: aliceblue;
      border-radius: 5px;
      padding: 10px 20px 10px 20px;
      max-width: 180px;
      font-size: 14px;
    }
    .admin-value {
      margin-left: auto;
      margin-right: 20px;
      margin-top: 40px;
      background-color: aliceblue;
      border-radius: 5px;
      padding: 10px 20px 10px 20px;
      max-width: 180px;
    }
  </style>
  <script>
  </script>
</head>
<body>
<div class="container">
  <div class="time">2024-07-02 13:33:44</div>
  <div class="label">#求助</div>
  <div class="public title">找会做小程序的人</div>
  <div class="public content">墙墙你好,帮我找几个会做微信小程序的人好不好啊?</div>
  <div class="public images"><image src="https://image.ruankun.xyz/" mode=""/></div>
  <div class="public contact">联系方式:1878355</div>
  <div class="admin-value">墙墙已收到,四川农业大学校园墙:pythonbutinghua</div>
</div>
</body>
</html>

是不是so easy,而且多张图片的情况下也能自适应,我这里都用的静态内容,当然你可以在springboot的controller中传入你需要的数据动态生成页面。

第二步、利用python selenium截取页面图

首先你要确保你会使用python调用selenium并截获页面,这个过程本身是非常简单的,但是它存在一个问题,就是截图是整个页面,需要对其进行裁剪,裁出你需要的部分,我的做法是将不需要的部分全部变成一个RGB值,然后截图后裁掉不需要的部分,值得说的是,RGB的值总共有255255 255个,所以一般情况下裁剪的过程中不会出现错误。

例子:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException, TimeoutException 
from PIL import Image
import random
import string

def generate_random_string(length=16):
    # 定义可选择的字符集,包括所有字母和数字
    characters = string.ascii_letters + string.digits
    # 使用random.choice从字符集中随机选择字符,并使用join方法将它们连接成一个字符串
    random_string = ''.join(random.choice(characters) for _ in range(length))
    return random_string

def crop_image_by_color(input_image_path, target_color, output_image_path):
    # 打开图像文件
    image = Image.open(input_image_path)
    # 转换为RGB模式,确保图像包含红、绿、蓝三个颜色通道
    image = image.convert('RGB')
    # 获取图像的宽度和高度
    width, height = image.size
    # 初始化x和y坐标为None,用于记录目标颜色的首个位置出现
    x_pos = None
    y_pos = None
    # 遍历图像,从左至右、从上至下搜索目标颜色
    for x in range(width):
        pixel = image.getpixel((x, 0))
        if pixel == target_color:
            x_pos = x
            break
    for y in range(height):
        pixel = image.getpixel((0, y))
        if pixel == target_color:
            y_pos = y
            break
        # 如果已找到x_pos和y_pos,则无需继续遍历
        if x_pos is not None and y_pos is not None:
            break
    
    # 根据找到的坐标裁剪图像
    cropped_image = image.crop((0, 0, x_pos + 1, y_pos + 1))
    # 注意:crop方法的坐标是左闭右开的,因此x_pos和y_pos需要加1以确保包含目标像素
    
    # 保存裁剪后的图像
    cropped_image.save(output_image_path)


# get直接返回,不再等待界面加载完成
desired_capabilities = DesiredCapabilities.CHROME
desired_capabilities["pageLoadStrategy"] = "none"

# 设置微软驱动器的环境
options = webdriver.EdgeOptions()
options.use_chromium = True
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('--headless')
# 设置浏览器不加载图片,提高速度
# options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})

# 创建一个微软驱动器
driver = webdriver.Edge(options=options)
try:
    # 打开指定的网页
    url = "http://localhost:8080/index"
    driver.get(url)

    # 等待页面加载完成(可选,根据页面加载情况调整)
    # 例如,等待某个元素加载完成
    # element_present = EC.presence_of_element_located((By.ID, "someElementId"))
    # WebDriverWait(driver, 10).until(element_present)

    # 截图并保存
    random_str = generate_random_string()
    screenshot_path = random_str+ ".png"
    driver.save_screenshot(screenshot_path)
    crop_image_by_color(random_str + '.png', (73,39,10), random_str + '2.png')
    print(random_str)
finally:
    # 关闭浏览器
    driver.quit()

第三步、在springboot中调用python脚本

在controller或者service中调用执行脚本,并拿到文件名后上传到七牛云,最后将链接返回前端,我这里只跑出调用脚本成功的一步,后面上传并返回链接可以自己尝试写:

	@GetMapping("/generateChat")
    public ResponseEntity<String> generateChat(){
        try {
            Process process = Runtime.getRuntime().exec("C:/Users/qkmc/.conda/envs/python310/python.exe D:/IdeaProjects/campuswall/src/main/resources/pythonScript/generateChat.py");
            // 读取脚本的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String result = "";
            String line;
            while ((line = reader.readLine()) != null) {
                result += line;
            }
            // 等待进程结束并获取退出状态
            int exitCode = process.waitFor();
            if (exitCode == 0){
                return ResponseEntity.ok(result);
            }else {
                return ResponseEntity.ok("python异常退出:" + exitCode);
            }

        } catch (IOException e) {
            return ResponseEntity.ok("error");
        } catch (InterruptedException e) {
            return ResponseEntity.ok("被打断了");
        }
    }

默认情况下,生成的图片存在根目录下,你可以自己解决这个问题:

测试成功:

相关推荐
Root_Smile几秒前
【C++】类和对象
开发语言·c++
Reese_Cool2 分钟前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法
一行玩python16 分钟前
SQLAlchemy,ORM的Python标杆!
开发语言·数据库·python·oracle
「QT(C++)开发工程师」20 分钟前
【qt版本概述】
开发语言·qt
NightCyberpunk23 分钟前
HTML、CSS
前端·css·html
xcLeigh34 分钟前
HTML5超酷响应式视频背景动画特效(六种风格,附源码)
前端·音视频·html5
zhenryx35 分钟前
前端-react(class组件和Hooks)
前端·react.js·前端框架
ZwaterZ37 分钟前
el-table-column自动生成序号&&在序号前插入图标
前端·javascript·c#·vue
TheITSea1 小时前
云服务器宝塔安装静态网页 WordPress、VuePress流程记录
java·服务器·数据库
AuroraI'ncoding1 小时前
SpringMVC接收请求参数
java