Im Thema RE: Assembler - Fortsetzung
unter Beitrag #8
hatte Andy diese Programm erarbeitet:
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>
;~ #include <assembleit2_64.au3>
#AutoIt3Wrapper_UseX64=n
#cs _countpixelcolors ;
Use32 ;32Bit!
org $PTR_SOURCE_ASMCODE ;only needed for assembleit debugger
mov edi,dword[esp+4] ;pointer bitmap
mov ecx,dword[esp+8] ;width bitmap
mov ebx,dword[esp+12] ;height bitmap
mov esi,dword[esp+16] ;pointer pixelstruct
movd xmm1,dword[esp+20] ;pointer textstruct
rdtsc ;timer sichern
push eax
;~ _asmdbg_() ;debugger
mov eax,ebx ;h
mul ecx ;w*h
mov edx,eax ;w*h
movd xmm0, edx ;sichern anzahl
;zuerst werden die Pixel durchlaufen, die Farbe jedes Pixels wird an der Speicherstelle seines "Farbwerts" hochgezählt
@pixel_count: ;alle pixel
mov eax,[edi] ;farbe
and eax,0xFFFFFF ;eliminieren alpha-channel
;~ _asmdbg_()
inc dword [esi+eax*4] ;farbwert=farbwert+1, address=colorRGB^^
;add dword [esi+eax*4],1 ;schneller?
add edi,4 ;nächste farbe
sub edx,1 ;pixelcounter
jnz near @pixel_count ;jump if not zero(<0)
;***********************************************************************************
;jetzt werden die gezählten Farbwerte nacheinander als Text in HEX-Darstellung und der Anzahl als Integerwert in eine textstruct geschrieben
;Format: 6BF1E5,1234567@crlf
movd xmm4,edi ;sichern pointer bitmap
mov edx,0x1000000 ;anzahl farben 0xFFFFFF +1
movd ebx,xmm1 ;pointer textstruct
mov edi,-4 ;pointer colorstruct
@count_colors:
sub edx,1 ;jedes pixel
jz @end ;alle pixel durchlaufen
mov ecx,[esi+edx*4] ;ecx=anzahl, edx=farbwert; esi=pointer pixelstruct
cmp ecx,0
je @count_colors ;wenn ungleich null...ist farbe gefunden
;~ _asmdbg_()
;hex-werte farbe =6 Bytes
;aus den 6 nibbles die 6 bytes machen, nibble+48 (0x30) =ASCII-Ziffer
;zuerst aus den beiden bytes ( Bit 4444333322221111) die nibble erweitern zu 0000444400003333 und 0000222200001111
movd xmm3,eax ;sichern wg registerpressure
movd xmm4,edx ;aka push/pop
movd xmm5,esi
movd xmm6,ecx
mov eax,edx
mov edi,eax
;schneller ist natürlich eine LUT^^, aber so geht es auch
;**************************************************************
mov edx,0 ;6 nibbles
_int2hex:
mov ecx,20 ;5*4 shiften
lea esi,[4*edx] ;anzahl der zu shiftenden bits
sub ecx,esi ;ecx=20,ecx
shr eax,cl ;nach al shiften
and al,0xF ;obere 4 nibble eliminieren
cmp al,9 ;größer oder kleiner als A?
jle _groesserA
add al,7 ;A-F
_groesserA:
add al,48 ;1-9
mov byte[ebx+edx],al ;ascii-hexcode in struct
mov eax,edi
add edx,1
; _asmdbg_()
cmp edx,6 ;alle 6 nibble bearbeitet?
jne _int2hex
add ebx,edx ;ein zeichen (6 bytes) weiter
mov byte [ebx],44 ;komma
add ebx,1 ;ein zeichen weiter
mov edi,ebx ;pointer text
movd ebx,xmm6 ;anzahl integer
;************************************************************
;aus einer Zahl(Registerinhalt) einen ZiffernString machen: http://dcla.rkhb.de/umwandlung/int2dez.html
;und in die struct schreiben
push ebx ;alle benötigten Register sichern
push ecx ;alle benötigten Register sichern
mov eax, ebx ;Zahl laden
mov ebx, 10 ;Divisor
xor ecx, ecx ;ECX=0 (Anzahl der Ziffern)
Schleife_1:
xor edx, edx
div ebx ; EDX:EAX / EBX = EAX Rest EDX
push dx ; LIFO
add cl,1 ; ADD soll schneller sein als INC
or eax, eax ; AX = 0?
jnz Schleife_1 ; nein: nochmal
Schleife_2:
pop ax ; gepushte Ziffern zurückholen
or al, 00110000b ; Umwandlung in ASCII
stosb ; Nur AL nach [EDI] (EDI ist ein Zeiger auf den String)
loop Schleife_2 ; bis keine Ziffern mehr da sind
mov byte [edi],0Dh ;CR CarriageReturn, man könnte auch ein Komma (ascii=2C) einsetzen, dazu noch ein nullbyte als EndOfString
add edi,1 ;ein Byte weiter
pop ecx ;Register wiederherstellen
pop ebx ;Register wiederherstellen
;************************************************************Ende Ziffer aus Register
movd esi,xmm5
movd edx,xmm4 ;restaurieren
mov ebx,edi
jmp @count_colors ;schleife alle farben
@end:
ret
#ce
AutoItSetOption("GUIOnEventMode", 1) ;event mode
_GDIPlus_Startup() ;tt
Global $ptr_bitmap, $hbmp, $iwidth, $iheight ;werden ByRef von _CreateNewBmp32FromFile ausgefüllt
$sFile = FileOpenDialog("Bilder", @ScriptDir, "Bilder (*.jpg;*.bmp;*.png)")
$DC_bitmap = _CreateNewBmp32FromFile($sFile, $ptr_bitmap, $hbmp, $iwidth, $iheight)
;assembled code by AssembleIt_64
$binarycode = "0x8B7C24048B4C24088B5C240C8B742410660F6E4C24140F315089D8F7E189C2660F6EC28B0725FFFFFF00FF048683C70483EA010F85EAFFFFFF660F6EE7BA00000001660F7ECBBFFCFFFFFF83EA010F848C0000008B0C9683F90074EF660F6ED8660F6EE2660F6EEE660F6EF189D089C7BA00000000B9140000008D34950000000029F1D3E8240F3C097E020407043088041389F883C20183FA0675D901D3C6032C83C30189DF660F7EF3535189D8BB0A00000031C931D2F7F3665280C10109C075F366580C30AAE2F9C6070D83C701595B660F7EEE660F7EE289FBE96BFFFFFF5B0F3129D8C3"
$tCodeBuffer = DllStructCreate("byte[" & StringLen($binarycode) / 2 - 1 & "]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1, $binarycode)
$colorstruct = DllStructCreate("uint[" & 256 ^ 3 & "]");anzahl möglicher Farben
$ptr_colorstruct = DllStructGetPtr($colorstruct)
$textstruct = DllStructCreate("char[" & 18 * $iwidth * $iheight & "]");maximale Anzahl Zeichen
$ptr_textstruct = DllStructGetPtr($textstruct)
;9 Stellen integer
;6 Stellen Hexdarstellung
;1 Stellen Komma
;2 Stellen CRLF
$t = TimerInit()
;Pixelfarben zählen und in Hexcode,Anzahl umwandeln, schreiben in textstruct
DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), "ptr", $ptr_bitmap, "int_ptr", $iwidth, "int_ptr", $iheight, "int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
;~ $ret = _AssembleIt2("uint", "_countpixelcolors", "ptr", $ptr_bitmap, "int_ptr", $iWidth, "int_ptr", $iHeight, "int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
;~ ConsoleWrite('Takte: ' & $ret & @CRLF) ;### Debug Console
;in der dllstruct stehen nun die Farbe,Anzahl
$text = DllStructGetData($textstruct, 1)
$text = StringTrimRight($text, 1) ;letztes LF entfernen
$m = TimerDiff($t)
$text = StringReplace($text, @CR, @CRLF) ;autoit is fast too^^
$number_colors = @extended + 1
MsgBox(0, "Timer ASM picelcounter", "Within " & Int($m) & "ms " & $number_colors & " colors were counted!")
;anzeigen als text
FileDelete("Pixelcounter.txt")
FileWrite("Pixelcounter.txt", $text)
ShellExecute("Pixelcounter.txt")
$colorarray = StringSplit($text, @LF)
_ArrayDisplay($colorarray)
;Autoit-Version, dauert.....sehr lange^^
;~ For $color = 1 To 256 ^ 3 ;alle farben
;~ $anzahl = DllStructGetData($colorstruct, 1, $color);auslesen
;~ If $anzahl <> 0 Then ConsoleWrite(Hex($color - 1, 6) & @TAB & $anzahl & @CRLF)
;~ Next
$hGUI = GUICreate("ASM Pixelcounter", $iwidth, $iheight);GUI
$DC_gui = _WinAPI_GetDC($hGUI) ;Device-context
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
GUISetState()
_WinAPI_BitBlt($DC_gui, 0, 0, $iwidth, $iheight, $DC_bitmap, 0, 0, 0xCC0020);bitmap in DC blitten
Do
Until Not Sleep(100) ;
Func _Exit()
_GDIPlus_Shutdown()
GUIDelete()
Exit
EndFunc ;==>_Exit
Func _CreateNewBmp32FromFile($bmpfile, ByRef $ptr, ByRef $hbmp, ByRef $iwidth, ByRef $iheight) ;ptr to bitmapdata, it is possible to manipulate one pixel if needed
Local $hbitmap, $hdc, $hcdc
$hbitmap = _GDIPlus_ImageLoadFromFile($bmpfile)
If @error Or $hbitmap = 0 Then
MsgBox(0, "Func _CreateNewBmp32FromFile()", "Error opening File: " & @CRLF & $bmpfile)
Return -1
EndIf
$hbmpfile = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hbitmap)
$iwidth = _GDIPlus_ImageGetWidth($hbitmap)
$iheight = _GDIPlus_ImageGetHeight($hbitmap)
$hcdc = _WinAPI_CreateCompatibleDC(0)
_WinAPI_SelectObject($hcdc, $hbmpfile) ;image im hcdc
;neue bitmap
$tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
DllStructSetData($tBMI, 1, DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
DllStructSetData($tBMI, 2, $iwidth)
DllStructSetData($tBMI, 3, -$iheight) ;minus =standard = bottomup
DllStructSetData($tBMI, 4, 1)
DllStructSetData($tBMI, 5, 32) ;32 Bit = 4 Bytes => AABBGGRR
$adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
$hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
$ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
$hdc = _WinAPI_CreateCompatibleDC(0)
_WinAPI_SelectObject($hdc, $hbmp) ;leere bitmap im hdc
_WinAPI_BitBlt($hdc, 0, 0, $iwidth, $iheight, $hcdc, 0, 0, $srccopy);image in leere bitmap
_WinAPI_DeleteDC($hcdc)
_WinAPI_DeleteObject($hbmpfile)
Return $hdc ;DC der Bitmap zurückgeben
EndFunc ;==>_CreateNewBmp32FromFile
Alles anzeigen
Es fertigt eine Staistik über alle in einer Bitmap-Datei vorkommenden Farben an.
Hier eine kleine Beispieldatei: rot1.bmp
In dem Programm ist ein fertiger $binarycode eingefügt (Zeile216) , der von der Fuktion DllCallAddress aufgerufen wird. Das klappt auch einwandfrei und die Statistik wird angezeigt.
Wird der $binarycode jedoch neu erzeugt, so funktioniert es nicht. Am besten kann man das bewerkstelligen, indem man unter der Zeile216 : $binarycode = "0x8B7C24048B4C240.....
die beiden Befehle
$binarycode = _AssembleIt2("retbinary", "_countpixelcolors")
MsgBox(0,"",$binarycode)
einfügt Der dabei entstehned $binarycode unterscheiden sich von dem in Zeile216 eingetragenen hinten um die letzten Bytes.
Wo steck der Fehler?
Vielen Dank schon einmal für eine Antwort!