哪种方法可以直接从dataToURL-image字符串创建画布模式?

时间:2015-04-09 20:39:14

标签: javascript performance canvas html5-canvas race-condition

我正在使用我以前用

制作的图像
var patternImageAsDataURL= canvasObject.toDataURL('image/png');

在稍后阶段,我想制作一个画布图案对象。下面的代码不起作用 - 我假设在转到最后一行时根本没有加载图像,在createPattern函数中需要它。

var img = document.createElement('img');
img.src = patternImageAsDataURL;
// canvasctx was created somewhere else in the program
pattern = canvasctx.createPattern(img,'repeat');

我在最后一行收到错误:NS_ERROR_NOT_AVAILABLE:。 (当在最后两行之间的img的宽度和高度上使用console.log时,我发现当它不起作用时,尺寸为0。)

稍后使用相同的dataURL完成相同的操作时,它确实有效。虽然图像(img)应该总是重新创建。 (因为我在Firefox中进行了一些内部优化,所以我可以看到它的原因。但是这里除非有人确实知道了答案,否则这是非正式的。)将它们打印到控制台时的宽度和高度是正确的

虽然我很快会编写一些模式处理服务,但是应该解决这个问题,我的问题一般是关于速度问题和简单性。 (如果我使用带有模式的20到50个对象的代码,我宁愿选择内存或省时功能的精益解决方案。)

  

我能以某种方式更直接地(并且更快地)使用dataURL   createPattern函数?   和:   我可以强制程序在img.src = patternImageAsDataURL;命令之后等待,直到加载图像,然后继续处理代码? (就像在XMLrequests的同步模式中一样。)

(在当前的程序流程中,使用图像的onload事件是不可行的。)

这是在Firefox 32,Win 7上运行。

2 个答案:

答案 0 :(得分:2)

创建模式的更快,更直接的方式

您可以使用第二个canvas元素作为模式的源。

这使您可以完全跳过从源画布创建ImageURL和Image的临时步骤,这样您的模式创建速度就会更快。

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// Make a temporary canvas to be the template for a pattern
var pc=document.createElement('canvas');
var px=pc.getContext('2d');
pc.width=4;
pc.height=4;
px.fillStyle='palegreen';
px.fillRect(0,0,2,2);
px.fillRect(2,2,2,2);

// Use the temporary canvas as the image source for "createPattern"
var pattern=ctx.createPattern(pc,'repeat');
ctx.fillStyle=pattern;
ctx.fillRect(50,50,100,75);
ctx.strokeRect(50,50,100,75);
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<h4>Using a temporary canvas as source for a Pattern.</h4>
<canvas id="canvas" width=300 height=300></canvas>

答案 1 :(得分:1)

选项1 - 画布作为图像源

显而易见的当然是使用画布本身作为模式的图像源。

createPattern()可以将图片,画布,上下文(虽然并非所有浏览器都允许)或甚至视频source

  

CanvasPattern createPattern(CanvasImageSource image,
  [TreatNullAs = EmptyString] DOMString重复);

其中CanvasImageSource定义为:

  

typedef(HTMLImageElement或
  HTMLVideoElement或
  HTMLCanvasElement或
  CanvasRenderingContext2D或
  ImageBitmap)CanvasImageSource;

这也是允许您稍后不使用onload的唯一方法(前提是生成模式但未从图像/视频源中提取)。

如果不使用回调(或承诺),您无法处理异步行为,并期望程序正常工作。期间。

选项2 - 数据URI

如果由于某种原因无法使用原始画布作为源,则必须异步处理图像。为它添加一个onload处理程序并从其中继续:

var img = document.createElement('img');
img.onload = function() {
    pattern = canvasctx.createPattern(this, 'repeat');
    // continue from here..
};
img.src = patternImageAsDataURL;

请注意,由于在图像处理本身之上的额外编码/解码过程,此过程相对较慢。您可以在this answer

中找到有关此内容的更多详细信息

选项3 - Blob和对象URL

Blob允许您以二进制形式存储数据。这优于将二进制数据作为编码字符串存储,与data-URI一样。与数据URI相比,嵌入和提取的速度更快。

您可以将URL表单与Blob一起使用,并将其用作图像源。

首先直接从画布创建Blob:

var patternImageAsBlob = canvas.toBlob(...);  //IE: msToBlob()

这也是一个异步调用,因此您需要考虑到这一点。

例如:

var patternAsBlob;

canvas.toBlob(function(blob) {
    patternAsBlob = blob;
    // continue from here
}

然后当您需要它作为图像时,为它生成一个Object-URL:

  var img = new Image(),
      url = URL.createObjectURL(patternAsBlob);

    img.onload = function() {
        URL.revokeObjectURL(url);  // clean up by removing the url object
        pattern = canvasctx.createPattern(this, 'repeat');
        // continue from here..
    };
    img.src = url;

提示

如果要加载和设置多个图像,最好使图像加载器在所有资源中加载到数组中,完成后创建模式。

这将简化异步链调用(可选择使用promises,但在没有polyfill的情况下IE尚不支持)。

在较旧的浏览器中,您可能需要使用toblob的polyfill。可以找到一个 here

您可能需要“取消修正”createObjectURL(),这是一种方式:

 var domURL = self.URL || self.webkitURL || self;
 var url = domURL.createObjectURL( ... );