Mit StringFromASCIIArray ANSI-Zeichensatz erzeugen ?

  • Ich möchte mit der Funktion StringFromASCIIArray einen ANSI-Zeichensatz erzeugen.
    Wenn man nachfolgendes Programm abarbeitet, sieht man in den Zeilen 128 bis 159 der Spalte yyyyy des angezeigten Arrays, dass man mit

    StringFromASCIIArray($arr)

    wahrscheinlich den UTF-16 erhält.
    Aber mit

    StringFromASCIIArray($arr,0, UBound($array) - 1,1)

    kommen nur lauter Nullen (siehe Spalte zzzzzz) .

    [autoit]

    #Include <Array.au3>
    Local $array[300][4]
    Local $arr[300]
    $len=256
    For $i=0 To $len-1
    $arr[$i]=$i
    Next
    $str1=StringFromASCIIArray($arr)
    $str2=StringFromASCIIArray($arr,0, UBound($array) - 1,1)
    For $i=0 To $len-1
    $array[$i][0]=$i
    $array[$i][1]=$arr[$i]
    $array[$i][2]=Asc(StringMid($str1,$i+1,1))
    $array[$i][3]=Asc(StringMid($str2,$i+1,1))
    Next
    _ArrayDisplay($array, "Vergleich", 300 , 0 , "" , "|" , " Pos.|wwwww|xxxxx|yyyyy|zzzzz")

    [/autoit]

    Was habe ich falsch gemacht?

    4 Mal editiert, zuletzt von DOheim (3. Dezember 2013 um 10:54)

  • Hi,
    ändere mal in

    [autoit]

    $str2=StringFromASCIIArray($arr,1, UBound($array) - 1,1)

    [/autoit]

    also nicht von 0 bis 299, sondern von 1 bis 299, dann klappt es, scheint so, als hätte die Funktion ein Problem mit ANSI NULL.
    Darf ich fragen, was diese Tests für einen Hintergrund haben? Es gibt Funktionen, welche die Umwandlung von ANSI/ASCII/UTF8/UTF16 durchführen.

  • Vielen Dank Andy für Deine Antwort!!
    Das ist ja eigenartig, dass es erst ab 1,... funktioniert. Wie bist Du da nur drauf gekommen?
    Die Antwort auf Deine Frage findest Du unter:

    [ gelöst ] Zugriff auf Zeichen im String

    Ich habe eine Bitmap-Datei eingelesen und in ein Array umgewandelt. Dann habe ich eine große Anzahl von Pixeln verändert und das veränderte Array wieder zurückverwandelt und als neue Bitmap-Datei geschrieben. Und das hat nicht richtig geklappt.
    Nochmals vielen Dank.
    Gruß
    Dieter

  • Hallo Dieter,

    Zitat

    Ich habe eine Bitmap-Datei eingelesen und in ein Array umgewandelt. Dann habe ich eine große Anzahl von Pixeln verändert und das veränderte Array wieder zurückverwandelt und als neue Bitmap-Datei geschrieben. Und das hat nicht richtig geklappt.


    Viele Wege führen nach Rom :D
    Die Variante, die "Pixel" über ein Array auszutauschen, bzw. zu bearbeiten, ist eher ungewöhnlich. Die "Pixel" in einer Bitmap liegen "so schön" nebeneinander, da hättest du sicher kein zusätzliches Array gebraucht.
    Aber wenn es funktioniert, ist es ja gut :thumbup:

  • Nein, es funktioniert leider nicht.
    jetzt verstehe ich erst die Erläuterungen in der Hilfe zu StringFromASCIIArray.
    Er hört beim ersten Nullbyte auf zu übertragen. Und bei meiner Bitmap-Datei sind jede Menge Nullbytes enthalten.
    Das ist natürlich eine herbe Enttäuschung für mich.
    Wie meintest Du das:

    Zitat


    Die "Pixel" in einer Bitmap liegen "so schön" nebeneinander, da hättest du sicher kein zusätzliches Array gebraucht.


    StringReplace wäre nicht geeignet, da bei jedem Ersetzen eines Pixels immer der ganze String kopiert wird. Und das dauert.
    Oder hast Du noch etwas anderes im Hinterkopf?
    Vielen Dank für Deine Hilfe.
    Noch etwas anderes: Gibt es eigentlich in diesem Forum die Möglichkeit, sich per E-Mail benachrichtigen zu lassen, wenn ein neuer Beitrag eingegangen ist?

  • Hi,
    stringreplace() ersetzt pfeilschnell beliebige Strings. Ob die "Daten" nun Pixel in einer Bitmap sind oder ein Text ist dabei völlig irrelevant!
    Ich vermute, deine Bitmap-Dateien haben entweder das RGBA (32Bit) oder RGB(24-Bit) -Format.
    Wichtig ist das ehrlich gesagt nicht, wichtiger wäre vielmehr, was du genau machen willst!

    Die Bitmap wird definiert über ihren sog. Header, das ist ein Datenfeld von 54 Bytes, in dem die Bitmap beschrieben ist. Breite, Höhe, Farbformat usw.
    Dieser Header steht in der Bitmap-Datei vor den Pixel-Daten.

    Anbei ein kurzes Script, welches in einer Bitmap rot (ABGR 0xFF0000FF) durch Grün (ABGR 0xFF00FF00) ersetzt und zwar mittels stringreplace()

    Spoiler anzeigen
    [autoit]

    #include <ScreenCapture.au3>
    ;Farben in einer Bitmap-Datei ändern

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_datei = "Testbitmap.bmp"

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("") ;fenster mit rotem Inhalt erstellen
    GUISetBkColor(0xFF0000)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ; Erstellt einen Screenshot vom kompletten Bildschirm, Bitmapdatei erzeugen
    _ScreenCapture_SetBMPFormat(4) ;4 = 32 bpp; 8 Bit für jede RGB und Alpha Komponente

    [/autoit] [autoit][/autoit] [autoit]

    _ScreenCapture_Capture($bitmap_datei) ;screenshot vom Bildschirm erstellen und abspeichern
    Sleep(500) ;fenster anzeigen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = FileRead($bitmap_datei) ;Dateiinhalt
    $header = StringLeft($inhalt, 54) ;54byte Bitmap-Header

    [/autoit] [autoit][/autoit] [autoit]

    ;Farben je Pixel: Alpha,Blau,Grün,Rot
    $weiss = BinaryToString("0xFFFFFFFF") ;ABGR
    $schwarz = BinaryToString("0xFF000000") ;ABGR
    $rot = BinaryToString("0xFF0000FF")
    $gruen = BinaryToString("0xFF00FF00")

    [/autoit] [autoit][/autoit] [autoit]

    $inhalt = StringTrimLeft($inhalt, 54) ;header abschneiden

    [/autoit] [autoit][/autoit] [autoit]

    $inhalt = StringReplace($inhalt, $weiss, $schwarz, 0, 1);weiß durch schwarz ersetzen
    $inhalt = StringReplace($inhalt, $rot, $gruen, 0, 1);rot durch grün ersetzen

    [/autoit] [autoit][/autoit] [autoit]

    $ersetzt = @extended ;anzahl der ersetzten Pixel

    [/autoit] [autoit][/autoit] [autoit]

    FileDelete($bitmap_datei) ;alte datei löschen
    FileWrite($bitmap_datei, $header & $inhalt);und neu schreiben

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute($bitmap_datei)

    [/autoit]

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (1. Dezember 2013 um 18:48)

  • Recht vielen Dank, Andy, dass Du Dir so große Mühe mit mir gibst!

    Ich möchte in der Bitmap-Datei alle die verstreut liegenden Pixel, die in einem bestimmten Farbbereich
    .........( z.B.: rot zwischen 123 und 188
    ....................grün zwischen 0 und 20
    ....................blau zwischen 200 und 220 )
    liegen, einzeln heraussuchen und dann durch eine andere Farbe ersetzen.
    Und das dauert mit StringReplace bei einer großen Datei und vielen zu ersetzenden Pixeln eine Ewigkeit.

    Gruß
    Dieter

  • Hi,
    na dann sag das doch gleich^^
    Da die Bitmaps so einfach aufgebaut sind, lassen sie sich vortrefflich mit Assembler bearbeiten^^
    Aber zu deinem Problem:

    Zitat

    Und das dauert mit StringReplace bei einer großen Datei und vielen zu ersetzenden Pixeln eine Ewigkeit.

    Na, da schauen wir mal...
    Irgendwo hatte ich das schon mal in AutoIt programmiert, sooo lange hat das garnicht gedauert.
    20x20x50 = 20000 mögliche Pixelfarben...mit welcher Farbe sollen die ersetzt werden?

  • Hi,
    habe da mal etwas auf die schnelle gebastelt:
    Es wird jedes Pixel aus der Bitmap verglichen, ob es deinen Spezifikationen entspricht, wenn ja, wird die Farbe ausgetauscht, in der gesamten Bitmap.
    Ich habe dazu die Bitmap als String geladen und in eine Struct (in den Speicher) geschrieben, um jedes einzelne Pixel adressieren zu können.

    Bei mir dauert der Lauf durch die Bitmap incl. Austauschen ca. 8 Sekunden, bei 1680x1050 Pixeln.

    Spoiler anzeigen
    [autoit]

    #include <ScreenCapture.au3>
    ;Farben in einer Bitmap-Datei ändern

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_datei = "Testbitmap.bmp"

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("") ;fenster mit rotem Inhalt erstellen
    GUISetBkColor(0x960AD2)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ; Erstellt einen Screenshot vom kompletten Bildschirm, Bitmapdatei erzeugen
    _ScreenCapture_SetBMPFormat(4) ;4 = 32 bpp; 8 Bit für jede RGB und Alpha Komponente

    [/autoit] [autoit][/autoit] [autoit]

    _ScreenCapture_Capture($bitmap_datei) ;screenshot vom Bildschirm erstellen und abspeichern
    Sleep(500) ;fenster anzeigen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = FileRead($bitmap_datei) ;Dateiinhalt
    $header = StringLeft($inhalt, 54) ;54byte Bitmap-Header
    $inhalt = StringTrimLeft($inhalt, 54) ;header abschneiden

    [/autoit] [autoit][/autoit] [autoit]

    ;zähler
    $p = 0

    [/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $x = StringLen($inhalt) ;länge string

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $struct = DllStructCreate("byte[" & $x & "]") ;string im speicher BGRA
    $struct_pixel = DllStructCreate("dword[" & $x / 4 & "]", DllStructGetPtr($struct));an derselben adresse eine struct für die "Pixel"
    DllStructSetData($struct, 1, StringToBinary($inhalt));string in struct

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 1 to $x step 4 ;jedes Pixel in der Bitmap BGRA, 4 Byte sind 1 Pixel
    $b = DllStructGetData($struct, 1, $i) ;blau
    if $b > 200 and $b < 220 then
    $g = DllStructGetData($struct, 1, $i + 1);grün
    if $g < 20 then
    $r = DllStructGetData($struct, 1, $i + 2);rot
    if $r > 123 and $r < 188 then
    DllStructSetData($struct_pixel, 1, 0xFF000000, Int($i / 4) + 1) ;wenn treffer, schwarz schreiben, achtung little endian!
    $p += 1 ;ersetzen-zähler
    EndIf
    EndIf
    endif
    next
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $p = ' & $p & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $inhalt = BinaryToString(DllStructGetData($struct, 1)) ;Bitmap aus der struct in den string

    [/autoit] [autoit][/autoit] [autoit]

    FileDelete($bitmap_datei) ;alte datei löschen
    FileWrite($bitmap_datei, $header & $inhalt) ;und neu schreiben

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute($bitmap_datei)

    [/autoit] [autoit][/autoit] [autoit][/autoit]


    Wenn es noch schneller sein muss, dann sollte man eine Lösung per asm oder, am schnellsten, OpenCl verwenden.
    Selbst asm wäre in einigen Zeilen erledigt, beschränkt sich lediglich auf einige Vergleiche, die Struct ist ja vorhanden.

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (1. Dezember 2013 um 22:58)

  • Herzlichen Dank!
    Das muss ich mir erst einmal auf der Zunge zergehen lassen.
    Ich habe zwar mein ganzes berufliches Leben nur immer in Assembler auf "Großrechnern" programmiert (seit 1963). Habe sogar den inneren Kern von Betriebsystemen zerlegt und dort Fehler beseitigt und neue Eigenschaften hinzugefügt.
    Aber mich jetzt noch in einen PC-Assembler einzuarbeiten wäre mir - glaube ich - doch etwas aufwändig. Oder?
    Viele Grüße und nochmals vielen Dank
    Dieter

  • Hi,

    Zitat

    Ich habe zwar mein ganzes berufliches Leben nur immer in Assembler auf "Großrechnern" programmiert (seit 1963).

    Juhuuuuu, noch einer dieser Dinosaurier :thumbup: Da bin ich endlich nicht mehr alleine^^
    Obwohl ich um die Zeit, als du angefangen hast Großrechner zu programmieren, gerade mal geboren wurde :D
    Trotzdem fing ich schon relativ früh an als Schüler, Ende der Siebziger, mit per Maschinesprache programmierbaren Taschenrechnern rumzuwerkeln. 3435 Byte waren da das Limit an RAM, da musste das Programm, die Daten und auch noch die "Grafikausgabe" rein, selbstmodifizierender Code war selbstverständlich, da habe ich nicht mal drüber nachgedacht...
    Dann endlich der erste gebrauchte IBM-PC mit 8088-Prozessor (4,77 Mhz) , dem ich dann nach 1/2 Jahr sparen einen der superseltenen 8087 Coprozessoren gegönnt hatte um endlich SCHNELL mit "echten" Floats rechnen zu können. Dieser Coprozessor konnte sowieso nur direkt mit Maschinesprache bzw mit Assembler angesteuert werden. Compiler mit dem "x87-Schalter" gab es erst Jahre später.
    So habe ich die Ein-Ausgabe und das Grundgrüst der Programme in Basic geschrieben, die geschwindigkeitskritischen Teile dann in Assembler. Diese Kombination benutze ich heute noch, AutoIt als "Träger" und Assembler, wenns mal etwas schneller werden muss 8o

    Das geht sogar relativ einfach, entweder man erstellt mit einem Assembler eine DLL und ruft eine Funktion innerhalb dieser DLL aus AutoIt heraus auf, oder man schreibt den assemblierten Code in den Speicher und springt diesen aus AutoIt heraus direkt an, sehr simpel.
    Mittlerweile habe ich schon einen sehr leistungsfähigen Assembler (FASM) so mit AutoIt verbinden können, dass der Assemblercode "fast" inline im AutoItcode zu verwenden ist.
    Lange Rede, kurzer Sinn, gerade für die Bildbe- und Verarbeitung bietet sich Assembler an, das Bitmap-Format ist simpel, und die erreichbaren Geschwindigkeiten übertreffen (nach tagelanger Handoptimierung ^^ ) sogar manchmal die gängigen C-Compiler :rolleyes:
    Hier im Forum finden sich einige Threads und Beispiele zu diesem Thema, idR verwende ich nicht mehr als eine Handvoll Oldschool-8088-Assemblerbefehle, die zu "lernen" sollte das Problem nicht sein, und da du ja aus der Materie kommst, schonmal garnicht :thumbup:

    Für dein "Problem" benutze ich gerne mal AssembleIt() , aber lieber in der neuen Version AssembleIt2(). Damit reduziert sich die Laufzeit um geschätzt Faktor 100 bis 200.

    Spoiler anzeigen
    [autoit]

    #include <ScreenCapture.au3>
    #include "AssembleIt2.au3"

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;assemblercode ersetzt Farben bestimmter Spezifikation innerhalb einer Bitmap

    [/autoit] [autoit][/autoit] [autoit]

    #cs Farben_ersetzen
    use32 ;32-Bitmode

    [/autoit] [autoit][/autoit] [autoit]

    mov edi,[esp+4] ;pointer bitmap
    mov ecx,[esp+8] ;Bitmap anzahl bytes
    mov esi,[esp+12] ;pointer parameterstruct
    mov ebx,[esi+8] ;farbe_ersetzen
    mov edx,0 ;zähler ersetzte pixel

    [/autoit] [autoit][/autoit] [autoit]

    schleife:
    mov eax,[edi+ecx] ;pixel ARGB

    [/autoit] [autoit][/autoit] [autoit]

    cmp al,byte[esi+4] ;al>blau_von?
    jb naechstes_pixel ;wenn kleiner, nächstes pixel
    cmp al,byte[esi+5] ;al<blau_bis?
    ja naechstes_pixel ;wenn grösser, nächstes pixel

    [/autoit] [autoit][/autoit] [autoit]

    shr eax,8 ;al = ah
    cmp al,byte[esi+2] ;al>gruen_von?
    jb naechstes_pixel ;wenn kleiner, nächstes pixel
    cmp al,byte[esi+3] ;al<gruen_bis?
    ja naechstes_pixel ;wenn grösser, nächstes pixel

    [/autoit] [autoit][/autoit] [autoit]

    shr eax,8 ;al = ah
    cmp al,byte[esi+0] ;al>rot_von?
    jb naechstes_pixel ;wenn kleiner, nächstes pixel
    cmp al,byte[esi+1] ;al<rot_bis?
    ja naechstes_pixel ;wenn grösser, nächstes pixel

    [/autoit] [autoit][/autoit] [autoit]

    mov [edi+ecx],ebx ;pixel mit Farbe_ersetzen
    add edx,1 ;eins mehr ersetzt

    [/autoit] [autoit][/autoit] [autoit]

    naechstes_pixel:
    sub ecx,4 ;nächstes pixel
    cmp ecx,0 ;erstes pixel erreicht?
    jge schleife ;nein, weitermachen

    [/autoit] [autoit][/autoit] [autoit]

    mov eax,edx ;rückgabe anzahl ersetzte pixel

    [/autoit] [autoit][/autoit] [autoit]

    ret

    [/autoit] [autoit][/autoit] [autoit]

    #ce

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;Farben in einer Bitmap-Datei ändern

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_datei = "Testbitmap.bmp"

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("") ;fenster mit rotem Inhalt erstellen
    GUISetBkColor(0x960AD2)
    GUISetState()
    Sleep(500) ;fenster anzeigen
    ; Erstellt einen Screenshot vom kompletten Bildschirm, Bitmapdatei erzeugen
    _ScreenCapture_SetBMPFormat(4) ;4 = 32 bpp; 8 Bit für jede RGB und Alpha Komponente
    _ScreenCapture_Capture($bitmap_datei) ;screenshot vom Bildschirm erstellen und abspeichern

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = FileRead($bitmap_datei) ;Dateiinhalt
    $header = StringLeft($inhalt, 54) ;54byte Bitmap-Header
    $inhalt = StringTrimLeft($inhalt, 54) ;header abschneiden$bitmap_anzahl_bytes = StringLen($inhalt) ;länge string

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_anzahl_bytes = StringLen($inhalt)
    $struct_bitmap = DllStructCreate("byte[" & $bitmap_anzahl_bytes & "]") ;string im speicher BGRA als BYTEs
    $ptr_Bitmap = DllStructGetPtr($struct_bitmap) ;pointer startadresse Bitmap
    $struct_pixel = DllStructCreate("dword[" & $bitmap_anzahl_bytes / 4 & "]", $ptr_Bitmap);an derselben Adresse eine struct für die "Pixel" DWORD

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($struct_bitmap, 1, StringToBinary($inhalt)) ;string in struct

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;ab hier fängt der Assemblerteil an, zuerst wird eine hilfs-struct erstellt, damit man nicht so viele parameter an die Funktion übergeben muss
    $struct_parameter = DllStructCreate("byte Rot_von;" & _
    "byte Rot_bis;" & _
    "byte Gruen_von;" & _
    "byte Gruen_bis;" & _
    "byte Blau_von;" & _
    "byte Blau_bis;" & _
    "word _align;" & _ ;nur zur verdeutlichung, AutoIt aligned jeden anderen Datentyp an einer 8-Bit-grenze!
    "dword Farbe_ersatz") ;fängt bei startadresse +8 an, auch wenn das word _align weggelassen wird!
    $ptr_parameter = DllStructGetPtr($struct_parameter) ;pointer auf die parameter

    [/autoit] [autoit][/autoit] [autoit]

    ;farbfeld des Pixels, innerhalb dessen das Pixel durch eine bestimmte Farbe ersetzt wird
    $Rot_von = 123
    $Rot_bis = 188
    $Gruen_von = 0
    $Gruen_bis = 20
    $Blau_von = 200
    $Blau_bis = 220

    [/autoit] [autoit][/autoit] [autoit]

    ;in die struct schreiben, man könnte auch direkt die parameter schreiben^^
    DllStructSetData($struct_parameter, "Rot_von", $Rot_von) ;ESI
    DllStructSetData($struct_parameter, "Rot_bis", $Rot_bis) ;ESI+1
    DllStructSetData($struct_parameter, "Gruen_von", $Gruen_von) ;ESI+2
    DllStructSetData($struct_parameter, "Gruen_bis", $Gruen_bis) ;ESI+3
    DllStructSetData($struct_parameter, "Blau_von", $Blau_von) ;ESI+4
    DllStructSetData($struct_parameter, "Blau_bis", $Blau_bis) ;ESI+5
    ;dllstructcreate aligned an 8 byte grenzen, daher habe ich zur verdeutlichung das word _align in die struct eingefügt
    DllStructSetData($struct_parameter, "Farbe_ersatz", 0xFF00FF00) ;ESI+8 Achtung, wg little Endian ARGB !!!

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    ;code assemblieren und aufrufen
    $anzahl_pixel_ersetzt = _AssembleIt2("uint", "Farben_ersetzen", "ptr", $ptr_Bitmap, "int", $bitmap_anzahl_bytes, "ptr", $ptr_parameter)

    [/autoit] [autoit][/autoit] [autoit]

    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $anzahl_pixel_ersetzt = ' & $anzahl_pixel_ersetzt & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = BinaryToString(DllStructGetData($struct_bitmap, 1)) ;Bitmap aus der struct in den string

    [/autoit] [autoit][/autoit] [autoit]

    FileDelete($bitmap_datei) ;alte datei löschen
    FileWrite($bitmap_datei, $header & $inhalt) ;und neu schreiben

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute($bitmap_datei)

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;alternativ kann man auch einmal assemblieren, dann nur noch den code in den speicher schreiben und callen
    ;Assembleit ist dann nicht mehr erforderlich

    [/autoit] [autoit][/autoit] [autoit]

    $ret_asm = _AssembleIt2("retbinary", "Farben_ersetzen") ;assemblieren
    ;$ret_asm = "0x8B7C24048B4C24088B74240C8B5E08BA000000008B040F3A460472243A4605771FC1E8083A460272173A46037712C1E8083A06720B3A46017706891C0F83C20183E90483F9007DCC89D08B4608C3"
    $struct_asm = DllStructCreate("byte[" & StringLen($ret_asm) / 2 - 1 & "]") ;platz für asmcode im speicher
    $ptr_asm = DllStructGetPtr($struct_asm) ;pointer asmcode
    DllStructSetData($struct_asm, 1, $ret_asm) ;asmcode in struct schreiben

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $ret = DllCallAddress("uint:cdecl", $ptr_asm, "ptr", $ptr_Bitmap, "int", $bitmap_anzahl_bytes, "ptr", $ptr_parameter)

    [/autoit]


    Mittels AssembleIt2() läuft der Code, welcher in AutoIt ca. 8 Sekunden gebraucht hat (nicht schlecht übrigens^^) nun in ca. 50 Millisekunden. Also wirklich 200x schneller...

    Allerdings sollte man bedenken, dass ja der komplette Code assembliert werden muss, das ist ja noch als "Overhead" beim Aufruf vorhanden.
    Assembliert man den Code mittels Assembleit einmal und schreibt diesen in den Speicher und called, dann bleibt als reine Laufzeit 5ms übrig, also 2000x schneller als der AutoIt-Code.
    Dann kann auch AssembleIt() völlig wegfallen...

    Spoiler anzeigen
    [autoit]


    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_UseX64=n

    [/autoit] [autoit][/autoit] [autoit]

    ;assemblercode ersetzt Farben bestimmter Spezifikation innerhalb einer Bitmap

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    #include <ScreenCapture.au3>
    ;Farben in einer Bitmap-Datei ändern

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_datei = "Testbitmap.bmp"

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("") ;fenster mit rotem Inhalt erstellen
    GUISetBkColor(0x960AD2)
    GUISetState()
    sleep(500)
    ; Erstellt einen Screenshot vom kompletten Bildschirm, Bitmapdatei erzeugen
    _ScreenCapture_SetBMPFormat(4) ;4 = 32 bpp; 8 Bit für jede RGB und Alpha Komponente
    _ScreenCapture_Capture($bitmap_datei) ;screenshot vom Bildschirm erstellen und abspeichern
    Sleep(500) ;fenster anzeigen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = FileRead($bitmap_datei) ;Dateiinhalt
    $header = StringLeft($inhalt, 54) ;54byte Bitmap-Header
    $inhalt = StringTrimLeft($inhalt, 54) ;header abschneiden$bitmap_anzahl_bytes = StringLen($inhalt) ;länge string

    [/autoit] [autoit][/autoit] [autoit]

    $bitmap_anzahl_bytes = StringLen($inhalt)
    $struct_bitmap = DllStructCreate("byte[" & $bitmap_anzahl_bytes & "]") ;string im speicher BGRA als BYTEs
    $ptr_Bitmap = DllStructGetPtr($struct_bitmap) ;pointer startadresse Bitmap
    $struct_pixel = DllStructCreate("dword[" & $bitmap_anzahl_bytes / 4 & "]", $ptr_Bitmap);an derselben Adresse eine struct für die "Pixel" DWORD

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($struct_bitmap, 1, StringToBinary($inhalt)) ;string in struct

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;ab hier fängt der Assemblerteil an, zuerst wird eine hilfs-struct erstellt, damit man nicht so viele parameter an die Funktion übergeben muss
    $struct_parameter = DllStructCreate("byte Rot_von;" & _
    "byte Rot_bis;" & _
    "byte Gruen_von;" & _
    "byte Gruen_bis;" & _
    "byte Blau_von;" & _
    "byte Blau_bis;" & _
    "word _align;" & _ ;nur zur verdeutlichung, AutoIt aligned jeden anderen Datentyp an einer 8-Bit-grenze!
    "dword Farbe_ersatz") ;fängt bei startadresse +8 an, auch wenn das word _align weggelassen wird!
    $ptr_parameter = DllStructGetPtr($struct_parameter) ;pointer auf die parameter

    [/autoit] [autoit][/autoit] [autoit]

    ;farbfeld des Pixels, innerhalb dessen das Pixel durch eine bestimmte Farbe ersetzt wird
    $Rot_von = 123
    $Rot_bis = 188
    $Gruen_von = 0
    $Gruen_bis = 20
    $Blau_von = 200
    $Blau_bis = 220

    [/autoit] [autoit][/autoit] [autoit]

    ;in die struct schreiben, man könnte auch direkt die parameter schreiben^^
    DllStructSetData($struct_parameter, "Rot_von", $Rot_von) ;ESI
    DllStructSetData($struct_parameter, "Rot_bis", $Rot_bis) ;ESI+1
    DllStructSetData($struct_parameter, "Gruen_von", $Gruen_von) ;ESI+2
    DllStructSetData($struct_parameter, "Gruen_bis", $Gruen_bis) ;ESI+3
    DllStructSetData($struct_parameter, "Blau_von", $Blau_von) ;ESI+4
    DllStructSetData($struct_parameter, "Blau_bis", $Blau_bis) ;ESI+5
    ;dllstructcreate aligned an 8 byte grenzen, daher habe ich zur verdeutlichung das word _align in die struct eingefügt
    DllStructSetData($struct_parameter, "Farbe_ersatz", 0xFF00FF00) ;ESI+8 Achtung, wg little Endian ARGB !!!

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;assemblercode in den Speicher schreiben, die folgenden Zeilen wurden von AssembleIt() erstellt
    $ret_asm = "0x8B7C24048B4C24088B74240C8B5E08BA000000008B040F3A460472243A4605771FC1E8083A460272173A46037712C1E8083A06720B3A46017706891C0F83C20183E90483F9007DCC89D0C3"
    $struct_asm = DllStructCreate("byte[" & StringLen($ret_asm) / 2 - 1 & "]") ;platz für asmcode im speicher
    $ptr_asm = DllStructGetPtr($struct_asm) ;pointer asmcode
    DllStructSetData($struct_asm, 1, $ret_asm) ;asmcode in struct schreiben

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    ;asmcode callen
    $ret = DllCallAddress("uint:cdecl", $ptr_asm, "ptr", $ptr_Bitmap, "int", $bitmap_anzahl_bytes, "ptr", $ptr_parameter)

    [/autoit] [autoit][/autoit] [autoit]

    $m = TimerDiff($t)

    [/autoit] [autoit][/autoit] [autoit]

    $anzahl_pixel_ersetzt = $ret[0] ;DllCallAddress gibt ein array zurück
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $anzahl_pixel_ersetzt = ' & $anzahl_pixel_ersetzt & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $inhalt = BinaryToString(DllStructGetData($struct_bitmap, 1)) ;Bitmap aus der struct in den string

    [/autoit] [autoit][/autoit] [autoit]

    FileDelete($bitmap_datei) ;alte datei löschen
    FileWrite($bitmap_datei, $header & $inhalt) ;und neu schreiben

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute($bitmap_datei)

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit]

    //EDIT Script für 64-Bit Windows-Versionen angepasst, #AutoIt3Wrapper_UseX64=n
    Auf meinem Win7-64-Laptop seltsames Verhalten. Die "GUI" wird, wenn kein sleep() nach dem GuiSetState() eingesetzt wird, nicht dargestellt!
    Bei Sleep(100) wird die GUI Transparent angezeigt ?(
    Bei sleep(500) läuft alles wie gewollt!

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    6 Mal editiert, zuletzt von Andy (25. Dezember 2013 um 19:57)

  • Du kannst einen ja bezüglich Assembler richtig auf den Geschmack bringen. Wenn mir meine Frau zukünftig genügend Zeit lässt (sie hat es gar nicht gern, wenn ich so viel am PC hocke), muss ich mich wirklich damit beschäftigen.

    Übrigens hatte der erste Rechner, den wir 1964 bekommen haben, den riesigen Hauptspeichen von 1024 Worten zu 18 Bit (=3 Bytes zu 6 Bit). Dafür hat er aber auch nicht so viel Platz gebraucht, ihm hat ein Raum mit 60 qm ausgereicht. Peripherer Speicher war eine Magnettrommel mit 64 K Worten. Ein- und Ausgabe erfolgte über Lochstreifen und Lochkarten. Trotzdem haben wir damit beispielsweise die Nettolohnabrechnung für das Werk mit 6000 Beschäftigten geschafft. Er hieß ZAM 2 Gamma. Es war einer von den beiden nach "Ost-Deutschland" exportierten.

    Du hast für mich ja ganz tolle Programme geschrieben. Unwahrscheinlich wie tief Du in der Materie steckst. Die Möglichkeiten von Strukturen in AutoIt hatte ich bisher nicht erkannt. Ich werde nun zunächst Deine Variante vom 1.12.13 mit DllStructSetData in mein BITMAP-Programm einarbeiten. Dann wird es schon flutschen. Die Assemblervariante werde ich dann in Angriff nehmen, wenn ich mich etwas mit dem Assembler beschäftigt habe. Denn verstehen möchte man ja doch, was man da so macht.
    Jedenfalls habe ich in den letzten Tagen sehr viel von Dir gelernt. Allein schon die Erkenntnis, dass man Assemblercode in ein AutoIt-Programm einbauen kann. Ich kann Dir gar nicht genug danken.

  • Hi,
    beim "normalen" programmieren in AutoIt benötigt man idR keine Structs, die Funktion erfüllen universelle Arrays viel einfacher und übersichtlicher.
    Der Vorteil an den Structs ist, dass man eine Speicheradresse bekommt, imho in AutoIt die einzige Möglichkeit direkt an Datenstrukturen im Speicher zu kommen.
    Die Speicheradresse ist somit der Schlüssel, um mit "schnellerem" Code (in welcher Programmiersprache auch immer) die Daten zu bearbeiten.

    Zitat

    Allein schon die Erkenntnis, dass man Assemblercode in ein AutoIt-Programm einbauen kann.

    Hehe, ja, das ist schon etwas seltsam. Da gibt es KOSTENLOS die geilsten Hochsprachencompiler, und die Bekloppten werkeln in einer SCRIPT-Sprache mit Assembler rum....viel bescheuerter geht es kaum noch :D
    Aber da stehe ich drüber, ich bin kein Programmierer, sondern Techniker. Ich mache das, weil es mir Spass macht. Wenn mir etwas keinen Spass macht, dann mache ich es nicht! Das Leben ist zu kurz, um sich mit Sachen rumzuschlagen, gegen die man eine Abneigung hat...