Como alterar a opacidade (alfa, transparência) de um elemento em um elemento de tela depois de ter sido desenhado?

196

Usando o <canvas>elemento HTML5 , eu gostaria de carregar um arquivo de imagem (PNG, JPEG, etc.), desenhá-lo na tela de forma completamente transparente e depois desbotá-lo. Eu descobri como carregar a imagem e desenhá-la no tela, mas não sei como alterar sua opacidade depois de desenhada.

Aqui está o código que tenho até agora:

var canvas = document.getElementById('myCanvas');

if (canvas.getContext)
{
    var c           = canvas.getContext('2d');
    c.globalAlpha   = 0;

    var img     = new Image();
    img.onload  = function() {
        c.drawImage(img, 0, 0);
    }
    img.src     = 'image.jpg';
}

Alguém por favor me apontará na direção certa como uma propriedade para definir ou uma função para chamar que mudará a opacidade?

Joe Lencioni
fonte

Respostas:

307

Também estou procurando uma resposta para essa pergunta (para esclarecer, quero poder desenhar uma imagem com opacidade definida pelo usuário, como como você pode desenhar formas com opacidade). Se você desenhar com formas primitivas, poderá definir preenchimento e traçado. cor com alfa para definir a transparência. Até onde eu concluí agora, isso não parece afetar o desenho da imagem.

//works with shapes but not with images
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";

Concluí que definir os globalCompositeOperationtrabalhos com imagens.

//works with images
ctx.globalCompositeOperation = "lighter";

Gostaria de saber se existe alguma terceira maneira de definir cores para que possamos pintar imagens e torná-las transparentes facilmente.

EDITAR:

Depois de cavar mais, concluí que você pode definir a transparência de uma imagem definindo o globalAlphaparâmetro ANTES de desenhar a imagem:

//works with images
ctx.globalAlpha = 0.5

Se você deseja obter um efeito de desbotamento ao longo do tempo, precisa de algum tipo de loop que altera o valor alfa, isso é bastante fácil, uma maneira de conseguir isso é a setTimeoutfunção, procure criar um loop a partir do qual você altera o alpha Tempo.

djdolber
fonte
7
globalAlpha funciona perfeitamente. Faz parte do padrão: whatwg.org/specs/web-apps/current-work/multipage/…
Aleris
42
Para ser preciso, não é o canvaselemento que possui a globalAlphapropriedade, mas o contexto que você obtém da tela.
Steve Blackwell
8
O comentário de Ian abaixo sobre ctx.save () e ctx.restore () impede que o globalAlpha afete o restante da tela.
Arosboro
1
Parece-me que, em vez de controlar a opacidade do que é desenhado na tela, seria mais simples e ainda serviria ao propósito de controlar apenas a opacidade de toda a tela depois que a imagem é desenhada (apenas uma vez). Use métodos CSS / style usuais para fazer isso (canvaselement.style.opacity = '0.3'; etc.) Mais tarde, com CSS3, você pode até dispensar o loop completamente e deixar o navegador lidar com o desbotamento (algo como transição: NNNms facilidade de entrada) ou até "animar" o desbotamento.
Chuck Kollars
1
Infelizmente, canvas2d.fillStyle = "rgba(255, 255, 255, 0.5)";não funciona. O valor deve estar em hexadecimal.
WebWanderer
113

Alguns exemplos de código mais simples para usar globalAlpha:

ctx.save();
ctx.globalAlpha = 0.4;
ctx.drawImage(img, x, y);
ctx.restore();

Se você precisar imgser carregado:

var img = new Image();
img.onload = function() {
    ctx.save();
    ctx.globalAlpha = 0.4;
    ctx.drawImage(img, x, y);
    ctx.restore()
};
img.src = "http://...";

Notas:

  • Defina o 'src'último, para garantir que seu onloadmanipulador seja chamado em todas as plataformas, mesmo se a imagem já estiver no cache.

  • Agrupe as alterações em itens como globalAlphaentre a savee restore(na verdade, use-as muito), para garantir que você não use configurações de outros lugares, principalmente quando partes do código de desenho serão chamadas a partir de eventos.

Ian
fonte
globalAlpha irá desfocar todas as imagens ou desenhos em uma tela, não é isso que você deseja.
Rabugento
6
@ Grumpy - não, globalAlphanão desfoca nada. Ele definirá o alfa para todos os desenhos subseqüentes (não altera nada já desenhado), e é por isso que no código de exemplo eu o envolvo savee restore, para limitar o que ele se aplica.
Ian
não tendo certeza de que o ctx.restore () restaurará o globalAlpha, talvez você também precise fazer isso no final (pelo menos era necessário nas versões anteriores do Chrome) ctx.globalAlpha = 1;
18717 Sean
1
@Sean - Se você não tiver certeza, deve verificar. Deve ter sido um Chrome muito antigo, ele funciona em todas as plataformas agora: jsfiddle.net/y0z9h9m7
Ian
14

Editar: A resposta marcada como "correta" não está correta.

É fácil de fazer. Experimente este código, trocando "ie.jpg" por qualquer imagem que você tenha à mão:

