Recht recht herzlichen Dank für deine ausführliche Erklärung.
Habe viel dazugelernt.
Gruß DOheim
Recht recht herzlichen Dank für deine ausführliche Erklärung.
Habe viel dazugelernt.
Gruß DOheim
Hallo Andy,
das Programm „Farben zählen“ hat ja nun auch die schwarzen Pixel erkannt.
Ich wunderte mich, dass es aber bei manchen Bitmapdateien abgebrochen ist und habe herausgefunden, dass die Bitmapdatei mindestens ein schwarzes Pixel besitzen muss.
Ich habe hinter der Sprungmarke
@count_colors:
die beiden Befehle eingefügt:
sub edx,0
jz @end
Nun ist alles in Butter.
Eine Frage habe ich noch:
Im Debugger-Fenster werden bei mir die übergebene Parameter um eine Position verschoben angezeigt. Z.B. die Werte von width und height stehen eigentlich in [esp+8] und [esp+12] werden aber im Debugger-Fenster unter [esp+12] und [esp+16] angezeigt.
Habe ich etwas falsch gemacht?
Das hatte ich bisher nicht bemerkt, dass im Kopf die Zeielnnummer steht. Vielen dank für de Hinweis.
Vielen Dank für eure netten Antworten.
Ich habe an meinem Rahmenprogramm noch etwas „herumgeschneidert“ und hoffe, dass es nun auch in fremder Umgebung funktioniert.
Statt über $CmdLine die Phase einzustellen, ist es einfacher den Wert in Zeile 22 einzutragen.
Protokoll() ist mein Autoit-Debugger. Bitte nicht daran stören.
Ich habe noch eine Frage:
Wäre es möglich, im Assemblerprogramm den Debugger-Aufruf z.B. so zu gestalten
Stelle3) _asmdbg_()
und dann im Debugger-Fenster die Zeichenfolge Stelle3 anzuzeigen? Das würde ungemein helfen.
Hier mein Rahmenprogramm:
;#AutoIt3Wrapper_Run_Au3Stripper=y
#cs ----------------------------------------------------------------------------
Rahmenprogramm für den Test von Assemblerfunktionen
$CmdLine[1] = Pfad-/Dateiname der Bitmapdatei
$CmdLine[2] = Bearbeitungsphase
Für Tests weiterer Assemblerfunktionen die Parameter für
_AssembleIt2() und DllCallAddress() sowie die Funktion Auswerten() anpassen.
#ce ----------------------------------------------------------------------------
#cs
#include "HilfsFunktionen.au3"
Global $Protokoll1=2 ; =2, dann wird protokolliert, aber beim ersten
; Aufruf ist die Datei zunächst zu löschen.
; =0, dann wird nicht protokolliert
; =1, dann wird protokolliert, ohne die Datei vorher zu löschen
$ProgrammName="FarbenZaehlen" ; für Protokoll
#ce
;-------------------------------------------------------------------------
;Protokoll("Anfang1")
; ===================================================================
; Bearbeitungsphase festlegen
$phase=2
$sFile=""
If $CmdLine[0]<>0 Then $sFile=$CmdLine[1]
If $CmdLine[0]=2 Then $phase=$CmdLine[2]
; -------------------------------------------------------------------
;$phase =1 _AssembleIt2("uint"
; Der Binärcode wird erzeugt und an Ort und Stelle abgearbeitet.
; Debuggen möglich. Diese Phase dient dem Test des Assemblerprogramms
; =2 _AssembleIt2("retbinary"
; Nach abgeschlossenem Test wird nunmehr der fertige Binärcode
; erzeugt. Zunächst wird allen Debugger-Aufrufe _asmdbg_() ein
; Semikolon voangestellt. Der Binärcode erscheint in der Datei
; binarycode.txt.
; Anschließend wird das Programm mittels der Funktion
; DllCallAddress("uint:cdecl" ausgeführt.
; =3 Der in Phase 2 erzeugte Binärcode wird der Datei binarycode.txt
; entnommen und mittels der Funktion DllCallAddress("uint:cdecl"
; ausgeführt.
; =0 oder ="" Der in der Datei binarycode.txt stehende Binärcode
; wurde direkt in das Programm als Variable $binarycode
; eingetragen und das Programm sollte dann auch compiliert werden.
; ===================================================================
#include <GDIPlus.au3>
;#include <WinAPI.au3>
;#include <Array.au3>
;#include <GUIConstantsEx.au3>
;#include <StructureConstants.au3>
;#include <WindowsConstants.au3>
#include <assembleit2_64.au3>;~
;#include <#FuncASS.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
cmp edx,0
jne @count_colors ;schleife alle farben
@end:
pop ebx
;rdtsc
sub eax,ebx
ret
#ce
_GDIPlus_Startup() ; Initialisiert (startet) Microsoft Windows GDI+
Global $ptr_bitmap, $hbmp, $iwidth, $iheight ;werden ByRef von _CreateNewBmp32FromFile ausgefüllt
; -------------------------------------
; Bitmapdatei zergliedert zur Verfügung stellen
If $sFile = "" Then
;$sFile = "rot1.bmp"
$sFile = FileOpenDialog("Zu untersuchende Bitmap-Datei", @ScriptDir, "Bilder (*.jpg;*.bmp;*.png)")
EndIf
$DC_bitmap = _CreateNewBmp32FromFile($sFile, $ptr_bitmap, $hbmp, $iwidth, $iheight)
; siehe D:\AU\Assembler\#FuncASS.au3
; -------------------------------------
; Die $colorstruct bereitstellen
$colorstruct = DllStructCreate("uint[" & 256 ^ 3 & "]");anzahl möglicher Farben
$ptr_colorstruct = DllStructGetPtr($colorstruct)
; -------------------------------------
; Die $textstruct bereitstellen.
$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
; -------------------------------------
; Bearbeitung durchführen
Select
Case $phase=1
;Protokoll("$phase1::"&$phase)
Local $ret = _AssembleIt2("uint", "_countpixelcolors", "ptr", $ptr_bitmap, _
"int_ptr", $iwidth, "int_ptr", $iheight, "int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
Auswerten($textstruct)
Case $phase=0
;Protokoll("$phase0::"&$phase)
$binarycode = "0x8B7C24048B4C24088B5C240C8B742410660F6E4C24140F315089D8F7E189C2660F6EC28B0725FFFFFF00FF048683C70483EA010F85EAFFFFFF660F6EE7BA00000001660F7ECBBFFCFFFFFF83EA018B0C9683F90074F5660F6ED8660F6EE2660F6EEE660F6EF189D089C7BA00000000B9140000008D34950000000029F1D3E8240F3C097E020407043088041389F883C20183FA0675D901D3C6032C83C30189DF660F7EF3535189D8BB0A00000031C931D2F7F3665280C10109C075F366580C30AAE2F9C6070D83C701595B660F7EEE660F7EE289FB83FA000F856DFFFFFF5B0F3129D8C3"
;Protokoll("$phase0::"&$phase)
Ausfuehren($binarycode)
Case $phase=2
;rotokoll("$phase2::"&$phase)
asmdbg(@ScriptLineNumber) ; Direktiven _asmdbg_() mit ";" versehen
$binarycode = _AssembleIt2("retbinary", "_countpixelcolors")
;rotokoll("$binarycode:..:"&$binarycode)
; Binären Assemblercode als Datei ausgeben:
$h=FileOpen("binarycode.txt",2)
FileWrite($h,StringMid($binarycode,3)) ; Ohne 0x
FileClose($h)
Ausfuehren($binarycode)
Case $phase=3
;Protokoll("$phase3::"&$phase)
$h=FileOpen("binarycode.txt")
$binarycode="0x"&FileRead($h)
FileClose($h)
Ausfuehren($binarycode)
EndSelect
MsgBox(0,"","Fertig",1)
;Protokoll("Exit")
Exit
;======================================================================
#cs ----------------------------------------------------------------------------
Erhält den durch die Assemblierung erzeugten Maschinencode $binarycode
und arbeitet diesen ab.
Als globale Variable müssen existiern:
- $ptr_bitmap Zeiger auf die Structur, welche die Bitmap-Daten enthält
- $iwidth Zeiger auf die Breite der Bitmap (Anzahl der Pixel-Spalten)
- $iheight Zeiger auf die Höhe der Bitmap (Anzahl der Pixel-Zeilen
- $ptr_colorstruct Zeiger auf Arbeitfeld (Structur) mit der Anzahl von
256^3 32-Bit-Integers, in welchem das Ass-Programm
die Farben zählt
- $ptr_textstruct Zeiger auf eine Structur, in welcher das Ass-Programm
das Ergebnis hinterlässt
#ce ----------------------------------------------------------------------------
Func Ausfuehren($binarycode)
;Protokoll("Ausführen >>>>")
$tCodeBuffer = DllStructCreate("byte[" & StringLen($binarycode) / 2 - 1 & "]") ;reserve Memory for opcodes
DllStructSetData($tCodeBuffer, 1, $binarycode)
$t = TimerInit()
; -----------
DllCallAddress("uint:cdecl", DllStructGetPtr($tCodeBuffer), _
"ptr", $ptr_bitmap, "int_ptr", $iwidth, "int_ptr", $iheight, _
"int_ptr", $ptr_colorstruct, "int_ptr", $ptr_textstruct)
; -----------
$m = TimerDiff($t)
; in der Structur $textstruct stehen nun die gefundenen Farben
; in der Form RRGGBB,Anzahl@LF
MsgBox(0, "Timer ASM picelcounter", "Within " & Int($m) & "ms " )
Auswerten($textstruct)
;Protokoll("Ausführen <<<<")
EndFunc
;======================================================================
#cs ----------------------------------------------------------------------------
Wertet das Ergebnis des Assemblerprogramms aus
#ce ----------------------------------------------------------------------------
Func Auswerten($textstruct)
;Protokoll("Auswerten >>>>")
$text = DllStructGetData($textstruct, 1)
$text = StringTrimRight($text, 1) ;letztes LF entfernen
$text = StringReplace($text, @CR, @CRLF) ;autoit is fast too^^
$number_colors = @extended + 1
;Protokoll("$number::"&$number_colors)
;Protokoll("$text:.:"&$text)
;Protokoll("Ausführen <<<<")
$colorarray = StringSplit($text, @LF)
Opt("WinTitleMatchMode", 2) ; 1=vom Anfang, 2=enthält, 3=genau, 4=fortgeschritten, -1 bis -4=Groß-/Klein ignorieren
WinSetState("SciTE","",@SW_HIDE )
Sleep(500)
_ArrayDisplay($colorarray,"$colorarray")
;Protokoll("Auswerten <<<<")
EndFunc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include-once
#cs ----------------------------------------------------------------------------
_CreateNewBmp32FromFile
asmdbg
Auswerten
#ce ----------------------------------------------------------------------------
;======================================================================
#cs ----------------------------------------------------------------------------
Zergliedert eine Bitmap-Datei
$bmpfile Pfad-/Dateiname der zue zergliedernden Datei
Hinterlässt:
$ptr Ponter auf das Pixelfeld der Datei. 4 Bytes je Pixel.
Beginnend mit dem linken oberen Pixel, zeielweise bis zum rechten unteren Pixel.
$hbmp Siehe: https://learn.microsoft.com/de-de/windows/win32/gdi/device-independent-bitmaps
$iwidth Breite der Bitmap, d.h. Anzahl Pixel pro Zeile
$iheight Höhe der Bitmap, d.h. Anzahl der Zeilen
#ce ----------------------------------------------------------------------------
#include <GDIPlus.au3>
Func _CreateNewBmp32FromFile($bmpfile, ByRef $ptr, ByRef $hbmp, ByRef $iwidth, ByRef $iheight) ;ptr to bitmapdata, it is possible to manipulate one pixel if needed
;Protokoll("_CreateNewBmp32FromFile >>>>")
Local $hbitmap, $hdc, $hcdc
$hbitmap = _GDIPlus_ImageLoadFromFile($bmpfile)
If @error Or $hbitmap = 0 Then
MsgBox(0, "Func _CreateNewBmp32FromFile()", "Error opening File: " & @CRLF & $bmpfile)
;Protokoll("_CreateNewBmp32FromFile <<<<")
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)
;Protokoll("_CreateNewBmp32FromFile <<<<")
Return $hdc ;DC der Bitmap zurückgeben
EndFunc ;==>_CreateNewBmp32FromFile
;======================================================================
#cs ----------------------------------------------------------------------------
Sucht den letzten Abschnitt mit Assemblercodse #cs .... #ce vor diesem
Funktionsaufruf auf und stellt im Assemblercode den Direktiven _asmdbg_()
ein Semikolon voran.
Als $number ist @ScriptLineNumber einzutragen. Das heißt, der Aufruf muss
immer so aussehen:
asmdbg(@ScriptLineNumber)
#ce ----------------------------------------------------------------------------
Func asmdbg($number)
;Protokoll("asmdbg >>>>")
$script=@ScriptFullPath
; -------------------------------------
; Scrip-Datei in Array $linearr einlesen
$lineanz=0
Local $linearr[$lineanz]
$h=FileOpen($script)
While 1
$line=FileReadLine($h)
If @error=-1 Then ExitLoop ; Dateiende
;Protokoll("$line::"&$line)
ReDim $linearr[$lineanz+1]
$linearr[$lineanz]=$line
$lineanz+=1
WEnd
FileClose($h)
;_ArrayDisplay($linearr)
; -------------------------------------
; Assemblerabschnitt suchen
$csx=-1
$cex=-1
$ass=0 ; d.h. außerhalb Kommentarabschnitt
For $i=0 To $number
;Protokoll("$i:.:"&$i)
;Protokoll("$linearr[$i]:.:"&$linearr[$i])
Select
Case StringInStr($linearr[$i],"#cs")
If $ass=1 Then Fehler("Zwei #cs folgen aufeinander - Zeile "&$i)
;If $cex<>-1 Then Fehler("Zwei #cs folgen aufeinander - Zeile "&$i
$csx=$i
$ass=1 ; d.h. innerhalb Kommentarabschnitt
Case StringInStr($linearr[$i],"#ce")
If $ass=0 Then Fehler("Vor #ce kein #cs gefunden - Zeile "&$i)
$cex=$i
$ass=0 ; d.h. Assemblerabschnitt beendet
EndSelect
Next
If $csx=-1 OR $cex=-1 Then Fehler("Keinen Assemblercode gefunden - Zeile "&$i)
If $cex<$csx Then Fehler("Kommentarabschnitt endet nicht - Zeile "&$csx)
; -------------------------------------
; Array $linearr in Hilsdatei ausgeben und dabei die _asmdbg_() mit ";" versehen
$hh=FileOpen("hilf.au3",2)
For $i=0 To $lineanz-1
If $i>$csx AND $i<$cex Then
$pos=StringInStr($linearr[$i],"_asmdbg_()")
If $pos Then ; _asmdbg_() gefunden
$po=StringInStr($linearr[$i],";",0,1,1,$pos)
If $po=0 Then ; es gibt noch kein ";"
If Stringleft($linearr[$i],1)<>" " Then
$linearr[$i]=";"&$linearr[$i]
Else
$linearr[$i]=";"&StringMid($linearr[$i],2)
EndIf
EndIf
EndIf
EndIf
FileWriteLine($hh,$linearr[$i])
Next
FileClose($hh)
;MsgBox(0,"","111")
FileCopy("hilf.au3",$script,1)
;MsgBox(0,"","222")
$sciteExe="C:\Program Files (x86)\AutoIt3\SciTE\SciTE.exe"
Run($sciteExe&" "&$script)
Opt("WinTitleMatchMode", 2) ; 1=vom Anfang, 2=enthält, 3=genau, 4=fortgeschritten, -1 bis -4=Groß
While 1
Sleep(100)
WinActivate(@ScriptName)
If WinActive(@ScriptName) Then Exitloop
WEnd
;Protokoll("asmdbg <<<<")
EndFunc
;-----------------
Func Fehler($text)
MsgBox(0,"",$text)
Exit
EndFunc
;-----------------
Alles anzeigen
Total gut !!!!!!!!!!!!
Wie schnell du das gefunden hast. Mit 89 ist man eben etwas langsamer.
Ganz bequem übernehme ich nun meinem inneren Schweinehund gahorchend den Binarycode so wie er ist in mein Bitmap-Programm.
Ich habe ja noch ein eigentlich einfaches Bitmap-Problem. Das verrate ich dir aber nicht. Sonst hast du es im Nu gelöst und ich lerne nichts hinzu . Wenn ich es aber dann gelöst habe, werde ich es in dir in diesem Thema miteilen. Wie ich dir damals schon gesagt hatte, habe ich Jahrzehnte Assembler programmiert. Aber es waren ja viel einfacher Rechner. Das hat heute ganz andere Dimensionen und das "Handwerkszeug" ist doch erheblich umfangreicher geworden. Jetzt habe ich mir erst einmal ein Rahmenprogramm geschrieben, das es mir beim Test leicht macht, zwischen den einzelnen Arbeitsphasen
_AssembleIt2("uint ..." ,
_AssembleIt2("retbinary ... " ,
nur DllCallAddress("uint:cdecl ... " ohne _AssembleIt
umzuschalten.
Recht vielen Dank für deine Mühe!
Gruß DOheim
Hallo Andy,
VielenDank für Deine Antwort.
Ich hatte ja damals den $binarycode aus deinem Programm in mein Bitmapprogramm mit großem Erfolg eingebaut. Die Rechenzeit hatte sich um den Faktor 500 verkürzt.
Aber ein Mangel bestand noch, dass die schwarzen Pixel (also Farbwert 0x000000) nicht erkannt wurden. Der Sache möchte ich nun auf den Grund gehen.
Vielen Dank für die neue Variante von AssembleIt2_64 v 313.zip. ZurZeit arbeite ich mit der von dir unter
<RE: AssembleIt2_64 incl. Debugger uvm...>
veröffentlichten Variante.
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!
Vielen Dank Oscar und Andy.
Vor einem Jahr war der CD-Spieler an unserm Radio ausgefallen.
Deshalb habe ich ein Programm geschrieben, das alle Lieder von den Weihnachts-CDs einliest,
- ihnen aus dem ID3-Tag (letzte 128 Bytes) Titel, Interpret und Album entnimmt
- ein ausdruckbares Verzeichnis erstellt und
- sie so auf einen USB-Stick kopiert, dass das Radio jedes Lied unter der Nummer findet, wie es in dem Verzeichnis steht.
Mein größter Lohn: Meine Frau hat sich gefreut und mich gelobt!
Nun wollte ich noch etwas änder und bin auf die oben geschilderten Probleme gestoßen.
Umso mehr freue ich mich, dass es mit
$h=FileOpen($lied,512)
nun alles wieder klappt.
Nochmals herzlichen Dank!
Ich möchte vorausschicken: ich arbeite mit Autoit 3.3.16.0
Ich will ein Weihnachtslied in Form einer mp3-Datei bearbeiten.
Zunächst sehe ich mir die Datei mit dem Hexeditor an (Bild 1).
Mit diesem Program möchte ich die Datei einlesen:
Als Ergebnis erhalte ich Bild 2. Damit kann man nichts anfangen.
Ich hole mir das alte Autoit 3.3.8.1 zurück. Unter diesem Autoit bringt das Programm das Ergebnis Bild 3. Also genau so wie es der Hexeditor angezeigt hat. Damit kann ich arbeiten.
Warum klappt das unter dem neuen Autoit 3.3.16.0 nicht?
Wer es selbst ausprobieren möchte:
unter diesem Link findet man
- das Lied Kommet ihr Hirten.mp3 sowie
- das obige unter Autoit 3.3.8.1 compilierte Programm test.exe
Ich hatte gar nicht bemerkt, dass BugFix inzwischen auch schon geantwortet hatte.
Jetztt habe ich mir die Beschreibung in der Hilfe von FileRead genau angesehen. Den Passus
" Eine Datei kann binär (byteweise) ausgelesen werden wenn FileOpen() mit dem Binärflag aufgerufen wird. "
hatte ich überlesen.
Dank Eurer Hilfe habe ich nun mehrere Möglichkeiten, das Problem aus dem Wege zu schaffen. Zumal alle etwa genauso schnell sind, muss ich mir noch an den Knöpfen abzählen, welche ich nun verwende.
Das Problem ist also für mich gelöst.
Nochmals recht vielen Dank für euer beider Hilfe.
Nun muss ich mich dem eigentlichen Grund für den Start dieses Themas widmen und Oscars GuiCtrlSetImageEx in mein Programm einbauen.
Das ist ja eine feine Sache!!!
Recht vielen Dank.
Ich muss mich wirklich mehr mit den WINAPI beschäftigen.
Nun muss ich mir noch überlegen, wie ich die Datei dann passend wieder schreibe.
Jedes Pixel eines Bildes besteht ja aus den drei Farben blau, grün und rot. In der Bitmapdatei wird entsprechend jedes Pixel durch drei Bytes beschrieben, welche die Werte 0 bis 255 annehmen können. Und diese Werte benötige ich, wenn ich Pixel bearbeiten möchte.
Beispiel:
Die Datei
soll mit demProgramm
bearbeitet werden.
Die Bitmapdatei rot1.bmp sieht 8-fach gezoomt so aus:
Jede Bitmap-Datei hat am Anfang einen 54 Bytes langen Header:
Danach folgen je drei Byte für jedes Pixel (blau grün rot). Das erste Pixel ist das in der linken unteren Ecke.
Das Programm Test.au3 ersetzt das 5. Pixel durch die Farbe weiß und gibt die veränderte Datei als rot2.bmp aus.
Die Bitmapdatei rot2.bmp sieht 8-fach gezoomt so aus:
Sollen in einer großen Bitmap-Datei viele Pixel bearbeitet werden, dann muss man dazu Assembler-Befehle verwenden. Sonst dauert es ewig.
Ich hoffe, dass ich deine Frage richtig interpretiert habe.
Hallo Oscar,
vielen Dank dafür, dass du dir so viel Mühe mit mir gibst.
Ich habe jedoch Schwierigkeiten dein Beispiel zu verstehen.
Ich kenne mich leider mit Strukturen und DLL-Aufrufen nicht aus.
Deshal habe ich die Information nicht gefunden, wie die im Feld "ASCII Chars" stehenden Zeichen ermittelt wurden.
In deinem Beispiel hattest du di Funktion BinaryLen verwendet. Das hat mich auf die Idee gebracht nach weiteren Binary-Funktionen zu suchen und ich habe die Funktion BinaryToString gefunden, die meine Wünsche erfüllt . Sie ist auch sehr schell und benötigt z. B für einen 1920 X 1080 - Screenschot nur 12 Millisekunden. Ich werde sie in meine Bitmap-Programme nach dem FileRead einfügen und dann wird alles wieder funktionieren.
Übrignes hatte Andy unter
im Beitrag #8
im Jahre 2016 ein Programm eingestellt, das sich mit der Auswertung einer Bitmap-Datei unter den bedingungen von Autoit 3.3.8.1 befasste. Wie ich festelle hat er das - ebenfalls unter Verwendung von Strukture - inzwischen auf die neuen Autoit-Versionen angepasst. Es stellt nun wieder fest, dass die Datei rot.bmp aus 81 Rot-Pixeln besteht.
Nochmasl recht vielen Dank
Gruß
Dieter
Ich habe jetzt die neuste Version von Autoit installiert.
Nun habe ich wieder das gleiche Problem: Wie kann ich eine Bitmap-Datei einlesen?
Ich habe beispielsweise die Datei
und möchte sie mit dem Programm
einlesen. Die Datei besitzt eine Länge von 306 Bytes und genau dies 306 Bytes will ich so einlesen. Eingelesen werden aber 614 Zeichen. Jedes Byte wird nämlich in Form von zwei Hexadezimal-Ziffern ins Textformat konvertiert.
Was kann ich tun?
Wie bereits gesagt, klappte das unter Autoit 3.3.8.1 noch einwandfrei. Wen es interessiert: ich habe noch einen Backup der Setup-Datei von Autoit 3.3.8.1 und kann diesen zur Verfügung stellen.
Wie sieht denn deiner Meinung nach eine (Bitmap)-Datei aus, so wie sie ist
Jedes Zeichen ( 8 Bit) in der Datei sollte, wenn es eingelesen ist, auch wieder als ein Zeichen mit den gleichen Bits erscheinen.
Beispielsweise soll also des Zeichen 10001111 hexadezimal als 0x8F erscheinen und nicht (wie bei Autoit3.3.12.0) als zwei Zeichen 0x3846 ("8F").
Ich werde als nächstes das neuste Autoit installieren und dann weitersehen.
Im Sommer arbeite ich viel im Garten, deshalb entschuldgt bitte, wenn meine Reaktionrn nur zögerlich erfolgen.
Ich melde mich wieder.
Dank und Gruß an euch alle
Dieter
Ich komme nicht weiter. Wen ich das Example unter
abarbeiten möchte, kommt diese STDOUT:
>"C:\Program Files (x86)\AutoIt3\SciTE\..\AutoIt3.exe" "C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.au3" /run /prod /ErrorStdOut /in "D:\Programmdaten\Desktop\CreateIcon\Example.au3" /UserParams
+>16:59:14 Starting AutoIt3Wrapper v.16.612.1119.0 SciTE v.3.6.6.0 Keyboard:00000407 OS:WIN_81/ CPU:X64 OS:X64 Environment(Language:0407) CodePage:0 utf8.auto.check:4
+> SciTEDir => C:\Program Files (x86)\AutoIt3\SciTE UserDir => C:\Users\ffff\AppData\Local\AutoIt v3\SciTE\AutoIt3Wrapper SCITE_USERHOME => C:\Users\ffff\AppData\Local\AutoIt v3\SciTE
>Running AU3Check (3.3.10.2) from:C:\Program Files (x86)\AutoIt3 input:D:\Programmdaten\Desktop\CreateIcon\Example.au3
! Au3check doesn't support input files encoded as UTF8 with BOM: D:\Programmdaten\Desktop\CreateIcon\Example.au3
D:\Programmdaten\Desktop\CreateIcon\Example.au3 - 1 error(s), 0 warning(s)
!>16:59:14 AU3Check ended. Press F4 to jump to next error.rc:2
+>16:59:14 AutoIt3Wrapper Finished.
>Exit code: 2 Time: 0.5582
Mit
Au3check doesn't support input files encoded as UTF8 with BOM
weiß ich nichts anzufangen.
Jetzt sehe ich es erst:
_GuiCtrlSetImageEx hat ja Oscar selbst geschrieben
Vielen Dank für eure Antworten!!!
oh-ha
IrfanView habe ich auch installiert und habe jetzt kapiert, wie du das meinst.
Mir würde nur nicht gefallen, eine andere Software in mein Problem einzubinden. Würde wahrscheinlich auch verlangsamen.
Aber wenn alles andere nicht geht, müsste ich das wohl so machen.
Mars
Es muss nicht sein, dass ich "die .png so wie sie ist", verwenden muss.
Winapi ist leider auch nicht so mein Ding.
Bitnugger
Die Funktion _GuiCtrlSetImageEx ist mir beim Googeln auch schon über den Weg gelaufen. Blos in meinem Autoit3.3.8.1 gibt es sie nicht. Ich hatte früher auch schon Autoit3.3.12.0 installiert, musste das aber wieder verwerfen, weil dort der Befehl FileRead so verändert wurde, dass man beispielsweise eine Bitmap-Datei nicht mehr einlesen konnte - so wie sie ist. Sie wird in Hex-Zeichen umgewandelt. Aber von dem Ordner "C:\Program Files (x86)\AutoIt3" hatte ich mir damals einen Backup zurückbehalten. Aber _GuiCtrlSetImageEx ist dort auch nicht enthalten.
Aber Dein Link zu _GuiCtrlSetImageEx hat mir insofern geholfen, als dort im Beispiel GuiCtrlSetImageEx.au3 die Funktion _GuiCtrlSetImageEx explizit ausgewiesen ist.
Damit werde ich nun erst einmal weiterexperimentieren.
Ich werde mich dann wieder zurückmelden.
Nochmals vielen Dank euch allen.
Gruß Dieter
Ich weiß nicht, wie du das meinst.
Es geht mir darum, ein Control zu erzeugen, welches ein Handel zurückgibt, auf das ich mich später beziehen kann. Z.B. durch anklicken mit der Maus.