Lockbits

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Ich steig da jetzt grad nicht so durch...
    also ich möchte direkt auf meiner Form bestimmte Pixel schwarz einfärben, und das möglichst schnell...
    Hab bis jetzt gelesen, dass Lockbits sehr schnell sei..
    Ist Lockbits dafür das optimale, oder würdet ihr das anders lösen ?

    Und könnt jemand mal ein grobes Beispiel geben wie man bestimmte Pixel auf der Form möglichst effizient (schnell) mit Lockbits einfärben kann ?
    Was ich so über Lockbits finde ist mir dann doch zu viel...
    hey, lockbits ist für bitmaps. die langsame alternative ist die setpixel funtkion der bitmap. die schnellere aber auch kompliziertere alternative lockbits. sieh mal im showroom nach, es gibt dort eine fastBitmap lib. diese bietet auch die funktionen setpixel und getpixel, allerdings sind sie über lockbit realisiert und damit sehr schnell UND einfach zu handhaben!

    wenn du nur sehr wenige pixel schwarz färben musst kannst du das auch direkt mit GDI+ machen. ansonsten einfach mit setpixel auf eine bitmap zeichnen und diese dann mit GDI+ auf die Form klatschen^^

    EDIT: heißt doch nciht fastbitmap lib^^ [Beta] FastGraphicsLib 1.0.0.5
    wie schon gesagt: Lockbits ist eine Technick, Bitmap-Pixel zu bearbeiten, aber ein Form ist keine Bitmap.

    Wennde auffm Form Pixel gefärbt haben willst, musstese halt gefärbt hin-zeichen, nämlich im _Paint-Event, und sagichgleich: Nimm das Graphics-Objekt, was die Eventargs dir liefern - keines selbst erstellen!
    @ erfinderdesrades

    aus deinem post kann ich nicht direkt entnehmen wie du das realisieren würdest. um einzelne pixel mittels GDI+ auf einer form schwarz zu färben kann man meines wissens ja nur den weg über fillrectangle gehen, oder?

    ich habe mal ein kleinen test gemacht (mit der Stopwatch-Klasse), was schneller ist: FastgraphicsLib vs GDI+
    Bedingungen: ein Panel von 500x500 Pixeln soll "pixel für pixel" schwarz gefärbt werden. die GraphicsLib braucht dafür 17ms, die methode über .FillRectangle 975ms. Die FastGraphicsLib ist also mehr als 50 mal schneller!
    .Drawrectangle und .DrawLine sind übrigens noch langsamer!


    ich würde also die pixel mittels der Lib auf eine Bitmap zeichnen und diese dann im paint event mit GDI auf die form
    naja, die Anforderung, pixel einzeln zu färben, scheint mirja eh vollkommen unwahrscheinlich. Üblicherweise will man doch Figuren zeichnen, und das geht mitte Draw-Methoden des Graphics-Objects.
    Aber dazu müsstesich der TE äußern.

    Edit:
    EDIT: heißt doch nciht fastbitmap lib
    Habs mir jetzt mal angeguckt - es sind ausschließlich Methoden zur Bitmap-Manipulation drinne, auch .FromScreen() fällt da hinein - gibt sie doch "eine neue Instanz der Klasse mit einem Abbild des übergebenen Bildschirmbereiches als Bitmap-Objekt." zurück.

    fastBitmap wäre vlt. tatsächlich der bessere Name ;)

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

    also ich habe ein array vom typ boolean, und das soll schrittweise durchgegangen werden und bei true soll ein pixel auf der form, der die koordinaten wie auch im array hat, gefärbt werden...
    fastgraphicslib ist ja echt gut, ich lads mir gleich runter :)
    Hi
    Du könntest auch mit SetPiixel für gdi arbeiten:

    VB.NET-Quellcode

    1. <System.Runtime.InteropServices.DllImport("gdi32")> _
    2. Private Shared Function SetPixel(ByVal hdc As IntPtr, x As Integer, y As Integer, argb As Integer) As Integer
    3. End Function


    Den argb-Wert ermittelst du entweder aus Color.Black.ToArgb() oder indem du einfach die argbs verrechnest:
    argb = a Or (r << 8) Or (g << 16) Or (b << 24)

    r, g und b sollten als Integer vorliegen, weil sonst beim Bitshift der Rest einfach weggeschnitten wird.
    Aso, ganz vergessen: Das Handle auf den Gerätekontext ermittelst du über graphics.GetHdc() und musst du vor Abschluss mit graphics.ReleaseGraphics() freigeben.
    Wenn du mehrere Punkte setzen musst, wäre es vielleicht auch eine Überlegung wert, das ganze mit einem Puffer zu lösen:

    VB.NET-Quellcode

    1. Dim bufferedGraphics As BufferedGraphics = BufferedGraphicsManager.Current.Allocate(graphics, Me.ClientRectangle)
    2. 'auf das bufferedGraphis-Objekt Zeichnen...
    3. bufferedGraphics.Render()
    4. bufferedGraphics.Dispose


    Gruß
    ~blaze~

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

    @ ~blaze~

    ich habe deine SetPixel-variante für GDI unter gleichen bedingungen getestet: die FastGraphicsLib ist mehr als 20 mal schneller xD
    Immerhin hat man so aber eine, gegenüber der gdi+ .fillrectangle, doppeltsoschnelle lösung. Der Große nachteil ist, dass der ungültige bereich sich nciht von alleine nachzeichnet (wie das mit dem Puffer abläuft weiß ich nicht..) und man die grafik nicht so einfach abspeichern kann wie es mit einer bitmap geht..
    irgendwie versteh ich die fastgraphicslib nicht so recht...bin noch ganz neu im gebiet grafik ;)

    Also man muss eine Bitmap erstellen, die die Größe des Fensters hat...dann mit der Fastgraphicslib darauf rummalen, und dann per GDI die Bitmap auf die Form zeichnen, hab ich das richtig verstanden ? ich bekomms gerade nciht so hin...
    ich habe deine SetPixel-variante für GDI unter gleichen bedingungen getestet: die FastGraphicsLib ist mehr als 20 mal schneller xD

    Aber wenn du rechnest, was das zeichnen des Bitmaps im vergleich zur Verwendung von GDI direkt zu zeichnen rechnest, dann ist GDI+ schneller...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    bitmap mittels setpixel = sehr langsam, nicht getestet
    GDI-Fillrectangle Methode = 975ms
    GDI-Setpixel Variante von ~blaze~ = 400ms
    FastgraphicsLib mittels Locbits = 17ms

    am schnellsten ist also das zeichnen direkt auf eine bitmap, aber mit lockbits. Die fastgraphicslib bietet die funtkion setpixel mit dem lockbitssystem, sodass es wie gewohnt zu handhaben ist UND sehr schnell ist

    @ juli90

    genau so^^
    erstelle die bitmap in größe des fensters, erstelle eine instanz fastgraphics mittels fastgraphics.frombitmap (so oder so ähnlich müsste das da heißen)
    dann kannst du mittels fastgraphics.setpixel darauf rummzeichnen und mittels .unlock gibst du die lockbits frei, d.h. .bitmap enthält das fertige bild^^
    dieses dann mit gdi auf die form zeichnen (im paint-event!) und fertig
    am schnellsten ist also das zeichnen direkt auf eine bitmap, aber mit lockbits. Die fastgraphicslib bietet die funtkion setpixel mit dem lockbitssystem, sodass es wie gewohnt zu handhaben ist UND sehr schnell ist

    Das zeichnen direkt auf das Bitmap was du meinst und gemessen hast, ist nur das schreiben von ein paar Bytes im Speicher, wie gesagt, wenn du dann noch, die Zeit fürs zeichnen dazurechnest, sieht das gleich ganz anders aus...(Es sei denn es wird natürlich beim zeichnen viel gerechnet, dann ist auch ein Bitmap schneller, da es nur einmalig berechnet werden muss), aber dies ist hier ja nicht der Fall...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    so, ich veröffentliche mal hier mein testprogramm. ich habe die zeichenroutine komplett in einzelne subs ausgelagert, was heißt, dass der sub alles enthält- von deklarieren aller variablen bis hin zum zeichnen auf die form (die bitmaps werden mit GDI auf die form gezeichnet, der schritt entfällt logischerweise wenn direkt mit GDI gezeichnet wird). Ergebnis:

    GDI+ FillRectangle.........= 2029 ms
    GDI Setpixel.................= 376 ms
    Bitmap herkömmlich......=284 ms
    Bitmap FastGraphicsLib..= 28 ms


    @ jvbsl

    die fastgraphicslib, und damit lockbits, ist der testsieger^^
    die zeit zum zeichnen der bitmap ist in der messung berücksichtigt. wenn du mir nicht glaubst lade dir das testprogramm im dateianhang. Da kann man beim zeichnen zugucken und merkt auch ohne messung was schneller ist. GDI bleibt trotzdem langsam, es wird in der zeichenroutine nichts großartiges berechnet, lediglich in einer schleife .fillrectangle mit dem rectangle(x,y,1,1) gezeichnet.

    Für den, den es interessiert, hier die zeichenroutinen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. <System.Runtime.InteropServices.DllImport("gdi32")> _
    2. Private Shared Function SetPixel(ByVal hdc As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal argb As Integer) As Integer
    3. End Function
    4. Public Sub Zeichne_GDI_Setpixel(ByVal size As Point, ByVal e As Control)
    5. Dim tmpIntPtr As IntPtr = e.CreateGraphics.GetHdc
    6. Dim tmpArgb As Integer = (Color.Black).ToArgb
    7. For x = 0 To size.X - 1
    8. For y = 0 To size.Y - 1
    9. SetPixel(tmpIntPtr, x, y, tmpArgb)
    10. Next
    11. Next
    12. End Sub
    13. Public Sub Zeichne_GDI_FillRec(ByVal size As Point, ByVal e As Control)
    14. With e.CreateGraphics
    15. For x = 0 To size.X - 1
    16. For y = 0 To size.Y - 1
    17. .FillRectangle(Brushes.Black, x, y, 1, 1)
    18. Next
    19. Next
    20. End With
    21. End Sub
    22. Public Sub Zeichne_Bitmap(ByVal size As Point, ByVal e As Control)
    23. Dim tmp As New Bitmap(size.X, size.Y)
    24. For x = 0 To size.X - 1
    25. For y = 0 To size.Y - 1
    26. tmp.SetPixel(x, y, Color.Black)
    27. Next
    28. Next
    29. e.CreateGraphics.DrawImage(tmp, 0, 0)
    30. End Sub
    31. Public Sub Zeichne_BitmapFGL(ByVal size As Point, ByVal e As Control)
    32. Dim tmp As New Bitmap(size.X, size.Y)
    33. Dim fg As FastGraphics = FastGraphics.FromBitmap(tmp)
    34. For x = 0 To size.X - 1
    35. For y = 0 To size.Y - 1
    36. fg.SetPixel(x, y, Color.Black)
    37. Next
    38. Next
    39. fg.Unlock()
    40. e.CreateGraphics.DrawImage(tmp, 0, 0)
    41. End Sub
    Dateien
    • SpeedTest.rar

      (16,34 kB, 144 mal heruntergeladen, zuletzt: )

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

    Ehrlich mal, dafür brauchst du wirklich keine extra Anwendung schreiben. Der Mechanismus von der FastGraphicsLib ist NATÜRLICH schneller, als der Zugriff auf den Device-Context. Device Contexts sind auch anders aufgebaut und haben noch andere Routinen mit drin. Die Color-Struktur enthält folgende Daten:
    -name
    -argb
    -knowncolor
    -state
    Natürlich total sinnvoll... Deswegen dürfte SetPixel auch so lahm sein. Da es auch noch das Pixelformat berücksichtigt wird die Geschwindigkeit noch mal reduziert. Die FastGraphicsLib schreibt halt direkt an der Position (x, y), also im Bitmap an der Position
    (x + y * bitmap.Width) * (pixelFormatSize \ 8), wenn pixelFormatSize in Bits angegeben ist, wie bei System.Drawing.Bitmap.GetPixelFormatSize.
    Graphics.FillRectangle geht entweder IMMER in einer Schleife vor oder überprüft vorher, ob Width und Height gleich 1 sind. Anschließend verwendet es dem Anschein nach für jeden Pixel Alphablending, auch wenn das nicht mal notwendig wäre, wenn die Vordergrund-Farbe opak ist. Die Formel
    C_N = a_A * c_F + (1-a_A) * c_B
    bzw. für den Alphakanal
    a_N = a_A + (1-a_A) * a_B
    gibt bekanntlich die Berechnung für das Alphablending an. Diese Formel mit 4 bzw. 5 für den Alphawert oder 5 bzw. 6 Operationen pro Farbkanal ist natürlich aufwendiger, als ein einfacher Schreibvorgang, der durch das C_N auch noch dazukommt. Selbst wenn man die Routine optimiert, ist der Vorgang sehr langsam. Wenn man die Bitmap zeichnet und CompositingMode = Drawing2D.CompositingMode.SourceCopy setzt, geht es übrigens schneller. Dabei wird auch das Alphablending deaktiviert.
    Hast du auch eingerechnet, dass die Kompilierung der Methoden auch noch mal Zeit kostet?

    Gruß
    ~blaze~
    Ehrlich mal, dafür brauchst du wirklich keine extra Anwendung schreiben. Der Mechanismus von der FastGraphicsLib ist NATÜRLICH schneller, als der Zugriff auf den Device-Context.

    Aber nicht schneller als das direkte Zeichnen auf den DeviceContext, wenn es darum geht das Bitmap zu erzeugen zu befüllen und dieses anschließend auf den DC zu zeichnen...

    @FreakJNS: Ich will gar nicht wissen, was du mit dem FillRectangle gemacht hast...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---