Hi!

It's been a while since i last posted, and now I'm in need of some expert assistance.

I've found this Control written in C# with .NET 1.0 on vbAccelerator and wanted to use it with my current project. I decided to convert the entire code to VB.NET but one of the subs contains "pointer code".

I know you can use combinations of IntPtr, Marshal and GCHandle to emulate(?) pointer handling, but I don't know how.
I would very much appreciate some help with converting this portion of the code.
More specifically those lines that contain "pointer code" (marked with red).

BitmapData bmData = glyph.LockBits(
            new Rectangle(0, 0, glyph.Width, glyph.Height),
            ImageLockMode.ReadWrite,
            PixelFormat.Format24bppRgb);
         IntPtr scan0 = bmData.Scan0;
         int nOffset = bmData.Stride - glyph.Width * 3;

         unsafe
         {
            byte * pDest = (byte *)(void *)scan0;

            for (int y = 0; y < glyph.Height; ++y)
            {
               for (int x = 0; x < glyph.Width; ++x)
               {
                  // Check whether transparent:
                  if (transColor.R == pDest[2] && 
                     transColor.G == pDest[1] &&
                     transColor.B == pDest[0])
                  {
                     // set to background colour
                     pDest[2] = backColor.R;
                     pDest[1] = backColor.G;
                     pDest[0] = backColor.B;
                  }
                  else
                  {
                     // Get HLS of existing colour:
                     Color pixel = Color.FromArgb(pDest[2], pDest[1], pDest[0]);
                     float lumPixel = pixel.GetBrightness();
                     if (lumPixel <= 0.9F)
                     {
                        float lumOffset = lumPixel / transLuminance;
                        lumPixel = backLuminance * lumOffset;
                        if (lumPixel > 1.0F)
                        {
                           lumPixel = 1.0F;
                        }
                     
                     }
                     // Calculate the new colour
                     HLSRGB newPixel = new HLSRGB(backHue, lumPixel,
                      backSaturation);

                     // set the values:
                     pDest[0] = newPixel.Blue;
                     pDest[1] = newPixel.Green;
                     pDest[2] = newPixel.Red;
                  }
                  // Move to next BGRA
                  pDest += 3;
               }
               pDest += nOffset;
            }
         }
         glyph.UnlockBits(bmData);

Any help or suggestions would be helpful.

Thanks!

Recommended Answers

All 7 Replies

