且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用getpixel和lockbit获得不同的颜色值

更新时间:2023-11-07 11:45:28

我几年前做了类似的事情.这是我在代码中留下的注释,以及一些代码.希望这对您有帮助...

I did something similar years ago. Here was a comment I left in my code, plus a bit of the code. Hope this is helpful...

'ok now its 1:20AM and I figured out that the reason they have to be applied in reverse is because that is the order (BGRA)

  Dim r, g, b As Integer

  b = sourceBuffer(sourceIndex) ' Blue (8 bits)
  g = sourceBuffer(sourceIndex + 1) ' Green (8 bits)
  r = sourceBuffer(sourceIndex + 2) ' Red (8 bits)

...

destinationBuffer(destinationIndex) = destinationB ' Blue (8 bits)
destinationBuffer(destinationIndex + 1) = destinationG ' Green
destinationBuffer(destinationIndex + 2) = destinationR ' Red
destinationBuffer(destinationIndex + 3) = destinationA ' Alpha





在鲍勃·鲍威尔(Bob Powell)关于锁定位的常见问题解答中也发现了这一点.





Found this also in Bob Powell''s FAQ''s on lockbits..

报价:

Format32BppArgb给定X和Y坐标,像素中第一个元素的地址为Scan0 +(y * stride)+(x * 4 ).这指向蓝色字节.以下三个字节包含绿色,红色和Alpha字节

Format32BppArgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y * stride)+(x*4). This Points to the blue byte. The following three bytes contain the green, red and alpha bytes



http://www.bobpowell.net/lockingbits.htm [



http://www.bobpowell.net/lockingbits.htm[^]


Good luck!

I have modified your code for how it should be. Hope this solves your issue.

Dim bd As Drawing.Imaging.BitmapData
Dim bg As Byte, bb As Byte, br As Byte, ba As Byte
Dim st As Integer
'create a buffer to hold the source data
Dim sourceBuffer(imageSize) As Byte

bd = jImg.LockBits(New Drawing.Rectangle(0, 0, jImg.Width, jImg.Height), Drawing.Imaging.ImageLockMode.ReadOnly, jImg.PixelFormat)

Dim imageSize As Integer = sourceData.Stride * sourceData.Height 'forgot to add this variable first edit

'copy the source image pixel data to the buffer
Marshal.Copy(bd.Scan0, sourceBuffer, 0, imageSize)

jImg.UnlockBits(bd)

For i As Integer = 0 To jImg.Height - 1 'added -1 so don't end up with index out of range

   st = bd.Stride * i 'get index for current row

   For j As Integer = 0 To jImg.Width - 1 'added -1 so don't end up with index out of range
      'Changed order to BGRA order
      bb = sourceBuffer(st)
      bg = sourceBuffer(st + 1)
      br = sourceBuffer(st + 2)
      ba = sourceBuffer(st + 3)

      jc2(i, j) = New Color(br, bg, bb, ba) 'not sure if you can do this... thinking it should be Color.FromARGB(a, r, g, b)

      st += 4 'increment for the 4 bytes we read

   Next

Next


好吧,这是完全正常的功能,并且可以通过将存储的像素倒出并验证图像正确来进行测试.


Ok this is fully functioning and tested by outputting stored pixels back out and verified image is correct.


Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ComparePixelReads()
    End Sub

    ''' <summary>
    ''' Compares the pixel reads.
    ''' </summary>
    Public Sub ComparePixelReads()
        Try


            Using sw As New System.IO.StreamWriter("D:\pixeltest\pixeloutput.txt", False)

                Dim tmp As System.Drawing.Bitmap = System.Drawing.Bitmap.FromFile("D:\pixeltest\ManagerPanel.bmp")
                Dim jImg As System.Drawing.Bitmap = ConvertToRGB(tmp)


                Dim jc2(jImg.Height, jImg.Width) As System.Drawing.Color
                Dim jc3(jImg.Height, jImg.Width) As System.Drawing.Color


                '//get pixel usage (very slow)
                For i As Integer = 0 To jImg.Height - 1
                    For j As Integer = 0 To jImg.Width - 1
                        Dim cl As System.Drawing.Color = jImg.GetPixel(j, i)
                        jc2(i, j) = cl
                    Next
                Next

                '//lock bits method (much faster)
                Dim bd As System.Drawing.Imaging.BitmapData = jImg.LockBits(New System.Drawing.Rectangle(0, 0, jImg.Width, jImg.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

                Dim sourceBuffer((bd.Stride * bd.Height)) As Byte
                '//copy intPtr to buffer
                System.Runtime.InteropServices.Marshal.Copy(bd.Scan0, sourceBuffer, 0, sourceBuffer.Length)

                '//unlock bits
                jImg.UnlockBits(bd)


                Dim st As Integer = 0
                Dim bb, bg, br, ba As Integer

                For i As Integer = 0 To jImg.Height - 1 '// 'added -1 so don't end up with index out of range

                    st = bd.Stride * i '//'get index for current row

                    For j As Integer = 0 To jImg.Width - 1 '// 'added -1 so don't end up with index out of range

                        '//'Changed order to BGRA order
                        bb = sourceBuffer(st)
                        bg = sourceBuffer(st + 1)
                        br = sourceBuffer(st + 2)
                        ba = sourceBuffer(st + 3)

                        jc3(i, j) = System.Drawing.Color.FromArgb(ba, br, bg, bb) '//'not sure if you can do this... thinking it should be Color.FromARGB(a, r, g, b)

                        st += 4 '//'increment for the 4 bytes we read

                    Next

                Next

                Dim outputCompare1 As New System.Drawing.Bitmap(jImg.Width, jImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
                Dim outputCompare2 As New System.Drawing.Bitmap(jImg.Width, jImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

                If (jc2.Length = jc3.Length) Then

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

                        For x As Integer = 0 To jImg.Width - 1
                            'write new pixels from jc2
                            outputCompare1.SetPixel(x, y, jc2(y, x))
                            'write new pixels from jc3
                            outputCompare2.SetPixel(x, y, jc3(y, x))

                            sw.WriteLine(String.Format("PixelGet: {0}      LockBitsGet: {1}", "(" & y.ToString() & ", " & x.ToString() + ")" & jc2(y, x).ToArgb().ToString(), "(" & y.ToString() & ", " & x.ToString() & ")" & jc3(y, x).ToArgb().ToString()))

                        Next

                    Next

                End If

                outputCompare1.Save("D:\pixeltest\jc2.bmp")
                outputCompare2.Save("D:\pixeltest\jc3.bmp")

            End Using

        Catch ex As Exception
            MessageBox.Show(ex.Message & vbCrLf & ex.StackTrace)
        End Try
    End Sub



    ''' <summary>
    ''' Converts to Format32bppArgb.
    ''' </summary>
    ''' <param name="original">The original.</param>
    ''' <returns></returns>
    Public Function ConvertToRGB(ByVal original As Bitmap) As Bitmap

        If original.PixelFormat = Imaging.PixelFormat.Format32bppArgb Then Return original

        Dim newImage As Bitmap = New Bitmap(original.Width, original.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution)

        Dim g As Graphics = Graphics.FromImage(newImage)
        g.DrawImageUnscaled(original, 0, 0)
        g.Dispose()

        Return newImage
    End Function