1

I have a png file(8indexed and transparent)in the resource,and want to change its fore color and show it in an image.I have tried this :

Image1.Source = new BitmapImage(new Uri($"pack://application:,,,/100.png", UriKind.Absolute));

it works fine without changing the color. Having Searched a lot, I combine some code all from the Internet and get the code below which looks fine,but returns strange reults.

Image

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // read image from base64
            const string base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAAHqsLF6AAAAAXNSR0IArs4c6QAAAgFQTFRFAAAA////gICAVVVVQEBAMzMzVVVVSUlJQEBAOTk5MzMzRkZGQEBAOzs7Nzc3MzMzQEBAPDw8NjY2MzMzNzc3NTU1MzMzOTk5Nzc3NTU1MzMzODg4NjY2NTU1MzMzOTk5Nzc3NjY2NDQ0MzMzODg4Nzc3NTU1NTU1Nzc3NDQ0Nzc3NjY2NTU1NDQ0MzMzNTU1MzMzNTU1NTU1NDQ0NjY2NDQ0NDQ0MzMzNjY2NTU1NDQ0NTU1NDQ0NDQ0MzMzNTU1NDQ0NTU1NDQ0NDQ0MzMzNTU1NDQ0NDQ0MzMzNDQ0MzMzMzMzNTU1NDQ0MzMzMzMzNTU1NDQ0MzMzNTU1NDQ0NTU1NDQ0MzMzNDQ0MzMzMzMzNTU1NDQ0NDQ0MzMzMzMzNTU1NDQ0NDQ0MzMzNDQ0NDQ0MzMzNDQ0NDQ0NDQ0MzMzMzMzNDQ0NDQ0NDQ0MzMzNDQ0MzMzNDQ0NDQ0MzMzMzMzNDQ0NDQ0MzMzMzMzNDQ0NDQ0MzMzMzMzNDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0MzMzMzMzNDQ0MzMzMzMzNDQ0MzMzMzMzNDQ0MzMzMzMzNDQ0MzMzMzMzMzMzNDQ0MzMzNDQ0NDQ0MzMzMzMzNDQ0NDQ0MzMzMzMzMzMzNDQ0NDQ0MzMzNDQ0NDQ0MzMzMzMzMzMzNDQ0NDQ0MzMzMzMz6OxZaQAAAKp0Uk5TAAECAwQFBgcICQoLDA0ODxARExQXGBkbHB0eICEiIyQlJicoKSorMDM2ODk6Ozw/QUNERUdJSktMTU5SU1RVVlhbXV5fYWJjZGdoaWpsbW5vcXN0dnl7fYCBgoOEhYaHiImKjI2OkJSXmJqbnJ2en6Okpqepqqutr7S1tri5ury/wMHEy8zNztDR1NbX2Nrb3t/g4ePl5+jp6uzt7u/w8fL09vf4+fr7/P1teFjdAAADCklEQVRYw+1W+z9UQRSftV6pKLJ5hLYXJSpJSkXvl95IT7WlhCh6IRU9FKt3itBzw/ev7Myd3XXv3Nm9u+mjH3J+uGfOOd9zZu6ZM3OGMT1hksE70ngT/8y3a5oUn6WBfWWWtNkYn3w9wr8PLDwy4mMoFthGyZzfOKnoLaLPaIpfLn7N4q/KYcJdhIK2yIp2vVAAeaJS9gqoYvG6RRxh7NNzeVXQJW3MuxdQI4gKsaYcxhAndukg8Q7G4og3B1zpdFN7wNw/FizHI/i6ZhnQijecJWTbRH6SFUESqT5uVPcAw+pJbsPlz2+s0bQdeMd0yWYYZRGAvN5JRSo6VVPYgHRt0ILvKnskYxnQ6CVjESbzIsChE1sQKGFtVlV8Aex/oIk6qytk7E8BlccEH9gv+KN4UzFc0ou/cFEC2L3bt2wB/9bDbS6XfYxt08rhC53Ug8p1UD2/r6knyGr1OmsxrvE8IFL9h75SWI8Blb0Up8317f8ppNK5ifHJXeCnGI264CikarT55A4ajmiHSU/HsTfgFJI6CRNKwBP0ajwWSFEnYgyozlz5EKZ98LUP1imOXqG4FyUSTarkclUasTrUyvYf6Dfu7W4J4H4h+LlMLyL3r9ekH9DDZugf0OLcqfnfBb5NsYNa1kZwopYyFJbDGkj3nC3a8NjzAGctpwQq1bY8coc70WIN9lagVRtFbb05zMN5HpQnaYo95J4c6r/E3YGB3FlhpSKqizt15wspvWGcpMH00P2ddEOhTK/JGiLNgVD951KyPs6RlPcowqagbglOpzNTaw1XCJsjmyMGgT7xpiGgw+z/TCSrgobdwIgZcAvaeyrbm9Uk2T7rsMvlqtkgmiCw0BSgD3jL+fJTBDyZFjSHfAdkZRUpD4WaxTICDxhaiJ33habQ93HJKN/4Hb7n26qn/K93hlVKaz8bK3GiImTXouGfYq6C+x6vd0+5tr0rPoyfsXQv5k4dattRHqw2uH8JQfodAU8qP+zXgkeIXhppfKlK3Sxj3jTfiW1TDTD7/PUsNkMW9Buw7SzXVIvh8wAAAABJRU5ErkJggg==";
            string imagebase64 = base64.Substring(base64.IndexOf(",") + 1);
            byte[] streamBase = Convert.FromBase64String(imagebase64);
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = new MemoryStream(streamBase);
            bitmapImage.EndInit();

            // change it to Bitmap
            Bitmap bmp = ImageSourceToBitmap(bitmapImage);

            // change color
            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    if (bmp.GetPixel(x, y) == Color.Black)
                    {
                        bmp.SetPixel(x, y, Color.Blue);
                    }
                }
            }

            // change it back to BitmapSource
            BitmapSource bitmapSource = BitmapToBitmapImage(bmp);
            Image1.Source = bitmapSource;

        }

        // methods below
        public static System.Drawing.Bitmap ImageSourceToBitmap(ImageSource imageSource)
        {
            BitmapSource m = (BitmapSource)imageSource;

            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); // 坑点:选Format32bppRgb将不带透明度

            System.Drawing.Imaging.BitmapData data = bmp.LockBits(
            new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

            m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
            bmp.UnlockBits(data);

            return bmp;
        }

        public BitmapImage BitmapToBitmapImage(Bitmap src)
        {
            MemoryStream ms = new MemoryStream();
            ((System.Drawing.Bitmap)src).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            image.StreamSource = ms;
            image.EndInit();
            return image;
        }

