【问题标题】:CanvasElement.toDataURL() for WebGL canvases用于 WebGL 画布的 CanvasElement.toDataURL()
【发布时间】:2015-09-13 23:34:19
【问题描述】:

我们开发复杂的基于 WebGL 的应用程序,并为我们的用户提供保存当前场景屏幕截图的能力。虽然此功能在 Chrome 和 Firefox 中按预期工作,但我们在 safari 中遇到了几个问题。

请看下面的代码。如您所见,我们使用 CanvasElement 的 toDataURL() 方法进行截图。虽然此代码在其他浏览器中按预期工作,但它在 safari 中生成错误的图像(至少对于 WebGL 画布)。

您可以通过打开this file 或在 safari 和其他浏览器中运行附加的代码 sn-p 轻松地自己重现问题。

我们做错了吗?这个问题有解决办法吗?

谢谢。

UPD:特别是对于那些说它与 preserveDrawingBuffer 相关的人,我将其更改为附加代码 sn-p 以表明即使将 preserveDrawingBuffer 设置为 true,它在 safari 中的行为仍然是错误的。

<script type="text/javascript" src="http://www.html5rocks.com/en/tutorials/webgl/webgl_fundamentals/webgl/resources/webgl-utils.js"></script>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
  attribute vec2 a_position;

  void main() {
    gl_Position = vec4(a_position, 0, 1);
  }
</script>

<script id="2d-fragment-shader" type="x-shader/x-fragment">
  void main() {
    gl_FragColor = vec4(0,1,0,1);  // green
  }
</script>

<div>
  <canvas id="canvas1" width="300" height="300"></canvas>
  <img id="img1"/>
</div>
<div>
  <canvas id="canvas2" width="300" height="300"></canvas>
  <img id="img2"/>
</div>
<div>
  <canvas id="canvas3" width="300" height="300"></canvas>
  <img id="img3"/>
</div>

<div>
  <canvas id="canvas4" width="300" height="300"></canvas>
  <img id="img4"/>
</div>
<div>
  <canvas id="canvas5" width="300" height="300"></canvas>
  <img id="img5"/>
</div>
<div>
  <canvas id="canvas6" width="300" height="300"></canvas>
  <img id="img6"/>
</div>

<script type="text/javascript">
  function test(canvas, img, premultipliedAlpha, alpha, preserveDrawingBuffer) {
    var gl = canvas.getContext("experimental-webgl", {
      premultipliedAlpha: premultipliedAlpha, 
      alpha: alpha,
      preserveDrawingBuffer: preserveDrawingBuffer
    });
    var vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
    var fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
    var program = createProgram(gl, [vertexShader, fragmentShader]);
    gl.useProgram(program);
    var positionLocation = gl.getAttribLocation(program, "a_position");

    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(
      gl.ARRAY_BUFFER,
      new Float32Array([
        -1.0, -1.0,
        1.0, -1.0,
        -1.0,  1.0,
        1.0, -1.0,
        1.0,  1.0]),
      gl.STATIC_DRAW);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    gl.drawArrays(gl.TRIANGLES, 0, 5);

    img.src = canvas.toDataURL();
  }

  window.onload = function() {
    test(document.getElementById("canvas1"), document.getElementById("img1"), true, true, false);
    test(document.getElementById("canvas2"), document.getElementById("img2"), false, true, false);
    test(document.getElementById("canvas3"), document.getElementById("img3"), false, false, false);

    test(document.getElementById("canvas4"), document.getElementById("img4"), true, true, true);
    test(document.getElementById("canvas5"), document.getElementById("img5"), false, true, true);
    test(document.getElementById("canvas6"), document.getElementById("img6"), false, false, true);
  };
</script>

【问题讨论】:

  • @LJ_1102 我不认为这与 preserveDrawingBuffer 有某种关系:我专门为你创建了 another testcase,将 preserveDrawingBuffer 设置为 true。它在 safari 中仍然无法正常工作。
  • @LJ_1102 我还修改了附加的代码 sn-p 以表明即使使用 preserveDrawingBuffer 它在 safari 中仍然无法正常工作。
  • @LJ_1102 另请注意,此处的 toDataURL() 调用是在实际渲染之后立即进行的,因此与您链接的问题相比,没有任何异步。

标签: canvas safari webgl todataurl


【解决方案1】:

我自己偶然发现了这个问题。我认为这只是 safari 中的一个错误:当您在获取 gl 上下文时设置 premultipliedAlpha: false 时,canvas.toDataURL() 将返回一个颠倒的图像。向苹果发送错误报告。

【讨论】:

    【解决方案2】:

    在 Mac 和 iPhone 上的 Safari 中,当 premultipliedAlpha: false 在创建 webgl 上下文时,toDataURL 返回一个垂直翻转的图像。

    这个错误在 2021 年仍然存在于 Safari 中。作为一种解决方法,我们可以复制到具有 2d 上下文的画布,将画布数据复制到该画布并调用 toDataURL

    
    function getDataUrl(origCanvas, mimeType){
            var canvas = document.createElement( 'canvas' );
            canvas.width = origCanvas.width;
            canvas.height = origCanvas.height;
            var destCtx = canvas.getContext('2d');
            if(!destCtx) {
                console.error("Cannot create context")
                return ""
            }
            destCtx?.drawImage(origCanvas, 0, 0);
    
            return destCtx.canvas.toDataURL(mimeType);
    }
    
    

    【讨论】:

      猜你喜欢
      • 2016-01-27
      • 2017-10-16
      • 1970-01-01
      • 2016-12-19
      • 2014-11-07
      • 2020-11-17
      • 2017-02-15
      • 1970-01-01
      • 2019-05-07
      相关资源
      最近更新 更多