Jak zmienić krycie (alfa, przezroczystość) elementu w elemencie canvas po jego narysowaniu?

196

Korzystając z <canvas>elementu HTML5 , chciałbym załadować plik obrazu (PNG, JPEG itp.), Narysować go całkowicie na płótnie całkowicie przezroczysto, a następnie go rozjaśnić. Zrozumiałem, jak załadować obraz i narysować go na płótno, ale nie wiem, jak zmienić jego krycie po narysowaniu.

Oto kod, który mam do tej pory:

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';
}

Czy ktoś wskaże mi właściwy kierunek, jak właściwość do ustawienia lub funkcja do wywołania, która zmieni krycie?

Joe Lencioni
źródło

Odpowiedzi:

307

Szukam również odpowiedzi na to pytanie (aby wyjaśnić, chcę być w stanie narysować obraz ze zdefiniowanym przez użytkownika kryciem, takim jak sposób rysowania kształtów z kryciem), jeśli rysujesz z prymitywnymi kształtami, możesz ustawić wypełnienie i obrys kolor z alfa, aby zdefiniować przezroczystość. O ile do tej pory doszedłem, wydaje się, że nie wpływa to na rysowanie obrazu.

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

Doszedłem do wniosku, że ustawienie globalCompositeOperationprac z obrazami.

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

Zastanawiam się, czy istnieje jakiś trzeci sposób ustawiania kolorów, abyśmy mogli przyciemnić obrazy i uczynić je łatwo przezroczystymi.

EDYTOWAĆ:

Po dalszym kopaniu doszedłem do wniosku, że możesz ustawić przezroczystość obrazu, ustawiając globalAlphaparametr PRZED narysowaniem obrazu:

//works with images
ctx.globalAlpha = 0.5

Jeśli chcesz osiągnąć efekt zanikania w czasie, potrzebujesz jakiejś pętli, która zmienia wartość alfa, jest to dość łatwe, jednym ze sposobów na osiągnięcie tego jest setTimeoutfunkcja, spójrz na to, aby utworzyć pętlę, z której zmienisz wartość alfa czas.

djdolber
źródło
7
globalAlpha działa idealnie. Jest częścią standardu: whatwg.org/specs/web-apps/current-work/multipage/…
Aleris
42
Mówiąc ściślej, to nie canvaselement ma globalAlphawłaściwość, ale kontekst, który otrzymujesz z obszaru roboczego.
Steve Blackwell
8
Komentarz Iana poniżej dotyczący ctx.save () i ctx.restore () zapobiega wpływowi globalAlpha na resztę obszaru roboczego.
Arosboro,
1
Wydaje mi się, że nie kontroluję krycia tego, co jest rysowane na płótnie, byłoby to prostsze i nadal służyłoby do kontrolowania krycia całego płótna po narysowaniu obrazu (tylko raz). Aby to zrobić, użyj zwykłych metod CSS / style (canvaselement.style.opacity = '0.3'; itp.) Później w CSS3 możesz nawet zrezygnować z pętli i pozwolić przeglądarce zamiast tego zająć się zanikaniem (coś w stylu - przejście: NNNms opacyity easy-in-out), a nawet „animować” zanikanie.
Chuck Kollars
1
Niestety canvas2d.fillStyle = "rgba(255, 255, 255, 0.5)";nie działa Wartość musi być szesnastkowa.
WebWanderer
113

Prostszy przykładowy kod do użycia globalAlpha:

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

Jeśli musisz imgzostać załadowany:

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

Uwagi:

  • Ustaw 'src'ostatni, aby zagwarantować, że onloadprogram obsługi jest wywoływany na wszystkich platformach, nawet jeśli obraz jest już w pamięci podręcznej.

  • Zawiń zmiany w rzeczy globalAlphamiędzy a savei restore(w rzeczywistości używaj ich dużo), aby upewnić się, że nie blokujesz ustawień z innych źródeł, szczególnie gdy fragmenty kodu rysowania będą wywoływane ze zdarzeń.

