How to use ColorMatrix to highlight a specific color in WPF

HoneyBee 186 Reputation points
2021-08-10T01:00:57.037+00:00

I have an image file with text and pictures.

This is a typical document image form.

Converted colors using ColorMatrix.

The ColorMatrix structure is shown below.

  // create the negative color matrix
            colorMatrix = new ColorMatrix(new float[][]
            {
                new float[] {-1, 0, 0, 0, 0},
                new float[] {0, -1, 0, 0, 0},
                new float[] {0, 0, -1, 0, 0},
                new float[] {0, 0, 0, 1, 0},
                new float[] {1, 1, 1, 0, 1}
            });

            imageAttributes.SetColorMatrix(colorMatrix);

Register and use ColorMatrix with ImageAttributes.

After conversion, the characters are not clear.

After the black is converted to white, the thickness comes out thin.

Is there any way to make only white color thicker?

I want to make the text much clearer and bolder when I change the color.

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,671 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,235 questions
{count} votes

Accepted answer
  1. Hui Liu-MSFT 38,251 Reputation points Microsoft Vendor
    2021-08-26T07:35:36+00:00

    For making the colors bolder and the font clearer, you could try the following code.
    The code of xaml:

    float contrast = 1f;  
      float gamma = 8.5f;  
       private Bitmap MakeGrayscaleWithColorMatrix(Bitmap original)  
            {   
                Bitmap newBitmap = new Bitmap(original.Width, original.Height);   
                Graphics g = Graphics.FromImage(newBitmap);   
                ColorMatrix colorMatrix = new ColorMatrix(   
                new float[][]  
                {  
                     new float[] { contrast, 0, 0, 0, 0},  
                     new float[] {0, contrast, 0, 0, 0},  
                     new float[] { 0, 0f, contrast, 0, 0},  
                     new float[] {0, 0, 0, 1, 0},  
                     new float[] {0, 0, 0, 0, 1}  
                }) ;  
    
                ImageAttributes attributes = new ImageAttributes();  
    
                attributes.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);  
                attributes.SetGamma(gamma,ColorAdjustType.Bitmap);  
    
                g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),  
                   0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);   
                g.Dispose();  
                return newBitmap;  
            }  
    

    The picture of result:
    126527-color.png

    You can also refer to the links(https://stackoverflow.com/questions/55849048/resize-bitmap-image-and-make-bolder-lines and https://stackoverflow.com/questions/34116706/how-to-repair-dimmed-image-of-book-page/34121073#34121073 ) for more.


    If the response is helpful, please click "Accept Answer" and upvote it. 
    Note: Please follow the steps in our [documentation][3] to enable e-mail notifications if you want to receive the related email notification for this thread. 

    [3]: https://learn.microsoft.com/en-us/answers/articles/67444/email-notifications.html


2 additional answers

Sort by: Most helpful
  1. HoneyBee 186 Reputation points
    2022-03-31T04:01:47.903+00:00

    @Hui Liu-MSFT
    Hi.
    Long time no see.

    Thanks to you, I solved the above problem well.

    But since then I have a few questions
    I ran the test.

    I have to get the ImageSource (or BitmapImage) of the control to do this.

    So convert BitmapImage to Bitmap and
    I applied SetColormatrix here.

    So far there aren't many speed issues.
    It's just cumbersome.

    The problem occurred when I DrawImage on the Graphics object.

    A lot of time is wasted here.

    Is there any way to make this 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;  
            }  
    
    0 comments No comments

  2. HoneyBee 186 Reputation points
    2022-08-05T01:10:36.817+00:00

    @Hui Liu-MSFT

    @Hui Liu-MSFT

    It's been a while since I've written an answer.
    Your ideas have been of great help to me.

    But still I haven't solved the speed problem.

    And I got a way to improve the speed even faster.

    It is to use WriteableBitmap .

    Below is my code.

    It works very fast.

    But I can't work to make it much sharper via Gamma settings like in your answer.

    Any ideas on how to quickly set the Gamma value in my source code?

    public static WriteableBitmap ConvertNagativePage(BitmapImage source)  
            {  
                FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();  
                newFormatedBitmapSource.BeginInit();  
                newFormatedBitmapSource.Source = source;  
                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);  
      
                return wb;  
            }  
      
            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);  
            }  
    
    0 comments No comments