Canvas toDataURL无法返回完整的图像

6
我正在开发一个jQuery插件,用于对图像添加水印(是的,我很清楚JavaScript/HTML5水印系统的许多缺点,但暂且不要管它)。每张图片的基本方法如下:
  • 将图像粘贴到画布的背景上
  • 在上面添加水印图像的数据
  • 用包含水印的画布的src替换原始图像的src
如果我用画布本身替换图像元素,看起来好像能工作得很好。所有的元素都出现在画布上了。但是当我获取画布的dataURL时,除了最后绘制到它上面的图像之外,什么都没有显示出来。我甚至不介意这个问题,只是因为这个插件还需要替换链接到图像的href,所以要用包含水印的data URL来替换。
以下是当前的代码:
(function($){

    $.fn.extend({

        cmark: function(options) {

            var defaults = {
                type: 'image',
                content: 'watermark.png',
                filter: 'darker',
                scale:300,
                box: {
                    top         :   0.5,
                    left        :   0.5,
                    width       :   0.75,
                    height      :   0.75,
                    bgcolor     :   '#000000',
                    bgopacity   :   0.5,
                    fgopacity   :   1
                },

                callback_unsupported: function(obj){
                    return obj;
                }

            }

            var getScale = function(w, h, scale){
                ratio = Math.min(scale/w, scale/h);
                scalew = Math.round(ratio*w);
                scaleh = Math.round(ratio*h);
                return [scalew,scaleh];
            }



            var options =  $.extend(defaults, options);

            return this.each(function() {

                obj = $(this);

                canvas = document.createElement('canvas');

                if(!window.HTMLCanvasElement){
                    return options.callback_unsupported(obj);
                }


                /*  if selecting for images, reset the images. Otherwise, 
                    we're replacing link hrefs with data urls. */

                if(obj.attr('src')){
                    target_img = obj.attr('src');
                }

                else if (obj.attr('href')){
                    target_img = obj.attr('href');
                }

                // get the filetype, make sure it's an image. If it is, get a mimetype. If not, return.

                ftype = target_img.substring(target_img.lastIndexOf(".")+1).toLowerCase();

                canvasbg = new Image();

                canvasbg.onload = function(){
                    iw = canvasbg.width;
                    ih = canvasbg.height;

                    scale = getScale(iw, ih, options.scale);

                    iw = scale[0];
                    ih = scale[1];

                    canvas.setAttribute('width', iw);
                    canvas.setAttribute('height', ih);

                    ctx = canvas.getContext('2d');

                    /* define the box as a set of dimensions relative to the size of the image (percentages) */

                    bw = Math.round(iw * options.box.width);
                    bh = Math.round(ih * options.box.height);

                    // for now the box will only ever be centered.
                    bx = Math.round((iw * options.box.top) - (bw/2));
                    by = Math.round(ih * options.box.left - (bh/2));

                    /* draw the box unless the opacity is 0 */
                    if(options.box.bgopacity > 0){
                        ctx.fillStyle = options.box.bgcolor;
                        ctx.globalAlpha = options.box.bgopacity;
                        ctx.fillRect(bx, by, bw, bh);
                    }

                    wm = new Image();

                    wm.onload = function(){
                        ww = wm.width;
                        wh = wm.height;

                        scalar = Math.max(bw, bh); // scale to within the box dimensions
                        scale = getScale(ww, wh, scalar);
                        ww = scale[0];
                        wh = scale[1];

                        ctx.globalCompositeOperation = options.filter;
                        ctx.drawImage(wm, bx, by, ww, wh);
                    }

                    wm.src = options.content;

                    ctx.drawImage(canvasbg, 0, 0, iw, ih);

                    obj.replaceWith(canvas);

                    $('body').append('<img src="'+canvas.toDataURL()+'">');

                    //obj.attr('src', canvas.toDataURL());
                }

                canvasbg.src = target_img;



            });
        }
    })
})(jQuery);

我添加了一行代码,用 data url 直接将图片转储到页面上进行测试,结果如下:左边是画布元素,右边是带有 data url 的图片:

on the left is the canvas, on the right is the image

所以,这个问题已经让我困扰了几天。也许我错过了什么非常明显的东西,但我找不到它。... 因为示例已不再在线而进行了编辑。抱歉。

如果您在某处托管了一个“可工作”的示例(显示您的问题),例如http://jsfiddle.net/,您可能会获得更多帮助。 - Phrogz
1个回答

3
首先,不要为了一个标签构建这么长的字符串缓冲区。
var img = new Image();
img.src = canvas.toDataURL();
$('body').append(img);

或者如果您更喜欢:

$('body').append($('<img>').attr('src', canvas.toDataURL()))

第二步,你需要在绘制水印之前获取画布的DataURL。绘制发生在wm.onload回调函数中,该函数在水印加载时发生。这可能要比canvasbg.onload触发的时间晚得多,而你在此处获取了DataURL。

将图像附加移动到wm.onload回调函数的末尾,你就可以了。


你肯定在正确的轨道上:我在 OP 的示例上运行了以下代码 document.getElementsByTagName("img")[0].src = document.getElementsByTagName("canvas")[0].toDataURL();,它显示了图像中的水印。 - Ruan Mendes
编辑了一下,我觉得我的神秘“限制”实际上是我的剪贴板或其他什么东西……这实际上是一个时间问题。 - Alex Wayne
这也证实了我在所有内容都加载完后运行了该命令行,并且它起作用了 :) - Ruan Mendes
就是这样!将这个代码添加到wm.onload回调的末尾就解决了问题:obj.attr('src', canvas.toDataURL()); - Kenneth Rapp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接