canvas.toDataURL () Помилка безпеки


76

Отже, я використовую карти Google, і отримую зображення, щоб воно виглядало так

<img id="staticMap"
        src="http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap
&markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318
&markers=color:red%7Ccolor:red%7Clabel:C%7C40.718217,-73.998284&sensor=false">

Мені потрібно це зберегти. Я знайшов це:

function getBase64FromImageUrl(URL) {
    var img = new Image();
    img.src = URL;
    img.onload = function() {

        var canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);

        var dataURL = canvas.toDataURL("image/png");

        alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));

    };
}

Але я отримую цю проблему:

Невпіймана Помилка безпеки: Не вдалося виконати 'toDataURL' на 'HTMLCanvasElement': забруднені полотна не можуть бути експортовані.

Я шукав виправлення. Я знайшов тут зразок Як використовувати CORS, але все одно я не можу зв’язати ці 2 шматки коду, щоб він працював. Можливо, я роблю це неправильно, і є простіший спосіб зробити це? Я намагаюся зберегти цю картинку, щоб я міг перенести дані на свій сервер. То, можливо, хтось зробив щось подібне і знає, як змусити .toDataURL()працювати так, як мені це потрібно?

Відповіді:


100

Якщо Google не подає це зображення з правильним Access-Control-Allow-Originзаголовком, ви не зможете використовувати його зображення на полотні. Це пов’язано з відсутністю CORSсхвалення. Ви можете прочитати більше про це тут , але це по суті означає:

Хоча ви можете використовувати зображення без схвалення CORS на своєму полотні, це забруднює полотно. Після того, як полотно забруднене, ви більше не можете витягувати дані з полотна. Наприклад, ви більше не можете використовувати полотно toBlob (), toDataURL () або getImageData (); це призведе до помилки безпеки.

Це захищає користувачів від викриття приватних даних, використовуючи зображення для отримання інформації з віддалених веб-сайтів без дозволу.

Я пропоную просто передати URL-адресу на мову вашого сервера та використовувати curl для завантаження зображення. Будьте обережні, щоб дезінфікувати це!

РЕДАГУВАТИ:

Оскільки ця відповідь все ще є прийнятою відповіддю, вам слід перевірити відповідь @ shadyshrif , яка полягає у використанні:

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

Це спрацює, лише якщо у вас є правильні дозволи, але принаймні дозволить вам робити те, що ви хочете.


1
Я б продовжив віддалену альтернативну пропозицію від @Prisoner і запропонував зробити це поведінкою за замовчуванням. Сервер майже напевно зможе отримати img.src, тоді wget * / * cURL зображення швидше, ніж клієнт міг би закодувати зображення локального походження та ВСТАНОВИТИ його на сервер. Можливо, лише якщо потрібна автентифікація на стороні клієнта (тобто спроба вашого сервера закінчується на a 403), ви можете повернутися до використання canvas.toDataURL(img)в надії, що він подається з того самого джерела, що і сторінка. Ця поведінка за замовчуванням також призведе до вихідного файлу (EXIF та ін.)
Alastair

4
Я встановив для мого сегмента Google Cloud Storage значення "Access-Control-Allow-Origin: *", але я все ще отримую цю помилку безпеки при спробі використовувати метод toDataURL (). Зображення подається на Полотно за URL-адресою, згенерованою з "getImageServingUrl"
пан Пабло

1
Будь-яке рішення ще? Ця відповідь дме.
Yeats

Чудово! Велике спасибі за цю відповідь!
Кевін Вінсент

4
TIL: Дуже важливо встановити crossOriginатрибут перед налаштуванням img.src.
horstwilhelm

56

Просто використовуйте crossOriginатрибут і передайте 'anonymous'як другий параметр

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

6
Щоб пояснити, це не буде працювати для серверів, які безпосередньо не передають вам ресурс. Це означає, що це буде працювати лише для загальнодоступних ресурсів або неправильно налаштованих серверів.
m3nda

3
Мені також довелося додати мітку часу до URL-адреси зображення, щоб уникнути відповіді сервера зберігання 304 без заголовка Access-Control-Allow-Origin. Ось такimg.src = url + '?' + new Date().getTime();
Кірбі

у мене не працювало в IE11 із зображеннями, що використовують джерело data-url
AlexM

4

Цей метод не дозволить отримати помилку "Access-Control-Allow-Origin" із сервера, до якого ви отримуєте доступ.

var img = new Image();
var timestamp = new Date().getTime();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url + '?' + timestamp;

3

Спробуйте код нижче ...

<img crossOrigin="anonymous"
     id="imgpicture" 
     fall-back="images/penang realty,Apartment,house,condominium,terrace house,semi d,detached,
                bungalow,high end luxury properties,landed properties,gated guarded house.png" 
     ng-src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" 
     height="220"
     width="200"
     class="watermark">

2
в чому причина безглуздого значення fall-backатрибута?
y.bregey

0

У моєму випадку я використовував елемент керування WebBrowser (примушуючи IE 11), і я не міг уникнути помилки. Перехід на CefSharp, який використовує Chrome, вирішив це для мене.


0

У мене було таке саме повідомлення про помилку. У мене був файл у простому форматі .html, коли я передав файл у php в Apache, він працював

html2canvas(document.querySelector('#toPrint')).then(canvas => {
            let pdf = new jsPDF('p', 'mm', 'a4');
            pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, 0, 211, 298);
            pdf.save(filename);
        });

-3

За допомогою fabric js ми можемо вирішити цю проблему з помилками безпеки в IE.

    function getBase64FromImageUrl(URL) {
        var canvas  = new fabric.Canvas('c');
        var img = new Image();
        img.onload = function() {
            var canvas1 = document.createElement("canvas");
            canvas1.width = this.width;
            canvas1.height = this.height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(this, 0, 0);
            var dataURL = canvas.toDataURL({format: "png"});
        };
        img.src = URL;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.