利用周末写一个小工具:多设备预览图生成

起因是这样的,每次在调整完自己网站的时候,对于一些 UI 样式的调整,都需要提交代码并构建好后,通过第三方的预览图生成网站或者手动修图来制作一个网站预览图并重新上传提交代码。 这样似乎有些繁琐了,尝试寻求一个完美的工具来达到这个目的,但在 github 上寻一圈未果,所以就利用这个周末去写一个简单的工具来实现这个需求。

效果图

先来预览下效果图:

需求分析

  1. 收集多设备的外壳图片素材,必须带有透明通道,方便后续图片的合并
  2. 获取设备图片的屏幕尺寸(宽·高),截图的大小需贴合设备图片的尺寸
  3. 获取网页截图,需根据设备 UA 进行读取网页(这里使用 chromedp),然后裁剪成设备屏幕的尺寸
  4. 创建一个大的画布,将截图贴到画布上,接着将设备图片贴到截图上(这里需要考虑设备最终在画布上的坐标位置)
  5. 考虑 IPhone 设备的四角非直角,所以需要特殊处理下,将设备图片的圆角部分进行裁剪

实现思路

Step 1

利用 chromedp 包,读取本机带有 Chromium 内核的浏览器,初始化浏览器分配上下文,采用无头模式

ps:这里仅展示核心逻辑,完整代码请下滑到最底移步到 github 仓库查看

go 复制代码
// 初始化浏览器分配器上下文
browserPath, err := "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
opts := append(chromedp.DefaultExecAllocatorOptions[:],
    chromedp.ExecPath(browserPath),
    chromedp.NoFirstRun,
    chromedp.NoDefaultBrowserCheck,
    chromedp.Headless,
)
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()

并发读取网页,获取网页截图

go 复制代码
func takeScreenshotForDevice(ctx context.Context, url string, width, height int) (*image.RGBA, error) {
    var buf []byte
    
    err := chromedp.Run(ctx,
        chromedp.EmulateViewport(int64(width), int64(height)),
        chromedp.Navigate(url),
        chromedp.Sleep(3*time.Second),
        chromedp.WaitVisible("body", chromedp.ByQuery),
        chromedp.CaptureScreenshot(&buf),
    )
    if err != nil {
        return nil, err
    }

    img, _, err := image.Decode(bytes.NewReader(buf))
    if err != nil {
       return nil, err
    }

    bounds := img.Bounds()
    rgba := image.NewRGBA(bounds)
    draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)

    return rgba, nil
}

Step 2

创建画布

go 复制代码
canvas := imaging.New(2560, 1600, color.White)

Step 3

遍历所有截图并贴入画布,同时将设备外壳覆盖到截图上

ps:这里逻辑取值较复杂,故省略代码

go 复制代码
for _, dev := range Devices {
    ...
    // 读取设备图片
    ...

    // 解码图片数据
    ...

    // 转换为 RGBA 格式以便绘制
    ...

    // 将外壳覆盖到画布的对应位置(LayoutX/Y)
    ...
}

Step 4

保存并输出

go 复制代码
outFile := "output/preview.png"

f, err := os.Create(outFile)
if err != nil {
    panic(err)
}
defer f.Close()

if err := png.Encode(f, canvas); err != nil {
    panic(err)
}

fmt.Println("预览图生成成功:", outFile)

总结

复杂点

  • 设备在画布中的位置计算,以及截图的裁剪位置计算
  • 设备图片的圆角处理,这里用 ai 给的代码做了处理,也算是被 ai 坑了一回,四角虽做了处理,但是并没有透明化,也是耗费了很长时间才弄懂图片透明逻辑的处理

不足点

  • 访问页面未设置超时,对于一些网站访问会比较慢,可能会导致卡死,不过访问本地页面处理速度还是很快的,这里后续有时间优化下
  • 截图有时候内容会加载不全,问题同上

最后

源码已上传至 github 仓库:GitHub - vespeng/multi-device-preview,欢迎 fork 和 star。

相关推荐
Li_7695325 小时前
服务架构相关知识及演进
后端·架构
嗝o゚5 小时前
Flutter + 鸿蒙实现多模态智能终端实战:语音+手势+触控融合
flutter·华为·开源
码界奇点5 小时前
基于SpringBoot与Vue3的多租户中后台管理系统设计与实现
java·spring boot·后端·spring·车载系统·毕业设计·源代码管理
x***B4115 小时前
Spring Boot 实战项目如何写进简历?经验分享
经验分享·spring boot·后端
Code blocks5 小时前
SpringBoot从0-1集成Netty实现自定义协议开发
java·spring boot·后端
程序员爱钓鱼5 小时前
Node.js 编程实战:WebSocket实时通信详解
后端·node.js·trae
程序员爱钓鱼5 小时前
Node.js 编程实战:Cookie与Session深度解析
后端·node.js·trae
青梅主码5 小时前
麦肯锡最新发布《今天的消费者是如何花费他们的时间和金钱的?》:揭示2025年消费者在时间和金钱上的五大关键变化趋势
后端
coderCatIce5 小时前
MySQL-锁机制
后端·mysql