как сохранить данные canvas в файл

#javascript #html #node.js

#javascript #HTML #node.js

Вопрос:

я использую node.js для сохранения canvas в изображение img в файле записи извлекается с помощью toDataURL в моем элементе canvas. это не сохраняет файл, вот мой код

 var fs = IMPORTS.require('fs');
var path = IMPORTS.require('path');
path.exists('images/', function(exists){
    if (exists) {

        fs.writeFile('images/icon.png', img, function(err){
            if (err) 
                callback({
                    error: false,
                    reply: err
                });
            console.log('Resized and saved in');
            callback({
                error: false,
                reply: 'success.'
            });
        });
    }
    else {
        callback({
            error: true,
            reply: 'File did not exist.'
        });
    }
 });    
  

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

1. Можете ли вы включить свой код canvas или URL, который вы тестируете, чтобы мы могли запускать ваш код без необходимости написания какого-либо шаблона? (см. sscce.org ) Вы также можете немного уточнить свое описание, если хотите, чтобы люди помогли.

Ответ №1:

Вот буквальный пример того, как сохранить данные canvas в файл в Nodejs. Переменная img представляет собой строку, сгенерированную canvas.toDataURL() . Я предположил, что вы уже знаете, как опубликовать эту строку из браузера на свой сервер Nodejs.

Фрагмент HTML, который генерирует образец изображения, который я использовал:

 <canvas id="foo" width="20px" height="20px"></canvas>
<script>
var ctx = $('#foo')[0].getContext('2d');
for (var x = 0; x < 20; x  = 10) {
    for (var y = 0; y < 20; y  = 10) {
        if (x == y) { ctx.fillStyle = '#000000'; }
        else { ctx.fillStyle = '#8888aa'; }
        ctx.fillRect(x, y, 10, 10);
    }
}
console.log($('#foo')[0].toDataURL());
</script>
  

Фрагмент Nodejs для декодирования данных base64 и сохранения изображения:

 const fs = require("fs").promises;

(async () => {
  
  // string generated by canvas.toDataURL()
  const img = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0"
        "NAAAAKElEQVQ4jWNgYGD4Twzu6FhFFGYYNXDUwGFpIAk2E4dHDRw1cDgaCAASFOffhEIO"
        "3gAAAABJRU5ErkJggg==";
  
  // strip off the data: url prefix to get just the base64-encoded bytes
  const data = img.replace(/^data:image/w ;base64,/, "");
  
  const buf = Buffer.from(data, "base64");
  await fs.writeFile("image.png", buf);
})();
  

Вывод:

введите описание изображения здесь

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

1. Спасибо! Я не знал, что мне нужен Buffer , я просто пытался использовать base64.decode() с данными base64, но сгенерировал поврежденный файл.

2. Пример серверного кода работает для меня. Может ли кто-нибудь объяснить мне, почему это не работает с этими данными: pastebin.com/raw.php?i=3yhGiQWR

3. Я получил неопределенный буфер

4. для меня toDataUrl() строка содержала знаки плюс, которые body-parser превратились в пробелы в request.body , поэтому мне пришлось снова заменить их на знаки плюс, чтобы мой png не был поврежден: var data=img.slice(img.indexOf(',') 1).replace(/s/g,' ');

5. new Buffer устарел для nodejs . В этом случае вам следует использовать Buffer.from(data, 'base64'); now.

Ответ №2:

Я считаю, что Canvas это не хранит свои данные в Base64 внутренне. Он должен хранить данные в каком-то гораздо более эффективном двоичном формате. Итак, очевидно, что передача в base64 и обратно в двоичный PNG ужасно медленная и отнимает много памяти.

Быстрый поиск в документации node canvas дает:

Чтобы создать PNGStream, просто вызовите canvas.pngStream(), и поток начнет выдавать события данных, окончательно выдав end по завершении. При возникновении исключения выдается событие error.

 var fs = require('fs')
  , out = fs.createWriteStream(__dirname   '/text.png')
  , stream = canvas.pngStream();

stream.on('data', function(chunk){
  out.write(chunk);
});

stream.on('end', function(){
  console.log('saved png');
});
  

В настоящее время поддерживается только потоковая синхронизация. Если вы хотите сделать это асинхронно, вы можете попробовать использовать worker или cluster (лично я никогда не пробовал этого).

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

1. Console.log (‘сохраненный png’) выполняется до сохранения файла. Это потому, что поддерживается только синхронизация? Как я мог бы запустить событие после сохранения файла?