Экспорт холста в формате PNG без прозрачности (альфа-канал) - PullRequest
0 голосов
/ 25 мая 2018

** РЕДАКТИРОВАТЬ ** Я должен экспортировать большой холст (5Mo

Когда я экспортирую свой холст (с toDataUrl), он всегда возвращает мне представление base64 файла .png с альфа-каналом.Вес альфа-канала составляет около 25% данных изображения, и мне это не нужно.

Предлагаемый ответ:

  1. Сжатие PNG хорошо.Если альфа-канал плоский (все то же значение), он не займет много места . Даже при полностью непрозрачном альфа-канале (сжатый) файл .png больше.(около + 10% в нескольких тестах).
  2. Вы должны заполнить холст (используя нужный цвет для фона), прежде чем рисовать на нем. Iуже основал это решение на stackoverflow, но, похоже, оно не работает
  3. Base64-кодирование добавляет на 34% больше байтов.Уже решено.Использование этого решения: преобразование данных-данных-uri-в-файл-затем-добавление-в-данные (массив Uint8 в блоб в форму данных)

Есть ли способэкспортировать холст как .png, но без альфа-канала?Если "нет", есть ли способ (lib) в JavaScript для обрезки альфа-канала?Экспорт в формате .jpeg не является решением, мне нужен файл .png.

Спасибо!:)

Ответы [ 4 ]

0 голосов
/ 07 января 2019

Моя цель аналогична вашей: экспортировать холст в формате PNG и удалить информацию альфа-канала из его представления dataURL перед отправкой на сервер.Однако мои причины отличаются от ваших.Я хотел объединить полученные файлы изображений в виде PDF на другом конце, и библиотека, которую я использовал img2pdf , не могла обрабатывать информацию альфа-канала.Библиотека, которую я использовал для холста, была fabric.js , но проблема должна возникать при экспорте любого холста HTML5 через toDataUrl ().

К счастью, есть хорошая библиотека JavaScript, называемая pngjs , который может манипулировать файлами PNG в JavaScript.Он поставляется с асинхронными и синхронными процедурами.Вот как я конвертировал dataURL из альфы в не альфа.Вашего шага 3 (dataURL to Blog) должно быть достаточно, чтобы завершить работу.

let PNG = require('pngjs').PNG;

/* thehref: DataURL form of a png file. */
function removeAlphaFromDataUrl(thehref) {
  let dataurlstring = "data:image/png;base64,"
  let buff = new Buffer(thehref.slice(22), 'base64')
  let png = PNG.sync.read(buff);
  let options = { colorType: 2 };
  let buffer = PNG.sync.write(png, options);
  let output = buffer.toString('base64');
  let newhref = dataurlstring + output
  return newhref;
}

Надеюсь, это поможет.

0 голосов
/ 25 мая 2018

PNG сжатие это хорошо.Если альфа-канал плоский (все то же значение), он не займет много места.

Вы можете заполнить прозрачные и полупрозрачные пиксели, используя составную операцию "destination-over".

Следующая функция установит альфа-значение для всех пикселей на 1.

function fillAlpha(ctx, bgColor){  // bgColor is a valid CSS color ctx is 2d context
   // save state
   ctx.save();
   // make sure defaults are set
   ctx.globalAlpha = 1;
   ctx.setTransform(1, 0, 0, 1, 0, 0);
   ctx.filter = "none";

   // fill transparent pixels with bgColor
   ctx.globalCompositeOperation = "destination-over";
   ctx.fillStyle = bgColor;
   ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

   // cleanup
   ctx.restore();
}

Затем вы можете сохранить изображение в формате PNG с альфа-каналом как можно меньшего размера.

0 голосов
/ 26 мая 2018

Когда я экспортирую свой холст (с помощью toDataUrl), он всегда возвращает мне файл .png с альфа-каналом.

Нет, он не возвращает ".png файл ", toDataURL возвращает URL-адрес данных, который представляет собой строку, состоящую из заголовка ипредставление вашего файла в base64.Это представление base64 само по себе займет на 34% больше байтов, чем представленный двоичный файл.

Итак, чтобы исправить X вашей проблемы XY отправьте ваше изображение png в виде двоичного BLOB-объекта. .


Теперь, чтобы предоставить некоторый контент по вопросу Y,Я не проверял во всех браузерах, но я не думаю, что кто-либо реализовал что-то еще, кроме 32-битного вывода png.Это может измениться в будущем, более того, так как большинство UA теперь поддерживают параметр контекста {alpha: false} 2d, и что мы также, вероятно, будем иметь больший контроль над битовой глубиной, используемой в контексте, в надежде на ближайшее будущее.

Но на данный момент вам придется сделать это самостоятельно, запустив собственный png-кодер.

0 голосов
/ 25 мая 2018

Вы должны заполнить холст (используя цвет, который вы хотите для фона), прежде чем рисовать на нем.

Например, до:

var ctx = canvas.getContext('2d');
drawEverythingOnMyContext(ctx);
image = canvas.toDataURL();

После:

var ctx = canvas.getContext('2d');
// draw a background
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// draw then
drawEverythingOnMyContext(ctx);
image = canvas.toDataURL();
...