【问题标题】:Get a data URI from a HTML canvas on a Google Apps Script web page从 Google Apps 脚本网页上的 HTML 画布获取数据 URI
【发布时间】:2013-11-07 09:25:07
【问题描述】:

问题

我正在尝试使用此库实现签名收集器:github.com/szimek/signature_pad

收集器作为 Google Apps 脚本上的网络应用程序运行。我希望能够使用我们公司的用户列表和 Drive 以及签名来创建 PDF。

我使用常规 HTML 创建了表单,并从库的演示页面添加了 canvas 元素。

我可以绘制签名,但是当我尝试使用 canvas.toDataURL() 提取数据 URL 时,我收到以下消息:

Expected property "toDataURL" to be a function, not undefined: undefined

在 Chrome 开发者控制台中。

我的尝试

我假设 Google Caja 库(我几乎一无所知)没有实现或允许 toDataURL() 方法。我找到了这个库:http://www.nihilogic.dk/labs/canvas2image/,它可以创建画布 BMP 的 base64 编码版本。

这次我可以运行代码并提取一些数据,但是当我尝试在服务器端将图像重新组合在一起时,我得到的只是一个黑盒子。

这是一个演示该问题的示例应用程序:https://script.google.com/macros/s/AKfycbwXo0xFNWqiewoe4oh-cSxTdhmqRTyNDwL9xknbtOdk3rLbHZ8/exec

示例输出

Object [object Object] has no method 'toDataURL'

到开发者控制台。这应该是因为我使用的是 NATIVE 沙盒模式而不是 EMULATED。

这是可编辑项目的链接:https://script.google.com/d/19azWWXnrUO72ryDWhmhKJA-PqoOiDIRNPEIt61h2l_kduUbD87V4P311/edit?usp=sharing。也许某个好人可以为我建立一个合适的链接?

接下来是什么

  • 有没有办法让toDataURL() 方法工作?
  • BMP 解决方案应该起作用吗?怎么了?
  • 还有其他我可以使用的库/解决方案吗?

显然我没有提供任何代码。我可以根据要求这样做。如果 BMP 解决方案应该有效,那么我将向您展示我在做什么,我现在没有添加代码,因为它可能只是一个死胡同。

编辑:

  • getDataURL() 更正为toDataURL()
  • 添加了示例应用

【问题讨论】:

  • 我不确定canvas.getDataUrl(),你是说canvas.toDataURL吗?显然,在画布上绘制的任何图像都需要来自同一域才能使 toDataURL 工作...如果您的实例是这种情况,此 url 可能会帮助您coderwall.com/p/pa-2uw。如果这不是问题,我会尝试在 DevTools 中调试对画布的引用,只需检查 toDataURL 的值以及您的调用是否正确。也许用一个孤立的例子更新你的帖子让我们看看?
  • 嗨,是的,我的意思是toDataURL,我已经更新了我的问题以修复该错误,干杯。我的印象是,如果我在浏览器中绘制图像(而不是拉入外部图像),我会遇到这些安全问题。这不正确吗?我会尽快发布一些代码和一些开发工具输出。

标签: javascript html canvas google-apps-script


【解决方案1】:

这里的问题是 Google Apps 脚本在 Caja 沙箱中运行这一切(如您所知)。

沙箱提供给我们的canvas 对象是沙箱友好的TameSpecificElement 版画布,它没有附加toDataURL 方法。

这是因为 Caja 团队目前认为这是一种潜在的危险方法,还是因为它仍在开发中,我不确定。

在 Caja 源代码中:test-domado-canvas-guest 在 toDataURL 旁边有一个 TODO,但这并没有让我清楚这是因为实施正在开发中,还是只是为了确保它是测试有效的沙盒正在开发中,所以就未来的实施而言,您的猜测与我的猜测一样好。

但我认为可以放心地回答,在当前发布的版本下,canvas 的驯服版本不支持该操作。

您可以使用 Canvas 的上下文 getImageData 方法,该方法将返回一个包含 data 属性中所有像素的数组。我在您的应用引擎代码中对此进行了测试,并且可以正常工作!

之后,您必须将其转换为 base64 编码以滚动您自己的 dataUrl(可能需要一个好的 JavaScript 库来将像素数组转换为 PNG,像 http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/ 这样的东西可能会成功)。

这里是一些与上述库一起使用的示例代码,与您当前的示例相比,有一些效率变化。

window.saveButton.addEventListener("click", function (event) {
    if (window.signaturePad.isEmpty()) {
        alert("Please provide signature first.");
    } else {
        var captureWidth = 658;
        var captureHeight = 318;

        var p = new PNGlib(captureWidth, captureHeight, 256);
        var background = p.color(0, 0, 0, 0);
        var context = canvas.getContext("2d");
        var imageData = context.getImageData(0, 0, captureWidth, captureHeight);
        var data = imageData.data;
        var dataKeys = Object.keys(data);

        var thisPixelNumber = 0;

        // each pixel is represented by 4 bytes in the array, 
        // so we'll just advance 4 at a time here.  We're using dataKeys to determine the
        // length, because data property in this environment is an object not an array.
        for (var i=0; i < dataKeys.length; i+= 4) {
            var thisPixelNumber = i / 4,
                pixelColor = {
                    r: data[i],
                    g: data[i+1],
                    b: data[i+2],
                    a: data[i+3]
                };

            // only worry about transferring the pixel if it actually has a value, check the     alpha for this.
            // this is a massive time saver for us, reading memory being way faster than writing.
            if (pixelColor.a) {
                var x = thisPixelNumber % captureWidth,
                    y = Math.floor(thisPixelNumber / captureWidth);

                p.buffer[p.index(x, y)] = p.color(pixelColor.r, pixelColor.g, pixelColor.b,     pixelColor.a);
            }
        }

        // in the end just log out the url to the console.  Use Chrome DevTools to check this     value and click it to view the converted PNG
        console.log('data:image/png;base64,' + p.getBase64());
    }
});

【讨论】:

  • 感谢您的帮助。我使用了您链接到的库并循环访问了像素数组。整个过程非常缓慢。我认为这是图像大小、我可能不太理想的代码和 Caja 沙箱的组合。我有可能完全提高速度吗?我只会更新测试代码,这样你就可以看到我在做什么。再次感谢。
  • @Billy 看看我刚刚在编辑中添加的代码示例,如果你把它放在你的脚本中,它就会成功。它不是即时的,需要进行一些计算,但它不会挂起!请注意,我正在控制台记录数据 url,而不是像您那样使用 window.open,因此您必须手动单击 DevTools 控制台中的链接,然后执行任何操作以将其应用于您的用例,它就在那里说明它有效。祝你好运。
  • 太棒了,谢谢!有效。我唯一需要做的就是从表单中删除onsubmit="return false;"。这似乎是添加到您使用 NATIVE 模式的表单中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 2012-11-27
  • 1970-01-01
相关资源
最近更新 更多