Làm cách nào để sửa lỗi getImageData () Canvas đã bị làm hỏng bởi dữ liệu có nguồn gốc chéo?


131

Mã của tôi đang hoạt động rất tốt trên localhost của tôi nhưng nó không hoạt động trên trang web.

Tôi đã gặp lỗi này từ bảng điều khiển, cho dòng này .getImageData(x,y,1,1).data:

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 

một phần mã của tôi:

jQuery.Event.prototype.rgb=function(){
        var x =  this.offsetX || (this.pageX - $(this.target).offset().left),y =  this.offsetY || (this.pageY - $(this.target).offset().top);
        if (this.target.nodeName!=="CANVAS")return null;
        return this.target.getContext('2d').getImageData(x,y,1,1).data;
    }

Lưu ý: url hình ảnh của tôi (src) là từ url tên miền phụ


8
Tôi đang gặp lỗi này ngay cả khi img.src là url tương đối cục bộ: "img / foo.png" - vậy nguồn gốc chéo về vấn đề này là gì?
Sanford Staab

Xem stackoverflow.com/a/16218015/5175433 : "Chrome không xem xét các tệp cục bộ khác nhau có nguồn gốc từ cùng một tên miền."
A_P

Câu trả lời:


116

Như những người khác đã nói bạn đang "làm mờ" khung vẽ bằng cách tải từ một miền có nguồn gốc chéo.

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enables_Image

Tuy nhiên, bạn có thể ngăn điều này bằng cách cài đặt đơn giản:

img.crossOrigin = "Anonymous";

Điều này chỉ hoạt động nếu máy chủ từ xa thiết lập tiêu đề sau một cách thích hợp:

Access-Control-Allow-Origin "*"

Trình chọn tệp Dropbox khi sử dụng tùy chọn "liên kết trực tiếp" là một ví dụ tuyệt vời về điều này. Tôi sử dụng nó trên lẻprints.com để thu thập hình ảnh từ url hình ảnh hộp thư từ xa, vào khung vẽ của tôi và sau đó gửi dữ liệu hình ảnh trở lại máy chủ của tôi. Tất cả trong javascript


1
Điều này đã khắc phục được lỗi này khi tải hình ảnh imgur vào jsfiddle.net
Travis J

3
làm việc cho tôi nếu tôi đặt crossorigin trước sau đó đặt nguồn và sau đó truy cập dữ liệu khi tải
jones

2
Điều gì xảy ra nếu đó là một tệp cục bộ và ứng dụng của bạn hoàn toàn không sử dụng internet? Giống như một ứng dụng webview trên Android và hình ảnh chỉ nằm trong cùng thư mục với tệp html. Điều này không giải quyết nó.
Curtis

44

Tôi thấy rằng tôi phải sử dụng .setAttribute('crossOrigin', '')và phải thêm dấu thời gian vào chuỗi truy vấn của URL để tránh phản hồi 304 thiếu Access-Control-Allow-Origintiêu đề.

Cái này cho tôi

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');

3
Thử điều này mà không có máy chủ trên tệp cục bộ sẽ cho: Truy cập vào hình ảnh tại tệp ': /// C: /.../img/colorPaletteCtrl.png? 1507058959277' từ nguồn gốc 'null' đã bị chặn bởi chính sách CORS: Phản hồi không hợp lệ . Do đó, nguồn gốc 'null' không được phép truy cập.
Sanford Staab

1
Đơn giản chỉ cần sử dụng imgObj.setAttribute('crossOrigin', '')giải quyết nó cho tôi - cảm ơn! img.crossOrigin = "Anonymous"hoạt động tốt (như đã đề cập ở đây ). @SanfordStaab Trình duyệt coi các tệp cục bộ là trên một miền khác, nếu không, chủ sở hữu trang web có thể đọc các tệp cục bộ của bạn. Bạn cần yêu cầu hình ảnh từ cùng một tên miền hoặc các tiêu đề trong phản hồi yêu cầu của bạn cần thông báo cho trình duyệt biết rằng mã từ các tên miền khác có thể đọc tệp đó không sao.

19

Bạn sẽ không thể vẽ hình ảnh trực tiếp từ một máy chủ khác vào một khung vẽ và sau đó sử dụng getImageData. Đây là một vấn đề bảo mật và khung vẽ sẽ được coi là "vô vị".

Bạn có thể lưu một bản sao của hình ảnh vào máy chủ của mình bằng PHP và sau đó chỉ cần tải hình ảnh mới không? Ví dụ: bạn có thể gửi URL tới tập lệnh PHP và lưu nó vào máy chủ của bạn, sau đó trả lại tên tệp mới cho javascript của bạn như thế này:

<?php //The name of this file in this example is imgdata.php

  $url=$_GET['url'];

  // prevent hackers from uploading PHP scripts and pwning your system
  if(!@is_array(getimagesize($url))){
    echo "path/to/placeholderImage.png";
    exit("wrong file type.");
  }

  $img = file_get_contents($url);

  $fn = substr(strrchr($url, "/"), 1);
  file_put_contents($fn,$img);
  echo $fn;

