从木偶截图中保存图像数据的推荐方法是什么?

时间:2019-06-20 21:06:45

标签: node.js mongodb puppeteer

我正在开发一个用于在地图上绘制正在运行的路线并将其保存到mongodb数据库的应用程序。

当前,我正在使用puppeteer来访问应用程序中的路线,并将坐标作为查询字符串传递给地图组件。加载地图后,我将截屏,将返回的Buffer转换为base64编码的字符串,将其保存到数据库,然后使用该字符串在前端显示图像。

整个过程的中间件如下:

exports.screenshotMap = async (req, res, next) => {
  try {
    const { lineFeatures } = req.body;
    const browser = await puppeteer.launch({
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    // open new browser
    const page = await browser.newPage();

    // create array of coordinates from geojson features
    const coords = lineFeatures.map(line => line.geometry.coordinates);
    // reduce to 2D array of [lat, lon] coords
    const flattenedCoords = coords.reduce((accum, arr) => {
      return accum.concat(arr);
    }, []);
    // Stringify coords before using them as query string
    const coordsStr = JSON.stringify(flattenedCoords);

    // goto page with map sending coordintaes along
    await page.goto(`http://localhost:3000/test?coords=${coordsStr}`, {
      waitUntil: 'networkidle0',
    });

    // wait for map to load, call onLoad callback, and set state to make the h1 visible
   await page.waitForSelector('h1');
    // wait one more second to make sure all tiles for the map are loaded. Longer routes can require significantly more tiles
    await page.waitFor(1000);

    const image = await page.screenshot({
      type: 'jpeg',
      quality: 100,
      clip: {
        x: 0,
        y: 70,
        width: 640,
        height: 360,
      },
      omitBackground: true,
    });

    await browser.close();
    // convert buffer to base64 string
    const base64Image = await image.toString('base64');
    // attach to request object to be used in the next middleware
    req.image = base64Image;
    next();

  } catch (err) {
    res.status(400).send(err);
  }
};

此方法有效,但是我想知道是否有更好的方法。我已经读到存储Buffer数据更好的用于数据库内存,因为base64字符串很长。更好的方法是保存Buffer数据并将其转换为编码的字符串,然后再将其发送回客户端吗?是否有推荐的方式来处理此类数据?我有兴趣听别人的想法和方法。

1 个答案:

答案 0 :(得分:2)

我想出的解决方案是将屏幕截图返回的缓冲区保存到S3存储桶中,然后将唯一的标识符URL存储到我的数据库中。

以下是屏幕截图的中间件:

import puppeteer from 'puppeteer';
//import chromium from 'chrome-aws-lambda';

const takeMapImage = handler => async (req, res) => {
  try {
    const { lines } = req.body;

    // should work for most node projects
    const browser = await puppeteer.launch({
       args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    // if youre using lambda functions
    // const browser = await chromium.puppeteer.launch({
    //  executablePath: await chromium.executablePath,
    // args: chromium.args,
    // defaultViewport: chromium.defaultViewport,
    // headless: chromium.headless,
    // });

    // open new browser
    const page = await browser.newPage();

    const url = 'https://yourwebstieurl.com';

    await page.goto(
      `${url}`,
      {
        waitUntil: 'networkidle0',
      }
    );

    // provide some waiting time if needed
    await page.waitFor(1000);

   // image buffer returned from screenshot
    const imageBuffer = await page.screenshot({
      type: 'jpeg',
      quality: 100,
      clip: {
        x: 0,
        y: 0,
        width: 640,
        height: 360,
      },
      omitBackground: true,
    });


    // attach to request object to be used in the next middleware
    req.buffer = imageBuffer;

    next();

  } catch (err) {
    console.log(err);
    return res
      .status(422)
      .send({ message: 'there was an error taking picture' });
  }
};

然后使用中间件将图像保存到s3。您将需要创建一个存储桶并获取凭据:

import AWS from 'aws-sdk';
import uuid from 'uuid/v1';

// create your s3instance with your credentials
const s3 = new AWS.S3({
  accessKeyId: process.env.S3_ACCESS_KEY_ID,
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
});

const saveImageToS3 = handler => async (req, res) => {
  try {
    // use user id as identifier in S3 bucket
    const { id } = req.user;
    const { buffer } = req;

    // s3 file name
    const key = `${id}/${uuid()}.jpeg`;

    const params = {
      Bucket: 'your-bucket-name',
      Key: key,
      Body: buffer,
      ContentEncoding: 'base64',
      ContentType: 'image/jpeg',
    };

    // upload to bucket
    const response = await s3.upload(params).promise();
    // pass url to next middleware to save to db
    req.image = response.Location;
    next();
  } catch (e) {
    console.log(e);
    return res.status(422).json({ message: 'user error saving image to s3' });
  }
};