Sdílet prostřednictvím


Neparovatelné režimy prolnutí

Jak jste viděli v článku SkiaSharp separable blend mode, separable blend mode provádí operace s červenými, zelenými a modrými kanály samostatně. Neparovatelné režimy blendu se nedají oddělit. Díky tomu, že pracujete na úrovních barev Hue, Sytost a Luminosity, můžou režimy nesouvisející směsi měnit barvy zajímavými způsoby:

Neseparovatelný vzorek

Model Hue-Saturation-Luminosity

Abyste porozuměli neparovatelným režimům blendu, je nutné s cílem a zdrojovými pixely zacházet jako s barvami v modelu Hue-Saturation-Luminosity. (Luminosity se také označuje jako Světlost.)

Barevný model HSL byl popsán v článku Integrace s Xamarin.Formsukázkovým programem v tomto článku umožňuje experimentovat s barvami HSL. Pomocí statických SKColor SKColor.FromHsl metod můžete vytvořit hodnotu pomocí hodnot Hue, Saturation a Luminosity.

Hue představuje dominantní vlnovou délku barvy. Hodnoty hue se pohybují od 0 do 360 a cyklicky procházejí přídatnou a subtraktivní primarie: Červená je hodnota 0, žlutá je 60, zelená je 120, azurová je 180, modrá je 240, purpurová je 300 a cyklus se vrátí zpět na červenou na 360.

Pokud neexistuje žádná dominantní barva , například barva je bílá nebo černá nebo šedá, je odstín nedefinovaný a obvykle je nastaven na hodnotu 0.

Hodnoty sytosti mohou být v rozsahu od 0 do 100 a označují čistotu barvy. Hodnota sytosti 100 je nejčistší barva, zatímco hodnoty nižší než 100 způsobují, že barva bude šedá. Hodnota sytosti 0 má za následek odstín šedé.

Hodnota Luminosity (nebo Světelnost) označuje, jak jasně barva je. Hodnota Luminosity 0 je černá bez ohledu na ostatní nastavení. Podobně je hodnota Luminosity 100 bílá.

Hodnota HSL (0, 100, 50) je hodnota RGB (FF, 00, 00), což je čistě červená. Hodnota HSL (180, 100, 50) je hodnota RGB (00, FF, FF), čistá azurová. S poklesem sytosti se zmenší dominantní barevná komponenta a ostatní komponenty se zvětší. Na úrovni sytosti 0 jsou všechny komponenty stejné a barva je šedý odstín. Snížit Luminosity jít na černou; zvýšit Luminosity jít na bílou.

Režimy prolnutí podrobně

Stejně jako ostatní režimy blendu zahrnují čtyři neparovatelné režimy blendu cíl (což je často rastrový obrázek) a zdroj, což je často jedna barva nebo přechod. Režimy blendu kombinují hodnoty Hue, Saturation a Luminosity z cíle a zdroje:

Režim blendu Komponenty ze zdroje Komponenty z cíle
Hue Odstín Sytost a světelnost
Saturation Sytost Hue a Luminosity
Color Hue a sytost Světelnost
Luminosity Světelnost Hue a sytost

Podívejte se na specifikaci W3C pro kompilaci a prolnutí úrovně 1 pro algoritmy.

Stránka Režimy neparable Blend obsahuje Picker možnost výběru jednoho z těchto režimů blendu a tří Slider zobrazení pro výběr barvy HSL:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
             xmlns:skiaviews="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.NonSeparableBlendModesPage"
             Title="Non-Separable Blend Modes">

    <StackLayout>
        <skiaviews:SKCanvasView x:Name="canvasView"
                                VerticalOptions="FillAndExpand"
                                PaintSurface="OnCanvasViewPaintSurface" />

        <Picker x:Name="blendModePicker"
                Title="Blend Mode"
                Margin="10, 0"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKBlendMode}">
                    <x:Static Member="skia:SKBlendMode.Hue" />
                    <x:Static Member="skia:SKBlendMode.Saturation" />
                    <x:Static Member="skia:SKBlendMode.Color" />
                    <x:Static Member="skia:SKBlendMode.Luminosity" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Slider x:Name="hueSlider"
                Maximum="360"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Slider x:Name="satSlider"
                Maximum="100"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Slider x:Name="lumSlider"
                Maximum="100"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <StackLayout Orientation="Horizontal">
            <Label x:Name="hslLabel"
                   HorizontalOptions="CenterAndExpand" />

            <Label x:Name="rgbLabel"
                   HorizontalOptions="CenterAndExpand" />

        </StackLayout>
    </StackLayout>
</ContentPage>

