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("被打断了");
        }
    }

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

测试成功:

相关推荐
秋子aria9 小时前
模块的原理及使用
前端·javascript
菜市口的跳脚长颌9 小时前
一个 Vite 打包配置,引发的问题—— global: 'globalThis'
前端·vue.js·vite
胖虎2659 小时前
实现无缝滚动无滚动条的 Element UI 表格(附完整代码)
前端·vue.js
小左OvO9 小时前
基于百度地图JSAPI Three的城市公交客流可视化(一)——线路客流
前端
星链引擎9 小时前
企业级智能聊天机器人 核心实现与场景落地
前端
GalaxyPokemon9 小时前
PlayerFeedback 插件开发日志
java·服务器·前端
爱加班的猫9 小时前
深入理解防抖与节流
前端·javascript
自由日记9 小时前
学习中小牢骚1
前端·javascript·css
泽泽爱旅行9 小时前
业务场景-opener.focus() 不聚焦解决
前端
earthzhang20219 小时前
【2051】【例3.1】偶数
开发语言·数据结构·算法·青少年编程·图论