SHARE
TWEET

ImagePut #4 - isBitmapEqual: Negative Stride?

iseahound May 26th, 2020 1,653 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include ImagePut.ahk
  2. ImagePut.gdiplusStartup()
  3.  
  4. pBitmap1 := ImagePut("Bitmap", "xd.png")
  5. pBitmap2 := ImagePut("Bitmap", "x2.png")
  6. pBitmap3 := ImagePut("Bitmap", "x3.png")
  7. pBitmap4 := ImagePut("Bitmap", "x4.png")
  8.  
  9. errors := 0
  10.  
  11. Loop 100000 {
  12.  
  13. QPC(1)
  14. isBitmapEqual1(pBitmap1, pBitmap2)
  15. old += QPC()
  16.  
  17.  
  18. QPC(1)
  19. isBitmapEqual2(pBitmap1, pBitmap2)
  20. new += QPC()
  21.  
  22. }
  23.  
  24. ImagePut.DisposeImage(pBitmap1)
  25. ImagePut.DisposeImage(pBitmap2)
  26. ImagePut.DisposeImage(pBitmap3)
  27. ImagePut.DisposeImage(pBitmap4)
  28.  
  29. if (old > new)
  30.    winner := "New Version wins by " old - new " and is " Abs(old - new)/new*100 "% faster."
  31. else
  32.    winner := "Old Version wins by " new - old " and is " Abs(old - new)/old*100 "% faster."
  33.  
  34. MsgBox % "Control:`t`t" control "`nOld Version:`t" old "`nNew Version:`t" new "`n" winner
  35. MsgBox % "Number of errors:`t" errors
  36. return
  37.  
  38. Esc:: ExitApp
  39.  
  40.    isBitmapEqual1(ByRef pBitmap1, ByRef pBitmap2, Format := 0x26200A) {
  41.       ; Make sure both bitmaps are valid pointers.
  42.       if !(pBitmap1 && pBitmap2)
  43.          return false
  44.  
  45.       ; Check if pointers are identical.
  46.       if (pBitmap1 == pBitmap2)
  47.          return true
  48.  
  49.       ; The two bitmaps must be the same size.
  50.       DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", Width1)
  51.       DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", Width2)
  52.       DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", Height1)
  53.       DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", Height2)
  54.  
  55.       ; Match bitmap dimensions.
  56.       if (Width1 != Width2 || Height1 != Height2)
  57.          return false
  58.  
  59.       ; Create a RECT with the width and height and two empty BitmapData.
  60.       VarSetCapacity(Rect, 16, 0)                    ; sizeof(Rect) = 16
  61.          , NumPut(  Width1, Rect,  8,   "uint")      ; Width
  62.          , NumPut( Height1, Rect, 12,   "uint")      ; Height
  63.       VarSetCapacity(BitmapData1, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32
  64.       VarSetCapacity(BitmapData2, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32
  65.  
  66.       ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat.
  67.       DllCall("gdiplus\GdipBitmapLockBits"
  68.                ,    "ptr", pBitmap1
  69.                ,    "ptr", &Rect
  70.                ,   "uint", 1            ; ImageLockMode.ReadOnly
  71.                ,    "int", Format       ; Format32bppArgb is fast.
  72.                ,    "ptr", &BitmapData1)
  73.       DllCall("gdiplus\GdipBitmapLockBits"
  74.                ,    "ptr", pBitmap2
  75.                ,    "ptr", &Rect
  76.                ,   "uint", 1            ; ImageLockMode.ReadOnly
  77.                ,    "int", Format       ; Format32bppArgb is fast.
  78.                ,    "ptr", &BitmapData2)
  79.  
  80.       ; Get Stride (number of bytes per horizontal line) and two pointers.
  81.       Stride := NumGet(BitmapData1,  8, "int")
  82.       Scan01 := NumGet(BitmapData1, 16, "ptr")
  83.       Scan02 := NumGet(BitmapData2, 16, "ptr")
  84.  
  85.       ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte.
  86.       size := Stride * Height1
  87.       byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan01+0, "ptr", Scan02+0, "uptr", size, "uptr")
  88.  
  89.       ; Cleanup
  90.       DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap1, "ptr", &BitmapData1)
  91.       DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap2, "ptr", &BitmapData2)
  92.       return (byte == size) ? true : false
  93.    }
  94.  
  95.  
  96.    isBitmapEqual2(ByRef pBitmap1, ByRef pBitmap2, Format := 0x26200A) {
  97.       ; Make sure both bitmaps are valid pointers.
  98.       if !(pBitmap1 && pBitmap2)
  99.          return false
  100.  
  101.       ; Check if pointers are identical.
  102.       if (pBitmap1 == pBitmap2)
  103.          return true
  104.  
  105.       ; The two bitmaps must be the same size.
  106.       DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", Width1)
  107.       DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", Width2)
  108.       DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", Height1)
  109.       DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", Height2)
  110.  
  111.       ; Match bitmap dimensions.
  112.       if (Width1 != Width2 || Height1 != Height2)
  113.          return false
  114.  
  115.       ; Create a RECT with the width and height and two empty BitmapData.
  116.       VarSetCapacity(Rect, 16, 0)                    ; sizeof(Rect) = 16
  117.          , NumPut(  Width1, Rect,  8,   "uint")      ; Width
  118.          , NumPut( Height1, Rect, 12,   "uint")      ; Height
  119.  
  120.       ; Do this twice.
  121.       while ((i++:=i?i:0) < 2) { ; for(int i = 0; i < 2; i++)
  122.  
  123.          ; Create a BitmapData structure.
  124.          VarSetCapacity(BitmapData%i%, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32
  125.  
  126.          ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat.
  127.          DllCall("gdiplus\GdipBitmapLockBits"
  128.                   ,    "ptr", pBitmap%i%
  129.                   ,    "ptr", &Rect
  130.                   ,   "uint", 1            ; ImageLockMode.ReadOnly
  131.                   ,    "int", Format       ; Format32bppArgb is fast.
  132.                   ,    "ptr", &BitmapData%i%)
  133.  
  134.          ; Get Stride (number of bytes per horizontal line).
  135.          Stride%i% := NumGet(BitmapData%i%,  8, "int")
  136.  
  137.          ; If the Stride is negative, clone the image to make it top-down; redo the loop.
  138.          if (Stride%i% < 0) {
  139.             DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", pBitmapClone)
  140.             DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap%i%) ; Permanently deletes.
  141.             pBitmap%i% := pBitmapClone
  142.             i--
  143.          }
  144.  
  145.          ; Get Scan0 (top-left first pixel)
  146.          Scan0%i%  := NumGet(BitmapData%i%, 16, "ptr")
  147.       }
  148.  
  149.       ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte.
  150.       size := Stride1 * Height1
  151.       byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan01+0, "ptr", Scan02+0, "uptr", size, "uptr")
  152.  
  153.       ; Cleanup
  154.       DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap1, "ptr", &BitmapData1)
  155.       DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap2, "ptr", &BitmapData2)
  156.       return (byte == size) ? true : false
  157.    }
  158.  
  159. QPC( R := 0 ) {    ; By SKAN,  http://goo.gl/nf7O4G,  CD:01/Sep/2014 | MD:01/Sep/2014
  160.   Static P := 0,  F := 0,     Q := DllCall( "QueryPerformanceFrequency", "Int64P",F )
  161. Return ! DllCall( "QueryPerformanceCounter","Int64P",Q ) + ( R ? (P:=Q)/F : (Q-P)/F )
  162. }
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