2016-01-27 2 views
9

фона НастройкаВозможно ли создать изображение (blob или data-url) в веб-работнике из getImageData контекста canvas?

У меня есть веб-приложение, которое имеет дело с созданием изображения из набора других изображений. То, как я решил сделать это, - это чтение в виде набора изображений и размещение их на холсте HTML. Затем я экспортирую каждый холст как jpeg в сторонний API, используя toDataURL и конвертируя его в Blob. Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть многие из этих холстов, которые экспортируют данные в формате jpg и потребляют много ресурсов. Приложение замедляется и становится невосприимчивым, так как каждый холст пытается вызвать toDataURL.

Вопрос

Я обнаружил, что вызов холст-х toDataUrl() или toBlob() может быть очень медленным, особенно для больших размеров холста. Я бы хотел использовать многопоточный характер веб-работников.

Во-первых, я пробовал пропустить в объекте canvas, но была выброшена ошибка. Оказывается, объекты являются проблемой, и кажется, что они либо преобразуются в строки, либо терпят неудачу, когда их нельзя клонировать. В любом случае, я обнаружил, что передача данных изображения контекста действительно работает. Данные передаются в виде необработанных значений RGB как Uint8ClampedArray из метода контекста canvas getImageData().

Main.js

var canvas = document.createElement('canvas'); 
var context = canvas.getContext('2d'); 
var worker = new Worker('myWorker.js'); 
worker.postMessage({ 
    image: context.getImageData(0, 0, canvas.width, canvas.height) 
}); 

myWorker.js

this.onmessage = function(e) { 
    // GOAL: turn e.data.image into an image blob or dataUrl and return it. 
    // e.g. this.postMessage(new Blob([e.data.image.data], {type: 'image/jpg'}); 
} 

Я думаю, что это сводится к тому, зная, как преобразовать Uint8ClampedArray который содержит информацию RGB в JPG/PNG данные.

Причина, по которой я думаю, что это может быть полезно, заключается в том, что я считаю, что getImageData просто копирует существующую структуру данных из контекста canvas и, следовательно, не так дорого, как toDataUrl. Я захватил профиль центрального процессора при вызове что-то похожее на блок кода ниже:

var image = context.getImageData(0, 0, canvas.width, canvas.height) 
var dataUrl = canvas.toDataURL('image/jpeg'); 

и получил:

Performance results from getImageData and toDataURL

Таким образом, учитывая, что я хотел бы, чтобы разгрузить основную тяжесть процесса в веб-работника. Я даже не возражаю, если он занимает больше времени внутри веб-рабочего, если это происходит в другом процессе.

Пара лишних мыслей о нем:

  • Добавление дополнительных библиотек, чтобы сделать преобразование в порядке, но бонусные баллы для предложения, как добавить внешнюю библиотеку в качестве зависимости к файлам веб-рабочих. Сейчас я использую браузер для приложения. Возможно, создайте еще один браузерный веб-сайт?
  • Мне нужен jpeg в конце (для стороннего API), поэтому преобразование его в png настолько хорошее, чтобы быть шагом в преобразовании в jpeg.
  • Я попытался опускании encoderOptions, второй вариант в toDataURL, как способ ускорить процесс, но я не видел много изменений
+2

Это может быть возможно, но очень сложно, и я не уверен, какую пользу вы будете иметь: вы можете создать Blob и отправить его на главную страницу с веб-работника. Вы можете сделать кодировку в jpeg или png самостоятельно (даже если я рекомендую искать некоторые библиотеки). Начните с png, [specs] (https://www.w3.org/TR/PNG-Introduction.html) понятнее jpeg. Примечание: вам также необходимо отправить метаданные изображения. Но самая тяжелая операция - 'ctx.getImageData()'. Я не уверен, что вы выиграете что-либо, передав часть сжатия веб-работнику. – Kaiido

+0

Возможно, вам стоит показать нам свой код, чтобы мы могли узнать, можно ли что-то улучшить. (например, вы используете некоторые асинхронные методы, чтобы графический интерфейс не блокировался?) – Kaiido

+0

@ Kaiido - Я обновил вопрос, чтобы больше узнать о моем понимании проблемы. Похоже, что getImageData не так обременительна, как ожидалось. А что касается моего кода, я использую метод defercore defer для обертывания canvas.toDataURL, чтобы не блокировать пользовательский интерфейс, но как только начнется метод (который он в конечном итоге), он заблокирует выполнение других js. Кроме того, стоит отметить, что я делаю это много раз для многих изображений на странице, поэтому стоимость выше, чем сообщенные 400 мс. –

ответ

6

---- UPDATE-- -

Я думал, что поделюсь своим решением в качестве библиотеки npm: https://www.npmjs.com/package/jpeg-web-worker. В нем объясняется, как использовать предоставленного веб-работника для тяжелого подъема для вас.

---------------------

Я получил решение, которое работает для меня, ускоряя приложения и отзывчивость страницы в то же время создавая новые изображения.

Вот код приложения:

App

var canvas = $('#myCanvas')[0]; 
var context = canvas.getContext('2d'); 
var imageData = context.getImageData(0, 0, canvas.width, canvas.height); 
var worker = new Worker('myWorker.js'); 
worker.postMessage({ 
    image: imageData 
}); 
worker.onmessage = function(e) { 
    var blob = new Blob([e.data.data], {type: 'image/jpeg'}); 
    // use blob 
} 

А вот код работника:

работник

this.onmessage = function(e) { 
    var jpgInfo = encode(e.data.image, 50); 
    this.postMessage(jpgInfo); 
} 

function encode() { ... } // ported from jpeg-js 

Очевидно, что бушель lk этого ответа исходит от функции encode. Эта функция была изменена с модуля npm jpeg-js и, более конкретно, на файл encoder.js. Я портировал функцию кодирования, скопировав весь файл encoder.js в myWorker.js. Это не крошечный, но он также очень самодостаточен, что облегчает его работу. Единственная проблема, с которой я столкнулся, - это изменить код, чтобы он работал за пределами среды node.js, для которой он был создан.

Это оказалось сравнительно легко:

  1. Преобразовать «сопзЬ» объявления переменных в «вар»
  2. удаления ссылок на Buffer. Это был двухэтапный процесс. Сначала удалите определение atob (как это не нужно) вверху. Во-вторых, верните new Unit8Array в конце этой функции. В текущей версии на самом деле это прокомментировано прямо над ссылкой на буфер. Просто используйте это и удалите все под ним.
  3. Удаление ссылки на module.export. Это так же просто, как удаление этой строки, так как нам нужна только эта функция внутри этого файла.

У меня нет точных измерений времени, но оно прошло с ~ 10 секунд времени задержки, так как изображения были сгенерированы до секунды с запаздыванием. Я использую «время задержки» здесь, чтобы иметь в виду медленную производительность при использовании страницы.

 Смежные вопросы

  • Нет связанных вопросов^_^