Почему canvas.toDataURL() выдает исключение безопасности?

Неужели я недостаточно спал или что? Этот следующий код

var frame=document.getElementById("viewer");
frame.width=100;
frame.height=100;

var ctx=frame.getContext("2d");
var img=new Image();
img.src="http://www.ansearch.com/images/interface/item/small/image.png"

img.onload=function() {
    // draw image
    ctx.drawImage(img, 0, 0)

    // Here where the error happens:
    window.open(frame.toDataURL("image/png"));
}

выбрасывает эту ошибку:

SECURITY_ERR: DOM Exception 18

Нет, это не должно работать! Может кто-нибудь объяснить это, пожалуйста?

Ответ 1

В specs говорится:

Всякий раз, когда метод toDataURL() элемент холста, чей исходный чистый флаг установлено значение false, метод должен вызвать исключение SECURITY_ERR.

Если изображение идет с другого сервера, я не думаю, что вы можете использовать toDataURL()

Ответ 2

Настройка атрибута cross origin для объектов изображения, обработанных для меня (я использовал fabricjs)

    var c = document.createElement("img");
    c.onload=function(){
        // add the image to canvas or whatnot
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src='http://google.com/cat.png';

Для тех, кто использует fabricjs, здесь, как исправлять Image.fromUrl

// patch fabric for cross domain image jazz
fabric.Image.fromURL=function(d,f,e){
    var c=fabric.document.createElement("img");
    c.onload=function(){
        if(f){f(new fabric.Image(c,e))}
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src=d;
};

Ответ 3

Если изображение размещено на хосте, который устанавливает любой из Access-Control-Allow-Origin или Access-Control-Allow-Credentials, вы можете использовать Cross Origin Resource Sharing (CORS). Подробнее см. здесь (атрибут crossorigin).

Другой вариант - для вашего сервера иметь конечную точку, которая извлекает и обслуживает изображение. (например, http://your_hosthttps://stackoverflow.com/endpoint?url=URL) Недостатком этого подхода является латентность и теоретически ненужная выборка.

Если будет больше альтернативных решений, мне будет интересно услышать о них.

Ответ 4

Кажется, есть способ предотвратить, если хостинг изображений может предоставить следующие заголовки HTTP для ресурсов изображения, а браузер поддерживает CORS:

access-control-allow-origin: *
access-control-allow-credentials: true

Здесь говорится: http://www.w3.org/TR/cors/#use-cases

Ответ 5

У меня была такая же проблема, и все изображения размещались в одном домене... Итак, если у кого-то такая же проблема, вот как я решил:

У меня было две кнопки: одна для создания холста, а другая - для создания изображения с холста. Это работало только для меня, и жаль, что я не знаю, почему, когда я написал весь код на первой кнопке. Поэтому, когда я нажимаю, он генерирует холст и изображение одновременно...

У меня всегда есть эта проблема безопасности, когда коды были на разных функциях... =/

Ответ 6

Наконец, я нашел решение. Просто добавьте crossOrigin в качестве третьего параметра в fromURL func

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });

Ответ 7

Вы не можете помещать пробелы в свой идентификатор

Обновление

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

Ответ 8

Мне удалось заставить его работать, используя это:

Напишите это в первой строке вашего .htaccess на исходном сервере

Header add Access-Control-Allow-Origin "*"

Затем при создании элемента <img> сделайте это следующим образом:

// jQuery
var img = $('<img src="http://your_server/img.png" crossOrigin="anonymous">')[0]

// or pure
var img = document.createElement('img');
img.src='http://your_server/img.png';
img.setAttribute('crossOrigin','anonymous');

Ответ 9

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

www.example.com отличается от example.com

Поэтому убедитесь, что ваши изображения и URL-адрес, которые у вас есть в адресной строке, одинаковы, www или нет.

Ответ 10

Я использую fabric.js и могу решить эту проблему, используя toDatalessJSON вместо toDataURL:

canvas.toDatalessJSON({ format: 'jpeg' }).objects[0].src

Редактировать: Nevermind. Это приводит только к тому, что фоновое изображение экспортируется в JPG, без рисунка сверху, так что в конце концов оно оказалось не совсем полезным.