SHARE
TWEET

ImagePut #3 - Built-in vs. LockBits! vs. Graphics Context?

iseahound May 25th, 2020 2,665 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include ImageEqual.ahk
  2. ImagePut.gdiplusStartup()
  3.  
  4.  
  5. hBitmap := ImagePutHBitmap("xd.png")
  6.  
  7. ImagePutFile(from_hBitmap0(hBitmap), "0.png")
  8. ImagePutFile(from_hBitmap1(hBitmap), "1.png")
  9. ImagePutFile(from_hBitmap2(hBitmap), "2.png")
  10. if !ImageEqual("0.png", "1.png")
  11.    MsgBox % "0, 1"
  12. if !ImageEqual("0.png", "2.png")
  13.    MsgBox % "0, 2"
  14. if !ImageEqual("1.png", "2.png")
  15.    MsgBox % "1, 2"
  16.  
  17. errors := 0
  18.  
  19. Loop 10000 {
  20. QPC(1)
  21. pBitmap0 := from_hBitmap0(hBitmap)
  22. control += QPC()
  23.  
  24.  
  25. QPC(1)
  26. pBitmap1 := from_hBitmap1(hBitmap)
  27. old += QPC()
  28.  
  29.  
  30. QPC(1)
  31. pBitmap2 := from_hBitmap2(hBitmap)
  32. new += QPC()
  33.  
  34. if !ImageEqual(pBitmap0, pBitmap1) ;, pBitmap2)
  35.    errors+=1
  36.  
  37. ImagePut.DisposeImage(pBitmap0)
  38. ImagePut.DisposeImage(pBitmap1)
  39. ImagePut.DisposeImage(pBitmap2)
  40. }
  41.  
  42. if (old > new)
  43.    winner := "New Version wins by " old - new " and is " Abs(old - new)/new*100 "% faster."
  44. else
  45.    winner := "Old Version wins by " new - old " and is " Abs(old - new)/old*100 "% faster."
  46.  
  47. MsgBox % "Control:`t`t" control "`nOld Version:`t" old "`nNew Version:`t" new "`n" winner
  48. MsgBox % "Number of errors:`t" errors
  49. return
  50.  
  51. Esc:: ExitApp
  52.  
  53.  
  54. from_hBitmap0(ByRef image) {
  55.    ; This built-in version is 120% faster but ignores transparency.
  56.    DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", image, "ptr", 0, "ptr*", pBitmap)
  57.    return pBitmap
  58. }
  59.  
  60. from_hBitmap1(ByRef image) {
  61.    ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap
  62.    DllCall("GetObject"
  63.             ,    "ptr", image
  64.             ,    "int", VarSetCapacity(dib, 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize)
  65.             ,    "ptr", &dib) ; sizeof(DIBSECTION) = 84, 104
  66.       , width  := NumGet(dib, 4, "uint")
  67.       , height := NumGet(dib, 8, "uint")
  68.  
  69.    ; Create a handle to a device context and associate the image.
  70.    hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr")           ; Creates a memory DC compatible with the current screen.
  71.    obm := DllCall("SelectObject", "ptr", hdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context.
  72.  
  73.    ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB).
  74.    ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer.
  75.    cdc := DllCall("CreateCompatibleDC", "ptr", hdc, "ptr")
  76.    VarSetCapacity(bi, 40, 0)               ; sizeof(bi) = 40
  77.       , NumPut(      40, bi,  0,   "uint") ; Size
  78.       , NumPut(   width, bi,  4,   "uint") ; Width
  79.       , NumPut( -height, bi,  8,    "int") ; Height - Negative so (0, 0) is top-left.
  80.       , NumPut(       1, bi, 12, "ushort") ; Planes
  81.       , NumPut(      32, bi, 14, "ushort") ; BitCount / BitsPerPixel
  82.    hbm := DllCall("CreateDIBSection", "ptr", cdc, "ptr", &bi, "uint", 0
  83.             , "ptr*", pBits  ; pBits is the pointer to (top-down) pixel values.
  84.             , "ptr", 0, "uint", 0, "ptr")
  85.    ob2 := DllCall("SelectObject", "ptr", cdc, "ptr", hbm, "ptr")
  86.  
  87.    ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels.
  88.    DllCall("gdiplus\GdipCreateBitmapFromScan0"
  89.             , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap)
  90.  
  91.    ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB.
  92.    VarSetCapacity(Rect, 16, 0)              ; sizeof(Rect) = 16
  93.       , NumPut(  width, Rect,  8,   "uint") ; Width
  94.       , NumPut( height, Rect, 12,   "uint") ; Height
  95.    VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0)     ; sizeof(BitmapData) = 24, 32
  96.       , NumPut(     width, BitmapData,  0,   "uint") ; Width
  97.       , NumPut(    height, BitmapData,  4,   "uint") ; Height
  98.       , NumPut( 4 * width, BitmapData,  8,    "int") ; Stride
  99.       , NumPut(   0xE200B, BitmapData, 12,    "int") ; PixelFormat
  100.       , NumPut(     pBits, BitmapData, 16,    "ptr") ; Scan0
  101.  
  102.    ; Use LockBits to create a writable buffer that converts pARGB to ARGB.
  103.    DllCall("gdiplus\GdipBitmapLockBits"
  104.             ,    "ptr", pBitmap
  105.             ,    "ptr", &Rect
  106.             ,   "uint", 6            ; ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly
  107.             ,    "int", 0xE200B      ; Format32bppPArgb
  108.             ,    "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm.
  109.  
  110.    ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present.
  111.    DllCall("gdi32\BitBlt"
  112.             , "ptr", cdc, "int", 0, "int", 0, "int", width, "int", height
  113.             , "ptr", hdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY
  114.  
  115.    ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB.
  116.    DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData)
  117.  
  118.    ; Cleanup the buffer and device contexts.
  119.    DllCall("SelectObject", "ptr", cdc, "ptr", ob2)
  120.    DllCall("DeleteObject", "ptr", hbm)
  121.    DllCall("DeleteDC",     "ptr", cdc)
  122.    DllCall("SelectObject", "ptr", hdc, "ptr", obm)
  123.    DllCall("DeleteDC",     "ptr", hdc)
  124.  
  125.    return pBitmap
  126. }
  127.  
  128. from_hBitmap2(ByRef image) {
  129.    ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap
  130.    DllCall("GetObject"
  131.             ,    "ptr", image
  132.             ,    "int", VarSetCapacity(dib, 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize)
  133.             ,    "ptr", &dib) ; sizeof(DIBSECTION) = 84, 104
  134.       , width  := NumGet(dib, 4, "uint")
  135.       , height := NumGet(dib, 8, "uint")
  136.  
  137.    ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels.
  138.    DllCall("gdiplus\GdipCreateBitmapFromScan0"
  139.             , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap)
  140.    DllCall("gdiplus\GdipGetImageGraphicsContext", "ptr", pBitmap, "ptr*", pGraphics)
  141.    /*
  142.    ; Save original Graphics settings.
  143.    DllCall("gdiplus\GdipGetPixelOffsetMode",    "ptr",pGraphics, "int*",PixelOffsetMode) ; Default = 0; None = 3, 0?
  144.    DllCall("gdiplus\GdipGetCompositingMode",    "ptr",pGraphics, "int*",CompositingMode) ; default 0, SourceCopy = 1
  145.    DllCall("gdiplus\GdipGetCompositingQuality", "ptr",pGraphics, "int*",CompositingQuality)
  146.    DllCall("gdiplus\GdipGetSmoothingMode",      "ptr",pGraphics, "int*",SmoothingMode)
  147.    DllCall("gdiplus\GdipGetInterpolationMode",  "ptr",pGraphics, "int*",InterpolationMode)
  148.    MsgBox % PixelOffsetMode ", " CompositingMode ", " CompositingQuality ", " SmoothingMode ", " InterpolationMode
  149.    */
  150.    ;DllCall("gdiplus\GdipSetPixelOffsetMode",    "ptr",pGraphics, "int",3) ; Half pixel offset.
  151.    ;DllCall("gdiplus\GdipSetCompositingMode",    "ptr",pGraphics, "int",1) ; Overwrite/SourceCopy.
  152.  
  153.  
  154.    DllCall("gdiplus\GdipGetDC", "ptr", pGraphics, "ptr*", ddc)
  155.  
  156.    ; Create a handle to a device context and associate the image.
  157.    hdc := DllCall("CreateCompatibleDC", "ptr", ddc, "ptr")         ; Creates a memory DC compatible with the current screen.
  158.    obm := DllCall("SelectObject", "ptr", hdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context.
  159.  
  160.    ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present.
  161.    DllCall("gdi32\BitBlt"
  162.             , "ptr", ddc, "int", 0, "int", 0, "int", width, "int", height
  163.             , "ptr", hdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY
  164.  
  165.    ; Cleanup the buffer and device contexts.
  166.    DllCall("SelectObject", "ptr", hdc, "ptr", obm)
  167.    DllCall("DeleteDC",     "ptr", hdc)
  168.  
  169.    ; Release the graphics context and delete.
  170.    DllCall("gdiplus\GdipReleaseDC", "ptr", pGraphics, "ptr", ddc)
  171.    DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics)
  172.  
  173.    return pBitmap
  174. }
  175.  
  176. QPC( R := 0 ) {    ; By SKAN,  http://goo.gl/nf7O4G,  CD:01/Sep/2014 | MD:01/Sep/2014
  177.   Static P := 0,  F := 0,     Q := DllCall( "QueryPerformanceFrequency", "Int64P",F )
  178. Return ! DllCall( "QueryPerformanceCounter","Int64P",Q ) + ( R ? (P:=Q)/F : (Q-P)/F )
  179. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top