简体   繁体   English

使用C#将颜色合并到位图中(通用Windows应用程序)

[英]Merging a color into a bitmap using c# (universal windows application)

I have a .png resource that includes areas that need to be "colored" as described in the table below (these are my own definitions, if there are better terms that I should use feel free to educate me). 我有一个.png资源,其中包括需要按下表所述进行“着色”的区域(这些是我自己的定义,如果有更好的用语,我可以随时使用它来教育我)。 I need to "color" this image based on a ColorBrush (eg BGRA=#6572D8FF) such that ... 我需要基于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

The resultant image needs to be displayed using the following XAML ... 需要使用以下XAML显示生成的图像...

    <Viewbox Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
        <Grid Height="100" Width="100">
            <Image x:Name="currentImage" />
        </Grid>
    </Viewbox>

Placing the control onto a red background and specifying a blue ColorBrush, I was hoping to get the bottom image (which I created by simply putting a blue ellipse behind the original image) 我希望将控件放置在红色背景上并指定蓝色ColorBrush,希望获得底部图像(我通过在原始图像后面简单地放置一个蓝色椭圆来创建该图像)

在此处输入图片说明

Unfortunately I get the top image. 不幸的是我得到了最高的形象。 My transparency is lost and the alpha shading I was hoping to achieve is wrong. 我的透明度丢失了,我希望达到的Alpha阴影是错误的。 Any help (including you "idiot", you should do this like this) would be greatly appreciated. 任何帮助(包括您的“白痴”,您都应该这样)将不胜感激。

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

Well I found a solution. 好吧,我找到了解决方案。 I have no idea why it works though ... would love to be educated on that if somebody knows why. 我不知道为什么会这样……如果有人知道为什么会很乐意对此进行教育。 I added a second change to the for loops. 我在for循环中添加了第二个更改。

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixelIndex = 4 * (y * width + x);
                byte B = baseImagePixels[pixelIndex];
                byte G = baseImagePixels[pixelIndex + 1];
                byte R = baseImagePixels[pixelIndex + 2];
                byte A = baseImagePixels[pixelIndex + 3];
                if (!(B == 0xFF && G == 0xFF && R == 0xFF && A == 0x00)) {
                    baseImagePixels[pixelIndex] = colorBrush.Color.B;
                    baseImagePixels[pixelIndex + 1] = colorBrush.Color.G;
                    baseImagePixels[pixelIndex + 2] = colorBrush.Color.R;
                    baseImagePixels[pixelIndex + 3] = colorBrush.Color.A;
                } else if (B == 0xFF && G == 0xFF && R == 0xFF && A == 0x00) {
                    baseImagePixels[pixelIndex] = 0x00;
                    baseImagePixels[pixelIndex + 1] = 0x00;
                    baseImagePixels[pixelIndex + 2] = 0x00;
                    baseImagePixels[pixelIndex + 3] = 0x00;
                }
            }
        }

This looks like a premultiplied alpha issue to me, but that's just a wild guess. 在我看来,这似乎是一个预乘的alpha问题,但这只是一个疯狂的猜测。

Some graphic libraries require that pixels with alpha < 1.0 store their RGB components as: 一些图形库要求alpha <1.0的像素将其RGB分量存储为:

R' := R x A
G' := G x A
B' := B x A
A' := A

Hence RGB → 0xFFFFFF with zero alpha would be invalid. 因此,RGB→ 0xFFFFFF alpha值为零将无效。

Blending algorithms which expect to be fed with premultiplied alpha pixels produce unexpected results when their RGB values exceed their alpha . 当其RGB值超过其alpha值时,预期将与预乘alpha像素配合的混合算法会产生意外结果。

So fully transparent pixels are always encoded as 0x000000 with 0 alpha in a premultiplied alpha case. 因此,在预乘alpha情况下,始终将全透明像素始终编码为0x000000和0 alpha。

Have a look at the Wikipedia article on Alpha compositing : 看一下有关Alpha合成的Wikipedia文章:

Assuming that the pixel color is expressed using straight (non-premultiplied) RGBA tuples, a pixel value of (0.0, 0.5, 0.0, 0.5) implies a pixel that has 50% of the maximum green intensity and 50% opacity. 假设像素颜色是使用直的(未预乘)RGBA元组表示的,则像素值(0.0,0.5,0.0,0.5)表示最大绿色强度为50%,不透明度为50%的像素。 If the color were fully green, its RGBA would be (0, 1, 0, 0.5). 如果颜色是完全绿色,则其RGBA为(0,1,0,0.5)。

However, if this pixel uses premultiplied alpha, all of the RGB values (0, 1, 0) are multiplied by 0.5 and then the alpha is appended to the end to yield (0, 0.5, 0, 0.5). 但是,如果此像素使用预乘alpha,则将所有RGB值(0,1,0)乘以0.5,然后将alpha附加到末尾以产生(0,0.5,0,0.5)。 In this case, the 0.5 value for the G channel actually indicates 100% green intensity (with 50% opacity). 在这种情况下,G通道的0.5值实际上表示100%的绿色强度(不透明度为50%)。 For this reason, knowing whether a file uses premultiplied or straight alpha is essential to correctly process or composite it. 因此,知道文件是使用预乘还是直接Alpha对其正确处理或合成至关重要。

It also provides an explanation of how the various color merging operators work. 它还说明了各种颜色合并运算符的工作方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我可以使用DirectX和C#开发Windows通用应用程序吗 - Can I develop a Windows Universal Application using DirectX and C# 在通用Windows应用程序(c#)中复制对象 - Copy an object in universal Windows Application (c#) 如何使用c#在通用Windows应用程序中获取最新捕获的图像 - how to get latest captured image in universal windows application using c# C#通用Windows应用程序如何从互联网获取时间 - C# Universal Windows Application How to get time from internet 使用Windows API的C#Windows通用应用程序提供未经授权的响应 - C# Windows Universal Application consuming WebAPI gives Unauthorized response 使用手写笔绘制画布-Windows 10 Universal Application C# - Canvas drawing with stylus - Windows 10 Universal Application C# 通用Windows平台(UWP)应用程序的C#服务器/客户端应用程序 - C# Server / Client Application for Universal Windows Platform (UWP) apps C#Windows应用程序中Tabcontrol的背景色 - Background color for Tabcontrol in c# windows application 在C#Windows Form应用程序中加载位图图像 - Loading bitmap images in c# windows form application 在C#Windows应用程序中合并一行数据网格视图的单元格 - Merging cells of a row of data grid view in C# windows application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM