Results 1 to 21 of 21

Thread: Writing to a device context, blitting to a picturebox

  1. #1

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Writing to a device context, blitting to a picturebox

    Would it be faster to draw lines on a device context rather than a visible picturebox?

    And if so, (that would be splendid), would one then use the BltBit API function to copy the image to the picturebox?

  2. #2
    Addicted Member Geoff Gunson's Avatar
    Join Date
    Jun 1999
    Posts
    241
    Only theorising but wouldn't that mean twice as much work, firstly the calls to draw to the DC then a copy from one DC to another??

    BITBLT to a picture box is supposed to be the fastest graffix method, except for maybe directX.

    It just seems to be an abstraction to me.

    G

  3. #3

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    Well it comes down to is this:

    You may draw 5,000,000 lines in a loop to the picturebox

    versus

    Drawing 5,000,000 lines in memory, and blitting that all at once to a picturebox.....

    Which is faster? (I haven't work with bltbit yet, so I can't easily test it out)

    Here's my sample code (the important stuff in bold) so far for a form with a picturebox1 and a button (command1):
    VB Code:
    1. Option Explicit
    2. 'draws line from current position to point passsed API
    3. Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
    4. 'moves to new drawing position API
    5. Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
    6. 'determines performance of execution for testing purposes only
    7. Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
    8. 'allows us to create a pen of certain thickness and color
    9. Private Declare Function CreatePen Lib "gdi32.dll" (ByVal fnPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
    10. 'necessary to delete pen created with above API function so we don't have memory leaks
    11. Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
    12. 'selects our newly created pen or our old pen
    13. Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
    14. Private Declare Function LockWindowUpdate Lib "user32" (ByVal hWnd As Long) As Long
    15. Private Type mapLineType
    16.     XPosStart As Single
    17.     YPosStart As Single
    18.     XPosEnd As Single
    19.     YPosEnd As Single
    20.     Colour As Long
    21.     Thickness As Single
    22. End Type
    23. Private mapLine(500000) As mapLineType
    24. 'below type is needed for LineTo and MoveEx API functions
    25. Private Type POINTAPI
    26.         x As Long
    27.         y As Long
    28. End Type
    29.  
    30.  
    31.  
    32.  
    33.  
    34. Private Sub Command1_Click()
    35. Dim mypointapi As POINTAPI
    36. Dim hPen As Long  ' handle to the pen created API
    37. Dim hOldPen As Long  ' handle to Picture1's previously selected pen API
    38. Dim retval As Long  ' dummy api function return value API
    39. Dim i As Long
    40. 'needed for conversion from twips to pixels with API functions
    41. Dim picture1width As Long
    42. Dim picture1height As Long
    43. Dim flp As Long
    44. 'performance measuring variable
    45. Dim start As Long
    46. 'stores the h/w of the picturebox for use with API functions
    47. picture1width = (Picture1.Width / Screen.TwipsPerPixelX)
    48. picture1height = (Picture1.Height / Screen.TwipsPerPixelY)
    49. 'make some RANDOM DATA
    50. For i = 1 To 500000
    51. mapLine(i).XPosStart = Int(picture1width * Rnd)
    52. mapLine(i).YPosStart = Int(picture1height * Rnd)
    53. mapLine(i).XPosEnd = Int(picture1width * Rnd)
    54. mapLine(i).YPosEnd = Int(picture1height * Rnd)
    55. mapLine(i).Colour = Int(10000 * Rnd + 1)
    56. mapLine(i).Thickness = Int(1 * Rnd + 1)
    57. Next
    58. 'save the random data
    59. Open ("C:\testfile.tst") For Binary As #1
    60. Put #1, 1, mapLine
    61. Close #1
    62. 'Begin load
    63. start = GetTickCount
    64. Open ("C:\testfile.tst") For Binary As #1
    65. Get #1, 1, mapLine
    66. Close #1
    67. Debug.Print "loaded in : " & (GetTickCount - start) / 1000 & " seconds"
    68.  
    69. 'being draw
    70. start = GetTickCount
    71.  
    72. [b]
    73. ' Draw the rectangle filled using the solid yellow brush
    74.     flp = Picture1.hdc
    75.     LockWindowUpdate (flp)
    76.    
    77.     ' Stores pciture1's default brush so we can restore it after our new pen is deleted
    78.     hOldPen = SelectObject(flp, hPen)
    79.    
    80.     For i = 1 To 500000
    81.     'create a pen based on passed thickness and color
    82.     hPen = CreatePen(0, mapLine(i).Thickness, mapLine(i).Colour)
    83.     'select the pen
    84.     retval = SelectObject(flp, hPen)
    85.     'move to starting point
    86.     retval = MoveToEx(ByVal flp, mapLine(i).XPosStart, mapLine(i).YPosStart, mypointapi)
    87.     'draw line to ending point
    88.     retval = LineTo(ByVal flp, ByVal mapLine(i).XPosEnd, ByVal mapLine(i).YPosEnd)
    89.     ' Delete the pen we created to free up resources.
    90.     retval = DeleteObject(hPen)
    91.     ' Select the old pen for use by picture1
    92.     Next
    93.     retval = SelectObject(flp, hOldPen)
    94.     LockWindowUpdate (0)
    95.     Picture1.Refresh[/b]
    96.  
    97.  
    98. Debug.Print "Drawn in :" & (GetTickCount - start) / 1000 & " seconds"
    99. End Sub
    Last edited by nemaroller; Sep 20th, 2002 at 10:19 AM.

  4. #4
    Addicted Member Geoff Gunson's Avatar
    Join Date
    Jun 1999
    Posts
    241
    Well the reason I ask is BITBLT uses DC's, thats how it works, if you control the refresh IE draw all the lines to the picture box and just do 1 refresh then it should work out quicker.

    BITBLT Bit BLock Transfer, its only real function is to copy memory anyway. It is down to the control to render the screen.

    G

  5. #5

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    Well, if you run the above code and comment out the LineTO method, it processes the loop in 1.2 seconds on a 1.5ghz machine versus 6.9 seconds if you don't comment out the LineTO method.

    I imagine the Picturebox control would draw faster if it simply was given the whole array at once, instead of looping through a series of LineTO's...

    So, how do I use LineTo to a device context, then bitblt that to a picturebox. Then I can test which method is faster, or if it even makes a difference.

  6. #6

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    This is what I have come up with... but the PictureBox doesn't display the lines...

    VB Code:
    1. p1hdc = Picture1.hdc
    2. flp = CreateCompatibleDC(p1hdc)
    3.  
    4. ' Draw the lines
    5.    
    6.            
    7.     For i = 1 To 500000
    8.     'create a pen based on passed thickness and color
    9.     hPen = CreatePen(0, mapLine(i).Thickness, mapLine(i).Colour)
    10.     'select the pen
    11.     retval = SelectObject(flp, hPen)
    12.     'move to starting point
    13.     retval = MoveToEx(ByVal flp, mapLine(i).XPosStart, mapLine(i).YPosStart, mypointapi)
    14.     'draw line to ending point
    15.     retval = LineTo(ByVal flp, ByVal mapLine(i).XPosEnd, ByVal mapLine(i).YPosEnd)
    16.     ' Delete the pen we created to free up resources.
    17.     retval = DeleteObject(hPen)
    18.    
    19.     Next
    20.  
    21.     'assign Flp to picturebox1
    22.     retval = BitBlt(p1hdc, 0, 0, picture1width, picture1height, flp, 0, 0, vbSrcCopy)
    23.     'delete created DC
    24.     DeleteDC (flp)

  7. #7
    Addicted Member Geoff Gunson's Avatar
    Join Date
    Jun 1999
    Posts
    241
    I haven't done this part before but I think you might be able to use createdevicecontext

    http://216.26.168.92/vbapi/ref/c/createdc.html

    However it looks as if it needs an object in the first place

    G

  8. #8
    Addicted Member Geoff Gunson's Avatar
    Join Date
    Jun 1999
    Posts
    241
    Check the autorefresh property of the picturebox, make sure its false and call the picture box refresh sub after the BitBlt

    G

  9. #9

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    That unfortunately didn't do it....

    Any suggestions from anyone?

  10. #10

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    bumpity bump

  11. #11

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    heave

  12. #12

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    ho

  13. #13

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    what no one has attempted this before?

  14. #14

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    I know you're out there....

  15. #15

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    one more time..

  16. #16
    Fanatic Member
    Join Date
    Jun 2001
    Posts
    521
    I'm actually curious about this as well... have you tried the CreateDC/CreateCompatibleDC API? From MSDN, on the CreateCompatibleDC function:
    A memory DC exists only in memory. When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC. To select a bitmap into a DC, use the CreateCompatibleBitmap function, specifying the height, width, and color organization required.

  17. #17

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    Thanks Victor, with ur help, I implemented a CreateCompatibleBitmap.... and proved that writing to a memory device context was not any appreciably faster than writing directly to a picutrebox.

  18. #18
    Lively Member
    Join Date
    Sep 2002
    Posts
    89
    Drawing to a memory DC is going to be MUCH faster than drawing to the picture boxes DC or using the Line and Paint methods of the picture box.

    Depending on how much actual drawing you do, I would recommend almost ALWAYS using the DC. The single biggest advantage is that it is pretty much flicker free.

    So, create a compatible DC based on the picture box DC, use the API drawing functions to do waht you want, then flip the memory DC onto the picture box DC using BitBlt.

    To get you going, here's some sample code for creating, painting and destroying a memory DC:
    VB Code:
    1. Public Sub CreateDeviceContext(phSourceDC As Long, pWidth As Long, pHeight As Long, _
    2.                                 ByRef phBufferDC As Long, ByRef phBitmap As Long, _
    3.                                 ByRef phOldBitmap As Long)
    4.  
    5.     'Creates a matching device context
    6.     'based on the source context. Passes
    7.     'out the handle to the device context
    8.     'and the handle to the bitmap that is
    9.     'in the device context
    10.    
    11.     'Create the device context
    12.     phBufferDC = CreateCompatibleDC(phSourceDC)
    13.     'Create a matching bitmap
    14.     phBitmap = CreateCompatibleBitmap(phSourceDC, pWidth, pHeight)
    15.     'Copy the bitmap into the device context
    16.     phOldBitmap = SelectObject(phBufferDC, phBitmap)
    17.    
    18. End Sub
    19.  
    20. Public Sub DeleteDeviceContext(phBufferDC As Long, phBitmap As Long, _
    21.                                 phOldBitmap As Long)
    22.  
    23.     'Cleans up the device contexts and bitmaps
    24.     'that have been used to draw on.
    25.    
    26.     'Copy the old bitmap back into the device context
    27.     phBitmap = SelectObject(phBufferDC, phOldBitmap)
    28.     'Delete the bitmap
    29.     DeleteObject phBitmap
    30.     'Delete the device context
    31.     DeleteDC phBufferDC
    32.    
    33. End Sub
    34.  
    35. Public Sub PaintBufferToScreen(phDestDC As Long, phBufferDC As Long, _
    36.                                pWidth As Long, pHeight As Long)
    37.                                
    38.     'Copies the contents of the graphics buffer
    39.     'to the destination device context (generally
    40.     'the user controls DC)
    41.     BitBlt phDestDC, 0, 0, pWidth, pHeight, phBufferDC, 0, 0, SRCCOPY
    42.  
    43. End Sub

    You'll have to get the API declarations, but it's pretty easy to use:

    VB Code:
    1. Dim lhBufferDC as Long
    2. Dim lhBitmap as Long
    3. Dim lhOldBitmap as Long
    4.  
    5. 'Create the memory DC
    6. CreateDeviceContext Picture1.hDC, Picture1.ScaleWidth, Picture1.ScaleHeight, lhBufferDC, lhBitmap, lhOldBitmap
    7.  
    8. 'Do all you drawing against the DC in lhBufferDC
    9.  
    10. 'Copy back to the Picture box
    11. PaintBufferToScreen Picture1.hDC, lhBufferDC, Picture1.ScaleWidth, Picture1.ScaleHeight
    12.  
    13. 'Clean up
    14. DeleteDeviceContext lhBufferDC, lhBitmap, lhOldBitmap

    Just remember that when you use a memory DC< you MUST clean up (resotre old bitmaps, brushes, pens etc) otherwise you will eventually run out of device handles and everything will go haywire

    - gaffa

  19. #19

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    That's what I thought too Gaffa, but when I implemented a Blitting version of the program, it still took the same amount of time (just ever so slightly less 6.8 vs 7.0) to draw 500,000 lines..

    From what you posted, my code seems in order... so I guess it does not make a difference. (I had used API lineTo MoveEX and passing the picture1.hwnd as a parameter before) The relative part is in bold.

    VB Code:
    1. Option Explicit
    2. 'draws line from current position to point passsed API
    3. Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
    4. 'moves to new drawing position API
    5. Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
    6. 'determines performance of execution for testing purposes only
    7. Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
    8. 'allows us to create a pen of certain thickness and color
    9. Private Declare Function CreatePen Lib "gdi32.dll" (ByVal fnPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
    10. 'necessary to delete pen created with above API function so we don't have memory leaks
    11. Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
    12. 'selects our newly created pen or our old pen
    13. Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
    14.  
    15. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
    16. Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
    17. Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
    18. ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, _
    19. ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
    20.  
    21. Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
    22.     (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
    23.  
    24. Private Type mapLineType
    25.     XPosStart As Single
    26.     YPosStart As Single
    27.     XPosEnd As Single
    28.     YPosEnd As Single
    29.     Colour As Long
    30.     Thickness As Single
    31. End Type
    32. Private mapLine(500000) As mapLineType
    33. 'below type is needed for LineTo and MoveEx API functions
    34. Private Type POINTAPI
    35.         x As Long
    36.         y As Long
    37. End Type
    38.  
    39.  
    40.  
    41.  
    42.  
    43. Private Sub Command1_Click()
    44. Dim mypointapi As POINTAPI
    45. Dim hPen As Long  ' handle to the pen created API
    46. Dim hOldPen As Long  ' handle to Picture1's previously selected pen API
    47. Dim retval As Long  ' dummy api function return value API
    48. Dim i As Long
    49. 'needed for conversion from twips to pixels with API functions
    50. Dim picture1width As Long
    51. Dim picture1height As Long
    52. Dim p1hdc As Long
    53. Dim flp As Long
    54. Dim lBMP As Long
    55. 'performance measuring variable
    56. Dim start As Long
    57.  
    58. picture1width = (Picture1.Width / Screen.TwipsPerPixelX)
    59. picture1height = (Picture1.Height / Screen.TwipsPerPixelY)
    60. 'make some RANDOM DATA
    61. For i = 1 To 500000
    62. mapLine(i).XPosStart = Int(picture1width * Rnd)
    63. mapLine(i).YPosStart = Int(picture1height * Rnd)
    64. mapLine(i).XPosEnd = Int(picture1width * Rnd)
    65. mapLine(i).YPosEnd = Int(picture1height * Rnd)
    66. mapLine(i).Colour = Int(10000 * Rnd + 1)
    67. mapLine(i).Thickness = Int(1 * Rnd + 1)
    68. Next
    69. Open ("C:\testfile.tst") For Binary As #1
    70. Put #1, 1, mapLine
    71. Close #1
    72. 'Begin load and draw
    73. start = GetTickCount
    74. Open ("C:\testfile.tst") For Binary As #1
    75. Get #1, 1, mapLine
    76. Close #1
    77. Debug.Print "loaded in : " & (GetTickCount - start) / 1000 & " seconds"
    78.  
    79. start = GetTickCount
    80.  
    81.  
    82.  
    83. [b]
    84. p1hdc = Picture1.hdc
    85. lBMP = CreateCompatibleBitmap(Picture1.hdc, picture1width, picture1height)
    86.  
    87. flp = CreateCompatibleDC(p1hdc)
    88. Call SelectObject(flp, lBMP)
    89. ' Draw
    90.    
    91.      For i = 1 To 500000
    92.     'create a pen based on passed thickness and color
    93.     hPen = CreatePen(0, mapLine(i).Thickness, mapLine(i).Colour)
    94.     'select the pen
    95.     retval = SelectObject(flp, hPen)
    96.     'move to starting point
    97.     retval = MoveToEx(ByVal flp, mapLine(i).XPosStart, mapLine(i).YPosStart, mypointapi)
    98.     'draw line to ending point
    99.     retval = LineTo(ByVal flp, ByVal mapLine(i).XPosEnd, ByVal mapLine(i).YPosEnd)
    100.     ' Delete the pen we created to free up resources.
    101.     retval = DeleteObject(hPen)
    102.     DoEvents
    103.     Next
    104.     retval = SelectObject(flp, hOldPen)
    105.     'assign Flp to picturebox1
    106.     BitBlt p1hdc, 0, 0, picture1width, picture1height, flp, 0, 0, vbSrcCopy
    107.     'delete created DC and compatible bitmap
    108.     DeleteDC (flp)
    109.     Call DeleteObject(lBMP)
    110.    
    111.     Picture1.Refresh[/b]
    112.  
    113.  
    114. Debug.Print "Drawn in :" & (GetTickCount - start) / 1000 & " seconds"
    115. End Sub

  20. #20
    Lively Member
    Join Date
    Sep 2002
    Posts
    89
    Yeah, it takes about 5 seconds on my machine (about 2.5 if I use a single Pen handle instead of creationg and destroying one each time)

    I haven't tested the line method in the PictureBox...

    All the API drawing stuff I've done (and I write a lot of owner drawn user controls) , I've always used the memory DC (double buffering) approach, cos it IS faster than anything else I've tried. Admittedly, I'm not drawing 500000 lines in a box - generally I draw a lot of boxes and text etc...

    So I guess it's what ever suits...

    - gaffa

  21. #21

    Thread Starter
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704
    Well, this whole thing developed out of a question another forum user was asking.... on loading a 100mb file containing x,y coordinates and line thickness and color. The file was generated from a sorta CAD program used by municipalities or utilities to visualize a whole city and the pipes and streets, etc... we tackled the loading of the data aspect, but the drawing was another issue. And he realized, there was not just 500,000 lines, but 5,000,000 lines...CAD program output JPEG :http://www.vbforums.com/attachment.p...postid=1171042

    thread:
    http://www.vbforums.com/showthread.p...hreadid=198679

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width