CaptureToBitmap Farbtiefe Problem.

  • VB.NET

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von seby1302.

    CaptureToBitmap Farbtiefe Problem.

    Hallo an alle
    Ich habe ein kleines problem mit PixelFormat.Format32bppArgb

    VB.NET-Quellcode

    1. Dim WebBmp As Bitmap = CaptureToBitmap(webLoc.X, webLoc.Y, webSiz.Width, webSiz.Height)
    2. ' copy image to integer array
    3. Dim b(WebBmp.Width * WebBmp.Height - 1) As Integer
    4. Dim bd As BitmapData = WebBmp.LockBits(New Rectangle(Point.Empty, WebBmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
    5. Marshal.Copy(bd.Scan0, b, 0, b.Length)
    6. WebBmp.UnlockBits(bd)


    ich versuche verzweifelt die farbiefe zu ändern

    Und hätte gerne PixelFormat.Format24bppRgb

    Doch es läuft nur ab 32bpp
    Sobald ich weniger wie 32 versuche, kommt folgende fehler meldung

    Eine nicht behandelte Ausnahme des Typs "System.AccessViolationException" ist in mscorlib.dll aufgetreten.

    Zusätzliche Informationen: Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.



    Bitte um hilfe :)

    VB.NET-Quellcode

    1. Dim b(WebBmp.Width * WebBmp.Height - 1) As Integer

    Erstens: Array von mehreren Buffern erstellen
    Zweitens:
    Typischerweise sollte man Byte-Arrays für diesen Zweck verwenden. Ich weiß natürlich nicht, was Du mit den Integern machst. Ein Pixel würde hier 32 Bits, also 4 Bytes (nämlich A, R, G und B) benötigen, also genau einen Integer. Aber 24 Bits wären 3 Bytes, und es gibt keinen Ganzzahl-Datentyp, der 3 Bytes groß ist.
    Dann solltest Du das Erstellen des Byte-Arrays und LockBits umdrehen, denn die BitmapData-Klasse hat viele nützliche Properties (insbesondere Stride).
    Vergiss außerdem nicht, die Bitmap nach Gebrauch wieder zu disposen, damit der Speicher freigegeben wird.

    Hier ein Beispiel, wie es aussehen soll:

    VB.NET-Quellcode

    1. Dim Bytes As Byte()
    2. Using Bpm = CaptureToBitmap(...)
    3. Dim Bits = Bpm.LockBits(New Rectangle(0, 0, Bpm.Width, Bpm.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
    4. Bytes = New Byte(Bits.Stride * Bits.Height - 1) {}
    5. Marshal.Copy(Bits.Scan0, Bytes, 0, Bytes.Length)
    6. Bpm.UnlockBits(Bits) 'Wenn man ganz genau ist, würde man das noch in ein Finally packen, aber das lassen wir mal.
    7. End Using
    8. 'Hier mit Bytes arbeiten
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hallo Ok vielen dank das erklärt einiges.

    Jedoch weiß ich grad das ganze nicht umzu setzen.
    habe das jetzt so.

    VB.NET-Quellcode

    1. Dim X As Integer, Y As Integer
    2. Dim SightedFound As Boolean
    3. 'Sighted
    4. Dim SightedColor As Color = ColorTranslator.FromHtml("#8E221A")
    5. Dim SightedColorFound As Integer = SightedColor.ToArgb()
    6. ' get browser control location on screen
    7. Dim webLoc As Point = Me.WebBrowser3.PointToScreen(Me.WebBrowser3.Location)
    8. ' get browser size
    9. Dim webSiz As Size = Me.WebBrowser3.ClientSize
    10. ' take snap shot of browser
    11. Dim Bytes As Byte()
    12. Using Bpm = CaptureToBitmap(webLoc.X, webLoc.Y, webSiz.Width, webSiz.Height)
    13. Dim Bits = Bpm.LockBits(New Rectangle(0, 0, Bpm.Width, Bpm.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
    14. Bytes = New Byte(Bits.Stride * Bits.Height - 1) {}
    15. Marshal.Copy(Bits.Scan0, Bytes, 0, Bytes.Length)
    16. Bpm.UnlockBits(Bits) 'Wenn man ganz genau ist, würde man das noch in ein Finally packen, aber das lassen wir mal.
    17. End Using
    18. For i As Integer = 0 To Bytes.Length - 1
    19. If Bytes(i) = SightedColorFound Then
    20. X = i Mod bmp.Width
    21. Y = i \ bmp.Width
    22. SightedFound = True
    23. Exit For
    24. End If
    25. Next
    26. If SightedFound = True Then
    27. Do
    28. Windows.Forms.Cursor.Position = PointToScreen(New Point(X + webLoc.X, Y + webLoc.Y))
    29. mouse_event(MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, 0, 0, 0, IntPtr.Zero)
    30. sleep1(100)
    31. Loop While SightedFound = False
    32. Else
    33. ......Sighted nachricht
    34. End If
    35. bmp.Dispose()


    Bekomme jedoch volgende fehler
    Eine nicht behandelte Ausnahme des Typs "System.NullReferenceException" ist in test.exe aufgetreten.

    Zusätzliche Informationen: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.


    zeigt auf bmp.Dispose()

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „seby1302“ ()

    Keine fehler aber ich bekomme die meldung "Farbe nicht gefunden"

    VB.NET-Quellcode

    1. For i As Integer = 0 To Bytes.Length - 1
    2. If Bytes(i) = SightedColorFound Then
    3. X = i Mod bmp.Width
    4. Y = i \ bmp.Width
    5. SightedFound = True
    6. Exit For
    7. Else
    8. Label1.Text = "Farbe nicht gefunden"
    9. End If
    10. Next


    Und keine reaktion des maus zeiger, jedoch laggt alles, mehr wie vorher :(
    Könnte jedoch wegen fehlendes Dispose() sein?!

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „seby1302“ ()

    Ja, die Bytes beinhalten natürlich nur die einzelnen Subpixel.
    Das heißt: Jedes Pixel belegt 3 Bytes im Byte-Array (bei 24bpp).
    Verwende nicht oben SightedColor.ToArgb, sondern vergleiche R, G und B separat. Natürlich musst Du dann anders zählen:

    VB.NET-Quellcode

    1. For i = 0 To Bytes.Length - 1 Step 3
    2. If Bytes(i) = DieFarbe.R AndAlso Bytes(i + 1) = DieFarbe.G, etc. Then
    3. '...
    4. Next

    Es kann auch sein, dass die Farben andersrum im Array liegen, also dass Bytes(i) Blau ist, anstatt Rot.
    Um dann auf X und Y zu kommen, musst du i durch Width * 3 dividieren.
    Oder anders rum: Du verwendest zwei verschachtelte For-Schleifen:

    VB.NET-Quellcode

    1. For Y = 0 To Bpm.Height - 1
    2. For X = 0 To Bpm.Width - 1
    3. If Bytes(Y * Bpm.Width * 3 + X * 3) = DieFarbe.R AndAlso _
    4. Bytes(Y * Bpm.Width * 3 + X * 3 + 1) = DieFarbe.G, etc. Then
    5. '...
    6. Next
    7. Next

    Dann sind X und Y schon bekannt, dafür muss man bei der Indexierung mehr rechnen.

    Wenn das funktioniert, wie es soll, kannst Du folgende Verbesserungen vornehmen:
    1. Anstatt überall 3 fix in den Code zu schreiben, solltest Du es in eine Konstante auslagern, sodass Du, wenn Du mal 32bpp verwenden möchtest, nur eine Stelle ändern musst, anstatt überall im Code 3 durch 4 zu ersetzen.
    2. Wenn der zweite Code tatsächlich aufgrund der komplexeren Berechnung zu langsam ist, kannst Du ihn optimieren. Aber mach das erst, wenn Du ihn ausgiebig getestet hast.

    Edit:
    Ich weiß nicht, wo Du das bpm.Dispose hingeschrieben hast.
    So wie in Post #3 gezeigt bei Zeile 42 kann es nicht sein, außer Du verschweigst uns was. 1. wird die Bitmap automatisch durch das Verwenden des Using-Blocks verworfen. Man muss nicht selbst nochmal Dispose aufrufen. Und 2. kann der Code so garnicht kompilieren, denn außerhalb von Using gibt's die Variable der Bitmap nicht mehr. Diesbezüglich möchte ich auch hinweisen: Bpm.Height (und .Width) sind in meinem Code nur Platzhalter für die passenden Ausdrücke. Wo Du die herbekommst, ist Deine Entscheidung. Du kannst den Code natürlich in den Using-Block hineinschieben, wenn Du auf die Bitmap noch Zugriff brauchst.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Also das bmp.Dispose() steht bei mir gennau da wie aufm dem post 3.

    Das ganze ist im einem timer

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    Dim X As Integer, Y As Integer
    Dim SightedFound As Boolean

    'Sighted
    Dim SightedColor As Color = ColorTranslator.FromHtml("#8E221A")
    Dim SightedColorFound As Integer = SightedColor.ToArgb()
    etc......

    das was ich jedoch vergessen habe ist diese funktion

    VB.NET-Quellcode

    1. ' capture area as BMP
    2. Private Function CaptureToBitmap(ByVal X As Integer, ByVal Y As Integer, ByVal W As Integer, ByVal H As Integer) As Bitmap
    3. Dim img As New Bitmap(W, H)
    4. Using g = Graphics.FromImage(img)
    5. g.CopyFromScreen(New Point(X, Y), Point.Empty, New Size(W, H))
    6. End Using
    7. Return img
    8. End Function


    Hatte ich übersehen
    Dann musst Du noch irgendwo ein bmp deklariert haben, das Du nie verwendest. Vermutlich in der Klasse, in der der Code steht.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Damit meinst du wohl?

    VB.NET-Quellcode

    1. Dim bmp As Bitmap
    2. Dim g As Graphics
    3. Dim rect As Rectangle


    ich hab es jetzt zwahr geschafft das es mit 24 läuft, jedoch ruckelt alles gennau so wie vorher, und es ist immer noch viel zu langsam.

    Aber nun habe ich noch ein andres problem,
    was ich davor auch schon hatte.

    VB.NET-Quellcode

    1. ' capture area as BMP
    2. Private Function CaptureToBitmap(ByVal X As Integer, ByVal Y As Integer, ByVal W As Integer, ByVal H As Integer) As Bitmap
    3. Dim img As New Bitmap(W, H)
    4. Using g = Graphics.FromImage(img)
    5. g.CopyFromScreen(New Point(X, Y), Point.Empty, New Size(W, H))
    6. End Using
    7. Return img
    8. End Function


    Gibt mir nach, mal 1 min mal 10 min...
    fehler aus.

    Eine nicht behandelte Ausnahme des Typs "System.ArgumentException" ist in System.Drawing.dll aufgetreten.

    Zusätzliche Informationen: Ungültiger Parameter.


    Zeigt mal auf

    VB.NET-Quellcode

    1. Dim img As New Bitmap(W, H)

    Und mal widerum auf

    VB.NET-Quellcode

    1. g.CopyFromScreen(New Point(X, Y), Point.Empty, New Size(W, H))
    Verwendest du noch XP @ErfinderDesRades? Sicher wird der Gesamt Speicher im Reiter Performance ganz unten in % angezeigt. Zumindest ab Win 7..

    //Edit

    Eine nicht behandelte Ausnahme des Typs "System.ArgumentException" ist in System.Drawing.dll aufgetreten.Zusätzliche Informationen: Ungültiger Parameter.

    Dim img As New Bitmap(W, H)

    In diesen Fällen dürfte W oder H negativ sein.
    Das ist meine Signatur und sie wird wunderbar sein!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Mono“ ()