Kanvas yang kotor mungkin tidak diekspor

187

Saya ingin menyimpan kanvas saya ke img. Saya memiliki fungsi ini:

function save() {
    document.getElementById("canvasimg").style.border = "2px solid";
    var dataURL = canvas.toDataURL();
    document.getElementById("canvasimg").src = dataURL;
    document.getElementById("canvasimg").style.display = "inline";
}

Ini memberi saya kesalahan:

Uncaught SecurityError: Gagal mengeksekusi 'toDataURL' pada 'HTMLCanvasElement': Kanvas tercemar tidak boleh diekspor.

Apa yang harus saya lakukan?

pengguna3465096
sumber
Di browser apa? stackoverflow.com/a/21362569/476716 mengklaim ini adalah bug.
OrangeDog
1
pada chrome dan firefox
user3465096

Jawaban:

180

Untuk alasan keamanan, drive lokal Anda dinyatakan sebagai "domain lain" dan akan mencemari kanvas.

(Itu karena info Anda yang paling sensitif kemungkinan ada di drive lokal Anda!).

Saat pengujian coba solusi berikut ini:

  • Letakkan semua file terkait halaman (.html, .jpg, .js, .css, dll) di desktop Anda (bukan di dalam sub-folder).

  • Posting gambar Anda ke situs yang mendukung berbagi lintas domain (seperti dropbox.com). Pastikan Anda meletakkan gambar Anda di folder publik dropbox dan juga mengatur tanda asal silang saat mengunduh gambar (var img = Gambar baru (); img.crossOrigin = "anonim" ...)

  • Instal server web di komputer pengembangan Anda (server web IIS dan PHP keduanya memiliki edisi gratis yang berfungsi dengan baik di komputer lokal).

tandai
sumber
16
Terima kasih, pengaturan properti img.crossOrigin membantu saya!
zumek
5
@markE - Saya memuat data gambar dari localStorage alih-alih memuat dari file atau url apa pun, lalu melakukan manipulasi padanya seperti menambahkan teks. Kemudian mencoba sotre kembali ke localStorage menggunakan toDataURL (). Tetapi ini menunjukkan "Gagal menjalankan 'toDataURL' di 'HTMLCanvasElement': Kanvas yang dicat mungkin tidak diekspor". Dalam hal ini saya tidak menggunakan file atau url exteranl untuk mendapatkan masalah lintas domain. Lalu mengapa ini menyebabkan kesalahan ini?
Sajith
2
@ Samjth - Anda mungkin ingin memverifikasi jalur yang digunakan untuk gambar. Saya punya masalah ini juga karena saya sedang menguji langsung mengakses server virtual lokal saya melalui IP-nya (127.0.xx /) tetapi beberapa gambar dihubungkan melalui domain (localhost /). Setelah saya menggunakan localhost, ternyata berhasil. Jadi pastikan Anda tidak bertemu dengan sesuatu seperti itu.
Victor D.
1
(1) Lihat dari server web xampp, localhost / file, bukan c: / localdisk / file; maka chrome tidak akan mengeluh tentang Kesalahan Keamanan. (2) Atau gunakan bendera ini saat memulai chrome: --allow-file-access-from-files
mosh
1
Hanya menambahkan kemungkinan masalah lain: jika Anda mencoba untuk mengekspor kanvas yang berisi svg dengan ForeignObject, beberapa browser akan menandainya sebagai ternoda.
HairyFotr
128

Pada tag img atur crossorigin ke Anonymous.

<img crossorigin="anonymous"></img>
Annia Martinez
sumber
61
Tapi apa yang harus dilakukan dalam kasus kanvas HTML5, bukan elemen img
graphics123
11
Dalam kasus elemen kanvas, sumber masalahnya selalu dengan beberapa gambar (atau gambar) yang Anda gambar. Jadi, Anda hanya perlu melacak gambar dan mengatur atribut crossOrigin seperti yang ditunjukkan, sebelum memuatnya.
Fernando Echeverria
3
Ini menyelamatkan hari saya!
Chang
1
Senang membantu :)
Annia Martinez
9
ini jam 12 pagi di kantor dan saya menemukan jawaban sederhana ini, ini adalah kebahagiaan murni
Dheeraj
26

Jika seseorang melihat jawaban saya, Anda mungkin dalam kondisi ini:

1. Mencoba mendapatkan tangkapan layar peta di kanvas menggunakan openlayers (versi> = 3)
2. Dan melihat contoh mengekspor peta
3. Menggunakan ol.source.XYZ untuk merender lapisan peta

Bingo!

Menggunakan ol.source.XYZ.crossOrigin = 'Anonim' untuk menyelesaikan kebingungan Anda. Atau suka kode berikut:

     var baseLayer = new ol.layer.Tile({
         name: 'basic',
         source: new ol.source.XYZ({
             url: options.baseMap.basic,
             crossOrigin: "Anonymous"
         })
     });
sknight
sumber
1
fantastis. Berguna untuk semua sumber, seperti TileImage dan semacamnya.
Phil
Gemuk! Persis seperti yang saya cari sendiri, perbaikan mudah untuk demo OpenLayers yang saya lakukan.
Marc
Saya menggunakan lapisan ubin vektor dan setelah menambahkan propery ini ke sumber tetapi tidak berfungsi juga!
mahdi n75
Persis apa yang saya butuhkan :)
Ray
17

