【问题标题】:Cors tainted canvasCors 被污染的帆布
【发布时间】:2017-04-10 09:25:14
【问题描述】:

我正在运行 mjpeg 流媒体并尝试将流设置为 three.js 中的纹理。

我通过将其写入画布然后将画布作为纹理来做到这一点。 但是,我得到一个受污染的画布错误。

DOMException: Failed to execute 'texImage2D' on 'WebGLRenderingContext': 
Tainted canvases may not be loaded.

我已经在服务器上添加了crossOrigin头,它被接收为:

  Access-Control-Allow-Origin:*
  Content-type:multipart/x-mixed-replace; boundary=--jpgboundary
  Date:Tue, 04 Apr 2017 22:27:35 GMT
  Server:BaseHTTP/0.3 Python/2.7.9**strong text**

在客户端我添加了适当的 crossOrigin 属性

<p>Image to use:</p>
<img id="stream" crossorigin="anonymous" 
src="http://192.168.1.224:8080/cam.mjpg">


<p>Canvas:</p>
<canvas id="myCanvas" width="200" height="200" style="border:1px solid 
#d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

function updateCanvas() {
    var c = document.getElementById("myCanvas");
    var ctx2 = c.getContext("2d");
    var img = document.getElementById("stream");
    img.crossOrigin = "anonymous";
    ctx2.drawImage(img, 0, 0);
}

有没有人知道这里有什么不好的地方?

编辑:对不起,我应该澄清一下,把它放在画布上工作正常,问题是当我尝试将该画布用作纹理时,画布被污染并且失败

function init() {
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);
    document.body.appendChild(renderer.domElement);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000);
    camera.position.z = 500;
    scene.add(camera);
    window.setTimeout("updateCanvas()", 1000); //start with a delay
    texture = new THREE.Texture(canvas);
    var material = new THREE.MeshBasicMaterial({ map: texture });
    geometry = new THREE.BoxGeometry( 200, 200, 200 );
    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );
    canvas.width = canvas.height = size;
    renderer.setClearColor(0xeeeeee, 1);
}


function animate() {
   requestAnimationFrame(animate);
   updateCanvas();
   texture.needsUpdate = true;
   mesh.rotation.y += 0.01;
   renderer.render(scene, camera);
}

【问题讨论】:

  • 我不是在 src 之前设置 crossOrigin 属性吗?稍后我还会在我的代码中反复调用 updateCanvas,以更新下一帧。
  • @gman ,你知道gl.texImage2D&lt;img&gt; 的动画媒体上是否与context2d.drawImage() 具有相同的limitations 吗?
  • texImage2DdrawImage 更严格。 drawImage 可以在没有 CORS 权限的情况下拍摄跨域图像。这样做会将画布标记为脏。 texImage2D 未经许可不会跨域镜像。 WebGL 画布永远不会,因为没有 CORS 许可期限就不能使用跨域图像。
  • @gman,抱歉,我确实将讨论分开,并对您的回答发表了评论。如果用于纹理的 2d 画布之前被污染,那么 texImage2d 将无法正常工作?那么这可能是OP的问题。但我的问题是他甚至需要穿过 2d 画布吗? texImage2d 可以处理动画图像吗,不像 drawImage?
  • 正确,通过画布传递跨域非 CORS 许可视频将不起作用。穿过画布对 AFAIK 没有任何作用,除了可能让您在上传到纹理之前缩放视频。您可以使用a video tag directly with texImage2D。虽然最近有a bug in Chrome currently being fixed

标签: canvas http-headers cors webgl


【解决方案1】:

我看不出您的代码无法运行的任何原因。设置 img.crossOrigin 没有意义,因为在您的示例中已经下载了图像。

用来自 imgur 的图像尝试它是有效的。这表明问题出在您的服务器上?

function updateCanvas() {
  var c = document.getElementById("myCanvas");
  var ctx2 = c.getContext("2d");
  var img = document.getElementById("stream");
  ctx2.drawImage(img, 0, 0);
  try {
    const d = c.toDataURL();
    log("canvas is not dirty, CORS permission received, it can be used in WebGL");
  } catch (e) {
    log("canvas IS dirty, no CORS permission, it can *NOT* be used in WebGL");
  }
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join("\n");
  document.body.appendChild(elem);
}


document.getElementById("stream").addEventListener('click', updateCanvas);
img, canvas { width: 32px; }
p { margin: 0; }
<p>Click the Image:</p>
<img id="stream" crossorigin="anonymous" src="https://i.imgur.com/TSiyiJv.jpg">


<p>Canvas:</p>
<canvas id="myCanvas" width="200" height="200" style="border:1px solid 
#d3d3d3;">
</canvas>

也许检查一下 imgur 的标题,看看有什么不同?

【讨论】:

    【解决方案2】:

    这是一个 chrome 错误:

    我必须在我的本地主机上设置一个 ffserver + mjpeg 代理来确认这一点,但是, chrome 不会在运动 jpeg 流上发出的请求中保留 crossOrigin 标头...

    Firefox 没有这个错误,我也没有找到可靠的前端解决方法。

    实际上我发现的唯一解决方法是使用代理,这对于 mjpeg 流来说并不容易,但基于 express-js 的 this one 确实工作得很好。

    另外,请注意,浏览器应该只在画布上绘制 mjpeg 流的第一帧 [specs],chrome 在这里也有一个错误,不要依赖这个,因为它可能很快就会失败,当他们会解决的。


    编辑

    webgl 的 texImage2d 似乎与 limitations 关于动画图像的 drawImage 不同。

    因此,对于您的情况,甚至不要穿过 2D 画布。您可以直接在 &lt;img&gt; 标记内使用 mjpeg 流并将其用作更新纹理。
    (尽管您仍然必须使用 chrome 代理)

    【讨论】:

      猜你喜欢
      • 2014-11-16
      • 2013-02-07
      • 2019-02-18
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 2017-12-18
      • 2014-10-07
      相关资源
      最近更新 更多