1

I would like to Convert a BitmapImage to a Grayscale BitmapImage: Which I get from a method and therefore - the Width and Height are unknown to me. I have tried looking into options such as WritableBitmapEx and static extension methods but they haven't been helpful to me as I would like the return data type to be a BitmapImage as well as I then need to add it to List.

Is this possible in a Windows Phone app using C#? I would really appreciate if someone would shed some light into this. Thank you.

3 Answers3

1

Not sure of the namespaces here but something like this may work:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

FormatConvertedBitmap bitmapGreyscale = new FormatConvertedBitmap(bitmap, PixelFormats.Gray8, BitmapPalettes.Gray256, 0.0);
dodgy_coder
  • 12,407
  • 10
  • 54
  • 67
  • The type of namespace `FormatConvertedBitmap` could not be found. I don't think it is supported in Windows Phone :( –  Oct 13 '14 at 09:52
  • You can try adding a reference to PresentationCore.dll in your project references within the Visual Studio solution explorer. – dodgy_coder Oct 14 '14 at 06:54
1

The Algorithm is pretty simple:

using System.Windows.Media.Imaging;
using System.IO;

private WriteableBitmap ConvertToGrayScale(BitmapImage source)
{
    WriteableBitmap wb = new WriteableBitmap(source);               // create the WritableBitmap using the source

    int[] grayPixels = new int[wb.PixelWidth * wb.PixelHeight];

    // lets use the average algo 
    for (int x = 0; x < wb.Pixels.Length; x++)
    {
        // get the pixel
        int pixel = wb.Pixels[x];

        // get the component
        int red = (pixel & 0x00FF0000) >> 16;
        int blue = (pixel & 0x0000FF00) >> 8;
        int green = (pixel & 0x000000FF);

        // get the average
        int average = (byte)((red + blue + green) / 3);

        // assign the gray values keep the alpha
        unchecked
        {
            grayPixels[x] = (int)((pixel & 0xFF000000) | average << 16 | average << 8 | average);
        }
    }



    // copy grayPixels back to Pixels
    Buffer.BlockCopy(grayPixels, 0, wb.Pixels, 0, (grayPixels.Length * 4));

    return wb;            
}

private BitmapImage ConvertWBtoBI(WriteableBitmap wb)
{
    BitmapImage bi;
    using (MemoryStream ms = new MemoryStream())
    {
        wb.SaveJpeg(ms, wb.PixelWidth, wb.PixelHeight, 0, 100);
        bi = new BitmapImage();
        bi.SetSource(ms);
    }
    return bi;
}

<Image x:Name="myImage" Source="/Assets/AlignmentGrid.png" Stretch="None" />

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{       
    WriteableBitmap wb = ConvertToGrayScale((BitmapImage)this.myImage.Source);
    BitmapImage bi = ConvertWBtoBI(wb);


    myImage.Source = bi;       
}

Code in Action:

enter image description here

Chubosaurus Software
  • 8,133
  • 2
  • 20
  • 26
  • As always, I'm always satisfied with all your answers :) because they always work great! Although, I would like to share another answer that I found online which performs a bit faster than your answer and I would like to know why? MessageBox.Show((DateTime.Now - t1).ToString()); –  Oct 14 '14 at 15:30
  • 1
    @NavikGoswami no problem, I usually write solutions void of any optimization - I think that way they are easier to understand. There are a few things you can do to speed up the code I wrote above. I think you meant to post some code, but your comments got cut off. Just update your question, and I will take a look at it later. – Chubosaurus Software Oct 14 '14 at 18:54
  • Very true. Yes, the code got cut off. But anway, thanks for helping me! Would you also be able to answer this question -> http://stackoverflow.com/questions/26316702/scrolling-a-longlistselector-by-its-vertical-offset-by-getting-its-viewport-ca –  Oct 14 '14 at 19:00
0

You can't write to a BitmapImage: you'll need to convert it to a WriteableBitmap. Once you have a WriteableBitmap it's easy to access the buffer and convert the pixels to GreyScale.

WriteableBitmaps and BitmapImages both work very similarly since they are both BitmapSources. You can add them to the same List if you create your List as a List rather than List

It is unlikely the app will do anything with the List's contents that require the contents to be BitmapImages rather than BitmapSources.

Rob Caplan - MSFT
  • 21,714
  • 3
  • 32
  • 54