利用puppeteer做一次海报分享需求

你是否还因为前端插件生成图片模糊被ui和服务端嘲笑?

你是否还因为无法和ui小姐姐套近乎而感到伤心?

你又是否因为无法帮助行政小姐姐的忙而感到懊恼?

快来看看基于node的这款截图插件吧

需求背景:

最近设计小姐姐和我们研发同学提了一个需求。在用户预览分享组件时,动态生成一张海报图片 然后调用js-sdk分享

设计图如下:

image.png

  • 可以看到设计图上 ui元素很多,而且图片 文字都是动态获取的。直接让设计师出图显然不是最好选择

  • 第一个技术方案:我们是rn开发,使用了view-shop插件 截取某一个View 生成图片。但是缺点是由于生成的图片不是截取全屏而是某一个View盒子 所以必然会拉伸和模糊。舍弃

  • 依靠前端生成图片的方案很多,无非是通过canvas绘画最终生成img,或者将html截图输出img。最后,我通过nodejs+puppeteer 来实现导出一张图片

介绍一下puppeteer:Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome

我们要做的就是在node层模拟一个浏览器然后打开html在截屏,最后输出img即可

    // npm install puppeteer
    
    // index.js
    const Koa = require('koa');
    const Router = require('koa-router');
    const fs = require('fs');
    const path = require('path');
    
    router.get('/job-view', async (ctx, next) => {
        // 提前写好的 带有设计样式的页面
        const jobHtml = fs.readFileSync('./index.html', 'utf-8');
        ctx.body = jobHtml
        await next()
    })
    
    router.get('/job-view-to-img', async (ctx, next) => {
        const browser = await puppeteer.launch({
            defaultViewport: {
              width: 450,
              height: 800,
              isMobile: true,
              deviceScaleFactor: 3
            }
        });
        const page = await browser.newPage();
        const url = `http://localhost:3031/job-view?${ctx.querystring}`
        await page.goto(url);
        // 获取到的是一个buffer格式的img
        const imgBuffer = await page.screenshot({});
        // 重点来了:buffer可以直接当成图片的src来使用,所以 我们可以将这个接口直接当作img标签的src属性
        ctx.type = 'image/png';
        ctx.body = imgBuffer;
        await browser.close();
        await next()
    })
    
    app.use(router.routes())
    app.listen(3031)
复制代码
    // index.jsx
    render() {
        // 因为在node层定义的接口返回的是图片 所以可以直接拿来使用
        const url = `http://localhost:3031/job-view-to-img?${queryString}`
        return (
            <img src={url} />
        )
    }
复制代码
  • 这两段代码已经可以满足此次需求了。通过node中间层得到一个可以展示的url路径

  • 思考:如果下个迭代需要一个cdn链接应该如何做?

    // 我们对上文代码中的路由进行改造
    router.get('/job-view-to-img', async (ctx, next) => {
        const browser = await puppeteer.launch({
            defaultViewport: {
              width: 450,
              height: 800,
              isMobile: true,
              deviceScaleFactor: 3
            }
        });
        const page = await browser.newPage();
        const url = `http://localhost:3031/job-view?${ctx.querystring}`
        await page.goto(url);
        const imgBuffer = await page.screenshot({});
        // 把图片保存到本地
        const filePath = await path.join(`./view-shop${new Date().valueOf()}.png`)
        fs.writeFileSync(filePath, imgBuffer)
        // node里不支持formData 需要安装相应插件支持
        const formData = new FormData()
        formData.append('type', 'files')
        formData.append('file', fs.createReadStream(filePath))
        const {url} = await fetch('/upload', {body: formData})
        
        ctx.body = {
            status: 'ok!',
            data: {url}
        }
        await browser.close();
        await next()
    })
复制代码

这次需求带来的哪些思考??

  1. 我们怎么能更好的应对 ui设计要求高,并且动态化的需求?
  2. 对于一个增长/营销的团队,怎么利用前端优势帮助ui小姐姐或运营小姐姐提高效率呢?
  3. 我越来越意识到:前端并不只是单纯切图仔,而是要用专业知识帮助团队提高效率

所以我准备做一个工程化,一个适用于偏增长团队的(之前有在偏用户运营团队工作过的经历,在其中有大量的生成图片,裂变等需求。比较依赖ui对每个场景/每个用户出设计稿。)

他可以满足:

  • 通过跑脚本可以在本地生成N张不同用户的营销图片
  • 不受端的影响可以在前端生成分享图片
  • 图片要素从后端接口获取

那么有哪些场景呢:

  1. 运营小姐姐:我微信群里有20名同学,能不能给所有同学生成一张带有仪式感的图片?
  2. 行政小姐姐:我天天要做中午菜单的图片,好累,能不能自动生成
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享