Canvas.toDataUrl и картинки с другого домена


Возникла необходимость создавать картинки на клиенте с возможностью сохранения результата в файл. Для современных браузеров — нет никаких проблем: берём Canvas, загружаем изображение и рисуем его на «холсте» методом drawImage().

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var image = new Image();

image.src = 'image.jpg';  
image.onLoad = function () {
    ctx.drawImage(image);
}

Но нам нужно сохранить результат в файл. И это тоже можно сделать, вызывав метод toDataUrl(). Однако результат мы получим только в том случае, когда картинки грузились с того же самого домена, на котором расположен скрипт. У нас же всё по-взрослому — скрипты на одном домене, картинки на другом — всё для оптимизации скорости загрузки страниц сайта.

В таком случае мы получим не картинку в base64, а исключение типа «An attempt was made to break through the security policy of the user agent». Нельзя грузить что попало откуда попало! Но если очень хочется, то можно. Нужно выполнить два действия.

Действие первое — разрешить политику кросс-доменных запросов для загружаемого изображения.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var image = new Image();

image.setAttribute("crossorigin", "anonymous");
image.src = 'image.jpg';

Естественно, нужно добавить атрибут crossorigin до установки src.

Действие второе — добавить заголовок "Access-control-allow-origin": "*" для файла изображения.

Вот небольшой пример, демонстрирующий работу этого метода. По клику по изображению выводится результат попытки сохранения в dataURL. Первые два изображения — без CORS-аргументов, выводится исключение, третье — без заголовка сервера (оно вообще не грузится, в консоль падает сообщение об ошибке), четвёртое — грузится и отдаёт кодированный в base64 результат.