?>

Bạn sẽ sử dụng tập lệnh PHP với một số javascript ajax như thế này:

xi=new XMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();

xi.onreadystatechange=function() {
  if(xi.readyState==4 && xi.status==200) {
    img=new Image;
    img.onload=function(){ 
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    }
    img.src=xi.responseText;
  }
}

Nếu bạn sử dụng getImageDatatrên khung vẽ sau đó, nó sẽ hoạt động tốt.

Ngoài ra, nếu bạn không muốn lưu toàn bộ hình ảnh, bạn có thể chuyển tọa độ x & y cho tập lệnh PHP của mình và tính giá trị rgba của pixel ở bên đó. Tôi nghĩ rằng có những thư viện tốt để thực hiện kiểu xử lý ảnh đó trong PHP.

Nếu bạn muốn sử dụng phương pháp này, hãy cho tôi biết nếu bạn cần trợ giúp thực hiện nó.

chỉnh sửa-1: peeps chỉ ra rằng tập lệnh php bị lộ và cho phép internet có khả năng sử dụng nó một cách độc hại. có một triệu cách để xử lý việc này, một trong những cách đơn giản nhất là một số cách xáo trộn URL ... tôi nghĩ rằng các thực hành php an toàn xứng đáng có một google riêng; P

chỉnh sửa-2: theo yêu cầu phổ biến, tôi đã thêm một kiểm tra để đảm bảo đó là hình ảnh chứ không phải tập lệnh php (từ: PHP kiểm tra xem tệp có phải là hình ảnh không ).


15
Ngoài ra - Tải hình ảnh và tập lệnh từ hệ thống tệp cục bộ, gây ra vấn đề tương tự.
Guy Dafny

2
rằng không phải rất an toàn ai đó cố có thể làm ngập máy chủ của bạn với các tập tin lớn bằng cách sử dụng kịch bản php đó sẽ là xấu
LAX1DUDE

1
@ LAX1DUDE câu trả lời được cải thiện với một đơn giản kiểm tra an ninh
jumpjack

