【问题标题】:image onload not firing when try to create a new image into canvas. why?尝试在画布中创建新图像时不会触发图像加载。为什么?
【发布时间】:2016-01-12 13:18:23
【问题描述】:

我想获取一个 svg 并将其保存为 png(来自一个创建 svg 的 Chart 插件),我想我已经想出了如何实现这一点......

我一直在寻找为什么 onload 函数没有触发,但我仍然不明白为什么下面的代码不起作用。你好没有显示。这可能非常简单,但我现在无法看到它......

jQuery(function ($) {   

    var svg = $("#visualizer-152").find('svg');
    var imgsrc = 'data:image/svg+xml;base64,'+ btoa(svg);
    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");

    drawing = new Image();
    //All above seems to work, no errors in console and objects
    //seems to be created correctly

    drawing.onload = function () {
        alert('hello');
        context.drawImage(drawing,0,0);
        var base64 = canvas.toDataURL('image/png', 1);
    };

    drawing.src = imgsrc;
});

更新

将 onload 更改为,它似乎工作......

$( drawing ).load( "", function() {
    context.drawImage(drawing,0,0);
    var base64 = canvas.toDataURL('image/png', 1);
    console.log('base64');
   console.log(base64);
});

但现在另一个问题,我检索到这个错误:

未捕获的 InvalidStateError:无法执行“drawImage” 'CanvasRenderingContext2D':提供的 HTMLImageElement 在 “破碎”状态。

更新2 如果我尝试点击控制台中生成的数据字符串:

var imgsrc = 'data:image/svg+xml;base64,'+ btoa(svg);
console.log(imgsrc);

我在控制台中得到这个字符串:

data:image/svg+xml;base64,W29iamVjdCBPYmplY3Rd

浏览器中的这个错误:

此页面包含以下错误:

第 1 行第 1 列的错误:文档为空 下面是到第一个错误为止的页面渲染。

更新3: 我开始意识到实际问题是我无法正确获取源代码。我测试了手动将源设置为指向特定文件,然后它就可以工作了。通过查看生成的 svg 内容...(部分内容)

<div id="visualizer-152">
<div style="position: relative;">
<div dir="ltr" style="position: relative; width: 660px; height: 400px;">
<div aria-label="Ett diagram." style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;">
<svg width="660" height="400" aria-label="Ett diagram." style="overflow: hidden;">
<defs id="defs">
<clipPath id="_ABSTRACT_RENDERER_ID_0">
<rect x="125" y="77" width="411" height="247"></rect></clipPath>
</defs><rect x="0" y="0" width="660" height="400" stroke="none" stroke-  
width="0" fill="#ffffff"></rect>

并尝试一个明显有效的示例:(取自问题:How to convert svg to png using html5 canvas/javascript/jquery and save on server

http://jsfiddle.net/epistemex/xfh7nctk/23/

在jsfiddle中,源码被outerHTML抓取:

var svgText = document.getElementById("myViewer").outerHTML;

还有来自 fiddle 的 html..(开始)

<div id="container" width=500px height=400px>
    <svg class="svg-editor" 
    id="myViewer" 
    width="1400" 
    height="1400" 
    xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" 
    style="overflow:scroll;margin:0;">

但在我的情况下它不起作用,因为 html 看起来不一样并且 svg 没有 id。我尝试向 SVG 添加一个 ID,尝试向 SVG 添加一个类但没有成功。我还尝试使用 wrap() - jQuery 中的函数创建包装器,但也没有成功:

【问题讨论】:

  • base64 - 不是浏览器需要加载的东西。它已经加载了。这就是为什么你没有被解雇。
  • @primetwig - 这没有意义吗?我已经更新了问题。
  • 你需要等待 svg 被加载(如果它是一个文件)。就目前而言,您正在尝试在尚未加载源代码的情况下创建 base64。
  • @primetwig svg 是基于 jQuery(function ($) { ... 因为加载了 dom?或者你的意思是我必须做一些 onload svg 函数?创建了 svg,我可以访问它通过 var svg = $("#visualizer-152").find('svg');
  • 如果你在新窗口中打开var imgsrc = 'data:image/svg+xml;base64,'+ btoa(svg);的结果,你真的看到图像了吗?您的其余代码都很好,所以我怀疑图像数据已损坏。

标签: javascript jquery canvas svg todataurl


【解决方案1】:

这是您在小提琴中开始的一种变体,它似乎对我有用。这里缺少的是您必须调整画布大小以匹配您的图像,但您明白了。

var container = document.getElementById('container');
var svgText   = document.getElementById("myViewer").outerHTML;
var myCanvas  = document.getElementById("canvas");
var ctxt      = myCanvas.getContext("2d");
var DOMURL    = window.URL || window.webkitURL || window;

var svg = new Blob([svgText], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);

var img = new Image();
    img.onload = createPNG;
    img.src = url;

function createPNG() {
  ctxt.drawImage(img, 0, 0);
  var canvasData = myCanvas.toDataURL('image/png');
  // For the download button you can use one you have on your HTML
  // or create one like this. Notice the download attribute where you can name your file.
  // https://developer.mozilla.org/en/docs/Web/HTML/Element/a#Using_the_download_attribute_to_save_a_canvas_as_a_PNG
  var saveBtn = document.createElement('a');
      saveBtn.href = canvasData;
      saveBtn.textContent = 'Download PNG';
      saveBtn.download = 'FILENAME.png';
  DOMURL.revokeObjectURL(url);
  container.appendChild(saveBtn);
}

编辑: 要选择没有 ID 的 svg,您可以使用 querySelector 查询任何特定元素。尝试用这些替换前两行:

var container = document.getElementById('visualizer-152');
var svgText = container.querySelector('svg').outerHTML;

querySelector() 将仅返回它找到的第一个 svg 元素。如果您有多个 SVG,则可以使用 querySelectorAll(),它将返回一个包含所有 svg 元素的数组。

【讨论】:

  • 那么容器和 myViewer 应该是什么? (基于我在 update3 中写过的 Visualizer Plugin 生成的 html)
  • 容器不会影响图像的创建(获取 SVG 或生成 PNG),因此它可以是 HTML 中您想要放置下载按钮的任何元素。它可以是var container = document.getElementById('visualizer-152');,甚至只是你的身体标签var container = document.body;
  • 我明白你的意思。我将容器设置为 Visualizer-152 元素的包装器。但困难的部分是用什么替换 myViewer?因为在小提琴中 myViewer 指的是实际的 SVG,但是在生成的 html 中没有 svg 元素的 id。
  • 看看我的编辑是否有帮助。原则上,在 HTML 中获取元素应该不难,尤其是现在我们可以在 JS 中原生使用 querySelector
  • 我尝试了您的编辑并在尝试获取 outerHTML 时收到此错误:未捕获的 TypeError:无法读取 null 的属性“outerHTML”。我也试过 var svgText = container.querySelector('svg')[0].outerHTML;然后得到错误:Uncaught TypeError: Cannot read property '0' of null
猜你喜欢
  • 2016-03-28
  • 2019-01-19
  • 2016-03-25
  • 2013-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 2014-02-19
相关资源
最近更新 更多