I have an image in my UWP c# project, that is a transparent png with white foreground. I now want to change the white color from this png image into another color (like blueish).
Example (note that the colored image does not have a transparent background. This is due bad image processing software I'm using and to demonstrate the change of the white color. The Background should be transparent in the end result).
I remember, that this was possible in unity, now I want to do this now in an uwp-app. I thought about using the Lumia ImagingSDK or maybe the Composition API, but do not know, hot to do it with either those.
A way you could do this is using the Composition effect system.
Prerequisites
Additionally you can look to a gist I wrote here, which is a quick way to get up and running using the Composition API within a XAML app. It demos using an effect as well. Not only that, but it also covers loading an image using the Composition API (with a package I wrote).
Gettings Started
You'll want to do something very similar to the gist, but instead of defining an InvertEffect
, you'll want to define both a CompositeEffect
and a ColorSourceEffect
. What this will do is take an image and use it as a "mask", and then replaces the white in the image with a color. You would define the effect like this:
IGraphicsEffect graphicsEffect = new CompositeEffect
{
Mode = Microsoft.Graphics.Canvas.CanvasComposite.DestinationIn,
Sources =
{
new ColorSourceEffect
{
Name = "colorSource",
Color = Color.FromArgb(255, 255, 255, 255)
},
new CompositionEffectSourceParameter("mask")
}
};
The next step is to create an effect factory:
var effectFactory = compositor.CreateEffectFactory(graphicsEffect, new string[] { "colorSource.Color" });
The second parameter, while not required, is probably what you want in this case. Setting this parameter allows you to change the property after the effect has been compiled, which allows you to set it manually and every new effect brush you create or to animate that property on an effect brush. We'll just be setting it manually. Use your new effect factory to create a new effect brush. Note that this factory can create many new effect brushes with the definition you used above:
var effectBrush = effectFactory.CreateBrush();
However, first you'll need to apply your image as the mask. You can load your image into a surface using a library I wrote called CompositionImageLoader. You can also download it on nuget. After creating a surface with your image, create a CompositionSurfaceBrush
and apply it to an effect.
var imageLoader = ImageLoaderFactory.CreateImageLoader(compositor);
var surface = imageLoader.LoadImageFromUri(new Uri("ms-appx:///Assets/Images/HAvng.png"));
var brush = compositor.CreateSurfaceBrush(surface);
effectBrush.SetSourceParameter("mask", brush);
Note that you should probably keep your ImageLoader somewhere, as creating one over and over again will be expensive. All that's left to do is apply the effect brush to a visual and set the color:
visual.Brush = effectBrush;
effectBrush.Properties.InsertColor("colorSource.Color", Colors.Red);
And then you're done! Note that if you want to change the color after this, all you have to do is call the same InsertColor
method as above with a new color.
Final Product
In my test code, the method looked like this:
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var visual = compositor.CreateSpriteVisual();
visual.Size = new Vector2(83, 86);
visual.Offset = new Vector3(50, 50, 0);
_imageLoader = ImageLoaderFactory.CreateImageLoader(compositor);
var surface = _imageLoader.LoadImageFromUri(new Uri("ms-appx:///Assets/Images/HAvng.png"));
var brush = compositor.CreateSurfaceBrush(surface);
IGraphicsEffect graphicsEffect = new CompositeEffect
{
Mode = Microsoft.Graphics.Canvas.CanvasComposite.DestinationIn,
Sources =
{
new ColorSourceEffect
{
Name = "colorSource",
Color = Color.FromArgb(255, 255, 255, 255)
},
new CompositionEffectSourceParameter("mask")
}
};
_effectFactory = compositor.CreateEffectFactory(graphicsEffect, new string[] { "colorSource.Color" });
var effectBrush = _effectFactory.CreateBrush();
effectBrush.SetSourceParameter("mask", brush);
visual.Brush = effectBrush;
effectBrush.Properties.InsertColor("colorSource.Color", Colors.Red);
ElementCompositionPreview.SetElementChildVisual(this, visual);
Note that in this example the visual was attached to this
, which was my MainPage. You can attach it to any XAML element. If you'd like to see an example of a custom control that you can define in your XAML markup that creates and then resizes your visual as you resize the control, you can find that here.
To see more Composition related stuff, come on over to our GitHub page! We'll be happy to help you out with any questions you might have about the API.