1
nhờ vào phương pháp này nó cũng có thể để vượt qua một hình ảnh để tesseract.js cơ OCR mà không sử dụng Node.js (chỉ cần thêm các cuộc gọi đến Tesseract.recognize (img) trong img.onload () chức năng.
jumpjack

1
Bạn CẦN xác thực tên tệp, loại tệp / loại mime, vị trí và kích thước tải lên do người dùng cung cấp. Mã này dễ bị tấn công. Tôi sẽ để nó như một bài tập cho người đọc, nhưng tôi tin rằng có thể tải các tệp .php lên thư mục gốc của máy chủ web với mã này.
hiburn8

4

Tôi đã nhìn thấy lỗi này trên Chrometrong khi tôi đã được thử nghiệm mã của tôi tại địa phương. Tôi chuyển sang Firefoxvà tôi không thấy lỗi nữa. Có lẽ chuyển sang trình duyệt khác là một sửa chữa nhanh chóng.

Nếu bạn đang sử dụng giải pháp được đưa ra trong câu trả lời đầu tiên, thì hãy đảm bảo bạn thêm img.crossOrigin = "Anonymous";ngay sau khi bạn khai báo imgbiến (ví dụ var img = new Image();:).


2

Vấn đề của bạn là bạn tải một hình ảnh bên ngoài, có nghĩa là từ một tên miền khác. Điều này gây ra lỗi bảo mật khi bạn cố gắng truy cập bất kỳ dữ liệu nào trong bối cảnh canvas của bạn.


vâng, tôi nhận được hình ảnh từ tên miền phụ tải lên ... Tôi phải làm gì?
Erfan Safarpoor

1
Vâng, bạn có thể sử dụng proxy để truy xuất hình ảnh của mình, proxy này sẽ nằm trên cùng một tên miền với tên bạn đang chạy canvas.
axelduch

1
Tôi đang tải lên hình ảnh mới từ Máy tính của tôi và thử tải nó vào khung vẽ & tôi đang gặp lỗi này. Tôi không sử dụng bất kỳ loại hình ảnh máy chủ.
Piyush Dholariya

máy tính của bạn được xem bởi máy chủ nơi đặt tập lệnh (nhưng không được thực thi) dưới dạng miền bên ngoài, vì hình ảnh được sao chép vào khung vẽ được tạo trên máy tính của bạn, nơi tập lệnh được thực thi.
jumpjack

2

Bạn đang "làm mờ" khung vẽ bằng cách tải từ một miền có nguồn gốc chéo. Kiểm tra bài viết MDN này:

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enables_Image


tôi đã thêm <IfModule mod_setenvif.c> <IfModule mod_headers.c> <FilesMatch "\. (cur | gif | ico | jpe? g | png | svgz? | webp) $"> SetEnv If Origin ":" IS Kiểm soát-Cho phép-Xuất xứ "*" env = IS_CORS </ FilesMatch> </ IfModule> </ IfModule> để htaccess tất cả các tên miền nhưng không hoạt động!
Erfan Safarpoor

1
Bạn đang thử nghiệm trình duyệt nào? Và chắc chắn rằng bạn đã khởi động lại Apache.
srquinn

Tôi không thể khởi động lại apache ... tôi có tài khoản cpanel chia sẻ.
Erfan Safarpoor

2
Không thể giúp bạn định cấu hình thiết lập Apache của bạn, xin lỗi. Nó cũng nằm ngoài phạm vi của câu hỏi này. Gửi những rắc rối của bạn về việc thiết lập Apache sang một câu hỏi mới và cộng đồng sẽ sẵn lòng giúp bạn ở đó.
srquinn

1

Khi làm việc trên máy chủ, hãy thêm máy chủ

Tôi đã có một vấn đề tương tự khi làm việc trên địa phương. Url của bạn sẽ là đường dẫn đến tệp cục bộ, ví dụ: tệp: ///Users/PeterP/Desktop/folder/index.html.

Xin lưu ý rằng tôi đang dùng MAC.

Tôi đã làm tròn điều này bằng cách cài đặt máy chủ http trên toàn cầu. https://www.npmjs.com/package/http-server

Các bước:

  1. Cài đặt toàn cầu: npm install http-server -g
  2. Chạy máy chủ: http-server ~/Desktop/folder/

PS: Tôi giả sử bạn đã cài đặt nút, nếu không bạn sẽ không nhận được các lệnh npm chạy rất xa.


0

Như matt burn nói trong câu trả lời của anh ấy , bạn có thể cần bật CORS trên máy chủ nơi lưu trữ hình ảnh sự cố.

Nếu máy chủ là Apache, điều này có thể được thực hiện bằng cách thêm đoạn mã sau (từ đây ) vào cấu hình Virtualhost của bạn hoặc một .htaccesstệp:

<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>

... Nếu thêm nó vào Virtualhost, có lẽ bạn cũng cần phải tải lại cấu hình của Apache (ví dụ: sudo service apache2 reloadnếu Apache đang chạy trên máy chủ Linux)


0

Vấn đề của tôi đã rất rắc rối. Tôi chỉ cần mã hóa 64 hình ảnh để đảm bảo không có bất kỳ vấn đề nào về CORS


-2

Tôi gặp vấn đề tương tự ngày hôm nay, và giải quyết nó bằng mã sau đây.

Mã HTML:

<div style='display: none'>
  <img id='img' src='img/iak.png' width='600' height='400' />
</div>
<canvas id='iak'>broswer don't support canvas</canvas>

mã js:

var canvas = document.getElementById('iak')
var iakImg = document.getElementById('img')
var ctx = canvas.getContext('2d')
var image = new Image()
image.src=iakImg.src
image.onload = function () {
   ctx.drawImage(image,0,0)
   var data = ctx.getImageData(0,0,600,400)
}

mã như trên, và không có vấn đề tên miền chéo.


1
Giá trị src vẫn là nguồn gốc chéo, vậy làm thế nào để tránh vấn đề này?
Loveen Dyall

Cách tiếp cận này hoạt động khi chạy tệp html cục bộ (không có máy chủ) như tệp: /// X: /htmlfile.html. Hầu hết mọi người kết thúc câu nói của họ bằng ";". Điểm của câu lệnh "var data = .." là gì? Tôi muốn GIẢI THÍCH TẠI SAO điều này tránh được lỗi "tên miền chéo". Nhưng nó có, cảm ơn.
dcromley

karry đôi thông minh
Mari Selvan

1
@dcromley "Hầu hết mọi người kết thúc câu nói của họ bằng;" Sử dụng dấu chấm phẩy không được khuyến nghị theo tiêu chuẩn. Dấu chấm phẩy chỉ cần thêm nhiều công việc, trông xấu xí và mã hoạt động hoàn hảo mà không có chúng. Kiểm tra github.com/st
Chuẩn / st Chuẩn

1
@madprops developer.mozilla.org nói rằng "Các ứng dụng JavaScript bao gồm các câu lệnh với một cú pháp phù hợp. Một câu lệnh có thể kéo dài nhiều dòng. Nhiều câu lệnh có thể xảy ra trên một dòng nếu mỗi câu được phân tách bằng dấu chấm phẩy. Đây không phải là từ khóa , nhưng một nhóm từ khóa. " Vì vậy, tôi thuộc phe "sử dụng luôn". Tôi thậm chí còn không biết có một phe "không bao giờ". Tôi giả sử sau này cũng tin trái đất phẳng? (Đùa thôi - cảm ơn)
dcromley

-3

Tôi đã có cùng một vấn đề, và đối với tôi nó hoạt động bằng cách đơn giản là ghép https:${image.getAttribute('src')}


vui lòng giải thích những gì bạn đã làm
Yehuda Schwartz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.