Pro úsporu místa nejsou tři Slider zobrazení identifikována v uživatelském rozhraní programu. Musíte si uvědomit, že pořadí je Hue, Saturation a Luminosity. Dvě Label zobrazení v dolní části stránky zobrazují hodnoty barev HSL a RGB.

Soubor s kódem načte jeden z rastrových prostředků, zobrazí, že co nejvíce na plátně a pak pokryje plátno obdélníkem. Barva obdélníku je založena na třech Slider zobrazeních a režim blendu je ten, který je vybraný v :Picker

public partial class NonSeparableBlendModesPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(NonSeparableBlendModesPage),
                        "SkiaSharpFormsDemos.Media.Banana.jpg");
    SKColor color;

    public NonSeparableBlendModesPage()
    {
        InitializeComponent();
    }

    void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs e)
    {
        // Calculate new color based on sliders
        color = SKColor.FromHsl((float)hueSlider.Value,
                                (float)satSlider.Value,
                                (float)lumSlider.Value);

        // Use labels to display HSL and RGB color values
        color.ToHsl(out float hue, out float sat, out float lum);

        hslLabel.Text = String.Format("HSL = {0:F0} {1:F0} {2:F0}",
                                      hue, sat, lum);

        rgbLabel.Text = String.Format("RGB = {0:X2} {1:X2} {2:X2}",
                                      color.Red, color.Green, color.Blue);

        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();
        canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform);

        // Get blend mode from Picker
        SKBlendMode blendMode =
            (SKBlendMode)(blendModePicker.SelectedIndex == -1 ?
                                        0 : blendModePicker.SelectedItem);

        using (SKPaint paint = new SKPaint())
        {
            paint.Color = color;
            paint.BlendMode = blendMode;
            canvas.DrawRect(info.Rect, paint);
        }
    }
}

Všimněte si, že program nezobrazuje hodnotu barvy HSL vybranou třemi posuvníky. Místo toho vytvoří z těchto posuvníků hodnotu barvy a pak použije metodu ToHsl k získání hodnot Hue, Saturation a Luminosity. Důvodem je to, že FromHsl metoda převede barvu HSL na barvu RGB, která je uložena interně ve struktuře SKColor . Metoda ToHsl převede z RGB na HSL, ale výsledek nebude vždy původní hodnotou.

Například FromHsl převede hodnotu HSL (180, 50, 0) na barvu RGB (0, 0, 0), protože Luminosity je nula. Metoda ToHsl převede barvu RGB (0, 0, 0) na barvu HSL (0, 0, 0), protože hodnoty Hue a Sytost jsou irelevantní. Při použití tohoto programu je lepší zobrazit reprezentaci barvy HSL, kterou program používá, a nikoli barvu, kterou jste zadali pomocí posuvníků.

Režim SKBlendModes.Hue blendu používá úroveň odstínu zdroje a přitom zachovává úroveň sytosti a světelnosti cíle. Při testování tohoto režimu blendu musí být posuvníky sytosti a světelnosti nastaveny na jinou hodnotu než 0 nebo 100, protože v těchto případech není hue jednoznačně definován.

Neparovatelné režimy blendu – Hue

Když použijete posuvník na 0 (stejně jako na snímku obrazovky iOS vlevo), všechno se změní na červenou. To ale neznamená, že obrázek zcela chybí zeleně a modře. Je zřejmé, že ve výsledku jsou stále šedé odstíny. Například barva RGB (40, 40, C0) je ekvivalentní barvě HSL (240, 50, 50). Odstín je modrý, ale sytost hodnota 50 označuje, že existují i červené a zelené komponenty. Pokud je odstín nastaven na hodnotu 0 s SKBlendModes.Hue, barva HSL je (0, 50, 50), což je barva RGB (C0, 40, 40). Stále jsou modré a zelené komponenty, ale nyní je dominantní komponenta červená.

Režim SKBlendModes.Saturation blendu kombinuje úroveň sytosti zdroje s hue a Luminosity cíle. Stejně jako hue není sytost dobře definovaná, pokud je Luminosity 0 nebo 100. Teoreticky by mělo fungovat jakékoli nastavení Luminosity mezi těmito dvěma extrémními hodnotami. Zdá se však, že nastavení Luminosity má vliv na výsledek více, než by mělo. Nastavte světelnost na 50 a uvidíte, jak můžete nastavit úroveň sytosti obrázku:

Neseparovatelné režimy blendu – sytost

Tento režim blendu můžete použít ke zvýšení sytosti barev nudného obrázku nebo můžete snížit sytost dolů na nulu (jako na snímku obrazovky iOS vlevo) pro výsledný obrázek složený z pouze šedých odstínů.

