0

Adjust the contrast of an image in C# efficiently

solution for above question is not working in vb 2005

i need solution in vb2005

this is c# code below

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)
        {
            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;
        }
    }
}

NewBitmap.UnlockBits(data);

return NewBitmap;

}

& here is vb2005 code

Public Shared Function AdjustContrast(Image As Bitmap, Value As Single) As Bitmap

Value = (100F + Value) / 100F
Value *= Value
Dim NewBitmap As Bitmap = DirectCast(Image.Clone(), Bitmap)

Dim data As BitmapData = NewBitmap.LockBits(New Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat)

For y As Integer = 0 To NewBitmap.Height - 1
    Dim row As Pointer(Of Byte) = CType(data.Scan0, Pointer(Of Byte)) + (y * data.Stride)
    Dim columnOffset As Integer = 0
    For x As Integer = 0 To NewBitmap.Width - 1
        Dim B As Byte = row(columnOffset)
        Dim G As Byte = row(columnOffset + 1)
        Dim R As Byte = row(columnOffset + 2)

        Dim Red As Single = R / 255F
        Dim Green As Single = G / 255F
        Dim Blue As Single = B / 255F
        Red = (((Red - 0.5F) * Value) + 0.5F) * 255F
        Green = (((Green - 0.5F) * Value) + 0.5F) * 255F
        Blue = (((Blue - 0.5F) * Value) + 0.5F) * 255F

        Dim iR As Integer = CInt(Red)
        iR = If(iR > 255, 255, iR)
        iR = If(iR < 0, 0, iR)
        Dim iG As Integer = CInt(Green)
        iG = If(iG > 255, 255, iG)
        iG = If(iG < 0, 0, iG)
        Dim iB As Integer = CInt(Blue)
        iB = If(iB > 255, 255, iB)
        iB = If(iB < 0, 0, iB)

        row(columnOffset) = CByte(iB)
        row(columnOffset + 1) = CByte(iG)
        row(columnOffset + 2) = CByte(iR)

        columnOffset += 4
    Next
Next

NewBitmap.UnlockBits(data)

Return NewBitmap

End Function

Dim row As Pointer(Of Byte) = CType(data.Scan0, Pointer(Of Byte)) + (y * data.Stride)

above line gives error since vb does not support

Dim row As Pointer(Of Byte)

Community
  • 1
  • 1
Dandy
  • 467
  • 1
  • 10
  • 33
  • when code is converted from c# to vb.net it gives pointer error – Dandy Nov 01 '12 at 10:52
  • Without seeing the VB code you have its impossible to say how to fix the error your getting. You can try converting the code with this tool, http://www.developerfusion.com/tools/convert/csharp-to-vb/. I've used it for simple stuff, seems to work good. – Kratz Nov 01 '12 at 14:35
  • @Kratz i have udated code the code in vb gives error for pointer(of Byte) – Dandy Nov 02 '12 at 06:50
  • Check the VB example for the `.Scan0` property here, http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.scan0.aspx#Y400, since bitmap data is unmanaged, you may have to Marshal the data out, modify it, then Marshal it back in. – Kratz Nov 02 '12 at 12:26
  • @Kratz but the error is at Dim row As Pointer(Of Byte)which is "'System.Reflection.Pointer' has no type parameters and so cannot have type arguments." – Dandy Nov 03 '12 at 05:22
  • Right, there really isn't a good translation of the C# line `byte* row = (byte*)data.Scan0 + (y * data.Stride);`, so I think the `as Pointer(Of Byte)` is just invalid. I'm not an expert, but I don't think in VB you can do the same pointer addition you can in C. Also, I believe the pointer `.Scan0` is pointing to unmanaged memory, which I don't think you can access directly in VB. – Kratz Nov 03 '12 at 23:03

1 Answers1

2

Here's my attempt at the conversion. I'm using the IntPtr data structure to handle holding the unmanged pointer and to do the pointer addition to get an IntPtr for each row. Then as it goes through the row, I'm using the Marshal.ReadByte and Marshal.WriteByte methods to handle reading and writing the unmanaged data. I tested and it seems to work.

value = (100.0F + value) / 100.0F
    value *= value
    Dim NewBitmap As Bitmap = DirectCast(Image.Clone(), Bitmap)

    Dim data As BitmapData = NewBitmap.LockBits(New Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat)

    For y As Integer = 0 To NewBitmap.Height - 1

        Dim RowPtr = IntPtr.Add(data.Scan0, y * data.Stride)

        Dim columnOffset As Integer = 0
        For x As Integer = 0 To NewBitmap.Width - 1
            Dim B As Byte = System.Runtime.InteropServices.Marshal.ReadByte(RowPtr, columnOffset)
            Dim G As Byte = System.Runtime.InteropServices.Marshal.ReadByte(RowPtr, columnOffset + 1)
            Dim R As Byte = System.Runtime.InteropServices.Marshal.ReadByte(RowPtr, columnOffset + 2)

            Dim Red As Single = R / 255.0F
            Dim Green As Single = G / 255.0F
            Dim Blue As Single = 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

            Dim iR As Integer = CInt(Red)
            iR = If(iR > 255, 255, iR)
            iR = If(iR < 0, 0, iR)
            Dim iG As Integer = CInt(Green)
            iG = If(iG > 255, 255, iG)
            iG = If(iG < 0, 0, iG)
            Dim iB As Integer = CInt(Blue)
            iB = If(iB > 255, 255, iB)
            iB = If(iB < 0, 0, iB)

            System.Runtime.InteropServices.Marshal.WriteByte(RowPtr, columnOffset, CByte(iB))
            System.Runtime.InteropServices.Marshal.WriteByte(RowPtr, columnOffset + 1, CByte(iG))
            System.Runtime.InteropServices.Marshal.WriteByte(RowPtr, columnOffset + 2, CByte(iR))

            columnOffset += 4
        Next

    Next

    NewBitmap.UnlockBits(data)
Kratz
  • 4,280
  • 3
  • 32
  • 55
  • sorry for late feedback your code seems have been written in vs2010 where i am using vs2005 , vs2005 does not allow IntPtr.Add method – Dandy Nov 19 '12 at 10:27