Странное сжатие HTML-изображения

Я хочу использовать png-файл с кодировкой base64, который я получаю с сервера в WebGL. Для этого я загружаю закодированный png в объект HTML Image. Для моего приложения мне нужно, чтобы данные png были абсолютно без потерь, но значения пикселей, полученные шейдером, различаются в разных браузерах ... (если я загружаю изображение на холст и использую getImageData, полученные значения пикселей также различаются в разных браузерах). Должна быть какая-то странная фильтрация / сжатие значений пикселей, но я не могу понять, как и почему. Кто-нибудь знаком с этой проблемой?

Загрузка изображения с сервера:

var htmlImage = new Image();
htmlImage.src = BASE64_STRING_FROM_SERVER

Загрузка изображения в шейдер:

ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGB, ctx.RGB, ctx.UNSIGNED_BYTE, 
htmlImage); 

Попытка прочитать значения пикселей с помощью холста (разные значения в браузерах):

var canvas = document.createElement('canvas');
canvas.width = htmlImage.width;
canvas.height = htmlImage.height;
canvas.getContext('2d').drawImage(htmlImage, 0, 0, htmlImage.width, 
htmlImage.height);

// This data is different in, for example, the latest version of Chrome and Firefox
var pixelData = canvas.getContext('2d').getImageData(0, 0, 
htmlImage.width, htmlImage.height).data;   

Ожидается: stackoverflow.com/questions/26615580/…

Sergiu Paraschiv 10.12.2018 12:02
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
2
101
1

Ответы 1

Как указывает @Sergiu, по умолчанию браузер может применять к изображениям цветокоррекцию, гамма-коррекцию, цветовые профили или что-то еще.

В WebGL это можно отключить. Перед загрузкой изображения в текстуру вызовите gl.pixelStorei с gl.UNPACK_COLORSPACE_CONVERSION_WEBGL и передайте ему gl_NONE, как в

gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);

Это укажет браузеру не применять цветовые пространства, гамму и т. д. Это было важно для WebGL, потому что многие 3D-приложения используют текстуры для передачи вещей, отличных от изображений. Примеры включают в себя карты нормалей, карты высот, карты окклюзии окружающей среды, карты свечения, карты отражений и многие другие типы данных.

По умолчанию установлено

gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL);

Обратите внимание, что это, вероятно, работает только при получении данных непосредственно из изображения, а не при передаче изображения через 2d холст.

Обратите внимание: если вы получаете данные с холста WebGL, рисуя их на 2D-холсте, то все ставки отключены. Во всяком случае, в 2D-холсте используется предварительно умноженная альфа, поэтому копирование данных в 2D-холст и из него всегда происходит с потерями, если альфа <255. Используйте gl.readPixels, если вы хотите, чтобы данные не пострадали от каких-либо действий 2D-холста.

Обратите внимание, что одна из потенциальных проблем этого метода - скорость. Браузер, вероятно, предполагает, что когда вы загружаете изображение, оно в конечном итоге будет отображаться. У него нет возможности заранее узнать, что он будет использоваться в текстуре. Итак, вы создаете тег изображения, устанавливаете атрибут src, браузер загружает изображение, распаковывает его, подготавливает к отображению, затем генерирует событие загрузки, а затем вы загружаете это изображение в текстуру с помощью UNPACK_COLORSPACE_CONVERSION_WEBGL = NONE. Браузеру на этом этапе, возможно, придется повторно распаковать его, если он не сохранил версию, в которой уже не применено преобразование цветового пространства. Это вряд ли заметная проблема со скоростью, но и не ноль.

Чтобы обойти это, браузеры добавили ImageBitmap API. Этот API решает несколько проблем.

  1. Его можно использовать в веб-воркере, потому что это не элемент DOM, как Image.

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

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

К сожалению, с 2018/12 года он полностью поддерживается только Chrome. Firefox имеет частичную поддержку. В Safari их нет.

Это очень полезно, спасибо за подробный ответ! Я решил свою проблему с помощью атрибута UNPACK_COLORSPACE_CONVERSION_WEBGL, как вы сказали :)

svanheste 10.12.2018 17:16

Другие вопросы по теме