2010-07-23 6 views
12

He estado siguiendo las lecciones sobre transparencia y degradados en el sitio de Mozilla: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors pero no he sido capaz de resolver esto.¿Es posible crear una imagen de transparencia transparente/capa de enmascaramiento utilizando canvas?

Sé que puedo lograr estos efectos con una imagen png; Sin embargo, en el programa en el que estoy trabajando, el gradiente cambiará constantemente de acuerdo con el lugar donde se mueve la imagen.

Aquí hay un ejemplo del efecto que estoy buscando. http://home.insightbb.com/~epyonxl1/gradientex.jpg

Respuesta

6

He cedido un código aquí http://code.google.com/p/canvasimagegradient/ que agrega una función drawImageGradient al CanvasRenderingContext2D. Puede dibujar una imagen con un degradado lineal o radial. No funciona en IE, incluso con excanvas, debido a la falta de compatibilidad con getImageData/putImageData.

El siguiente código, por ejemplo, va a dibujar una imagen con un gradiente radial (contexto recuperar y carga de la imagen no se muestra):

var radGrad = ctx.createRadialGradient(
    img.width/2, img.height/2, 10, 
    img.width/2, img.height/2, img.width/2); 
radGrad.addColorStop(0, "transparent"); 
radGrad.addColorStop(1, "#000"); 

ctx.drawImageGradient(img, 112.5, 130, radGrad); 

El código funciona como sigue:

  1. Crear un elemento de lona dinámicamente y dibujar la imagen en él.
  2. Recupere los imageData para este nuevo lienzo.
  3. Recupere el imageData para la ubicación en el lienzo que desea dibujar la imagen.
  4. Iterate a través del destino imageData y actualiza cada píxel sumando un porcentaje (derivado del valor de transparencia del degradado) de la imagen y los valores de píxel de destino.
  5. Finalmente coloque los datos de imagen actualizados nuevamente en el lienzo de destino.

Obviamente, el rendimiento es un problema ya que las imágenes se agrandan. La imagen en http://code.google.com/p/canvasimagegradient/ tarda unos 6-10ms en dibujar. Una imagen de 1024x768 requiere unos 100ms-250ms para dibujar. Aún usable aunque siempre que no estés animando.

+0

Ah, sabía que después se me olvidó especificar que ya Saber cómo crear un degradado como este https://developer.mozilla.org/samples/canvas-tutorial/4_9_canvas_lineargradient.html que obtendría esta respuesta. Lamentablemente, estos solo se aplican a colores específicos. Si se trata de una imagen (color no sólido), por otro lado, este método simplemente no funciona. – mjrevel

+0

volví y eché un vistazo a la imagen y veo lo que quieres ahora. Buena pregunta. Estoy pensando que si sacas la imagen en un lienzo separado y recuperas los datos de la imagen, puedes aplicarle un degradado y luego superponerla sobre el lienzo original. Voy a jugar y ver qué puedo hacer. – Castrohenge

+0

Suena bien, no tendré que dedicarle mucho tiempo durante el fin de semana para trabajar en él, pero también veré lo que se me ocurrió. Mantenme informado sobre cualquier cosa que averigües también. Definitivamente quiero resolver esto. – mjrevel

14

Es posible usar el contexto.globalCompositeOperation para hacer la máscara

context.drawImage(img, 0, 0, img.width, img.height, 0,0, img.width, img.height); 
context.globalCompositeOperation = "destination-out"; 
gradient = context.createLinearGradient(0, 0, 0, img.height); 
gradient.addColorStop(0, "rgba(255, 255, 255, 0.5)"); 
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)"); 
context.fillStyle = gradient; 
context.fillRect(0, 0, img.width, img.height); 

Esto no lo haga por manipulación de píxeles y debe ser más rápido

+1

Acepto que esto debería ser más rápido y, probablemente, la respuesta correcta. – calipoop

+0

Hasta donde puedo ver, la razón por la cual esta no es la respuesta correcta es que solo está usando el degradado para impactar en un rectángulo de color sólido. El OP preguntó sobre el uso de un degradado para impactar una imagen. – Nathan

+0

@Nathan te equivocas, esto funciona perfectamente – Alnitak

8

Para combinar correctamente dos imágenes usando una transparencia máscara es necesario en primer lugar para tomar una de las dos imágenes y ponerlo en un fuera de la pantalla lienzo, y añadir la máscara de transparencia deseado usando context.globalCompositeOperation = destination-out por @ respuesta de Tommyka

var offscreen = document.createElement('canvas'); // detached from DOM 
var context = offscreen.getContext('2d'); 
context.drawImage(image1, 0, 0, image1.width, image1.height); 

var gradient = context.createLinearGradient(0, 0, 0, img.height); 
gradient.addColorStop(0, "rgba(255, 255, 255, 0.5)"); 
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)"); 
context.globalCompositeOperation = "destination-out"; 
context.fillStyle = gradient; 
context.fillRect(0, 0, image1.width, image1.height); 

Entonces, para fusionar las dos imágenes en realidad le º es necesario señalar a la otra imagen en otro lienzo, y luego simplemente señalar a la alfa-composited fuera de la pantalla de la lona por encima de eso:

var onscreen = document.getElementById('mycanvas'); 
var context2 = onscreen.getContext('2d'); 
context2.drawImage(image2, 0, 0, image2.width, image2.height); 
context2.drawImage(offscreen, 0, 0, onscreen.width, onscreen.height); 

demo en http://jsfiddle.net/alnitak/rfdjoh31/4/

+2

Esta debería ser la respuesta aceptada. Funciona tan bien como la solución de @ Castrohenge, pero no requiere manipulación (lenta) píxel por píxel. ¡Gracias por eso! – Nathan

Cuestiones relacionadas