Dim bmData As BitmapData = glyph.LockBits(New Rectangle(0, 0, glyph.Width, glyph.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Dim scan0 As IntPtr = bmData.Scan0
Dim nOffset As Integer = bmData.Stride - glyph.Width * 3

Dim pDest As Byte* = CByte(CType(scan0, void*))
For y As Integer = 0 To glyph.Height - 1
    
    For x As Integer = 0 To glyph.Width - 1
        ' Check whether transparent:
        If transColor.R = pDest(2) AndAlso transColor.G = pDest(1) AndAlso transColor.B = pDest(0) Then
            ' set to background colour
            pDest(2) = backColor.R
            pDest(1) = backColor.G
            pDest(0) = backColor.B
        Else
            ' Get HLS of existing colour:
            Dim pixel As Color = Color.FromArgb(pDest(2), pDest(1), pDest(0))
            Dim lumPixel As Single = pixel.GetBrightness()
            If lumPixel <= 0.9F Then
                Dim lumOffset As Single = lumPixel / transLuminance
                lumPixel = backLuminance * lumOffset
                If lumPixel > 1F Then
                    lumPixel = 1F
                    
                End If
            End If
            ' Calculate the new colour
            Dim newPixel As New HLSRGB(backHue, lumPixel, backSaturation)
            
            ' set the values:
            pDest(0) = newPixel.Blue
            pDest(1) = newPixel.Green
            pDest(2) = newPixel.Red
        End If
        ' Move to next BGRA
        pDest += 3
    Next
    pDest += nOffset
Next

glyph.UnlockBits(bmData)
commented: Brilliant helper! +2
commented: Great... +1

I'm wondering if you have tried this yourself? And it works?
For me, it doesn't work in VB = I've tried before posting.
This gives the error: End of statement expected. Dim pDest As Byte* = CByte(CType(scan0, void*)) The * indicates that this is a pointer and only works in C++/C#.
These types of declarations are not possible In VB.

I actually put the entire sub through an online conversiontool and that resultet in the very same code you posted.

Currently I'm working with Marshal and a byte array to see if I can get it to work.

Dim pDest As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(scan0))
 pDest = CByte(CType(scan0, Byte))

Suggestions and ideas are welcome.

Thanks!

yeah, i convert it in that tools...

Instead of:

Dim bmData As BitmapData = glyph.LockBits(New Rectangle(0, 0, glyph.Width, glyph.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Dim scan0 As IntPtr = bmData.Scan0
Dim nOffset As Integer = bmData.Stride - glyph.Width * 3
Dim pDest As Byte* = CByte(CType(scan0, void*))

I create a function for setting up my bitmaps, which works in the graphic editor I am writing just fine:

Dim bmData As BitmapData 
        Shared stride As Integer
        Shared Scan0 As System.IntPtr
        Shared nOffset As Integer
        Shared nWidth As Integer
        Shared bytes As Integer
        Shared p() As Byte
        Private Shared Function SetUpBitMap(ByVal b As Bitmap) As Boolean
            Try                
                bmData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
                stride = bmData.Stride
                Scan0 = bmData.Scan0
                nOffset = stride - b.Width * 3
                nWidth = b.Width * 3
                '
                '   Declare an array to hold the bytes of the bitmap.
                '   This code is specific to a bitmap with 24 bits per pixels.
                '
                bytes = b.Width * b.Height * 3
                ReDim p(bytes - 1)
                '
                '   Copy the RGB values into the array.
                '
                Marshal.Copy(Scan0, p, 0, bytes)
                Return True
            Catch ex As Exception
                MessageBox.Show("Error Fetching Bitmap " & ex.Message)
                Return False
            End Try
        End Function

I know this works because I use it, so give it a try.

I tried your solution bwKeller. It works! Thanks a bunch!! :-D

The next part is tricky, because within a nested For loop I need to set 3 colors for each pixel.

For y As Integer = 0 To glyph.Height - 1
     For x As Integer = 0 To glyph.Width - 1
          If transColor.R = pDest(nPixel + 2) AndAlso transColor.G = pDest(nPixel + 1) AndAlso transColor.B = pDest(nPixel) Then
               pDest(nPixel) = backColor.B
               pDest(nPixel + 1) = backColor.G
               pDest(nPixel + 2) = backColor.R
          End If
          nPixel += 3
     Next
     nPixel += nOffset
Next

However, the byte array only becomes 1083 (give or take a few) in size and pDest(nPixel + 1) is larger than that, I get an Index out of bounds error.

I'm guessing the array needs to be increased in size by a factor of nOffset so I'm just gonna test that and see what happens.
The array will probably be larger then needed. Would that screw up the bitmap?

Here is a function I use in conjunction with the previous SetUpBitMap() function to convert a graphic to grayscale. I think it should help you solve your issue:

Public Shared Function GrayScale(ByVal b As Bitmap) As Boolean
            If SetUpBitMap(b) Then
                Dim red As Byte, green As Byte, blue As Byte, Gray As Byte
                For counter As Integer = 0 To p.Length - 1 Step 3
                    blue = p(counter)
                    green = p(counter + 1)
                    red = p(counter + 2)
                    Gray = CByte((0.299 * red + 0.587 * green + 0.114 * blue))
                    p(counter) = Gray
                    p(counter + 1) = Gray
                    p(counter + 2) = Gray
                Next
                ' 
                '   Copy the RGB values back to the bitmap
                '
                System.Runtime.InteropServices.Marshal.Copy(p, 0, Scan0, bytes)
                '
                '   Unlock the bitmap
                '
                b.UnlockBits(bmData)
                Return True
            End If
        End Function

Thanks!
It works perfectly!!

This problem has now been solved...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.