How to use ImageAttributes for BitmapImage

asked 2022-03-31T06:18:35.243+00:00
HoneyBee 146 Reputation points

I'm working with WPF.

I need to work with ColorMatrix on my control's Background ImageSource.

The code below works fine.

But there is one problem.

Finally, at the moment of DrawImage to Graphics
It takes a long time.
It takes about 0.3 seconds.

I want to make this process faster.

look at my code
Convert ImageSource to Bitmap and
Create ImageAttributes and connect them to Graphics
Change this to ImageSorce again and use it.

This process is cumbersome and very slow.

Can't we make this simpler and faster?

ConvertBitmapToImageSource(NagativeBitmapFromSource(CurrentPageImage.ImageSource as BitmapImage));




  public ImageSource ConvertBitmapToImageSource(System.Drawing.Bitmap bitmap)
         {
             System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
             sw.Start();
             BitmapImage bitmapImage = new BitmapImage();
             using (MemoryStream memory = new MemoryStream())
             {
                 bitmap.Save(memory, ImageFormat.Png);
                 memory.Position = 0;
                 bitmapImage.BeginInit();
                 bitmapImage.StreamSource = memory;
                 bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                 bitmapImage.EndInit();
                 bitmapImage.Freeze();
             }
             sw.Stop();
             LogViewerAddItem("ConvertBitmapToImageSource : " + sw.Elapsed.ToString());
             return bitmapImage;
         }

         public System.Drawing.Bitmap NagativeBitmapFromSource(BitmapSource bitmapsource)
         {
             System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
             sw.Start();
             //convert image format
             var src = new System.Windows.Media.Imaging.FormatConvertedBitmap();
             src.BeginInit();
             src.Source = bitmapsource;
             src.DestinationFormat = System.Windows.Media.PixelFormats.Bgra32;
             src.EndInit();
             src.Freeze();
             LogViewerAddItem("FormatConvertedBitmap : " + sw.Elapsed.ToString());
             //copy to bitmap
             System.Drawing.Bitmap newBitmap = new System.Drawing.Bitmap(src.PixelWidth, src.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
             var data = newBitmap.LockBits(new System.Drawing.Rectangle(System.Drawing.Point.Empty, newBitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
             src.CopyPixels(System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
             newBitmap.UnlockBits(data);

             LogViewerAddItem("copy to bitmap : " + sw.Elapsed.ToString());

             using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(newBitmap))
             {
                 ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
                     new float[] {-0.30f, -0.30f, -0.30f,  0.00f,  0.00f},
                     new float[] {-0.59f, -0.59f, -0.59f,  0.00f,  0.00f},
                     new float[] {-0.11f, -0.11f, -0.11f,  0.00f,  0.00f},
                     new float[] { 0.00f,  0.00f,  0.00f,  1.00f,  0.00f},
                     new float[] { 1.00f,  1.00f,  1.00f,  0.00f,  1.00f }
                 });

                 using (ImageAttributes attributes = new ImageAttributes())
                 {
                     attributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                     //attributes.SetGamma(gamma, ColorAdjustType.Bitmap);
                     LogViewerAddItem("SetColorMatrix : " + sw.Elapsed.ToString());

                     //g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                     g.DrawImage(newBitmap, new System.Drawing.Rectangle(System.Drawing.Point.Empty, newBitmap.Size),
                        0, 0, newBitmap.Width, newBitmap.Height, System.Drawing.GraphicsUnit.Pixel, attributes);

                     attributes.Dispose();
                 }
                 g.Dispose();

                 LogViewerAddItem("Graphic DrawImage : " + sw.Elapsed.ToString());
             }

             sw.Stop();
             LogViewerAddItem(sw.Elapsed.ToString());
             return newBitmap;
         }
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,169 questions
No comments
{count} votes

Accepted answer
  1. answered 2022-03-31T09:30:51.84+00:00
    Castorix31 65,271 Reputation points

    A test with a WriteableBitmap (with an image1 Image containing the Butterfly) =>

    188625-graynegative.gif

                var imgSource = image1.Source;  
    
                FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();  
                newFormatedBitmapSource.BeginInit();  
                newFormatedBitmapSource.Source = (BitmapSource)imgSource;  
                newFormatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;                  
                newFormatedBitmapSource.EndInit();  
    
                WriteableBitmap wb = new WriteableBitmap(newFormatedBitmapSource);  
                int nWidth = wb.PixelWidth;  
                int nHeight = wb.PixelHeight;  
                int[] pixelData = new int[nWidth * nHeight];  
                int nWidthBytes = nWidth * 4;  
                wb.CopyPixels(pixelData, nWidthBytes, 0);  
                for (int i = 0; i < pixelData.Length; ++i)  
                {  
                    pixelData[i] ^= 0x00FFFFFF;  
                    pixelData[i] = MakePixelGray(pixelData[i]);  
                }  
                wb.WritePixels(new Int32Rect(0, 0, nWidth, nHeight), pixelData, nWidthBytes, 0);  
    
                image1.Source = wb;  
    

    Utility function :

        private static int MakePixelGray(int pixel)  
        {  
            byte blue = (byte)pixel;  
            byte green = (byte)(pixel >> 8);  
            byte red = (byte)(pixel >> 16);  
            byte alpha = (byte)(pixel >> 24);  
    
            byte gray = (byte)(((red * 77) + (green * 150) + (blue * 29) + 128) / 256);  
            return (int)(alpha << 24 | gray << 16 | gray << 8 | gray);  
        }  
    

1 additional answer

Sort by: Most helpful
  1. answered 2022-03-31T08:29:27.997+00:00
    HoneyBee 146 Reputation points

    I think you can get better results by using writeablebitmap .

    But no matter how much you search
    in wpf
    using writeablebitmap
    I don't know how to achieve something like the above result.

    Obviously, it is expected to be faster than Graphics.

    Does anyone have any idea how to do this?

    No comments