Ian
źródło
globalAlpha rozmyje wszystkie obrazy lub rysunki na płótnie, to nie jest to, czego chcesz.
Grumpy
6
@ Grumpy - nie, globalAlphaniczego nie rozmazuje. Ustawi alfa dla wszystkich kolejnych rysunków (nie zmieni niczego, co już zostało narysowane), dlatego w przykładowym kodzie zawijam go savei restore, aby ograniczyć to, czego dotyczy.
Ian
nie jestem pewien, czy ctx.restore () przywróci globalAlpha, być może będziesz musiał to zrobić na końcu (przynajmniej miałem to we wcześniejszych wersjach Chrome) ctx.globalAlpha = 1;
Sean
1
@Sean - Jeśli nie masz pewności, sprawdź. Musiał to być bardzo stary Chrome, działa teraz na wszystkich platformach: jsfiddle.net/y0z9h9m7
Ian
14

Edytować: Odpowiedź oznaczona jako „poprawna” jest nieprawidłowa.

To łatwe do zrobienia. Wypróbuj ten kod, zamieniając „ie.jpg” na dowolne przydatne zdjęcie:

<!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>

Kluczem jest właściwość globalAlpha.

Testowane z IE 9, FF 5, Safari 5 i Chrome 12 na Win7.

james.garriss
źródło
13

Wpis jest stary do tej pory, pójdę z moją sugestią. Sugestia oparta jest na manipulacji pikselami w kontekście kanwy 2d. Z MDN:

Możesz bezpośrednio manipulować danymi pikseli w płótnach na poziomie bajtów

Do manipulowania pikselami użyjemy tutaj dwóch funkcji - getImageData i putImageData

Użycie funkcji getImageData:

var myImageData = context.getImageData (lewo, góra, szerokość, wysokość);

i składnia putImageData:

context.putImageData (myImageData, dx, dy); // dx, dy - x i offset na płótnie

Gdzie kontekst jest kontekstem kanwy 2d

Aby uzyskać wartości czerwony zielony niebieski niebieski i alfa, wykonamy następujące czynności:

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];

Gdzie x jest przesunięciem x, y jest przesunięciem y na płótnie

Mamy więc kod czyniący obraz półprzezroczystym

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';

Możesz stworzyć własnych „shaderów” - zobacz pełny artykuł MDN tutaj

Soul_man
źródło
7

Możesz. Przezroczyste płótno można szybko wyblaknąć, korzystając z globalnej operacji kompozytowej docelowej . Nie jest w 100% idealny, czasem pozostawia pewne ślady, ale można go ulepszyć, w zależności od potrzeb (tj. Użyj „over-source” i wypełnij go białym kolorem alfa przy 0,13, a następnie zaniknij, aby przygotować płótno).

// 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
źródło
3

Myślę, że to najlepiej odpowiada na pytanie, w rzeczywistości zmienia wartość alfa czegoś, co już zostało narysowane. Może nie było to częścią interfejsu API, kiedy zadawano to pytanie.

biorąc pod uwagę kontekst 2d 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
źródło
Czym różni się ta odpowiedź od odpowiedzi Soul_mana udzielonej bardziej szczegółowo 7 lat wcześniej?
BReddy
-2

Jeśli używasz biblioteki jCanvas , podczas rysowania możesz użyć właściwości krycia . Jeśli potrzebujesz dodatkowo efektu zanikania, po prostu przerysuj z różnymi wartościami.

cen
źródło
-11

Nie możesz To grafika w trybie natychmiastowym. Ale możesz to trochę zasymulować, rysując nad nim prostokąt w kolorze tła z nieprzezroczystością.

Jeśli obraz jest nałożony na coś innego niż stały kolor, staje się nieco trudniejszy. W takim przypadku powinieneś być w stanie użyć metod manipulacji pikselami. Po prostu zapisz obszar przed narysowaniem obrazu, a następnie zmiksuj go ponownie z kryciem.

MPG
źródło
5
To nie jest właściwa odpowiedź, patrz poniżej
Ryan Badour
Masz rację, chociaż nie możesz zmienić krycia jednego z elementów narysowanych na kanwie, możesz zmienić krycie całego płótna. W niektórych przypadkach może to być wystarczające.
MPG
2
MPG - Twój komentarz (11 maja) jest również błędny. Możesz zmienić krycie płótna, ale nie tego chciał OP, ani tego, co sugerują powyższe odpowiedzi.
Ian