Поделиться через


Неразделимые режимы смешения

Как вы видели в статье SkiaSharp сепарируемые режимы смешения, режимы сепарируемых смешения выполняют операции с красными, зелеными и голубыми каналами отдельно. Неразделимые режимы смешивания не выполняются. Работая на уровнях цвета hue, Saturation и Luminosity, режимы неразделимого смешения могут изменять цвета интересными способами:

Неразрывный пример

Модель Hue-Saturation-Luminosity

Чтобы понять неразделимые режимы смешения, необходимо обрабатывать конечные и исходные пиксели как цвета в модели Hue-Saturation-Luminosity. (Luminosity также называется Lightness.)

Цветовая модель HSL обсуждалась в статье Интеграция сXamarin.Formsи пример программы в этой статье позволяет экспериментировать с цветами HSL. Можно создать значение с помощью значений SKColor Hue, Saturation и Luminosity с помощью статического SKColor.FromHsl метода.

Hue представляет доминирующую длину волны цвета. Значения Hue варьируются от 0 до 360 и циклически через аддитивные и субтрактивные первичные элементы: красный — 0, желтый — 60, зеленый — 120, синий — 180, синий — 240, 300, а цикл возвращается к красному в 360.

Если нет доминирующего цвета , например, цвет белый или черный или серый оттенк , то Hue не определен и обычно имеет значение 0.

Значения насыщенности могут варьироваться от 0 до 100 и указывать чистоту цвета. Значение насыщенности 100 является самым чистым цветом, а значения ниже 100 приводят к тому, что цвет становится более серым. Значение насыщенности 0 приводит к оттенку серого.

Значение Luminosity (или Lightness) указывает, насколько яркий цвет. Значение Luminosity 0 черное независимо от других параметров. Аналогичным образом значение Luminosity 100 является белым.

Значение HSL (0, 100, 50) — это значение RGB (FF, 00, 00), которое является чистым красным. Значение HSL (180, 100, 50) — это rgb-значение (00, FF, FF), чистое синя. По мере уменьшения насыщенности основной цветной компонент уменьшается, а другие компоненты увеличиваются. На уровне насыщенности 0 все компоненты одинаковы, и цвет является серым оттенком. Уменьшите светимость, чтобы перейти к черному; увеличьте Luminosity, чтобы перейти к белому.

Режимы смешения подробно

Как и в других режимах смешения, четыре неразделимых режима смешения включают назначение (это часто растровое изображение) и источник, который часто является одним цветом или градиентом. Режимы смешивания объединяют значения Hue, Saturation и Luminosity из назначения и источника:

Режим смешивания Компоненты из источника Компоненты из назначения
Hue Оттенок Насыщенность и светимость
Saturation Насыщенность Hue и Luminosity
Color Оттенки и насыщенность Яркость
Luminosity Яркость Оттенки и насыщенность

См. спецификацию W3C Compositing и Blending Level 1 для алгоритмов.

Страница режимов Picker неразрывной смешивания содержит один из этих режимов смешения и три Slider представления, чтобы выбрать цвет 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>

Чтобы сэкономить место, три Slider представления не определены в пользовательском интерфейсе программы. Вам нужно помнить, что порядок — Hue, Saturation и Luminosity. Два Label представления в нижней части страницы показывают значения цветов HSL и RGB.

Файл кода загрузит один из ресурсов растрового изображения, отображает, что максимально большой размер на холсте, а затем охватывает холст прямоугольником. Цвет прямоугольника основан на трех Slider представлениях, а режим смешивания — один из следующих вариантов: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);
        }
    }
}

Обратите внимание, что программа не отображает значение цвета HSL, выбранное тремя ползунками. Вместо этого он создает значение цвета из этих ползунков, а затем использует ToHsl метод для получения значений Hue, Saturation и Luminosity. Это связано с тем, что FromHsl метод преобразует цвет HSL в цвет RGB, который хранится внутри SKColor структуры. Метод ToHsl преобразуется из RGB в HSL, но результат не всегда будет исходным значением.

Например, FromHsl преобразует значение HSL (180, 50, 0) в цвет RGB (0, 0, 0), так как Luminosity значение равно нулю. Метод ToHsl преобразует цвет RGB (0, 0, 0, 0) в цвет HSL (0, 0, 0), так как значения оттенка и насыщенности не имеют значения. При использовании этой программы лучше увидеть представление цвета HSL, используемого программой, а не указанного с ползунками.

