Zavier Posted March 2, 2020 Share Posted March 2, 2020 Hello all, I have this code found somewhere, it compares 2 images: Functions: expandcollapse popupFunc _CompareImages($ciImageOne, $ciImageTwo) _GDIPlus_Startup() $fname1 = $ciImageOne If $fname1 = "" Then Exit $fname2 = $ciImageTwo If $fname2="" Then Exit $bm1 = _GDIPlus_ImageLoadFromFile($fname1) $bm2 = _GDIPlus_ImageLoadFromFile($fname2) ; MsgBox(0, "bm1==bm2", CompareBitmaps($bm1, $bm2)) Return CompareBitmaps($bm1, $bm2) _GDIPlus_ImageDispose($bm1) _GDIPlus_ImageDispose($bm2) _GDIPlus_Shutdown() EndFunc Func CompareBitmaps($bm1, $bm2) $Bm1W = _GDIPlus_ImageGetWidth($bm1) $Bm1H = _GDIPlus_ImageGetHeight($bm1) $BitmapData1 = _GDIPlus_BitmapLockBits($bm1, 0, 0, $Bm1W, $Bm1H, $GDIP_ILMREAD, $GDIP_PXF32RGB) $Stride = DllStructGetData($BitmapData1, "Stride") $Scan0 = DllStructGetData($BitmapData1, "Scan0") $ptr1 = $Scan0 $size1 = ($Bm1H - 1) * $Stride + ($Bm1W - 1) * 4 $Bm2W = _GDIPlus_ImageGetWidth($bm2) $Bm2H = _GDIPlus_ImageGetHeight($bm2) $BitmapData2 = _GDIPlus_BitmapLockBits($bm2, 0, 0, $Bm2W, $Bm2H, $GDIP_ILMREAD, $GDIP_PXF32RGB) $Stride = DllStructGetData($BitmapData2, "Stride") $Scan0 = DllStructGetData($BitmapData2, "Scan0") $ptr2 = $Scan0 $size2 = ($Bm2H - 1) * $Stride + ($Bm2W - 1) * 4 $smallest = $size1 If $size2 < $smallest Then $smallest = $size2 $call = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $ptr1, "ptr", $ptr2, "int", $smallest) _GDIPlus_BitmapUnlockBits($bm1, $BitmapData1) _GDIPlus_BitmapUnlockBits($bm2, $BitmapData2) Return $call[0]=0 EndFunc Call the function example: ; Define the two images (They can be different file formats) $img1 = "Image1.jpg" $img2 = "Image2.jpg" ; Compare the two images $duplicateCheck = _CompareImages($img1, $img2) MsgBox(0,"Is Duplicate?", $duplicateCheck) It works like charm, the only problem is that once images are loaded to compare, they cannot be deleted even if you don't need to call the function no more, the only way to delete them is exiting the script. So my question is, is there any way to unload the images from the compare function so the same script can delete them after compare? Thank you in advance Link to comment Share on other sites More sharing options...
Musashi Posted March 2, 2020 Share Posted March 2, 2020 As far as I can see, the function _CompareImages calls Return before a dispose has taken place. Try : Func _CompareImages($ciImageOne, $ciImageTwo) Local $bReturn _GDIPlus_Startup() $fname1 = $ciImageOne If $fname1 = "" Then Exit $fname2 = $ciImageTwo If $fname2="" Then Exit $bm1 = _GDIPlus_ImageLoadFromFile($fname1) $bm2 = _GDIPlus_ImageLoadFromFile($fname2) ; MsgBox(0, "bm1==bm2", CompareBitmaps($bm1, $bm2)) $bReturn = CompareBitmaps($bm1, $bm2) _GDIPlus_ImageDispose($bm1) _GDIPlus_ImageDispose($bm2) _GDIPlus_Shutdown() Return $bReturn EndFunc "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
Nine Posted March 2, 2020 Share Posted March 2, 2020 Why do you call "memcmp" if the files are not equal in size ? Isn't that enough to say that the files are different ? “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Musashi Posted March 2, 2020 Share Posted March 2, 2020 (edited) On 3/2/2020 at 2:29 PM, Nine said: Why do you (Zavier) call "memcmp" if the files are not equal in size ? Good point . @Zavier : Here a variant (Original from @UEZ - shortened by me), which checks before the actual comparison with "memcmp", if height and width match. expandcollapse popup#include <GDIPlus.au3> Global $g_hImg1, $g_hImg2, $g_bResult _GDIPlus_Startup() $g_hImg1 = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\Pic1.jpg") $g_hImg2 = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\Pic2.jpg") ; or Pic3.jpg (different size) $g_bResult = _GDIPlus_ImageCompare($g_hImg1, $g_hImg2) ConsoleWrite("+ Result=" & $g_bResult & " Error=" & @error & " Time (Sec.) =" & @extended & @CRLF) _GDIPlus_ImageDispose($g_hImg1) _GDIPlus_ImageDispose($g_hImg2) _GDIPlus_Shutdown() Func _GDIPlus_ImageCompare($hImage1, $hImage2) Local Const $iW = _GDIPlus_ImageGetWidth($hImage1), $iH = _GDIPlus_ImageGetHeight($hImage1) If ($iW <> _GDIPlus_ImageGetWidth($hImage2)) Then Return SetError(1, 0, False) If ($iH <> _GDIPlus_ImageGetHeight($hImage2)) Then Return SetError(2, 0, False) Local $t = TimerInit() ; <== for comparison time in seconds (not mandatory) Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hImage1, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB) Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hImage2, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB) Local $iScan1 = DllStructGetData($tBitmapData1, "Scan0") Local $tPixel1 = DllStructCreate("int[" & $iW * $iH & "];", $iScan1) Local $iStride = Abs(DllStructGetData($tBitmapData1, "Stride")) Local $iScan2 = DllStructGetData($tBitmapData2, "Scan0") Local $tPixel2 = DllStructCreate("int[" & $iW * $iH & "];", $iScan2) $iResult = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $iScan1, "ptr", $iScan2, "int", DllStructGetSize($tPixel1))[0] _GDIPlus_BitmapUnlockBits($hImage1, $tBitmapData1) _GDIPlus_BitmapUnlockBits($hImage2, $tBitmapData2) Return SetError(0, Int(TimerDiff($t)), $iResult = 0) EndFunc Test images : Pic1 and Pic2 -> same size, but different content, Pic3->different size (Error 1 = Different width, Error 2 = Different height) EDITED Edited March 3, 2020 by Musashi with correct DllCall "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
Nine Posted March 2, 2020 Share Posted March 2, 2020 @Musashi Why are you leaving out the last four bytes of the structure ? It should be : DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $iScan1, "ptr", $iScan2, "int", $iH * $iW * 4) ; or another way DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $iScan1, "ptr", $iScan2, "int", DllStructGetSize($tPixel1)) Musashi 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Musashi Posted March 2, 2020 Share Posted March 2, 2020 14 minutes ago, Nine said: Why are you leaving out the last four bytes of the structure ? To be honest with you, I simply took this line from the function of UEZ. My tests showed plausible results, so I didn't pay closer attention to it (that was probably a bit sloppy) . You know more about this topic anyway, so you might want to take a look for yourself. https://www.autoitscript.com/forum/topic/182010-problems-comparing-two-in-memory-bitmaps-using-memcmp/?do=findComment&comment=1308390 I have only implemented the case $bFastCmp. If you still think it is necessary afterwards, I will replace the DLL call, of course. "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
Zavier Posted March 2, 2020 Author Share Posted March 2, 2020 Thank you for the answers! The first script works pretty good, now my script is able to delete the images after the function ends. I did not code it so I really don't know why they used memcmp. Checking the width or height in my case is maybe not needed since all images are the same, just changes the content. I will try both scripts! Thank you both ! 😀 Link to comment Share on other sites More sharing options...
Nine Posted March 2, 2020 Share Posted March 2, 2020 (edited) http://pinvoke.net/default.aspx/msvcrt/memcmp.html?diff=y Shows really it is a count not a range, so it should be like I said. IDK why UEZ scripted like that. I am using a lot of memcpy in my scripts and it's working also with a count. Edited March 2, 2020 by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
UEZ Posted March 3, 2020 Share Posted March 3, 2020 Nine is right, to compare to full range of bitmap blocks you have to use $iW * $iH * $4 or DllStructGetSize($tPixel1) instead not to miss the last memory blocks in the compare functions. My formular doesn't cover the full range! Musashi 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Musashi Posted March 3, 2020 Share Posted March 3, 2020 (edited) 2 hours ago, UEZ said: Nine is right, to compare to full range of bitmap blocks you have to use $iW * $iH * $4 or DllStructGetSize($tPixel1) instead not to miss the last memory blocks in the compare functions. My formular doesn't cover the full range! First of all, thanks to @Nine and @UEZ for the clarification. On a closer look it is just logical, that the calculation with (... -1) does not capture the whole bitmap. 20 hours ago, Zavier said: The first script works pretty good, now my script is able to delete the images after the function ends. [...] Checking the width or height in my case is maybe not needed since all images are the same, just changes the content. I will try both scripts! @Zavier : Your original script also contains this bug. So you might want to use my modified version, even if your comparison images are always the same size . Edited March 3, 2020 by Musashi typo "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
Nine Posted March 3, 2020 Share Posted March 3, 2020 I would suggest a couple of things to streamline the code. You do not need to create the 2 $tPixel structures. Also $Stride is not required anymore. So use $iW*$iH*4 for the count. Save you a few lines of code. Not that I am finicky, but...well maybe I am Musashi 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Musashi Posted March 3, 2020 Share Posted March 3, 2020 1 hour ago, Nine said: I would suggest a couple of things to streamline the code ... Here is a cleaned up version. I have altered the function name from _GDIPlus_ImageCompare to _ImageCompare_GDIPlus to better distinguish it from the standard _GDIPlus_* functions. I have also removed the time measuring. Who wants to know the duration of the comparison can set TimerInit etc. itself. I hope this meets your demands . ; This directive is not mandatory : #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 6 -w 7 #include <GDIPlus.au3> Global $g_hImg1, $g_hImg2, $g_bCompareResult, $g_iSizeMismatch _GDIPlus_Startup() $g_hImg1 = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\Pic1.jpg") $g_hImg2 = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\Pic2.jpg") $g_bCompareResult = _ImageCompare_GDIPlus($g_hImg1, $g_hImg2) $g_iSizeMismatch = @error MsgBox(BitOR(4096,64), "Report", "Compare Images = " & $g_bCompareResult & @CRLF & "Size mismatch = " & $g_iSizeMismatch) _GDIPlus_ImageDispose($g_hImg1) _GDIPlus_ImageDispose($g_hImg2) _GDIPlus_Shutdown() Func _ImageCompare_GDIPlus($hImage1, $hImage2) Local Const $iWidth = _GDIPlus_ImageGetWidth($hImage1), $iHeight = _GDIPlus_ImageGetHeight($hImage1) If ($iWidth <> _GDIPlus_ImageGetWidth($hImage2)) Then Return SetError(1, 0, False) If ($iHeight <> _GDIPlus_ImageGetHeight($hImage2)) Then Return SetError(2, 0, False) Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hImage1, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32ARGB) Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hImage2, 0, 0, $iWidth, $iHeight, $GDIP_ILMREAD, $GDIP_PXF32ARGB) Local $iScan1 = DllStructGetData($tBitmapData1, "Scan0") Local $iScan2 = DllStructGetData($tBitmapData2, "Scan0") Local $iResult = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $iScan1, "ptr", $iScan2, "int", $iHeight * $iWidth * 4)[0] _GDIPlus_BitmapUnlockBits($hImage1, $tBitmapData1) _GDIPlus_BitmapUnlockBits($hImage2, $tBitmapData2) Return SetError(0, 0, $iResult = 0) EndFunc ;==>_ImageCompare_GDIPlus Nine 1 "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now