AccessViolationException when accessing pixel color (GetPixel())

Apr 19, 2013 at 5:02 PM
Hi,

I'm using WriteableBitmapEx to edit an image taken with tablet's cam with Windows 8 Pro but I got an AccessViolationException every time I try to get a pixel color value, here's the code:
Windows.Media.Capture.MediaCapture captureMgr = new MediaCapture();
await captureMgr.InitializeAsync();

IRandomAccessStream memoryStream = new InMemoryRandomAccessStream();
await captureMgr.CapturePhotoToStreamAsync(imageProperties, memoryStream);
await memoryStream.FlushAsync();
memoryStream.Seek(0);

WriteableBitmap tmpImage = new WriteableBitmap(1, 1); 
tmpImage.SetSource(memoryStream);
tmpImage.GetPixel(1, 1); // An AccessViolationException occurs.
What I'm doing wrong? Or maybe a library bug?
Coordinator
Apr 19, 2013 at 7:29 PM
You are using it wrong. The WinRT's SetSource will not load it right away, so when you access a pixel the buffer is not filled. Just check PixelWidth and PixelHeight

That's why WBX has the FromStrean extension method:
var tmpImage = await BitmapFactory.New(1, 1).FromStream(memoryStream);
  • Rene
Apr 20, 2013 at 5:30 PM
You're right, thank you. I changed the code and now it works well.
Mar 20, 2015 at 7:02 AM
Ive been trying to follow this suggestion but havent been able to so far. How should I change it to make this work?

The crazy thing here is that this work for a larger image (full hd) but not for a 512x424 image.

This is the code im using:
 private void SumPictures( WriteableBitmap currPicture )
        {     
            for (int col = 0; col < currPicture.PixelWidth; col++)
            {
                for (int row = 0; row < currPicture.PixelHeight; row++)
                {
                    Color currPixel = currPicture.GetPixel(col, row);  //<-- Error happens here. The console output prints the PixelWidth and PixelHeight correctly
                    Console.WriteLine("Col: " + col + " row: " + row + " currPicture.PixelWidth: " + currPicture.PixelWidth + " currPicture.PixelHeight: " + currPicture.PixelHeight);

                    _sumedAllImages[col][row].R += currPixel.R;
                    _sumedAllImages[col][row].G += currPixel.G;
                    _sumedAllImages[col][row].B += currPixel.B;
                    _sumedAllImages[col][row].A += currPixel.A; 
                }
            }
        }

        private void LoadAndAverageImages(string filePrefix)
        {
            string[] allPictures = Directory.GetFiles(selectFolder(), filePrefix + "*.png", SearchOption.AllDirectories);            

            //for (int i = 0; i < allPictures.Length; i++)
            Parallel.For(0, allPictures.Length, i =>
            {
                _filenameList.Add(allPictures[i]);
                WriteableBitmap currPicture = new WriteableBitmap((BitmapSource)(new BitmapImage(new Uri(allPictures[i]))));
                SumPictures(currPicture);
                if (i == 0)
                    _samplePicture = currPicture;
                Console.WriteLine("currPicture: " + i);
            });           

            for (int col = 0; col < _samplePicture.PixelWidth; col++)
            {
                for (int row = 0; row < height; row++)
                {
                    Color currPixelSum = new Color();
                    currPixelSum.R = (byte)_sumedAllImages[col][row].R;
                    currPixelSum.G = (byte)_sumedAllImages[col][row].G;
                    currPixelSum.B = (byte)_sumedAllImages[col][row].B;
                    currPixelSum.A = (byte)_sumedAllImages[col][row].A;

                    _samplePicture.SetPixel(col, row, currPixelSum);
                }
            }

            Console.WriteLine("Loaded " + allPictures.Length + " pictures!");
        }
Thank you!
Coordinator
Mar 20, 2015 at 2:49 PM
Edited Mar 20, 2015 at 2:50 PM
Same issues. You want to access the pixels but the loading is asynchronously, so the pixel data was not loaded.
            WriteableBitmap currPicture = new WriteableBitmap((BitmapSource)(new __BitmapImage(new Uri(allPictures[i]))));__
Sometimes it might have been loaded but that's good luck.

You should rather use the WBX method FromStream(stream)
Also, you can't create a WB on a background thread so running the creation of WBs needs to happen before your Parallel loop on the UI thread.

Something like this (not tested nor compiled);
var wbs = new List<WriteableBitmap>();
foreach(var fileName in Directory.GetFiles(selectFolder(), filePrefix + "*.png", SearchOption.AllDirectories))
{
    using(var stream = File.OpenRead(fileName))
    {
          var wb = BitmapContext.New(1, 1).FromStream(stream);
          wbs.Add(wb);
    }
}

Parallel.For(0, wbs.Count, i =>
            {
                var currPicture = wbs[i];
                SumPictures(currPicture);
                if (i == 0)
...
Mar 21, 2015 at 6:04 AM
Edited Mar 21, 2015 at 6:09 AM
So the error I had when opening a new Image is now gone, but Im still seeing the same error when getting a single pixel from the loaded image.

The code is basicly the same you posted, but I had to make my own FromStream method, which goes as follows:
 public static WriteableBitmap MyFromStream(WriteableBitmap bmp, Stream stream)
        {
            var bmpi = new BitmapImage();
                bmpi.BeginInit();
                bmpi.StreamSource = stream;
                bmpi.EndInit();
            bmp = new WriteableBitmap(bmpi);
            return bmp;
        }
And its accessed like this:
var wbs = new List<WriteableBitmap>();
            for ( int i = 0; i < allPictures.Length; i++ )
            {
                using( var stream = File.OpenRead( allPictures[i]) )
                {
                    //var wb = BitmapFactory.New(1, 1).FromStream(stream);
                    var wb = MyFromStream(BitmapFactory.New(1, 1), stream);
                    wbs.Add(wb);
                }
            }
So the error is happening here now. What is the right way of accessing a single pixel? Just to make it crystal clear, I need to access the whole image, pixel by pixel.
 //for (int i = 0; i < allPictures.Length; i++)
            Parallel.For(0, wbs.Count, i =>
            {
                var currPicture = wbs[i];
                SumPictures(currPicture);
                if (i == 0)
                    _samplePicture = currPicture;
                Console.WriteLine("currPicture: " + i);
            });

private void SumPictures( WriteableBitmap currPicture )
        {     
            for (int col = 0; col < currPicture.PixelWidth; col++)
            {
                for (int row = 0; row < currPicture.PixelHeight; row++)
                {
                    Color currPixel = currPicture.GetPixel(col, row);  //<-- Error happens here.

                    _sumedAllImages[col][row].R += currPixel.R;
                    _sumedAllImages[col][row].G += currPixel.G;
                    _sumedAllImages[col][row].B += currPixel.B;
                    _sumedAllImages[col][row].A += currPixel.A; 
                }
            }
        }
And for last, but not least, when calling BitmapFactory.New(1,1), the description says that New receives the Width and Height of the newly created WriteableBitmap, so how come Im passing it as 1?

Thanks for the support!