Попытка сравнить два элемента Canvas

Я использую ниже код для сравнения двух элементов холста

function createImage(html, can) {
     var canvas = $( "#" + can );
     var ctx = canvas[0].getContext("2d");
     var data = "<svg xmlns='http://www.w3.org/2000/svg' width='1000' height='1000'>" +
                    "<foreignObject width='100%' height='100%'>" +
                        "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                            html +
                        "</div>" +
                    "</foreignObject>" +
                "</svg>";
    var DOMURL = self.URL || self.webkitURL || self;
    var img = new Image();
    img.crossOrigin = '';
    var svg = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
    var url = DOMURL.createObjectURL(svg);
    img.onload = function () {
        ctx.drawImage(img, 0, 0);
        DOMURL.revokeObjectURL(url);
    };
    img.src = url;
    //return img.src;
    return canvas[0];
}
var a1 = createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>","can1");
var a2 = createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>", "can2");
setTimeout(function() {
    var ctx1 = a1.getContext('2d');
    var imageData = ctx1.getImageData(0, 0, a1.width, a1.height);
    var pixels = imageData.data;
    var ctx2 = a2.getContext('2d');
    var imageData2 = ctx2.getImageData(0, 0, a2.width, a2.height);
    var pixels2 = imageData2.data, count;
    for(var i = 0, il = pixels.length; i < il; i++) {
        if(pixels[i] == pixels2[i]){
            count++;
        }
    }
    if(count === pixels.length && count === pixels2.length){
        alert("Match");
    }
},5000);

Но он возвращает мне ошибку, как ниже

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

Как я могу избавиться от этой ошибки?

Ответ 1

Причина, по которой вы получаете ошибку кросс-оригинала, связана с использованием <svg> с объявлениями пространства имен, расположенными в http://www.w3.org/, который имеет другое происхождение:

var data = "<svg xmlns='http://www.w3.org/2000/svg' width='1000' height='1000'>" +
             "<foreignObject width='100%' height='100%'>" +
               "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                    html +
               "</div>" +
             "</foreignObject>" +
           "</svg>";

Я могу сказать, что этот метод является тем из Рисование объектов DOM в холст на MDN.

При повторном доступе к данным,

var ctx1 = a1.getContext('2d');
var imageData = ctx1.getImageData(0, 0, a1.width, a1.height);

вы попадете в ошибку:

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

Вы можете проверить это на Chrome:

Вы можете вернуть данные только из функции, чтобы избежать получения этой ошибки. Но из-за асинхронного характера img.onload,

img.onload = function () {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);
};

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

Таким образом, вы должны использовать альтернативный метод построения холста с объектами DOM, который не полагается на <svg>, например html2canvas.

function createImage(html) {
    var dfd = new $.Deferred();
    var el = document.createElement("div");
        el.innerHTML = html;
        el.style.display = 'inline-block';
        document.body.appendChild(el);
    html2canvas(el, {
      onrendered: function(canvas) {
          document.body.appendChild(canvas);
          document.body.removeChild(el);
          dfd.resolve(canvas.toDataURL());
      }
    });
    return dfd;
}
$.when(
    createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>"), 
    createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>")
).done(function(a1, a2){
   if (a1 === a2) {
      alert("Match"); 
   }
});

См. DEMO.

Ответ 2

О проблемах с "ошибкой пересечения"

Невозможно получить данные изображения из холста, потому что холст был испорчен данными перекрестного происхождения. SECURITY_ERR: исключение DOM 18

Это проблема безопасности, вызванная навигационной "политикой пересечения".


Эта ошибка появится, если вы "загрязнили" ваш холст. Это делается путем рисования изображений на холсте, которые имеют другое происхождение. Например, если ваш холст размещен на веб-сайте www.example.com, и вы используете изображения с сайта www.wikipedia.org, то ваш флаг canvas origin-clean установлен на false внутренне.

Как только флаг начала-очистки установлен на false, вам больше не разрешено вызывать toDataURL или getImageData


Технически изображения имеют одинаковое происхождение, если совпадают домены, протоколы и порты.


Если вы работаете локально (файл://), то в любом обратном изображении будет установлен флаг. Это делает отладку раздражающей, но с Chrome вы можете запустить ее с флагом --allow-file-access-from-files, чтобы разрешить это.


Чтобы узнать больше, прочитайте статью: " Понимание правил безопасности изображений Canvas HTML5.

Кредиты Саймон Саррис

Мои файлы находятся в том же домене или активирован флаг хрома, и я все еще получаю эту ошибку, что происходит?

Проблема заключается в том, что Chrome (в настоящее время) всегда окрашивает холст, когда на него нарисован документ SVG.

Для более подробного объяснения см. вопрос ниже:

Растрирование SVG-документа в документе

Хорошо, использование svg кажется проблемой, поэтому как ее исправить?

Во время моего письма Антоний ответил на это!

Посмотрите его ответ.