<!DOCTYPE HTML>
<html>
    <head>
        <script>
            var canvas;
            var context;
            var ga = 0.0;
            var timerId = 0;

            function init()
            {
                canvas = document.getElementById("myCanvas");
                context = canvas.getContext("2d");
                timerId = setInterval("fadeIn()", 100);
            }

            function fadeIn()
            {
                context.clearRect(0,0, canvas.width,canvas.height);
                context.globalAlpha = ga;
                var ie = new Image();
                ie.onload = function()
                {
                    context.drawImage(ie, 0, 0, 100, 100);
                };
                ie.src = "ie.jpg";

                ga = ga + 0.1;
                if (ga > 1.0)
                {
                    goingUp = false;
                    clearInterval(timerId);
                }
            }
        </script>
    </head>
    <body onload="init()">
        <canvas height="200" width="300" id="myCanvas"></canvas>
    </body>
</html>

A chave é a propriedade globalAlpha.

Testado com IE 9, FF 5, Safari 5 e Chrome 12 no Win7.

james.garriss
fonte
13

O post é antigo até agora, vou com a minha sugestão. A sugestão é baseada na manipulação de pixels no contexto da tela 2D. Do MDN:

Você pode manipular diretamente dados de pixel em telas no nível de bytes

Para manipular pixels, usaremos duas funções aqui - getImageData e putImageData

Uso da função getImageData:

var myImageData = context.getImageData (esquerda, superior, largura, altura);

e sintaxe putImageData:

context.putImageData (myImageData, dx, dy); // dx, dy - deslocamento de x e y na sua tela

Onde o contexto é o seu contexto 2D da tela

Portanto, para obter valores de verde, azul e alfa vermelhos, faremos o seguinte:

var r = imageData.data[((x*(imageData.width*4)) + (y*4))];
var g = imageData.data[((x*(imageData.width*4)) + (y*4)) + 1];
var b = imageData.data[((x*(imageData.width*4)) + (y*4)) + 2];
var a = imageData.data[((x*(imageData.width*4)) + (y*4)) + 3];

Onde x é x offset, y é y offset na tela

Portanto, ter código tornando a imagem semitransparente

var canvas = document.getElementById('myCanvas');
var c = canvas.getContext('2d');
var img = new Image();
img.onload  = function() {
   c.drawImage(img, 0, 0);
   var ImageData = c.getImageData(0,0,img.width,img.height);
   for(var i=0;i<img.height;i++)
      for(var j=0;j<img.width;j++)
         ImageData.data[((i*(img.width*4)) + (j*4) + 3)] = 127;//opacity = 0.5 [0-255]
   c.putImageData(ImageData,0,0);//put image data back
}
img.src = 'image.jpg';

Você pode criar seus próprios "shaders" - veja o artigo completo da MDN aqui

Soul_man
fonte
7

Você pode. A tela transparente pode ser desbotada rapidamente usando a operação composta global de destino final . Não é 100% perfeito, às vezes deixa alguns traços, mas pode ser aprimorado, dependendo do que for necessário (por exemplo, use 'source-over' e preencha-o com a cor branca com alfa em 0,13 e depois desbote para preparar a tela).

// Fill canvas using 'destination-out' and alpha at 0.05
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.beginPath();
ctx.fillRect(0, 0, width, height);
ctx.fill();
// Set the default mode.
ctx.globalCompositeOperation = 'source-over';
Og2t
fonte
3

Eu acho que isso responde melhor à pergunta, na verdade altera o valor alfa de algo que já foi desenhado. Talvez isso não fizesse parte da API quando essa pergunta foi feita.

dado o 2d contexto c.

function reduceAlpha(x, y, w, h, dA) {
    var screenData = c.getImageData(x, y, w, h);
    for(let i = 3; i < screenData.data.length; i+=4){
    screenData.data[i] -= dA; //delta-Alpha
    }
    c.putImageData(screenData, x, y );
}
Dillon
fonte
Como essa resposta é diferente da resposta de Soul_man dada com mais detalhes sete anos antes?
BReddy
-2

Se você usar a biblioteca jCanvas, poderá usar a propriedade opacidade ao desenhar. Se você precisar de um efeito de desbotamento, basta redesenhar com valores diferentes.

cen
fonte
-11

Você não pode. São gráficos de modo imediato. Mas você pode simular isso desenhando um retângulo sobre ele na cor de fundo com uma opacidade.

Se a imagem ultrapassar algo que não seja uma cor constante, fica um pouco mais complicada. Você deve poder usar os métodos de manipulação de pixel neste caso. Apenas salve a área antes de desenhar a imagem e depois misture-a novamente com uma opacidade.

MPG
fonte
5
Esta não é a resposta certa veja abaixo
Ryan Badour
Você está correto, embora não possa alterar a opacidade de um dos elementos que você desenhou na tela, você pode alterar a opacidade de toda a tela. Em alguns casos, isso pode ser suficiente.
MPG
2
MPG - seu comentário (11 de maio) também está errado. Você pode alterar a opacidade da tela, mas não é isso que o OP queria, nem o que está sendo sugerido nas respostas acima.
Ian