Jika Anda menggunakan ctx.drawImage()fungsi, Anda dapat melakukan hal berikut:

var img = loadImage('../yourimage.png', callback);

function loadImage(src, callback) {
    var img = new Image();

    img.onload = callback;
    img.setAttribute('crossorigin', 'anonymous'); // works for me

    img.src = src;

    return img;
}

Dan dalam panggilan balik Anda sekarang Anda dapat menggunakan ctx.drawImagedan mengekspornya menggunakantoDataURL

mehulmpt
sumber
6
Ini tidak berhasil untuk saya. Masih menerima Tainted canvases may not be exported.pesan kesalahan.
Sam Sverko
1
ini bekerja untuk saya. Terima kasih. @SamSverko pastikan atur atribut sebelum img.src.
aijogja
14

Dalam kasus saya, saya menggambar ke tag kanvas dari video. Untuk mengatasi kesalahan kanvas tercemar saya harus melakukan dua hal:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>
  • Pastikan header Access-Control-Allow-Origin diatur dalam respons sumber video (pengaturan crossdomain.example.com yang benar)
  • Atur tag video untuk memiliki crossorigin = "anonim"
jdramer
sumber
5

Sepertinya Anda menggunakan gambar dari URL yang belum menyetel tajuk Akses-Kontrol-Bolehkan-Asal yang benar dan karenanya menjadi masalah .. Anda dapat mengambil gambar itu dari server Anda dan mendapatkannya dari server Anda untuk menghindari masalah CORS ..

Prasanna Aarthi
sumber
Mungkinkah Anda lebih tepat tentang jawaban Anda, karena saya tidak benar-benar tahu semua konsep itu. Bagaimana cara saya mengambil gambar itu dari server saya?
user3465096
dari mana Anda mengambil gambar itu, apakah itu dari server Anda atau yang lain?
Prasanna Aarthi
Bunyinya seperti ini: loadImage ("example.jpg", 0, 0, 500, 300); Saya dapat meletakkan url gambar acak atau gambar pada folder yang sama di komputer saya, masih sama
user3465096
ya, tapi saya baru saja membuat gambar pada cat dan masih sama
user3465096
1
Saya memberi Access-Control-Allow-Origin: * untuk file tersebut, tetapi masih menunjukkan kesalahan
Harikrishnan
5

Saya menyelesaikan masalah menggunakan useCORS: trueopsi

 html2canvas(document.getElementsByClassName("droppable-area")[0], { useCORS:true}).then(function (canvas){
        var imgBase64 = canvas.toDataURL();
        // console.log("imgBase64:", imgBase64);
        var imgURL = "data:image/" + imgBase64;
        var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_"+new Date().getTime()+".jpeg").appendTo("body");
        triggerDownload[0].click();
        triggerDownload.remove();
    });
Ahmad Zahabi
sumber
3

Lihat [CORS enabled image] [1] dari MDN. Pada dasarnya Anda harus memiliki server hosting gambar dengan header Access-Control-Allow-Origin yang sesuai.

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

Anda akan dapat menyimpan gambar-gambar itu ke Penyimpanan DOM seolah-olah mereka disajikan dari domain Anda jika tidak, Anda akan mengalami masalah keamanan.

var img = new Image,
    canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d"),
    src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"; // insert image url here

img.crossOrigin = "Anonymous";

img.onload = function() {
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage( img, 0, 0 );
    localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
    img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    img.src = src;
}

BerlinaLi
sumber
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
Gowtham Shiva
Terima kasih atas pemberitahuannya. Saya baru saja menambahkan konten dari tautan MDN :)
BerlinaLi
1

Sama seperti build pada jawaban @ markE — jika Anda ingin membuat server lokal. Anda tidak akan memiliki kesalahan ini di server lokal.

Jika Anda menginstal PHP di komputer Anda:

  1. Buka terminal / cmd Anda
  2. Arahkan ke folder tempat file situs web Anda berada
  3. Saat berada di folder ini, jalankan perintah php -S localhost:3000 ← Perhatikan ibukota 'S'
  4. Buka browser Anda dan di bilah URL pergi ke localhost: 3000 . Situs web Anda seharusnya berjalan di sana.

atau

Jika Anda memiliki Node.js diinstal di komputer Anda:

  1. Buka terminal / cmd Anda
  2. Arahkan ke folder tempat file situs web Anda berada
  3. Saat berada di folder ini, jalankan perintah npm init -y
  4. Jalankan npm install live-server -gatausudo npm install live-server -g di mac
  5. Jalankan live-serverdan itu akan secara otomatis membuka tab baru di browser dengan situs web Anda terbuka.

Catatan: ingat untuk memiliki file index.html di root folder Anda atau Anda mungkin memiliki beberapa masalah.

Ludolfyn
sumber
0

Saya juga memecahkan kesalahan ini dengan menambahkan useCORS : true,kode saya seperti -

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();
Jeet
sumber