Ressourcen Komprimieren

  • Moin,

    Als Ressource werden Bilder, Dateien und sonstiger Kram immer mal gerne in AutoIt eingebunden.
    Nachteil dabei ist die enorme Größenzunahme.

    Im folgenden gehe ich von einer "optimal" komprimierten Dateiquelle aus.
    (beim Einbinden einer DLL wurde z.B. schon UPX auf maximum genutzt, bei Bildern .png mit Maximaleinstellungen, oder MP3 oder oder oder. Eine Datei ohne weiter komprimierbare Strukturen)

    Man hat zurzeit 3 Möglichkeiten:
    1. Einbinden als HexString (per Stringtobinary). Das gibt eine Dateigröße von 200%
    2. Einbinden als Base64 (UEZ hat dazu ein schönes Skript gebastelt). Dateigröße ist 133%
    3. Komprimieren des HexStrings durch Ersetzung häufiger Zeichenketten durch Nicht Hex Zeichen, oder selbiges mit Base64.

    Am Effektivsten ist Nummer 2 in Verbindung mit Nummer 3.
    Es wird beim "Nachkomprimieren" aber nie eine sonderlich hohe Leistung erziehlt. (idr bleibt das Resultat über 120%)

    Man sieht: je höher die Basis, desto näher ist das Ergebnis an der ursprünglichen Größenordnung.
    Das habe ich mir auch gedacht und einen Konverter von B16 (also einem String aus Hexadezimalzeichen) in B216 und zurück gebastelt.
    Bei 216 zeichen kann man wunderbar mit winzigen Verlusten 31 Bit als 4 Zeichen darstellen. Die Endgröße ist also nur 32/31 Mal so groß. ( das sind 3,23%)

    Leider ist das Skript noch nicht gut getestet.
    Daher bitte ich darum es einfach mal irgendwo einzubauen und rennen zu lassen.

    Wenn es was taugt kann man damit sämtliche als Ressource eingebauten Daten von 125-200% auf 103% einpacken.

    Test
    [autoit]


    #include <Memory.au3>
    #include <Array.au3>

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

    Local $sInput = 'Hallo Leute, alles klar ? Was macht man mit AutoIt ?!* Testen wir das doch direkt mal aus ! Ich meine es ernst. Der Text hier muss schon ganz schön lange werden. <<<<<<<<<<>>>>>>>>>>'
    Local $sTmp, $iLen = StringLen($sInput)

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

    ConsoleWrite(@CRLF)

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

    $sTmp = $sInput
    ConsoleWrite('Base 256: "' & $sTmp & '"' & @CRLF)
    ConsoleWrite('Stringlen: ' & StringLen($sTmp) & ' ( + ' & Round((StringLen($sTmp)/$iLen - 1)*100,2) & ' %)'& @CRLF & @CRLF)

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

    $sTmp = _StrToB16($sInput)
    ConsoleWrite('Base 16: "' & $sTmp & '"' & @CRLF)
    ConsoleWrite('Stringlen: ' & StringLen($sTmp) & ' ( + ' & Round((StringLen($sTmp)/$iLen - 1)*100,2) & ' %)'& @CRLF & @CRLF)

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

    $sTmp = _StrToB2($sInput)
    ConsoleWrite('Base 2: "' & $sTmp & '"' & @CRLF)
    ConsoleWrite('Stringlen: ' & StringLen($sTmp) & ' ( + ' & Round((StringLen($sTmp)/$iLen - 1)*100,2) & ' %)'& @CRLF & @CRLF)

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

    $sTmp = _StrToB64($sInput)
    ConsoleWrite('Base 64: "' & $sTmp & '"' & @CRLF)
    ConsoleWrite('Stringlen: ' & StringLen($sTmp) & ' ( + ' & Round((StringLen($sTmp)/$iLen - 1)*100,2) & ' %)'& @CRLF & @CRLF)

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

    $sTmp = _StrToB216($sInput)
    ConsoleWrite('Base 216: "' & $sTmp & '"' & @CRLF)
    ConsoleWrite('Stringlen: ' & StringLen($sTmp) & ' ( + ' & Round((StringLen($sTmp)/$iLen - 1)*100,2) & ' %)'& @CRLF & @CRLF)

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

    ConsoleWrite('Decode:' & @CRLF)
    $sTmp = $sInput
    ConsoleWrite('Base 256: "' & $sTmp & '"' & @CRLF)

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

    $sTmp = _B16ToStr(_StrToB16($sInput))
    ConsoleWrite('Base 16: "' & $sTmp & '"' & @CRLF)

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

    $sTmp = _B2ToStr(_StrToB2($sInput))
    ConsoleWrite('Base 2: "' & $sTmp & '"' & @CRLF)

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

    $sTmp = _B216ToStr(_StrToB216($sInput))
    ConsoleWrite('Base 216: "' & $sTmp & '"' & @CRLF)

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

    ConsoleWrite(@CRLF)

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

    ConsoleWrite('Hexstring (B16) -> B216 -> Hexstring (B16)' & @CRLF)

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

    $sTmp = '0x' & _StrToB16($sInput)
    ConsoleWrite('Base 16: "' & $sTmp & '"' & @CRLF)

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

    $sTmp = _B16ToB216($sTmp)
    ConsoleWrite('Base 216: "' & $sTmp & '"' & @CRLF)

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

    $sTmp = _B216ToB16($sTmp)
    ConsoleWrite('Base 16: "' & $sTmp & '"' & @CRLF)

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

    ; Funktionen:

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

    ;~ _StrToB2
    ;~ _StrToB16
    ;~ _StrToB64 - Nicht von mir.
    ;~ _StrToB216
    ;~ _B2ToStr
    ;~ _B16ToStr
    ;~ _B216ToStr

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

    ;~ _B2ToB16
    ;~ _B2ToB216
    ;~ _B16ToB2
    ;~ _B16ToB216 -> Ressource Komprimieren
    ;~ _B216ToB2
    ;~ _B216ToB16 -> Ressource Dekomprimieren

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

    Func _B216ToB16($s)
    Return '0x' & _B2ToB16(_B216ToB2($s))
    EndFunc

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

    Func _B16ToB216($s)
    Return _B2ToB216(_B16ToB2(StringTrimLeft($s,2)))
    EndFunc

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

    Func _StrToB2($s)
    Return _B16ToB2(_StrToB16($s))
    EndFunc

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

    Func _StrToB216($s)
    Return _B2ToB216(_B16ToB2(_StrToB16($s)))
    EndFunc

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

    Func _B2ToStr($s)
    Return _B16ToStr(_B2ToB16($s))
    EndFunc

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

    Func _B2ToB216($s)
    Local Static $_a = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
    Local Static $a = _ToArray($_a)
    Local $sRet = ''
    Local $iParts = Ceiling(StringLen($s)/31)
    ;~ _ArrayDisplay($a)
    Local $iNullen = $iParts*31 - StringLen($s), $Array, $o, $sTmp

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

    ;~ ConsoleWrite($iNullen & @CRLF)

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

    $s &= StringLeft('0000000000000000000000000000000', $iNullen)

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

    For $i = 1 To $iParts Step 1
    $o = StringRight('0000000000' & _B2ToB10(StringLeft($s, 31)),10)
    ;~ ConsoleWrite($o & ' - ')
    $Array = StringSplit(_DecToBX($o, 216), ' ')
    $sTmp = ''
    For $x = 1 To $Array[0]-1 Step 1
    $sTmp &= $a[$Array[$x]]
    ;~ ConsoleWrite($Array[$x] & ' ')
    Next
    ;~ ConsoleWrite(@CRLF)
    $sRet &= StringRight('!!!!' & $sTmp, 4)
    ;~ $sRet &= _DecToBX($o, 216) & @CRLF
    ;~ $sRet &= $o & ' ' & Hex($o, 8) & ' ' & _DecToBX($o, 216) & StringRight('000000000' & _BXToDec( & @CRLF
    ;~ $sRet &= StringLeft($s, 31) & @CRLF
    ;~ $sRet &= _B10ToB216(StringRight('0000000000' & _B2ToB10(StringLeft($s, 31)),10)) & ''
    $s = StringTrimLeft($s, 31)
    Next

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

    $sRet &= $a[StringRight('000' & $iNullen,3)]

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

    ;~ FileWrite('blaaa.txt', $sRet)

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

    Return $sRet
    EndFunc

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

    Func _B216ToB2($s)

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

    Local $iNullen = _Asc216(StringRight($s, 1))
    $s = StringTrimRight($s, 1)

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

    Local $iParts = StringLen($s)/4, $sTmp, $sRet = ''

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

    For $i = 1 To $iParts Step 1
    $sTmp = StringLeft($s, 4)
    ;~ ConsoleWrite(_Asc216(StringLeft($sTmp, 1)) * 216^3 & ' ' & _Asc216(StringMid($sTmp, 2, 1)) * 216^2 & ' ' & _Asc216(StringMid($sTmp, 3, 1))*216 & ' ' & _Asc216(StringRight($sTmp, 1)) & @CRLF)
    $sTmp = Int(_Asc216(StringMid($sTmp, 1, 1)) * 216^3) + Int(_Asc216(StringMid($sTmp, 2, 1)) * 216^2) + Int(_Asc216(StringMid($sTmp, 3, 1)) * 216) + Int(_Asc216(StringMid($sTmp, 4, 1)))
    $sRet &= StringRight('0000000000000000000000000000000' & _B16ToB2(Hex(StringRight('0000000000' & $sTmp,10),8)), 31)
    $s = StringTrimLeft($s, 4)
    Next

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

    $sRet = StringTrimRight($sRet, $iNullen)

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

    ;~ ConsoleWrite(@CRLF & _StrToB2('Hallo Leute, alles klar ? Was macht man mit AutoIt ?!*'))
    ;~ ConsoleWrite(@CRLF & $sRet & @CRLF)

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

    Return $sRet
    EndFunc

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

    Func _Asc216($s)
    Local Static $_a = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
    Local Static $a = _ToArray($_a)
    For $i = 0 To 215 Step 1
    If $s == $a[$i] Then Return $i
    Next
    EndFunc

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

    Func _B216ToStr($s)
    Return _B2ToStr(_B216ToB2($s))
    EndFunc

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

    Func _B2ToB16($s)
    Local $sRet = ''
    For $i = 1 To StringLen($s) Step 4
    $sRet &= Hex(Int(_B2ToB10(StringMid($s, $i, 4))),1) & ''
    Next
    Return $sRet
    EndFunc

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

    Func _ToArray($s)
    Local $a[StringLen($s)]
    For $i = 0 To UBound($a) - 1 Step 1
    $a[$i] = StringMid($s, $i+1, 1)
    Next
    Return $a
    EndFunc

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

    Func _BXToDec($i, $iBase)
    Local $iRet, $a = StringSplit($i, ' ')
    For $i = 1 To $a[0] - 1 Step 1
    $iRet += $iBase^($i-1)*$a[$a[0]-$i]
    Next
    Return $iRet
    EndFunc

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

    Func _DecToBX($i, $iBase)
    Local $x, $s
    While Not ($i = 0)
    $x = Int($i/$iBase) ; Teilen
    $s = StringRight('000' & Int(Round((($i/$iBase)-$x)*$iBase,0)),3) & ' ' & $s; Rest
    $i = $x
    WEnd
    Return $s
    EndFunc

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

    Func _B2ToB10($i)
    Local $iRet = 0, $iLen = StringLen($i)
    For $e = $iLen To 1 Step -1
    $iRet += 2 ^ ($iLen - $e) * Int(StringMid($i, $e, 1))
    Next
    Return $iRet
    EndFunc

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

    Func _StrToB64($Data, $LineBreak = 0)
    Local $Opcode = "0x5589E5FF7514535657E8410000004142434445464748494A4B4C4D4E4F505152" _
    & "535455565758595A6162636465666768696A6B6C6D6E6F707172737475767778" _
    & "797A303132333435363738392B2F005A8B5D088B7D108B4D0CE98F0000000FB6" _
    & "33C1EE0201D68A06880731C083F901760C0FB6430125F0000000C1E8040FB633" _
    & "83E603C1E60409C601D68A0688470183F90176210FB6430225C0000000C1E806" _
    & "0FB6730183E60FC1E60209C601D68A06884702EB04C647023D83F90276100FB6" _
    & "730283E63F01D68A06884703EB04C647033D8D5B038D7F0483E903836DFC0475" _
    & "0C8B45148945FC66B80D0A66AB85C90F8F69FFFFFFC607005F5E5BC9C21000"
    Local $pProc = _MemVirtualAlloc(0, BinaryLen($Opcode), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    Local $CodeBuffer = DllStructCreate("byte[" & BinaryLen($Opcode) & "]", $pProc)
    DllStructSetData($CodeBuffer, 1, $Opcode)
    $Data = Binary($Data)
    Local $Input = DllStructCreate("byte[" & BinaryLen($Data) & "]")
    DllStructSetData($Input, 1, $Data)
    $LineBreak = Floor($LineBreak / 4) * 4
    Local $OputputSize = Ceiling(BinaryLen($Data) * 4 / 3)
    $OputputSize = $OputputSize + Ceiling($OputputSize / $LineBreak) * 2 + 4
    Local $Ouput = DllStructCreate("char[" & $OputputSize & "]")
    DllCall("user32.dll", "none", "CallWindowProc", "ptr", DllStructGetPtr($CodeBuffer), "ptr", DllStructGetPtr($Input), "int", BinaryLen($Data), "ptr", DllStructGetPtr($Ouput), "uint", $LineBreak)
    _MemVirtualFree($pProc, BinaryLen($Opcode), $MEM_DECOMMIT)
    Return DllStructGetData($Ouput, 1)
    EndFunc ;==>_Base64Encode

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

    Func _B16ToB2($s)
    Local Static $a[16] = ['0000','0001','0010','0011','0100','0101','0110','0111','1000','1001','1010','1011','1100','1101','1110','1111']
    Local $sOut
    For $i = 1 To StringLen($s) Step 1
    $sOut &= $a['0x' & StringMid($s, $i, 1)]
    Next
    Return $sOut
    EndFunc

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

    Func _StrToB16($s)
    Return StringTrimLeft(StringToBinary($s),2)
    EndFunc

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

    Func _B16ToStr($s)
    Return BinaryToString('0x' & $s)
    EndFunc

    [/autoit]


    .
    .

  • Hi,
    hab den Code nur überflogen, die Funktion ASC216 kannst du durch ein (sauschnelles) stringinstr() ersetzen und $a=_ToArray($_a) ist die langsame Version von $a=StringSplit($_a,"")

    Ansonsten klasse :D

    /EDIT/Aber da gibts ein kleines Problem^^
    Je nach Zeichencodetabelle und verwendeter Codepage werden die Zeichen

    Code
    Base 216: "^WÖHPX2;o”O”íÊþÍ7+Mn15!’qnöÊTi

    mit anderen Ascii-Codes ausgewertet!
    Das könntest du umgehen, indem du sowohl beim kodieren als auch beim dekodieren dieselbe Codepage verwendest....

    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

    3 Mal editiert, zuletzt von Andy (8. August 2012 um 20:39)

  • Bevor ich dein Skript teste, eine kleine Anmerkung zu 2.: die Ressource wird in ein Base64 umgewandelt, aber vorher, wenn erwünscht, mit dem Built-In Kerner32 Funktion komprimiert, so dass je nach Datentyp die Ressource noch kleiner wird.
    Aber du hast recht, dass nach der Komprimierung und Umwandlung in B64 die Zeichenfolgen noch verkleinerbar ist. Ok, das ist nicht dein Ansatz.

    Werde mal File to Base216 String Code Generator basteln und es mit
    File to Base64 String Code Generator vergleichen.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    2 Mal editiert, zuletzt von UEZ (9. August 2012 um 16:49)