Režim SKBlendModes.Color blendu zachovává světelnost cíle, ale používá hue a sytost zdroje. Opět to znamená, že jakékoli nastavení posuvníku Luminosity někde mezi extrémními hodnotami by mělo fungovat.

Neseparovatelné režimy blendu – barva

Krátce uvidíte aplikaci tohoto režimu blendu.

A konečně, režim mixu SKBlendModes.Luminosity je opakem SKBlendModes.Color. Zachová odstín a sytost cíle, ale používá Luminosity zdroje. Režim Luminosity mixu je nejtajnější ze dávky: Posuvníky Hue a Sytost ovlivňují obrázek, ale i ve střední Luminosity není obrázek odlišný:

Neparable Blend Modes - Luminosity

Teorii, zvýšení nebo snížení Luminosity obrázku by mělo být světlejší nebo tmavší. Tento příklad vlastnosti Luminosity nebo tato definice výčtu SKBlendMode může být zajímat.

Obecně se nejedná o případ, že byste chtěli použít jeden z neparovatelných režimů blendu se zdrojem, který se skládá z jedné barvy použité na celý cílový obrázek. Účinek je prostě příliš velký. Efekt budete chtít omezit na jednu část obrázku. V takovém případě bude zdroj pravděpodobně zahrnovat transparancy, nebo možná zdroj bude omezen na menší grafiku.

Matný režim pro oddělitelný režim

Tady je jeden z rastrových obrázků, které jsou součástí ukázky. Název souboru je Banana.jpg:

Banánová opice

Je možné vytvořit matný, který zahrnuje jen banán. Toto je také prostředek v ukázce. Název souboru je BananaMatte.png:

Banánová matná

Kromě černého banánového tvaru je zbytek rastrového obrázku průhledný.

Stránka Modrý banán používá tuto matnou k úpravě odstínu a sytosti banánu, který opice drží, ale změnit nic jiného na obrázku.

V následující BlueBananaPage třídě se Banana.jpg bitmapa načte jako pole. Konstruktor načte BananaMatte.png bitmapu matteBitmap jako objekt, ale tento objekt se nezachovává za konstruktorem. Místo toho se vytvoří třetí rastrový obrázek s názvem blueBananaBitmap . Nakreslený matteBitmap na SKPaint blueBananaBitmap nákresu následuje s Color jeho nastavením na modrou a jeho BlendMode nastavenou na SKBlendMode.SrcIn. Zůstávají blueBananaBitmap převážně průhledné, ale s pevným čistým modrým obrazem banánu:

public class BlueBananaPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
        typeof(BlueBananaPage),
        "SkiaSharpFormsDemos.Media.Banana.jpg");

    SKBitmap blueBananaBitmap;

    public BlueBananaPage()
    {
        Title = "Blue Banana";

        // Load banana matte bitmap (black on transparent)
        SKBitmap matteBitmap = BitmapExtensions.LoadBitmapResource(
            typeof(BlueBananaPage),
            "SkiaSharpFormsDemos.Media.BananaMatte.png");

        // Create a bitmap with a solid blue banana and transparent otherwise
        blueBananaBitmap = new SKBitmap(matteBitmap.Width, matteBitmap.Height);

        using (SKCanvas canvas = new SKCanvas(blueBananaBitmap))
        {
            canvas.Clear();
            canvas.DrawBitmap(matteBitmap, new SKPoint(0, 0));

            using (SKPaint paint = new SKPaint())
            {
                paint.Color = SKColors.Blue;
                paint.BlendMode = SKBlendMode.SrcIn;
                canvas.DrawPaint(paint);
            }
        }

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform);

        using (SKPaint paint = new SKPaint())
        {
            paint.BlendMode = SKBlendMode.Color;
            canvas.DrawBitmap(blueBananaBitmap,
                              info.Rect,
                              BitmapStretch.Uniform,
                              paint: paint);
        }
    }
}

Obslužná rutina PaintSurface nakreslí rastrový obrázek s opicí držící banán. Za tímto kódem následuje zobrazení znaku blueBananaBitmap SKBlendMode.Color. Na povrchu banánu se odstín a sytost každého pixelu nahradí plnou modrou barvou, která odpovídá hodnotě odstínu 240 a sytosti 100. Luminosity ale zůstává stejná, což znamená, že banán má i nadále realistickou texturu navzdory své nové barvě:

Modrý banán

Zkuste změnit režim blendu na SKBlendMode.Saturation. Banán zůstává žlutý, ale je to silnější žlutá. V reálném životě to může být žádoucí účinek než otáčení banán modré.