node.jspuppeteerpuppeteer-cluster

How to save a canvas as an image using puppeteer?


I'm trying to load a page with a canvas and then save it as an image.

For example, this page. On Chrome, I can right click the canvas with a circle on the upper right side of the page and click save image. I want to do this exact same thing but through NodeJS and Puppeteer. Is this possible?

So far I'm trying to select it via

const express = require('express')
const router = express.Router()
const puppeteer = require('puppeteer')
const { Cluster } = require('puppeteer-cluster')

(async () => {
    
    const cluster = await Cluster.launch({
        concurrency: Cluster.CONCURRENCY_PAGE,
        maxConcurrency: 2,
    })
    
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    await cluster.task(async({ page, data: url }) => {
        // let starmapId = 'celestial-canvas'

        await page.goto(url)
        const canvas = await page.evaluate(() => document.querySelector('#myCanvas'))
        return canvas  // .toDataURL()
    })
    
    router.get('/export/canvas', function(req, res) {
        
        // Get URL
        var url = 'https://www.w3schools.com/html/tryit.asp?filename=tryhtml5_canvas_tut_path2'
        
        cluster.execute(url).then( canvas => {
            console.log(canvas)
            res.send(canvas)
        })
    })
    
})();

module.exports = router

But canvas is returning null.


Solution

  • In your example, the canvas is inside an iframe. So you need to get the frame first, then you will able to transfer the string with the data URL:

    import puppeteer from 'puppeteer';
    
    const browser = await puppeteer.launch(/* { headless: false, defaultViewport: null } */);
    
    try {
      const [page] = await browser.pages();
    
      await page.goto('https://www.w3schools.com/html/tryit.asp?filename=tryhtml5_canvas_tut_path2');
    
      const frame = await (await page.$('#iframeResult')).contentFrame();
    
      const data = await frame.evaluate(() => {
        return document.querySelector('#myCanvas').toDataURL();
      });
      console.log(data); // data:image/png;base64,iVBORw0K...
    } catch(err) { console.error(err); } finally { await browser.close(); }