我有一个.png资源,其中包括需要按下表所述进行“着色”的区域(这些是我自己的定义,如果有更好的用语,我可以随时使用它来教育我)。我需要基于ColorBrush(例如BGRA =#6572D8FF)对图像进行“着色”,以便...
// Input Output
// Transparent BGRA=#FFFFFF00 --> #FFFFFF00
// AlphaOnly BGRA=#00000000 --> #6572D800 // Colored area
// Alpha-Shaded BGRA=#000000aa --> #6572D8aa // Colored area
// Solid colors BGRA=#bbggrrFF --> #rrggbbFF
需要使用以下XAML显示生成的图像...
<Viewbox Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
<Grid Height="100" Width="100">
<Image x:Name="currentImage" />
</Grid>
</Viewbox>
我希望将控件放置在红色背景上并指定蓝色ColorBrush,希望获得底部图像(我是通过在原始图像后面简单地放置一个蓝色椭圆来创建的)
不幸的是我得到了最高的形象。我的透明度丢失了,我希望达到的Alpha底纹是错误的。任何帮助(包括您的“白痴”,您都应该这样)将不胜感激。
public sealed class MyImage : Control {
public MyImage() {
this.DefaultStyleKey = typeof(MyImage);
Loaded += MyImage_Loaded;
}
private async void MyImage_Loaded(object sender, RoutedEventArgs e) {
((Image)this.GetTemplateChild("currentImage")).Source = await ColorImage();
}
private async Task<WriteableBitmap> ColorImage() {
// Get the image as a byte array
StorageFile fileImage = await StorageFile.GetFileFromApplicationUriAsync(new Uri(BaseImageUri, UriKind.Absolute));
ImageProperties propsImage = await fileImage.Properties.GetImagePropertiesAsync();
int height = (int)propsImage.Height;
int width = (int)propsImage.Width;
byte[] baseImagePixels = await ReadPixels(fileImage);
// Modify the mask by adding the accent color
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
byte B = baseImagePixels[4 * (y * height + x) + 0];
byte G = baseImagePixels[4 * (y * height + x) + 1];
byte R = baseImagePixels[4 * (y * height + x) + 2];
byte A = baseImagePixels[4 * (y * height + x) + 3];
if (R == 0x00 && G == 0x00 && B == 0x00 && A != 0xFF) {
baseImagePixels[4 * (y * height + x) + 0] = ColorBrush.Color.B;
baseImagePixels[4 * (y * height + x) + 1] = ColorBrush.Color.G;
baseImagePixels[4 * (y * height + x) + 2] = ColorBrush.Color.R;
}
}
}
WriteableBitmap coloredImage = new WriteableBitmap((int)propsImage.Width, (int)propsImage.Height);
using (Stream stream = coloredImage.PixelBuffer.AsStream()) {
await stream.WriteAsync(baseImagePixels, 0, baseImagePixels.Length);
}
return coloredImage;
}
private async Task<byte[]> ReadPixels(StorageFile file) {
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(await file.OpenAsync(FileAccessMode.Read));
BitmapTransform transform = new BitmapTransform();
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
new BitmapTransform(),
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage);
return pixelData.DetachPixelData();
}
public String BaseImageUri {
get { return (String)GetValue(BaseImageUriProperty); }
set {
if (value.StartsWith("ms-appx:///")) {
SetValue(BaseImageUriProperty, value);
} else {
SetValue(BaseImageUriProperty, "ms-appx:///" + value);
}
}
}
public static readonly DependencyProperty BaseImageUriProperty =
DependencyProperty.Register("BaseImageUri", typeof(String), typeof(MyImage), new PropertyMetadata(0));
public SolidColorBrush ColorBrush {
get { return (SolidColorBrush)GetValue(ColorBrushProperty); }
set { SetValue(ColorBrushProperty, value); }
}
public static readonly DependencyProperty ColorBrushProperty =
DependencyProperty.Register("ColorBrush", typeof(SolidColorBrush), typeof(MyImage), new PropertyMetadata(0));
}
在我看来,这似乎是一个预乘的alpha问题,但这只是一个疯狂的猜测。
一些图形库要求alpha <1.0的像素将其RGB分量存储为:
R' := R x A
G' := G x A
B' := B x A
A' := A
因此0xFFFFFF
,alpha值为零的RGB→将无效。
当其RGB值超过其alpha值时,预期将与预乘alpha像素一起馈送的混合算法会产生意外结果。
因此0x000000
,在预乘alpha情况下,始终将完全透明的像素编码为0 alpha。
看一下有关Alpha合成的Wikipedia文章:
假设像素颜色是使用直的(未预乘)RGBA元组表示的,则像素值(0.0,0.5,0.0,0.5)表示最大绿色强度为50%,不透明度为50%的像素。如果颜色是完全绿色,则其RGBA将为(0,1,0,0.5)。
但是,如果此像素使用预乘alpha,则将所有RGB值(0,1,0)乘以0.5,然后将alpha附加到末尾以产生(0,0.5,0,0.5)。在这种情况下,G通道的0.5值实际上表示100%的绿色强度(不透明度为50%)。出于这个原因,知道文件是使用预乘还是直接Alpha是正确处理或合成该文件的关键。
它还说明了各种颜色合并运算符的工作方式。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句