canvas toDataURL non restituisce un’immagine completa

Sto costruendo un plugin jQuery che filtra le immagini (e sì, sono ben consapevole dei molteplici inconvenienti di un sistema di watermarking javascript / html5, ma per ora lo ignoro.) Il metodo di base per ogni immagine è:

  • incollare l’immagine sullo sfondo di una canvas
  • aggiungi i dati per un’immagine filigrana oltre a quella,
  • sostituisci la Src dell’immagine originale con quella della canvas (che ora contiene la filigrana).

Ora sembra funzionare bene se sostituisco l’elemento immagine con la canvas stessa .. tutti gli elementi compaiono sulla canvas. Ma quando ottengo il dataURL della canvas, appare tutto tranne l’ultima immagine disegnata su di essa. Non mi dispiacerebbe nemmeno se questo plugin dovesse anche sostituire i link alle immagini, e quindi sostituire gli hrefs con gli url di dati (con la filigrana).

Questo è il codice corrente:

(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(''); //obj.attr('src', canvas.toDataURL()); } canvasbg.src = target_img; }); } }) })(jQuery); 

Ho aggiunto una riga che scarica un’immagine con l’url di dati direttamente sulla pagina per il test e questo è quello che vedo … a sinistra c’è l’elemento canvas, a destra l’immagine con l’url dati:

a sinistra c'è la tela, a destra c'è l'immagine

Quindi sì, questo mi ha costretto per un paio di giorni per ora. Probabilmente mi manca qualcosa di orribilmente ovvio ma non riesco a vederlo.

… modificato perché l’esempio non è più online. spiacente.

Prima di tutto, non creare un buffer di stringa così grande per un tag.

 var img = new Image(); img.src = canvas.toDataURL(); $('body').append(img); 

O se preferisci:

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

In secondo luogo, stai ricevendo dati URL della canvas prima di disegnare la filigrana. Il disegno viene wm.onload funzione wm.onload callback, che si verifica quando viene caricata la filigrana. Questo potrebbe non funzionare fino a quando canvasbg.onload si avvia, che è dove si ottiene il dataURL.

Quindi sposta l’immagine in codice alla fine del richiamo wm.onload e dovresti essere bravo.