挑战:修复 Canvas 插件以使用 CORS?

Challenge: Fix a Canvas plugin to work with CORS?

我正在向任何 Canvas 专家寻求帮助!

我需要修复 jQuery/Canvas 插件。我在 Canvas 方面很弱。

基本上我希望能够模糊图像,我已经使用这个 Canvas 脚本完成了: http://www.quasimondo.com/BoxBlurForCanvas/FastBlur2Demo.html

https://github.com/Quasimondo/QuasimondoJS/blob/master/blur/StackBoxBlur.js

但它不适用于托管在另一个域上的图像(我在 app.example.com 和 api.example.com 上拥有所有内容)。所以我需要更新它以尊重 CORS/crossOrigin。我与原始开发人员有 documented the issue,但我怀疑他是否会修复它(自从他以主要方式触及它以来已有多年)。

Canvas 大师的工作时间可能很轻松。

插件通过调用这个来工作:

stackBoxBlurImage( sourceImageID, targetCanvasID, radius, blurAlphaChannel, iterations );

我试过这样做:

var img = document.getElementById( imageID );
    img.crossOrigin = '';
var w = img.naturalWidth;
var h = img.naturalHeight;

但这并不能解决问题。

理想情况下,我希望能够输入 $('.image')(或只是 URL,因为我不需要 un-blurred 图片弄乱 DOM) 和 $('.canvas') 元素,而不是两个 ID。这样,在事件中切换模糊图像可能会更容易一些(比如在菜单打开时模糊图像等)。

如果重要的话,我会在 Ember 应用程序中使用它。我也不想使用某种 PHP 代理脚本,这似乎是一种破解方法。

更新

我在此处添加了一个中断示例: http://dev.rickanddrew.com/

图片在这里。如果您查看响应 header,我认为 CORS 设置正确: http://image.rickanddrew.com/image.jpg

回答

感谢下面的肯,我明白了!这就是我现在的方式 运行:

function stackBoxBlurImage( imageURL, $canvasObj, radius, blurAlphaChannel, iterations )
{

// Cache vars
var img = document.createElement('img');
var canvas = $canvasObj[0];

// Make it work with CORS
img.crossOrigin = '';
img.src = imageURL;     

// Wait till image loads
img.onload = function(e) {

    // Setup image vars         
    var w = img.naturalWidth;
    var h = img.naturalHeight;

    // Setup Canvas size
    canvas.style.width  = w + "px";
    canvas.style.height = h + "px";
    canvas.width = w;
    canvas.height = h;

    // Add image to Canvas
    var context = canvas.getContext("2d");  
    context.drawImage(img, 0, 0, canvas.width, canvas.height);
    context.clearRect( 0, 0, w, h );
    context.drawImage( img, 0, 0 );    

    // Abort if radius is invalid
    if ( isNaN(radius) || radius < 1 ) return;

    // Blur!
    stackBoxBlurCanvasRGB( canvas, 0, 0, w, h, radius, iterations );
};
}

谢谢!

#1 CORS 订单很重要

CORS 请求未正确使用。就像现在一样,设置了图像标签的 src,然后在模糊脚本中设置了 crossOrigin post:

function stackBoxBlurImage( imageID, canvasID, radius, blurAlphaChannel, iterations )
{

    var img = document.getElementById( imageID );   // we already have the image.
        img.crossOrigin = '';                       // too late for this...

    ...

这将不起作用,因为必须先设置 crossOrigin ,然后再设置 图像 src。 CORS 使用请求与 URL 请求一起发送(如果服务器不喜欢它,我们就没有图像...)。

所以要解决,要么将 crossOrigin 添加到 img 标签本身:

<img id="image" crossOrigin="anonymous" src="image.jpg">

或者如果您愿意或需要动态设置 src,则在加载 JavaScript 之前不要设置 src(在这种情况下,我建议动态创建图像元素,如嗯):

<img id="image">

然后:

var image = document.getElementById("image");
image.crossOrigin = "";
image.onload = blur;
image.src = "image.jpg";

function blur() {
    stackBoxBlurImage( 'image', 'canvas', 30);              
}

#2 负载很重要

脚本的调用方式也存在问题,这会阻止图像数据可用(新加载、无缓存等)。如果图片已经存在于缓存中,这个问题就更难检测了(虽然新用户在第一次加载时可能看不到任何东西......)。

改变这个:

jQuery(document).ready(function(){
    stackBoxBlurImage( 'image', 'canvas', 30);              
})

至:

$(window).load(function() {
    stackBoxBlurImage( 'image', 'canvas', 30);
})

ready只是表示DOM准备好了,不一定是图像数据。为此,必须使用 load

服务器也有一个有趣的响应,其中图像请求似乎被解释为纯文本。但我没有深入挖掘,因为上面的步骤应该首先解决(或者我只是眨了眨眼:)):