Как восстановить PNG, возвращаемый canvas.toBlob() в NodeJS

#javascript #node.js #puppeteer

#javascript #node.js #кукловод

Вопрос:

Допустим, у меня есть холст в HTML-файле (ничего особенного). И я использую Puppeteer, чтобы нарисовать что-то на холсте в контексте браузера, а затем передать это в контекст NodeJS, где я сохраняю это как PNG-файл, используя OpenCV.

Поскольку двоичные данные не могут быть переданы между двумя контекстами (браузер и узел), я должен преобразовать двоичные данные в строку и восстановить двоичные данные в узле. Следующий код делает именно это:

 const puppeteer = require('puppeteer');
const cv = require('opencv4nodejs');

const pup = puppeteer.launch({
    headless: false,
    args: [
        '--use-gl=swiftshader',
        '--no-sandbox',
        '--enable-surface-synchronization',
        '--disable-web-security',
    ]
}).then(async browser => {
    const page = (await browser.pages())[0];
    page.on('console', msg => console.log(msg.text()));
    page.on("pageerror", function(err) {
        const theTempValue = err.toString();
        console.log("Page error: "   theTempValue);
    });
    page.on("error", function (err) {
        const theTempValue = err.toString();
        console.log("Error: "   theTempValue);
    });

    await page.exposeFunction('_setupCompleted', async () => {
        await page.evaluate(async () => {
            const c = document.getElementById("myCanvas");

            const dataUrl = c.toDataURL("image/png");
            const txt = await new Promise(resolve => c.toBlob((blb) => blb.text().then(resolve), "image/png"));
            await window._saveMat(dataUrl, txt);
        });

        await browser.close();
    });

    await page.exposeFunction('_saveMat', async (dataUrl, txt) => {
        dataUrl = dataUrl.replace(/^data:image/png;base64,/, "");
        const dataUrlBuffer = Buffer.from(dataUrl, 'base64');
        const dataUrlMat = cv.imdecode(dataUrlBuffer, -1);
        cv.imwrite(`./dataUrl.png`, dataUrlMat);


        const txtBuffer = Buffer.from(txt, 'utf8');
        const txtMat = cv.imdecode(txtBuffer, -1);
        cv.imwrite(`./txtMat.png`, txtMat);
    });

    await page.goto('http://127.0.0.1:8887/index.html', {
        waitUntil: 'networkidle2',
    });
});
  

В данном коде я передаю PNG двумя способами. Сначала я использую toDataURL метод canvas. Этот метод кодирует двоичные данные canvas с использованием base64 и добавляет к нему некоторую подпись. После получения код в Node удалит подпись и декодирует base64. Эта часть кода работает отлично, и она отлично сохраняет PNG.

Другой подход использует toBlob метод canvas. Этот метод возвращает большой двоичный объект, который я вызову его text методом, чтобы преобразовать его в строку. На стороне узла я попытаюсь восстановить буфер из переданной строки. Эта часть не выполняется. По-видимому, восстановленный буфер не является допустимым PNG, и imdecode методу не удается создать объект mat на его основе.

Мой вопрос в том, как я могу восстановить тот же буфер, который я получаю от toDataURL использования текста, который я получаю от toBlob метода в NodeJS?

Комментарии:

1. Не преобразуйте большой двоичный объект в text , процесс кодирования почти наверняка повредит некоторые кодовые точки, поскольку это двоичный, а не закодированный текст.

2. @PatrickRoberts Спасибо. Означает ли это, что я застрял с toDataURL ?

3. Нет, вы должны использовать arrayBuffer() вместо text() и создавать Buffer непосредственно из него, не указывая кодировку, поскольку это необработанные двоичные данные.