Click here to Skip to main content
15,891,204 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Ok, so I'm using some code that adjusts an images contrast:
public static Bitmap AdjustContrast(Bitmap Image, float Value) 
        { 
            Value = (100.0f + Value) / 100.0f; 
            Value *= Value; 
            Bitmap NewBitmap = (Bitmap)Image.Clone(); 
            BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat); 
            
            unsafe 
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    byte* row = (byte*)data.Scan0 + (y * data.Stride);
                    int columnOffset = 0;

                    for (int x = 0; x < NewBitmap.Width; ++x)
                    {
                        try
                        {
                            byte B = row[columnOffset];
                            byte G = row[columnOffset + 1];
                            byte R = row[columnOffset + 2];
                            float Red = R / 255.0f;
                            float Green = G / 255.0f;
                            float Blue = B / 255.0f;
                            Red = (((Red - 0.5f) * Value) + 0.5f) * 255.0f;
                            Green = (((Green - 0.5f) * Value) + 0.5f) * 255.0f;
                            Blue = (((Blue - 0.5f) * Value) + 0.5f) * 255.0f;
                            int iR = (int)Red;
                            iR = iR > 255 ? 255 : iR;
                            iR = iR < 0 ? 0 : iR;
                            int iG = (int)Green;
                            iG = iG > 255 ? 255 : iG;
                            iG = iG < 0 ? 0 : iG;
                            int iB = (int)Blue;
                            iB = iB > 255 ? 255 : iB;
                            iB = iB < 0 ? 0 : iB;
                            row[columnOffset] = (byte)iB;
                            row[columnOffset + 1] = (byte)iG;
                            row[columnOffset + 2] = (byte)iR;
                            columnOffset += 4;
                        }
                        catch (AccessViolationException av)
                        {
                            MessageBox.Show("Access violation!");
                        }
                    }

                }
            } 
            NewBitmap.UnlockBits(data); 
            return NewBitmap; 
        }


It seemed to be working fine. I could load an image and make ajustments using this method. I have another two methods for brightness and scaling which don't have unsafe code. They don't cause any problems. Anyway, all of a sudden I seem to get an access violation that only occurs when altering colour images. It occurs in this line:

byte B = row[columnOffset];


But not in the first iteration. For example when I use an image that's Width = 1024, Height = 1184, the error occurs when columnOffset reaches 3072.

I'm stuck for ideas as to what the problem is as surely it should treat a greyscale image the same as a colour one.

Help would be much appreciated.

And yes, I could try another contrast adjustment method, which I will. But I'd really like to know what the problem is here - morbid curiosity perhaps...

Thanks, Jib.
Posted

Are you sure the image is 32 bit per pixel and not 24 bit per pixel? Check out the PixelFormat and use the size of that.

columnOffset += Image.GetPixelFormatSize(NewBitmap.PixelFormat);


http://msdn.microsoft.com/en-us/library/system.drawing.image.getpixelformatsize.aspx[^]

As side note:
This exception handling is not very helpful especially during debugging because every exception gives Access violation even if it is something else. Just show the error raised or include it as "technical error". Further you could (or maybe should) use Debug.Write to output the complete error with stack trace and everything so you can check it out more easy.
C#
catch (AccessViolationException av)
{
    MessageBox.Show(String.Format("An error occured\nTechnical error: {0}"), av.Message));
}


Good luck!
 
Share this answer
 
v3
Comments
Jibrohni 16-Dec-10 7:38am    
Thank you very much. Although I couldn't actually find .GetPixelInformation I simply changed the line:

BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat);

to:

BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);

So this keeps a standard bitdepth value.

And I agree with the error catch - I'd just put it there to see if I could handle the error (which I couldn't).

But yeah, GetPixelFormatSize didn't seem available to me???

Thanks again.
E.F. Nijboer 16-Dec-10 7:51am    
Nice that it worked out. Your solution of specifying the PixelFormat is even better, considering that there is no actual check on the PixelFormat so a 8bpp image (or any other below 24bpp) would then cause trouble. I also updated the answer with a link to msdn on Image.GetPixelFormatSize.
public static Bitmap AdjustContrast(Bitmap Image, float Value) 
        { 
            Value = (100.0f + Value) / 100.0f; 
            Value *= Value; 
            Bitmap NewBitmap = (Bitmap)Image.Clone(); 
            BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat);
            //BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);


            int bitsPerPixel = (Bitmap.GetPixelFormatSize(Image.PixelFormat)) / 8;

            unsafe 
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    byte* row = (byte*)data.Scan0 + (y * data.Stride);
                    int columnOffset = 0;

                    for (int x = 0; x < NewBitmap.Width; ++x)
                    {
                        try
                        {
                            byte B = row[columnOffset];
                            byte G = row[columnOffset + 1];
                            byte R = row[columnOffset + 2];
                            float Red = R / 255.0f;
                            float Green = G / 255.0f;
                            float Blue = B / 255.0f;
                            Red = (((Red - 0.5f) * Value) + 0.5f) * 255.0f;
                            Green = (((Green - 0.5f) * Value) + 0.5f) * 255.0f;
                            Blue = (((Blue - 0.5f) * Value) + 0.5f) * 255.0f;
                            int iR = (int)Red;
                            iR = iR > 255 ? 255 : iR;
                            iR = iR < 0 ? 0 : iR;
                            int iG = (int)Green;
                            iG = iG > 255 ? 255 : iG;
                            iG = iG < 0 ? 0 : iG;
                            int iB = (int)Blue;
                            iB = iB > 255 ? 255 : iB;
                            iB = iB < 0 ? 0 : iB;
                            row[columnOffset] = (byte)iB;
                            row[columnOffset + 1] = (byte)iG;
                            row[columnOffset + 2] = (byte)iR;

                            columnOffset += bitsPerPixel;
                        }
                        catch (AccessViolationException av)
                        {
                            MessageBox.Show("Access violation!");
                        }
                    }
                    

                }
            } 
            NewBitmap.UnlockBits(data); 
            return NewBitmap; 
        }


Please ignore the try ctach block...

Jib
 
Share this answer
 
v2
Comments
wizardzz 16-Dec-10 12:06pm    
I don't think you should post your own answer to your own question. Especially when someone helped you through it.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900