I wonder whick part makes trouble in it. Sorry for my poor English. Any suggestion would be appreciated!

Update:

  1. I'm using some weather icons, and the weather website only give me some png files. Path/drawinggroup/streamgeometry sounds great, but it's nearly impossible for me to draw them again in WPF.
  2. I want to show the image directly, but Stack Overflow tells me "You need at least 10 reputation to post images." emmm....
  3. Sorry to use fuzzy image, but I want to convey the massage is that not only the exact black should change to the exact blue, the lighter black should also change to lighter blue.
  4. I make an smaller reproducible example.
Kelatte
  • 17
  • 6
  • Are you using it like an icon of button or something? In that case, won't it be easier to make a path/drawinggroup/streamgeometry and put it in a resource dictionary? With this method change the color can be done even with binding. – DrkDeveloper Feb 15 '21 at 15:38
  • The question is difficult to understand. What are _"strange results"_? Please note that links to third-party sites aren't useful. You should upload images directly, so they wind up on imgur.com. Also, WPF has a perfectly usable bitmap-handling API; converting to GDI+ to edit colors and then converting back is inefficient and unnecessary. Finally, for your specific purpose, you might prefer to use a WPF `Effect` based on a GPU shader. See [this question and my answer](https://stackoverflow.com/questions/45093399/how-to-invert-color-of-xaml-png-images-using-c) for details about that. – Peter Duniho Feb 15 '21 at 16:50
  • In case "*8indexed*" means your bitmap has the `PixelFormats.Indexed8` format, you could easily create a new BitmapSource with a different color palette. – Clemens Feb 15 '21 at 17:12
  • That said, looking at the bitmap on the third-party site, it looks like a combination of things: the image is being displayed without full opacity, what you think is a white background is actually transparent pixels, and it's got compression artifacts that prevent the edges of the graphic in the middle from being set to blue (since they aren't exactly the black color). – Peter Duniho Feb 15 '21 at 17:16
  • You should update the post with a proper [mcve]; upload the original image directly to Stack Overflow in the post (i.e. not a third-party site and using the exact image, not a combined image), embed the image as Base64 in your [mcve], or include some extra code to generate the bitmap as a preface to the example code (only do this last one if you can in fact produce the same output with the generated bitmap as your original). – Peter Duniho Feb 15 '21 at 17:20

1 Answers1

-1

I tried custom ShadeEfect and it's amazingly cool!

hlsl code:

sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 color = tex2D(input, uv);
    color.b = 1;
    return color;
}

effect code:

class ChangeColorEffect : ShaderEffect
{
    private const string _kshaderAsBase64 = @"AAP///7/HwBDVEFCHAAAAE8AAAAAA///AQAAABwAAAAAAQAASAAAADAAAAADAAAAAQACADgAAAAAAAAAaW5wdXQAq6sEAAwAAQABAAEAAAAAAAAAcHNfM18wAE1pY3Jvc29mdCAoUikgSExTTCBTaGFkZXIgQ29tcGlsZXIgMTAuMQCrUQAABQAAD6AAAIA/AAAAAAAAAAAAAAAAHwAAAgUAAIAAAAOQHwAAAgAAAJAACA+gQgAAAwAAD4AAAOSQAAjkoAEAAAIACAuAAADkgAEAAAIACASAAAAAoP//AAA=";
    private static readonly PixelShader _shader;
    
    static ChangeColorEffect()
    {
        _shader = new PixelShader();
        _shader.SetStreamSource(new MemoryStream(Convert.FromBase64String(_kshaderAsBase64)));
    }

    public ChangeColorEffect()
    {
        PixelShader = _shader;
        UpdateShaderValue(InputProperty);
    }

    public Brush Input
    {
        get { return (Brush)GetValue(InputProperty); }
        set { SetValue(InputProperty, value); }
    }

    public static readonly DependencyProperty InputProperty =
        ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(ChangeColorEffect), 0);

}

xaml code:

<Image x:Name="Image1" Width="256" Height="256" Source="100.png">
    <Image.Effect>
        <local:ChangeColorEffect/>
    </Image.Effect>
</Image>
Kelatte
  • 17
  • 6