不可分隔的混合模式
如您在SkiaSharp可分隔混合模式一文中所見,可分隔混合模式會分別在紅色、綠色和藍色通道上執行作業。 不可分隔的混合模式不會。 藉由根據色彩的 Hue、飽和度和亮度層級運作,不可分隔的混合模式可以透過有趣的方式改變色彩:
Hue-Saturation-Luminosity 模型
若要瞭解不可分隔的混合模式,必須將目的地和來源圖元視為 Hue-Saturation-Luminosity 模型中的色彩。 (亮度也稱為光性。
HSL 色彩模型已在與整合Xamarin.Forms一文中討論,以及該文章中的範例程式允許使用 HSL 色彩進行實驗。 您可以使用 Hue、飽和度和 Luminosity 值搭配靜態SKColor.FromHsl
方法來建立SKColor
值。
Hue 代表色彩的主要濃度。 Hue 值的範圍從 0 到 360,並迴圈到加法和減法初選:紅色是 0,黃色是 60,綠色是 120,青色是 180,藍色為 240,洋紅是 300,迴圈回到紅色在 360。
如果沒有佔主導地位的色彩,例如,色彩是白色或黑色或灰色陰影,則 Hue 是未定義且通常設定為 0。
飽和度值的範圍可以從 0 到 100,並表示色彩的純潔度。 飽和度值為 100 是純色,而低於 100 的值會導致色彩變灰。 飽和度值為 0 會導致灰色的陰影。
Luminosity (或 Lightness) 值表示色彩的亮度。 不論其他設定為何,0 的亮度值為黑色。 同樣地,100 的亮度值為白色。
HSL 值 (0, 100, 50) 是 RGB 值 (FF, 00, 00), 這是純紅色。 HSL 值 (180, 100, 50) 是 RGB 值 (00, FF, FF, FF), 純青色。 隨著飽和度降低,主要色彩元件會減少,並增加其他元件。 在飽和度層級為 0 時,所有元件都相同,且色彩為灰色陰影。 減少發光度以移至黑色;增加亮度去白色。
混合模式詳細
與其他混合模式一樣,四種不可分隔的混合模式涉及目的地(通常是位圖影像)和來源,這通常是單一色彩或漸層。 混合模式結合了目的地和來源的 Hue、飽和度和亮度值:
混合模式 | 來源的元件 | 來自目的地的元件 |
---|---|---|
Hue |
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、飽和度和亮度。 頁面底部的兩 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、飽和度和 Luminosity 值。 這是因為 FromHsl
方法會將 HSL 色彩轉換成 RGB 色彩,而 RGB 色彩會儲存在 SKColor
結構內部。 方法 ToHsl
會從 RGB 轉換成 HSL,但結果不一定是原始值。
例如, FromHsl
將 HSL 值 (180, 50, 0) 轉換為 RGB 色彩 (0, 0, 0, 0),因為 Luminosity
是零。 方法 ToHsl
會將 RGB 色彩 (0, 0, 0, 0) 轉換為 HSL 色彩 (0, 0, 0, 0),因為 Hue 和飽和度值無關。 使用此程式時,最好是看到程式所使用的 HSL 色彩表示,而不是您使用滑桿指定的色彩。
SKBlendModes.Hue
混合模式會使用來源的 Hue 層級,同時保留目的地的飽和度和亮度層級。 當您測試此混合模式時,飽和度和亮度滑桿必須設定為 0 或 100 以外的專案,因為在這些情況下,Hue 並非唯一定義。
當您使用 將滑桿設定為0時(如同左側的iOS螢幕快照),一切都會變成紅色。 但這並不表示影像完全不存在綠色和藍色。 很明顯,結果中仍有灰色陰影。 例如,RGB 色彩 (40, 40, C0) 相當於 HSL 色彩 (240, 50, 50)。 Hue 為藍色,但 50 的飽和度值也表示也有紅色和綠色元件。 如果 Hue 設定為 0,HSL SKBlendModes.Hue
色彩為 (0, 50, 50, 50),這是 RGB 色彩 (C0, 40, 40)。 仍有藍色和綠色元件,但現在佔主導地位的元件是紅色。
SKBlendModes.Saturation
混合模式結合了來源的飽和度層級與目的地的 Hue 和亮度。 和 Hue 一樣,如果亮度為 0 或 100,則不會定義飽和度。 理論上,這兩個極端之間的任何亮度設定都應該奏效。 不過,Luminosity 設定似乎比結果更會影響結果。 將亮度設定為 50,您可以看到如何設定圖片的飽和度層級:
您可以使用此混合模式來增加沉悶影像的色彩飽和度,或將飽和度減少到零(如左側的 iOS 螢幕快照),以產生只由灰色陰影組成的影像。
SKBlendModes.Color
混合模式會保留目的地的亮度,但會使用來源的 Hue 和飽和度。 同樣地,這表示極端之間的任何 Luminosity 滑桿設定都應該正常運作。
您很快就會看到此混合模式的應用程式。
最後, SKBlendModes.Luminosity
混合模式與相反 SKBlendModes.Color
。 它會保留目的地的 Hue 和飽和度,但會使用來源的亮度。 Luminosity
混合模式是最神秘的批次:色調和飽和度滑桿會影響影像,但即使在中等亮度,影像也不明顯:
理論上,增加或減少影像的亮度應該使它變淺或更暗。 此 Luminosity 屬性範例 或此 SKBlendMode Enum 定義 可能感興趣。
通常不是您想要使用其中一個不可分隔的混合模式,以及套用至整個目的地影像的單一色彩的來源。 效果太好了。 您想要將效果限制為影像的一部分。 在此情況下,來源可能會納入交易,或來源可能會限製為較小的圖形。
可分隔模式的啞光
以下是範例中作為資源的其中一個位圖。 檔案名為 Banana.jpg:
可以建立一個啞光,只包含香蕉。 這也是範例中的資源。 檔案名為 BananaMatte.png:
除了黑色香蕉形狀之外,位陣圖的其餘部分是透明的。
藍色香蕉頁面會使用該啞光來改變猴子持有的香蕉色調和飽和度,但要改變影像中沒有其他內容。
在下列 BlueBananaPage
類別中 ,Banana.jpg 位圖會載入為欄位。 建構函式會將 BananaMatte.png 位圖載入為 matteBitmap
物件,但不會將該物件保留在建構函式之外。 相反地,會建立名為 blueBananaBitmap
的第三個位圖。 在 matteBitmap
上 blueBananaBitmap
繪製 ,後面接著 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 和飽和度都會由純藍色取代,其對應到色調值為 240,飽和度值為 100。 然而,亮度仍然相同,這意味著香蕉繼續有一個現實的紋理,儘管它的新顏色:
請嘗試將混合模式變更為 SKBlendMode.Saturation
。 香蕉仍然黃色,但它是一個更強烈的黃色。 在現實生活中的應用程式中,這可能比將香蕉變成藍色更理想的效果。