为什么我的画布在转换为图像后空白?

编程入门 行业动态 更新时间:2024-10-24 19:14:34
本文介绍了为什么我的画布在转换为图像后空白?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我试图转换此页面上的画布元素使用以下代码段(例如在JavaScript控制台中输入):

I am trying to convert the canvas element on this page to a png using the following snippet (e.g. enter in JavaScript console):

(function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL("image/png"); return image; })($$('canvas')[0]);

请注意,原始画布在调整页面大小后会变为空白。

Unfortunately, the png I get is completely blank. Notice also that the original canvas goes blank after resizing the page.

为什么 canvas 如何将此画布转换为png?

Why does the canvas go blank? How can I convert this canvas to a png?

推荐答案

Kevin Reid's preserveDrawingBuffer 建议是正确的,但有(通常)更好的选择。

Kevin Reid's preserveDrawingBuffer suggestion is the correct one, but there is (usually) a better option. The tl;dr is the code at the end.

将渲染网页的最终像素放在一起并协调渲染WebGL内容的代价可能更加昂贵所以。通常的流程是:

It can be expensive to put together the final pixels of a rendered webpage, and coordinating that with rendering WebGL content even more so. The usual flow is:

  • JavaScript问题绘制命令到WebGL上下文
  • JavaScript返回,到主浏览器事件循环
  • WebGL上下文将绘图缓冲区(或其内容)转到合成器以集成到当前正在屏幕上呈现的网页中
  • JavaScript issues drawing commands to WebGL context
  • JavaScript returns, returning control to the main browser event loop
  • WebGL context turns drawing buffer (or its contents) over to the compositor for integration into web page currently being rendered on screen
  • Page, with WebGL content, displayed on screen
  • 请注意,这与大多数OpenGL应用程序不同。在那些,渲染的内容通常直接显示,而不是与一堆其他东西在一个页面上合成,其中一些可能实际上是在WebGL内容和混合。

    Note that this is different from most OpenGL applications. In those, rendered content is usually displayed directly, rather than being composited with a bunch of other stuff on a page, some of which may actually be on top of and blended with the WebGL content.

    在步骤3之后,WebGL规范被修改为将绘图缓冲区视为基本上为空。你在devtools中运行的代码是在第4步之后,这就是为什么你得到一个空缓冲区。对规范的这种改变允许在步骤3之后消隐的平台基本上是在硬件(如在许多移动GPU中)实际发生的那些平台上的大的性能改进。如果你想要解决这个问题,有时在步骤3后复制的WebGL内容,浏览器将必须总是在步骤3之前绘制缓冲区的副本,这将使你的帧速率下降

    The WebGL spec was changed to treat the drawing buffer as essentially empty after Step 3. The code you're running in devtools is coming after Step 4, which is why you get an empty buffer. This change to the spec allowed big performance improvements on platforms where blanking after Step 3 is basically what actually happens in hardware (like in many mobile GPUs). If you want work around this to sometimes make copies of the WebGL content after step 3, the browser would have to always make a copy of the drawing buffer before step 3, which is going to make your framerate drop precipitously on some platforms.

    您可以做到这一点,强制浏览器通过设置 preserveDrawingBuffer 为true。根据规范:

    You can do exactly that and force the browser to make the copy and keep the image content accessible by setting preserveDrawingBuffer to true. From the spec:

    可以通过设置WebGLContextAttributes对象的preserveDrawingBuffer属性来更改此默认行为。如果此标志为真,则绘图缓冲区的内容将被保留,直到作者清除或覆盖它们。如果此标志为假,则在渲染函数返回后,尝试使用此上下文作为源图像执行操作可能导致未定义的行为。这包括readPixels或toDataURL调用,或者使用此上下文作为另一个上下文的texImage2D或drawImage调用的源映像。

    This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object. If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them. If this flag is false, attempting to perform operations using this context as a source image after the rendering function has returned can lead to undefined behavior. This includes readPixels or toDataURL calls, or using this context as the source image of another context's texImage2D or drawImage call.

    代码只是改变上下文创建行:

    In the example you provided, the code is just changing the context creation line:

    gl = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true});

    请记住,在某些浏览器中它会强制使用较慢的路径,什么和如何渲染。你应该在大多数桌面浏览器,其中副本实际上不是必须做的,这些组成绝大多数WebGL功能的浏览器,但只是现在。罚款。

    Just keep in mind that it will force that slower path in some browsers and performance will suffer, depending on what and how you are rendering. You should be fine in most desktop browsers, where the copy doesn't actually have to be made, and those do make up the vast majority of WebGL capable browsers...but only for now.

    但,还有另一个选项(在规范的下一段有些混乱地提到)。

    However, there is another option (as somewhat confusingly mentioned in the next paragraph in the spec).

    你在步骤2之前自己复制:在你的所有绘制调用完成之后,但在你的代码控制到浏览器之前。这是当WebGL绘图缓冲区仍然在生产和可访问,你应该没有访问像素的问题。你使用相同的 toDataUrl 或 readPixels 调用,否则,它只是时间重要。

    Essentially, you make the copy yourself before step 2: after all your draw calls have finished but before you return control to the browser from your code. This is when the WebGL drawing buffer is still in tact and is accessible, and you should have no trouble accessing the pixels then. You use the the same toDataUrl or readPixels calls you would use otherwise, it's just the timing that's important.

    在这里你会得到两个世界的最好的。你得到一个绘图缓冲区的副本,但你不支付它在每一帧,即使你不需要一个副本(这可能是大多数),如你做的 preserveDrawingBuffer 设置为true。

    Here you get the best of both worlds. You get a copy of the drawing buffer, but you don't pay for it in every frame, even those in which you didn't need a copy (which may be most of them), like you do with preserveDrawingBuffer set to true.

    在您提供的示例中,只需将代码添加到 drawScene ,您应该会在下面看到画布的副本:

    In the example you provided, just add your code to the bottom of drawScene and you should see the copy of the canvas right below:

    function drawScene() { ... var webglImage = (function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL('image/png'); return image; })(document.querySelectorAll('canvas')[0]); window.document.body.appendChild(webglImage); }

    更多推荐

    为什么我的画布在转换为图像后空白?

    本文发布于:2023-07-19 08:56:13,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1154921.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:画布   转换为   图像   空白

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!