Jump to content

AndyG

Active Members
  • Posts

    409
  • Joined

  • Last visited

  • Days Won

    4

AndyG last won the day on April 14 2024

AndyG had the most liked content!

1 Follower

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

AndyG's Achievements

  1. Yes, and much more advantage if one knows the "bitmap" FILE ( ! ) format? Skip the first 54 bytes (file header) and you will find....the "pixels" aka image data pixelarray (depending on the 1/2/4/8/16/24/32 Bit per Pixel mode (see header...)). So no need to CreateBitmapFromFile() because a simple "open" file gives access to the pixel data array.... Go and get the first "line" of the bitmap (as a char-string) and search in the screenshot (transfer the screenshot-bytes into a char-array...others say "string") with StringInstr(). If the first line of the bitmap is found in the screenshot, the comparison of the next "line" in the bitmap with the next "line" in the screenshot is easy. Because the position of the text ( a char-array ist the same as a byte array) is known in the screenshot-"text", the comparison with the next "lines" is only a comparison of "text" (StringMid() is our friend) . I have written a few example scripts with this method to find a "bitmap in a bitmap". I have to look for them at the weekend Speed-challenge opened!
  2. Haha...thx, i made this centuries ago...if I remember right, it was a contribution to some other "digital desktop clock" scripts which took some hundret lines of code...my intention was to write a script in less than 50 lines of code. The "bitbanging" aka producing a polygon, means the position and orientation of an "equal shape", I taught myself about 40 years ago when I programmed "graphical" games for a calculator (sharp PC1401) with a 7-segment LC display in machine code. yepp, rotation is the key...and it is not necessary to use "graphical stuff" like GDI(+) or something like that to read or write "pixels"! A bitmap is an array of bytes/words/dwords representing the "pixels". If you put an AutoIt dllstruct "over" a bitmap (at the bitmap's starting address in memory), you can read or write "pixels" with a simple DllStructGetData() / DllStructSetData(), or, much faster, define/read the dllstruct as a "string" (characters) and use the super-fast AutoIt string commands like StringInstr() to locate a specific sequence of "bytes" (characters). As Werty mentioned, the first column of the digit is unique. This requires seven "bit tests" due to the way the pixels are arranged in memory, as each "pixel" is in a different area of the bitmap. After rotating the image, only one test is required, as the "pixels" of the first column are now in a row, one after the other. So only one read from memory is required to get the "number". And since the position of the next "number" on the screen is known in the bitmap's memory, a search for a sequence of 4 consecutive "numbers" would only require 4 reads from memory. This means that the first step is to look for the first "digit", then look at the (known) next position in memory and check if the byte at that position is the second "digit", and so on... With this technique the search of a sequence of "numbers" on a screenshot is possible in a few (milli)-Seconds. In native AutoIt code....
  3. Hi! if it has to look more like a "real" 7-segment ...how about this? (I wrote it many years ago....@UEZ, do you remember^^) #include <GDIPlus.au3> #include <WindowsConstants.au3> #include <GUIConstantsEx.au3> Dim $ws[12] = [0, 0, 10, -7, 50, -7, 60, 0, 50, 7, 10, 7] ;Koordinaten Polygonzug: von links nach rechts WAAGRECHTER Balken, von rechts nach links SENKRECHTER Balken Dim $ziffer[10] = [239, 10, 118, 94, 154, 220, 253, 14, 254, 222] ;alle gesetzten bits des Indexes in der 7-segmentanzeige ergeben die Ziffer Dim $balkenpos[8] = [0, "60.0", "0.0", "60.60", "0.60", "0.60", "0.120", "0.0"] ;position der Leuchtbalken der 7-Segmentanzeige innerhalb der Ziffer Dim $p[7][2] ;nimmt die polygonzug-koordinaten zum Zeichnen auf $p[0][0] = 6 ;6 Punkte im Polygonzug _GDIPlus_Startup() Global $hgui = GUICreate('Uhr', 620, 175, -1, -1, $WS_POPUP) ;GUI erstellen ohne Rahmen Global $hWnd = WinGetHandle($hgui) ;Handle holen Global $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd) ;"Leinwand" erstellen, auf der gezeichnet werden kann GUICtrlCreateLabel("", 0, 0, 620, 175, Default, $GUI_WS_EX_PARENTDRAG) ;verschieben des Fensters möglich machen durch 2. Fenster GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) ;das 2. Fenster transparent machen GUISetBkColor(0x000000) ;Hintergrund der GUI schwarz GUISetState() ;GUI anzeigen AdlibRegister("_time", 1000) ;jede Zehntelsekunde ein Refresh der Zeitanzeige Do ;Endlosschleife, solange bis.. Until GUIGetMsg() = -3 ;..ESC gedrückt wird _GDIPlus_GraphicsDispose($hGraphic) ;freigeben _GDIPlus_Shutdown() Func _time() ;Uhrzeit anzeigen :o) For $k = 1 To 6 ;die 6 Ziffern der Uhrzeit $setbits = $ziffer[StringMid(String(@HOUR & @MIN & @SEC), $k, 1)] ;gesetzte Bits in der siebensegmentanzeige anhand der Ziffer in der Uhrzeit holen For $bitnr = 7 To 1 Step -1 ;alle Bits durchlaufen _drawpolygon(BitAND($setbits, 128), $k * 100 - 80 + ($k = 1 Or $k = 3 Or $k = 5) * 20, $bitnr) ;parameter: bit gesetzt ja/nein, position der gesamten ziffer,nummer des bits(gerade=waagrechter balken, ungerade=senkrechter balken) $setbits = BitShift($setbits, -1) ;nächstes Bit holen Next Next $brush = _GDIPlus_BrushCreateSolid(0xFF440000 + (@SEC / 2 = Int(@SEC / 2)) * 0xBB0000) ;Pinsel erstellen, wenn Ziffer gerade, dann farbig, ansonsten schwarz _GDIPlus_GraphicsFillEllipse($hGraphic, 202, 55, 15, 15, $brush) ;Punkte zeichnen _GDIPlus_GraphicsFillEllipse($hGraphic, 402, 55, 15, 15, $brush) _GDIPlus_GraphicsFillEllipse($hGraphic, 202, 105, 15, 15, $brush) _GDIPlus_GraphicsFillEllipse($hGraphic, 402, 105, 15, 15, $brush) _GDIPlus_BrushDispose($brush) ;Pinsel auflösen EndFunc ;==>_time Func _drawpolygon($bit, $xpos, $bitnr) ;zeichnet einen polygonzug ("Balken") an die entsprechende Position $split = StringSplit($balkenpos[$bitnr], ".", 3) ;x- und y-koordinaten des Balkens innerhalb der Ziffer holen $b = (($bitnr / 2) = Int($bitnr / 2)) ;$bit gerade => $b = true => Balken waagrecht, ansonsten Balken senkrecht $step = -1 + 2 * $b ;schrittweite durch das $WS-Array For $i = 11 - 11 * $b To 11 * $b Step 2 * $step ;array mit waagrechten (bit=gerade) oder (Bit=ungerade) senkrechten Balken füllen $r = Int(Abs((11 * (Not ($b))) - $i) / 2) + 1 ;abhängig von der Reihenfolge, egal ob $i von 0 bis 11 oder von 11 bis 0, $r muss immer 1,2,3,4,5,6 $p[$r][0] = $ws[$i] + $split[0] + $xpos ;x- und $p[$r][1] = $ws[$i + $step] + $split[1] + 30 ;y-position in das polygonarray schreiben Next $brush = _GDIPlus_BrushCreateSolid(0xFF440000 + ($bit <> 0) * 0xBB0000) ;wenn bit gesetzt, dann farbig, ansonsten schwarz _GDIPlus_GraphicsFillPolygon($hGraphic, $p, $brush) ;Balken zeichnen _GDIPlus_BrushDispose($brush) EndFunc ;==>_drawpolygon If you want to know how it works....read the code!
  4. Hey UEZ, nice one as always ^^ I found a very cool python script here https://scipython.com/blog/floyd-steinberg-dithering/ After some tests I have realised that I can get similar results with your script when multiplying the $iColors with 3 (approximately^^). But with low numbers of $iColors, something strange is happening: Global $iColors = 16, $iDitherMode =1 Changing to $iColors = 17, $iDitherMode =1 , the result looks much better. What is the reason for that behaviour?
  5. Hi, the reason for these "artefacts" is the accumulation of all rounding errors caused by the use of byte "colours" aka AARRGGBB. You will get better results when you calculate only with floating numbers. Unfortunately AutoIt is not able to "cast" a hex value into a float number (or i cannot remember it ^^), DEC() is able to cast hex into double but double is 64bit and does`nt fit into a 32bit "Pixel" AARRGGBB First to do is to store "floats" instead of AARRGGBB within the whole image Get the pixel value via _GDIPlus_BitmapGetPixel(), write this value into a dword struct which is on the same address as a float struct and read the dword (aka float) $floatstruct = DllStructCreate("float") $dwordstruct = DllStructCreate("dword", DllStructGetPtr($floatstruct)) ;AARRGGBB to float For $y = 0 To $Height - 1 For $x = 0 To $Width - 1 $oldPixel = Dec(Hex(_GDIPlus_BitmapGetPixel($Image, $x, $y), 2)) / 255 ;get float number between 0 and 1 DllStructSetData($floatstruct, 1, $oldPixel) ;write into float struct $oldPixel = DllStructGetData($dwordstruct, 1) ;read as dword (aka "pixel" AARRGGBB) _GDIPlus_BitmapSetPixel($Image, $x, $y, $oldPixel) ;store the float number as "pixel" AARRGGBB Next Next Now the "image" is an array of floats. In the next step you have to read the floating point numbers (aka oldpixel) via _GDIPlus_BitmapGetPixel(), calculate if more or less than 0.5 and set the newpixel value and set the the black or white pixel in the image and the quant_error For $y = 0 To $Height - 1 For $x = 0 To $Width - 1 $oldPixel = _GDIPlus_BitmapGetPixel($Image, $x, $y) ;pixel as dword DllStructSetData($dwordstruct, 1, $oldPixel) ;write into dwordstruct (place of floatstruct) $oldPixel = DllStructGetData($floatstruct, 1) ;read float If $oldPixel <= 0.5 Then $newpixel = 0 Else $newpixel = 1 EndIf _GDIPlus_BitmapSetPixel($Image, $x, $y, String("0xFF" & Hex($newpixel * 255, 2) & Hex($newpixel * 255, 2) & Hex($newpixel * 255, 2))) $quant_error = $oldPixel - $newpixel Now Floyd-Steinberg: As mentioned before, other languages can handle images and floating point numbers, I transferred dwords and floats via DllStructs. ;-------Floyd-Steinberg $pixel = _GDIPlus_BitmapGetPixel($Image, $x + 1, $y);get pixel integer/DWORD AARRGGBB DllStructSetData($dwordstruct, 1, $pixel) ;set into DWORD struct $col = DllStructGetData($floatstruct, 1) ;read float from DWORD $float = $col + (7 / 16 * $quant_error) ;calculate with float DllStructSetData($floatstruct, 1, $float) ;write into float struct $pixel = DllStructGetData($dwordstruct, 1) ;get dword from float and _GDIPlus_BitmapSetPixel($Image, $x + 1, $y, $pixel) ;write the "float" as a "pixel" which leads to the script: ;$aligncomment=60 #include <GDIPlus.au3> HotKeySet("{ESC}", "_exit") _GDIPlus_Startup() Global $Image = _GDIPlus_BitmapCreateFromFile("graytest.png") ;~ Global $Image = _GDIPlus_BitmapCreateFromFile("dithercompare.png") ;~ Global $Image = _GDIPlus_BitmapCreateFromFile("test50.png") Global $Width = _GDIPlus_ImageGetWidth($Image), $Height = _GDIPlus_ImageGetHeight($Image) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $Height = ' & $Height & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $Width = ' & $Width & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $Gui = GUICreate("Floyd-Steinberg Dithering", $Width, $Height) GUISetState() $Graphics = _GDIPlus_GraphicsCreateFromHWND($Gui) _GDIPlus_GraphicsDrawImageRect($Graphics, $Image, 0, 0, $Width, $Height) $floatstruct = DllStructCreate("float") $dwordstruct = DllStructCreate("dword", DllStructGetPtr($floatstruct)) ;AARRGGBB to float For $y = 0 To $Height - 1 For $x = 0 To $Width - 1 $oldPixel = Dec(Hex(_GDIPlus_BitmapGetPixel($Image, $x, $y), 2)) / 255 ;get float number between 0 and 1 DllStructSetData($floatstruct, 1, $oldPixel) ;write into float struct $oldPixel = DllStructGetData($dwordstruct, 1) ;read as dword (aka "pixel" AARRGGBB) _GDIPlus_BitmapSetPixel($Image, $x, $y, $oldPixel) ;store the float number as "pixel" AARRGGBB Next Next _GDIPlus_GraphicsDrawImageRect($Graphics, $Image, 0, 0, $Width, $Height) ;show image with "floats" For $y = 0 To $Height - 1 For $x = 0 To $Width - 1 $oldPixel = _GDIPlus_BitmapGetPixel($Image, $x, $y) ;pixel as dword DllStructSetData($dwordstruct, 1, $oldPixel) ;write into dwordstruct (place of floatstruct) $oldPixel = DllStructGetData($floatstruct, 1) ;read float If $oldPixel <= 0.5 Then $newpixel = 0 Else $newpixel = 1 EndIf _GDIPlus_BitmapSetPixel($Image, $x, $y, String("0xFF" & Hex($newpixel * 255, 2) & Hex($newpixel * 255, 2) & Hex($newpixel * 255, 2))) $quant_error = $oldPixel - $newpixel ;-------Floyd-Steinberg $pixel = _GDIPlus_BitmapGetPixel($Image, $x + 1, $y);get pixel integer/DWORD AARRGGBB DllStructSetData($dwordstruct, 1, $pixel) ;set into DWORD struct $col = DllStructGetData($floatstruct, 1) ;read float from DWORD $float = $col + (7 / 16 * $quant_error) ;calculate with float DllStructSetData($floatstruct, 1, $float) ;write into float struct $pixel = DllStructGetData($dwordstruct, 1) ;get dword from float and _GDIPlus_BitmapSetPixel($Image, $x + 1, $y, $pixel) ;write the "float" as a "pixel" $pixel = _GDIPlus_BitmapGetPixel($Image, $x - 1, $y + 1) DllStructSetData($dwordstruct, 1, $pixel) ;set into DWORD struct $col = DllStructGetData($floatstruct, 1) ;read float from DWORD $float = $col + (3 / 16 * $quant_error) ;calculate with float DllStructSetData($floatstruct, 1, $float) ;write into float struct $pixel = DllStructGetData($dwordstruct, 1) ;get dword from float and _GDIPlus_BitmapSetPixel($Image, $x - 1, $y + 1, $pixel) $pixel = _GDIPlus_BitmapGetPixel($Image, $x, $y + 1) DllStructSetData($dwordstruct, 1, $pixel) ;set into DWORD struct $col = DllStructGetData($floatstruct, 1) ;read float from DWORD $float = $col + (5 / 16 * $quant_error) ;calculate with float DllStructSetData($floatstruct, 1, $float) ;write into float struct $pixel = DllStructGetData($dwordstruct, 1) ;get dword from float and _GDIPlus_BitmapSetPixel($Image, $x, $y + 1, $pixel) $pixel = _GDIPlus_BitmapGetPixel($Image, $x + 1, $y + 1) DllStructSetData($dwordstruct, 1, $pixel) ;set into DWORD struct $col = DllStructGetData($floatstruct, 1) ;read float from DWORD $float = $col + (1 / 16 * $quant_error) ;calculate with float DllStructSetData($floatstruct, 1, $float) ;write into float struct $pixel = DllStructGetData($dwordstruct, 1) ;get dword from float and _GDIPlus_BitmapSetPixel($Image, $x + 1, $y + 1, $pixel) Next _GDIPlus_GraphicsDrawImageRect($Graphics, $Image, 0, 0, $Width, $Height) ; to see the errors quick instead of waiting for the whole image Next _GDIPlus_GraphicsDrawImageRect($Graphics, $Image, 0, 0, $Width, $Height) While GUIGetMsg <> -3 Sleep(10) WEnd Func _exit() Exit EndFunc ;==>_exit Interesting side effect: If an image is filled with 50% gray the result of Floyd-Steinberg should be a checkboard pattern. In the "real world", floating point numbers have restrictions, mentioned hundrets of thousands of times here in this forum.... So at the end, in the "real world" (of floating point numbers) there is an error which shows some artefacts in the "checkboard" pattern ( 50% gray as test50.png). These errors are inevitably and independant of the used computer language. Floyd Steinberg dithering.zip
  6. @Andreik, yes, x-thousand times faster than "native" AutoItcode is not that bad! But there are, independent of the language/compiler you use, much more (possible) improvements. Depending on the size of the files to be compared and the available RAM, you could load the "golden pattern"-file (file to compare with) and then (in a loop) 15 files to compare. Why 15? There are 16 SSE/AVX-register (YMM0-YMM15 in x64-mode) available, each, you know it, 32 bytes wide. So you have to load the "golden pattern" only once and then then you are able to compare 32 byte(s) in the "source" to 32 bytes in each of the 15 loaded files. The loopcount is shortened by a factor of 32, also the number of comparisons by a factor of 15 ( per number of loaded files). Loop unrolling is implemented too Results in (lets forget the overhead and so it is better to calculate in my old brain ) ~30 * ~10 ~~ 300 times faster (comparing to your 27bytes long (I love it^^)) code! Not to mention all the file- and processorcache "goodies" you would benefit from. I'm sure there are many more, and faster, ways to accomplish such a "simple" task.....
  7. Hi, compile a program "Get_Discord_Status_loaded_64Bit.exe" as a 64bit-application. Write the status into a file or return it elsewhere.... Compile a program "Get_Steam_Status_loaded_32Bit.exe" as a 32bit-application. Write the status into a file or return it elsewhere.... Compile your program as a 32/64bit-Application and evaluate the status from the file.
  8. __ExampleA() Func __ExampleA() Local $BinaryString = StringToBinary("Hello @World") Local $Bin_Len = BinaryLen($BinaryString) ConsoleWrite('BinaryLen: ' & $Bin_Len & @TAB & 'BinaryString: ' & $BinaryString & @CRLF) Local $tSTRUCT1 = DllStructCreate('uint; Byte[' & $Bin_Len & ']') DllStructSetData($tSTRUCT1, 1, $Bin_Len, 1) For $i = 1 To $Bin_Len ;you have to write bytes...because it is not a string! or you can make a memcpy DllStructSetData($tSTRUCT1, 2, Dec(StringMid($BinaryString, $i * 2 + 1, 2)), $i) ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : stringmid($BinaryString,$i*2+1,2) = ' & StringMid($BinaryString, $i * 2 + 1, 2) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console Next ConsoleWrite('[Data uint ]: ' & DllStructGetData($tSTRUCT1, 1) & @CRLF) ConsoleWrite('[Data String ]: ' & DllStructGetData($tSTRUCT1, 2) & @CRLF) Local $pVariant = DllStructGetPtr($tSTRUCT1) ConsoleWrite('[$pVariant ]: ' & $pVariant & @CRLF & @CRLF & @CRLF) ;end of writing data into memory ;start reading data from memory with known pointer $struct_stringlen = DllStructCreate("uint", $pVariant) ;get first 4 bytes = uint =stringlen $stringlen = DllStructGetData($struct_stringlen, 1) ;lets get the binarystring $struct_binarystring = DllStructCreate("byte[" & $stringlen & "]", $pVariant + 4) ;place the struct at the pointer +4 because uint is 4 bytes $binary = DllStructGetData($struct_binarystring, 1) $string = BinaryToString($binary) ConsoleWrite(" Stringlen = " & $stringlen & @CRLF & " Binary = " & $binary & @CRLF & " String = " & $string & @crlf & @crlf) EndFunc ;==>__ExampleA If you have an ANSI/ASCII String, it is much easier because the transformation to binary data is omitted. You can write the (ANSI/ASCII) string directly into the memory. This works with char and wchar (16 bit unicode). __ExampleB() Func __ExampleB() Local $String = "Hello @World" Local $Len = StringLen($String) ConsoleWrite('StringLen: ' & $Len & @TAB & 'String: ' & $String & @CRLF) Local $tSTRUCT1 = DllStructCreate('uint; char[' & $Len & ']') ;or wchar if unicode!!! DllStructSetData($tSTRUCT1, 1, $Len) DllStructSetData($tSTRUCT1, 2, $String) ConsoleWrite('[Data uint ]: ' & DllStructGetData($tSTRUCT1, 1) & @CRLF) ConsoleWrite('[Data String ]: ' & DllStructGetData($tSTRUCT1, 2) & @CRLF) Local $pVariant = DllStructGetPtr($tSTRUCT1) ConsoleWrite('[$pVariant ]: ' & $pVariant & @CRLF & @CRLF & @CRLF) ;end of writing data into memory ;start reading data from memory with known pointer $struct_stringlen = DllStructCreate("uint", $pVariant) ;get first 4 bytes = uint =stringlen $stringlen = DllStructGetData($struct_stringlen, 1) ;lets get the string char or wchar if unicode $struct_string = DllStructCreate("char[" & $stringlen & "]", $pVariant + 4) ;place the struct at the pointer +4 because uint is 4 bytes $String = DllStructGetData($struct_string, 1) ConsoleWrite(" Stringlen = " & $stringlen & @CRLF & " String = " & $String & @CRLF & @CRLF) EndFunc ;==>__ExampleB
  9. Yes, use the appropriate string managemennt system. The pointer points to a memoryblock where the first 4 bytes (UINT/DWORD) contains the string length and the rest of the memory contains the string/data. Then the data format is irrelevant.
  10. Hi! Nice example of the XY-Problem! What the Problem is: What the User think the Problem is: No, you are lying to yourself! The MAIN problem is that the app is crashing....you need to fix THIS! You don't have to solve problems, you have to eliminate problems!
  11. Oh no! Please use those >50 years old techniques more! I am always so impressed and surprised when examining/investigate such a piece of "gold" code😇 I played the "original" Sokoban in the 80s, it was fun at all! So thank you so much transferring the idea into AutoIt code!
  12. 63 Moves....but 50 Seconds needed....😁 And btw....xor al, 0x7f, SO CUTE!!😍
  13. Hi, you could replace the line _WinAPI_RedrawWindow($hGUI) with GUICtrlSetState($BTN1,$GUI_SHOW) to show the Control after displaying the GDI(+)-stuff or use _WinAPI_RedrawWindow($hGUI,0,0,$RDW_INVALIDATE + $RDW_ALLCHILDREN)
  14. Hi! As always in this cases (I know what I am talking about 🐵 , sometimes I "don´t see the wood for the trees" also) ...look at what you are posting in the picture....you compare "Elvis" with "Elvis.mkv"...that doesn´t work 😃 You have to trim the extension ".mkv" from the title, thats all! In Line 190 $strMovieTitle = StringTrimRight($arrLocalLib [$i],4) ;trims the extension from filename
×
×
  • Create New...