Ребята, извиняюсь если не туда.
Подскажите, что делаю не правильно (заренее скажу, что кое-как проблему победил, но это не торт).
Пытаюсь разобраться с воркерами и с безболезненной передачей ему данных (с точки зрения производиительности).
Ситуация следующая:
1. Имеется массив ImageData.data (тип Uint8ClampedArray)
2. передаю его буфер в воркер. Соответственно воркер получает сам буфер, т.е. тип массива ArraBufferView. В воркере пока ничего не делаю (позже воркер будет делать преобразования изображения и накладвать фильтры), возвращаю этот буфер обратно в основной поток (как есть, т.е. тестирую передачу данных воркеру и обратно).
3. Взвращенный буфер привожу к типу Uint8ClampedArray.
4. Далее нужно поместить полученные значения из воркера в ImageData.data и отобразить.
Как раз в этом пункте начинаются прблемы.
Примерный код п.п. 1-3:
// Создаем канвас, отображаем картинку, получаем ImageData
var cnv, ctx, imData;
cnv = document.createElement('canvas');
cnv.height = h; // картинку img, h и w получем по коду выше (не суть)
cnv.width = w;
ctx = cnv.getContext('2d');
panorama.context.drawImage(img,0,0);
imData = ctx.getImagedata(0,0,w,h);
...
// создан воркер, определен обработчик события onmessage
// передаем данные воркеру (передаю буфер)
worker.postMessage(imData.data.buffer, [imData.data.buffer]);
console.info(imData.data.byteLength);
Поясню, передача работает корректно, т.к. при успешной передаче, imData.data.byteLength будет 0 (ноль), что и подтверждает информация в косоле.
Отступление. Кто не знает, скажу, если передвать данные просто как массив, т.е. так: worker.postMessage(imData.data), то массив два раза будет конвертироваться в json-объект, 1-й раз при передаче туда, 2-й раз - оттуда, что накладно при передаче нескольких МБайт данных. При передаче буффера содержимое не копируется, а предполагаю, старый массив перестает ссылать на участок памяти, на него ссылается event.data внутри воркера.
Кто знает как происходит, подскажите плз, ибо русской инфы в инете не нашел, а английского не знаю, так, только знакомые слова.
Конец отступления.
Теперь начинаются танцы с бубном.
Данные от воркера я получаю и делаю различные проверки, которые подтверждают, что воркер отдает в event.data тот же буффер, но сложности возникают при его отображнии на канвасе.
Попытка №1. Первое что приходит в голову, это взять и присвоить буффер из event.data обратно в imData:
imData.data.buffer = event.data
Далее пытаюсь отобразить полученное:
ctx.putImageData(imData,0,0);
Но в этой строке получаю ошибку:
SyntaxError: An invalid or illegal string was specified
*Чешу затылок* Ошибок быть не должно (исключительно мое мнение, которое оcновано на скудных знаниях JS)
Вопр. №1: Почему не сработало присвоение буфера? Ведь это былоб эффективно.
Попытка №2. Тогда создаю объект типа Uint8ClampedArray из полученного буфера и пытаюсь тупо присвоить созданный массив массиву ImData.data (по сути ImData.data становится ссылкой на resImData, это меня вполне устраивает, т.к. я пытаюсь уйти от лишних переборов большого массива).
var resImData = new Uint8ClampedArray(event.data);
imData.data = resImData;
ctx.putImageData(imData,0,0);
*Печально* В результате та же ошибка, и тот же вопрос что и при первой попытке (в обоих примерах массив ImData.data получается исходного размера, данные читаются, например alert(imData.data[3] показывает значение прозрачности пикселя).
Попытка №3. Делаю то, от чего хотел уйти, а именно перебор данных большого массива. Т.е. вместо присвоения ссылки как в примере №2 использую метод set() обекта Uint8ClampedArray.
var resImData = new Uint8ClampedArray(event.data);
imData.data.set(resImData);
ctx.putImageData(imData,0,0);
*убица веником* Новая ошибка "RangeError: invalid array length".
Вопр. №2 Почему не putImageData не захотел работать с этим массивом даже после перебора?
Попытка №4 (На самом деле попыток, как и мыслей, интересных слов, было ооочень много).
После некольких кружек кофе подумалось "а что если в воркер в парметрах передать не сам imData.data.buffer, а буффер из ссылки", т.е. так (переделал п.2 описанные в самом начале, хотя мысль пипец как бредовая):
...
// создам ссылку на массив imData.data
var imDataTest = imData.data;
// передаем данные воркеру (передаю буфер)
worker.postMessage(imDataTest.buffer, [imDataTest.buffer]);
console.info(imDataTest.byteLength);
А дальше осталось то, что и было в попытке №2:
var resImData = new Uint8ClampedArray(event.data);
imData.data.set(resImData);
ctx.putImageData(imData,0,0);
*в шоке* Сработало, потом сделал несколько преобразований изображения в воркере, чтоб убедиться, что отображаются именно данные полученные из воркера.
Вопр. №3 Что произошло, ведь массивы во всех случаях получились одинаковые?
Вопр. №4 Как можно обойтись без метода set(), т.е. без переборов массива при передачи и приемке данных в воркер/из воркера?