Эта статья продолжает серию статей о WebGL. Если вы их ещё не читали, рекомендую начать с ранних уроков.
При работе с WebGL часто приходится скачивать изображения и загружать их в видеокарту, чтобы в дальнейшем использовать в текстуре. Уже было рассмотрено несколько подобных примеров. Например, в статье об обработке изображений, в статье о текстурах и в статье о реализация функции DrawImage.
Обычно мы загружаем изображение примерно следующим образом:
Проблема в том, что изображения могут содержать в себе личные данные (например, капча, подпись, ню и т.д.). Веб-страница часто содержит рекламу и другие подобные вещи, которые не находятся под контролем страницы, поэтому браузер должен ограничить эти вещи от доступа к одержимому приватных изображений.
Простое использование <img src="private.jpg">
не представляет проблемы, ведь
несмотря на то, что изображение отобразится в браузере, скрипт не сможет получить
доступ к его содержимому. А вот Canvas2D API
обладает инструментами заглянуть внутрь изображения. Для начала отображаем
изображение в canvas
Затем получаем данные
Но если изображение пришло с другого домена, браузер отметит canvas запятнанным
и вы получите ошибку безопасности при вызове ctx.getImageData
.
В WebGL всё ещё сложнее. Функция gl.readPixels
в WebGL является эквивалентом
ctx.getImageData
, поэтому, казалось бы, блокирование этой функции было бы
достаточным в плане безопасности, но, оказывается, даже при невозможности прочитать
пиксели напрямую можно создать шейдеры, которые потребуют более долгого времени
выполнения на основе цветов изображения. Используя эту информацию, вы сможете
использовать временной интервал, чтобы заглянуть внутрь изображения и получить
доступ к его содержимому.
Поэтому WebGL просто блокирует все изображения, которые приходят с других доменов. Например, следующий небольшой пример с вращающимся прямоугольником использует текстуру с другого домена. Обратите внимание, что текстура не загружается, а в консоли браузера выводится ошибка.
Как обойти это ограничение?
CORS = Cross Origin Resource Sharing (совместное использование ресурсов между разными источниками). Веб-страница может запросить у сервера, на котором расположено изображение, разрешение на использование изображения.
Для этого необходимо установить атрибут crossOrigin
в какое-либо значение, тогда
браузер при получении изображения с сервера будет запрашивать разрешение, если
домен отличается.
crossOrigin
может принимать 3 значения. Первое из них - undefined
, это значение по умолчанию, и оно
означает "не запрашивать разрешения". Второе значение - anonymous
, которое значит "запрашивать разрешения,
но не отправлять дополнительную информацию". Последнее значение - use-credentials
, означающее "отправлять
куки и другую информацию, по которой сервер сможет определить, стоит ли давать разрешения или нет". При
установке любого другого значения сервер будет считать, что установлено значение anonymous
.
Мы можем написать функцию, которая проверит, находится ли наше изображение
на том же домене, и в зависимости от этого установит атрибут crossOrigin
.
Использовать функцию можно следующим образом:
Следует отметить, что запрос разрешение вовсе НЕ означает, что это разрешение будет дано. Это зависит от сервера. Github-страницы дадут разрешение, как и flickr.com или imgur.com, но большинство других сайтов такого разрешения не дадут. Под "разрешением" здесь понимаются HTTP-заголовки, которые сервер отправляет вместе с изображением.
Также важно помнить, что разрешений от сервера недостаточно. Если изображение приходит
с другого домена, вам нужно установить атрибут crossOrigin
, в противном случае вы
не сможете использовать изображение, даже если сервер пришлёт нужные заголовки.