В режиме SKBlendModes.Hue смешивания используется уровень Hue источника при сохранении уровней насыщенности и luminosity назначения. При тестировании этого режима смешивания необходимо задать ползунки насыщенности и светимости, отличные от 0 или 100, так как в этих случаях Hue не определяется уникальным образом.

Неразрывные режимы смешивания — Hue

При использовании ползунка значение 0 (как и с снимок экрана iOS слева), все становится красным. Но это не означает, что изображение полностью отсутствует зеленого и синего. Очевидно, что в результате по-прежнему присутствуют серые оттенки. Например, цвет RGB (40, 40, C0) эквивалентен цвету HSL (240, 50, 50). Hue синий, но значение насыщенности 50 указывает, что также есть красные и зеленые компоненты. Если для hue задано значение 0, то цвет HSL имеет значение (0 SKBlendModes.Hue, 50, 50), который является цветом RGB (C0, 40, 40). Есть все еще синий и зеленый компоненты, но теперь доминирующий компонент красный.

Режим SKBlendModes.Saturation смешивания объединяет уровень насыщенности источника с Hue и Luminosity назначения. Как и Hue, насыщенность не определена, если Luminosity равно 0 или 100. В теории, любой параметр Luminosity между этими двумя крайностями должен работать. Тем не менее, параметр Luminosity, кажется, влияет на результат больше, чем он должен. Задайте значение 50 светимости, и вы увидите, как задать уровень насыщенности рисунка:

Неразрывные режимы смешения — насыщенность

Этот режим смешения можно использовать для увеличения насыщенности цвета скучного изображения или уменьшения насыщенности до нуля (как на снимке экрана iOS слева) для результирующих изображений, состоящих только из серых оттенков.

Режим SKBlendModes.Color смешивания сохраняет Luminosity назначения, но использует Hue и Saturation источника. Опять же, это означает, что любой параметр ползунка Luminosity где-то между крайностями должен работать.

Неразделимые режимы смешения — цвет

Вскоре вы увидите приложение этого режима смешивания.

Наконец, SKBlendModes.Luminosity режим смешивания является противоположностью SKBlendModes.Color. Он сохраняет хью и насыщенность назначения, но использует Luminosity источника. Режим Luminosity смешивания является самым таинственным из пакета: ползунки Hue и Saturation влияют на изображение, но даже на средний Luminosity, изображение не отличается:

Неразрывные режимы смешивания — Luminosity

В теории увеличение или уменьшение светимости изображения должно сделать его светлее или темнее. Этот пример свойства Luminosity или этот S КБ lendMode Enum может быть интересен.

Обычно это не так, что вы хотите использовать один из неразделимых режимов смешения с источником, состоящим из одного цвета, примененного ко всему целевому изображению. Эффект слишком велик. Вы хотите ограничить эффект одной частью изображения. В этом случае источник, вероятно, будет включать транспараранность, или, возможно, источник будет ограничен меньшим графическим элементом.

Матовый для разрежимаемого режима

Ниже приведен один из растровых изображений, включенных в пример в качестве ресурса. Имя файла Banana.jpg:

Банановая обезьяна

Можно создать матовое, которое охватывает только банан. Это также ресурс в примере. Имя файла BananaMatte.png:

Банан Мате

Помимо черной фигуры банана, остальная часть растрового изображения является прозрачной.

Синяя банановая страница использует этот мат для изменения Hue и насыщенности банана , что обезьяна держит, но изменить ничего другого в изображении.

В следующем BlueBananaPage классе Banana.jpg растровое изображение загружается в виде поля. Конструктор загружает растровое изображение BananaMatte.png как matteBitmap объект, но он не сохраняет этот объект за пределами конструктора. Вместо этого создается третье растровое изображение blueBananaBitmap . Нарисуется blueBananaBitmapmatteBitmap наследуемом SKPaint с Color его набором синего цвета и его BlendMode наборомSKBlendMode.SrcIn. Остается blueBananaBitmap в основном прозрачным, но с твердым синим изображением банана:

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

Обработчик PaintSurface рисует растровое изображение с обезьяной, удерживая банан. За этим кодом следует отображение blueBananaBitmap с помощью SKBlendMode.Color. На поверхности банана каждый пиксель Hue и Saturation заменен твердым синим цветом, который соответствует значению оттенка 240 и насыщенности 100. Тем не менее, Luminosity остается тем же, что означает, что банан продолжает иметь реалистичную текстуру, несмотря на его новый цвет:

Синий банан

Попробуйте изменить режим SKBlendMode.Saturationсмешивания на . Банан остается желтым, но это более интенсивный желтый. В реальном приложении это может быть более желательным эффектом, чем превратить банан синие.