(CodeFlag, Anzahl, Zeichen)
aaaaaxxxxxxxPPPPPPPPPP
(CodeFlag, 5, a)
+
(CodeFlag, 7, x)
+
(CodeFlag, 10, P)
FF0561 FF0778 FF0A50.
(CodeFlag, NoCode)
FF00.
type
T8Bit = Byte; // Denkhilfe!
const
CodeFlag: T8Bit = $FF; // binär: 1111 1111
NoCode: T8Bit = $00; // binär: 0000 0000 aus T8Bit\[1..MaxCount]
MaxCount: T8Bit = $FE; // binär: 1111 1110
(* Komprimiert den Quellstrom "Source" in den Zielstrom "Destination"
mittels RLE und 8Bit zur Basis.
Beispiele:
(Exemplarisch sind AB, vw und XY ein 8Bit-Zeichen und FF ist das CodeFlag)
Aus ABvwXYAB folgt ABvwXYAB (keine Komprimierung!).
ABABXYXYXY > ABABXYXYXY (ebenfalls keine Komprimierung!).
ABABABABXY > FF04ABXY (40Bit > 32Bit).
ABABABABAB > FF05AB (40Bit > 24Bit).
vwABABABABAB > vwFF05AB (48Bit > 32Bit).
vwABABABABABXY > vwFF05ABXY (56Bit > 40Bit).
XYABABABABvwXYXYXYXY > XYFF04ABvwFF04XY (80Bit > 64Bit).
Allerdings:
FF > FF00 (8Bit > 16Bit), das kann "nicht" optimiert werden!
FFAB > FF00AB (16Bit > 24Bit).
FFFF > FF00FF00 (16Bit > 32Bit), das kann optimiert werden!
FFFFFF > FF00FF00FF00 (24Bit > 48Bit), das kann auch optimiert werden!
Aber:
FFFFFFFF > FF04FF (32Bit > 24Bit). *)
procedure RLE8Compress(Source, Destination: TMemoryStream);
(* Versucht die folgenden Zeichen aus den Quellstrom zu komprimieren.
Ich sage dazu "lokale Komprimierung"!
Das Komprimieren ist erst dann möglich, wenn mindestens vier
gleiche Zeichen (Bytes bzw. 8Bit) aufeinander folgen.
Beispiele:
ABABAB > "Versuch schlägt fehl!".
FFFFFF > "Versuch schlägt fehl!".
ABABABAB > FF04AB (32Bit > 24Bit).
ABABABABAB > FF05AB (40Bit > 24Bit).
ABABABABABAB > FF06AB (48Bit > 24Bit).
usw. bis ... > FFFEAB (2040Bit > 24Bit) *)
function Try8BitCompress: Boolean;
var
Counting: Boolean;
Count: T8Bit;
Try8Bit: packed array[0..3] of T8Bit; // vier 8Bit-Zeichen
Next8Bit: T8Bit;
begin
// Initialisierung: Komprimierversuch schlug fehl.
Result := FALSE;
(* Prüfe, ob die nächsten vier Zeichen komprimiert werden können.
Dazu müssen vier gleiche Zeichen vorhanden sein. *)
// Existenz von vier Zeichen
if (Source.Size - Source.Position < SizeOf(Try8Bit)) then Exit;
// Vergleich der vier Zeichen
Source.ReadBuffer(Try8Bit, SizeOf(Try8Bit));
Source.Position := Source.Position - SizeOf(Try8Bit); // Spuren vernichten!
if (Try8Bit[0] <> Try8Bit[1]) then Exit;
if (Try8Bit[1] <> Try8Bit[2]) then Exit;
if (Try8Bit[2] <> Try8Bit[3]) then Exit;
(* Es gibt also zumindest vier gleiche Zeichen.
Die Komprimierung der folgenden Zeichen kann also beginnen! *)
// Neuer Rückgabewert: Komprimierversuch gelingt!
Result := TRUE;
(* Kleine Optimierung:
Da die nächsten vier Zeichen sicherlich gleich sind,
so muss man diese Zeichen nicht nochmal auf Gleichheit prüfen,
und kann deshalb dementsprechend initialisieren. *)
Source.Position := Source.Position + SizeOf(Try8Bit);
Count := SizeOf(Try8Bit); // Zähler für gleiche Zeichen.
(* Der eigentliche Komprimier-Algorithmus (lokal)!
Jetzt werden nur gleiche Zeichen aus den Zeichenstrom gezählt,
jedoch bei MaxCount ist spätestens Schluss! *)
if (Source.Size - Source.Position > 0) then
repeat
Source.ReadBuffer(Next8Bit, 1);
Counting := (Try8Bit[0] = Next8Bit); // kann gezählt werden?
if Counting then Inc(Count, 1)
else Source.Position := Source.Position - 1; // falls nein, zurücksetzen
until (not Counting) or (Count >= MaxCount) or
(Source.Size - Source.Position < 1);
(* Die gesammelte Information wird mit 24 Bit in den Zielstrom gespeichert:
die ersten acht Bit sind das CodeFlag also $FF;
die nächsten acht Bit sind die Anzahl der Vorkommen gleicher Zeichen;
und die letzten acht Bit sind das Zeichen, dessen Vorkommen
gezählt wurde. *)
Destination.WriteBuffer(CodeFlag, 1); // Flag für Komprimierungscode
Destination.WriteBuffer(Count, 1); // Anzahl der Zeichen
Destination.WriteBuffer(Try8Bit[0], 1); // das Zeichen
end;
(* Das einzelne Zeichen wird unkomprimiert aus den Quellstrom übernommen.
Diese Procedure wird verwendet, wenn nicht lokal komprimiert werden konnte.
Beispiele:
Aus AB folgt AB (AB ist ein 8Bit-Zeichen).
Aus F7 folgt F7 (F7 ist ein 8Bit-Zeichen).
Allerdings aus FF folgt FF00, also aus 8Bit werden 16Bit,
d.h. die Kodierung wird hier länger :-( ABER, nur in diesem Fall!!! *)
procedure NoCompress;
var
Next: T8Bit;
begin
// Gibt es noch ein 8Bit-Zeichen?
if (Source.Size - Source.Position < 1) then Exit; // falls nein, Ausstieg
(* Lese das nächste 8Bit-Zeichen aus den Quellstrom,
schreibe dieses Zeichen in den Zielstrom! *)
Source.ReadBuffer(Next, 1);
Destination.WriteBuffer(Next, 1);
(* Falls das gelesene Zeichen zugleich ein Code-Zeichen ist,
dann muss zusätzlich noch ein Zeichen folgen, das anzeigt,
dass es sich hier "nicht" um eine Komprimierung handelt. *)
if (Next = CodeFlag) then Destination.WriteBuffer(NoCode, 1);
end;
begin
// Initialisierung
Source.Position := 0;
Destination.Clear;
(* Der eigentliche Komprimier-Algorithmus!
Wiederhole, solange der Quellstrom nicht vollständig abgearbeitet wurde!
Es wird in jedem Schleifendurchlauf versucht eine "lokale" Komprimierung
(Try8BitCompress) durchzuführen;
Falls keine "lokale" Komprimierung durchgeführt werden konnte,
so wird das einzelne Zeichen unkomprimiert übernommen (NoCompress). *)
while (Source.Size - Source.Position > 0) do
if not Try8BitCompress then NoCompress;
// Finalisierung
Source.Position := 0;
Destination.Position := 0;
end;
(* Macht die 8-Bit-RLE-Komprimierung wieder rückgängig. *)
procedure RLE8Decompress(Source, Destination: TMemoryStream);
var
CodeCount: T8Bit;
Next: T8Bit;
(* Lokale Dekodierung!
Das nächste Zeichen wird Count-mal-so-oft in den Zielstrom geschrieben. *)
procedure Decode8(Count: T8Bit);
var
i: T8Bit; // denn Count: T8Bit
MultiNext: T8Bit;
begin
Source.ReadBuffer(MultiNext, 1);
for i := Count downto 1 do
Destination.WriteBuffer(MultiNext, 1);
end;
begin
// Initialisierung
Source.Position := 0;
Destination.Clear;
(* Der eigentliche Dekomprimier-Algorithmus! *)
while (Source.Size - Source.Position > 0) do
begin
// Lese ein 8Bit-Zeichen!
Source.ReadBuffer(Next, 1);
// Prüfe, ob es sich bei diesem 8Bit-Zeichen um ein CodeFlag handelt!
if (Next = CodeFlag) then
begin
// Lese nächstes Zeichen, vielleicht ist es die Anzahl!
Source.ReadBuffer(CodeCount, 1);
(* Hier wird entschieden, ob das Next als einfaches 8Bit-Zeichen
abgespeichert werden soll,
oder ob eine lokale Komprimier-Kodierung vorliegt. *)
if (CodeCount = NoCode) then Destination.WriteBuffer(Next, 1)
else Decode8(CodeCount);
end
else Destination.WriteBuffer(Next, 1); // Next wird einfach übernommen
end;
// Finalisierung
Source.Position := 0;
Destination.Position := 0;
end;
type
// Prozeduraler Typ für die RLE-Algorithmen
TMem2Mem = procedure(Source, Destination: TMemoryStream);
// Hilfsprozedur, um redundanten Code zu vermeiden.
procedure MemAsFile(const SrcFile, DestFile: string; Mem2Mem: TMem2Mem);
var
SrcFileStream, DestFileStream: TFileStream;
Source, Destination: TMemoryStream;
begin
SrcFileStream := TFileStream.Create(SrcFile, fmOpenRead);
DestFileStream := TFileStream.Create(DestFile, fmCreate);
Source := TMemoryStream.Create();
Destination := TMemoryStream.Create();
try
Source.CopyFrom(SrcFileStream, SrcFileStream.Size);
Mem2Mem(Source, Destination);
DestFileStream.CopyFrom(Destination, Destination.Size);
finally
Destination.Free;
Source.Free;
DestFileStream.Free;
SrcFileStream.Free;
end;
end;
procedure RLE8CompressFile(const SrcFile, DestFile: string);
begin
MemAsFile(SrcFile, DestFile, RLE8Compress);
end;
procedure RLE8DecompressFile(const SrcFile, DestFile: string);
begin
MemAsFile(SrcFile, DestFile, RLE8Decompress);
end;
(* Anwendungsbeispeile mit bel. Dateien. *)
RLE8CompressFile('MeinLeben.txt', 'MeinLeben.rle8');
RLE8CompressFile('MeinPassphoto.bmp', 'MeinPassphoto.comp');
RLE8DecompressFile('MeinLeben.rle8', 'MeinLeben.txt~');
RLE8DecompressFile('MeinPassphoto.comp', 'MeinPassphoto.bmp~');
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
00 16 32 48 64 |
48 61 61 61 61 61 61 61 61 61 61 61 61 6C 6C 6F 21 21 21 0D 0A 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 63 68 20 62 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 69 6E 73 21 21 21 21 |
Haaaaaaaaaaaallo !!!··iiiiiiiiiii iiiiiiiiiiiiiiii ch biiiiiiiiiiii iiiiiiiiins!!!! |
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
00 16 |
48 FF 0C 61 6C 6C 6F 21 21 21 0D 0A FF 1B 69 63 68 20 62 FF 15 69 6E 73 FF 04 21 |
H•·allo!!!··•·ic h b•·ins•·! |
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
000 016 032 048 064 080 096 112 128 144 160 176 192 208 224 240 256 272 288 304 320 336 352 368 384 400 416 432 448 464 480 496 512 528 544 560 576 592 608 624 |
42 4D 76 02 00 00 00 00 00 00 76 00 00 00 28 00 00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00 00 00 00 02 00 00 CE 0E 00 00 CE 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF 00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF 00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 77 77 00 00 00 00 00 00 00 00 77 77 00 00 00 00 77 77 00 00 00 00 00 00 00 00 77 77 00 00 00 77 77 77 77 00 00 00 00 00 00 77 77 77 77 00 00 77 77 77 77 00 00 00 00 00 00 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 00 77 77 77 77 77 77 77 77 77 77 00 00 00 00 00 00 77 77 77 77 77 77 77 77 77 77 00 00 00 00 00 00 00 77 77 77 77 77 77 77 77 00 00 00 00 00 00 00 00 77 77 77 77 77 77 77 77 00 00 00 00 00 00 00 00 00 77 77 77 77 77 77 00 00 00 00 00 00 00 00 00 00 77 77 77 77 77 77 00 00 00 00 00 00 00 00 00 00 77 77 77 77 77 77 00 00 00 00 00 00 00 00 00 00 77 77 77 77 77 77 00 00 00 00 00 00 00 00 00 77 77 77 77 77 77 77 77 00 00 00 00 00 00 00 00 77 77 77 77 77 77 77 77 00 00 00 00 00 00 00 77 77 77 77 77 77 77 77 77 77 00 00 00 00 00 00 77 77 77 77 77 77 77 77 77 77 00 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 77 00 00 00 00 77 77 77 77 77 00 00 77 77 77 77 00 00 00 00 00 00 77 77 77 77 00 00 77 77 77 77 00 00 00 00 00 00 77 77 77 77 00 00 00 77 77 00 00 00 00 00 00 00 00 77 77 00 00 00 00 77 77 00 00 00 00 00 00 00 00 77 77 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
BMv·······v···(· ·· ··· ········· ······•···•····· ············•··• ···••·•···•·•·•• ··•••·•••···•··• ···••·•···•·•·•• ··•••··········· ················ ········ww······ ··ww····ww······ ··ww···wwww····· ·wwww··wwww····· ·wwww··wwwww···· wwwww··wwwww···· wwwww···wwwww··w wwww····wwwww··w wwww·····wwwwwww www······wwwwwww www·······wwwwww ww········wwwwww ww·········wwwww w··········wwwww w··········wwwww w··········wwwww w·········wwwwww ww········wwwwww ww·······wwwwwww www······wwwwwww www·····wwwww··w wwww····wwwww··w wwww···wwwww···· wwwww··wwwww···· wwwww··wwww····· ·wwww··wwww····· ·wwww···ww······ ··ww····ww······ ··ww············ ················ ······ |
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
000 016 032 048 064 080 096 112 128 144 160 176 192 208 224 240 256 272 288 304 320 336 352 |
42 4D 76 02 FF 06 00 76 00 00 00 28 00 00 00 20 00 00 00 20 00 00 00 01 00 04 FF 06 00 02 00 00 CE 0E 00 00 CE 0E FF 10 00 80 00 00 80 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 00 FF 00 00 00 00 FF 00 FF 00 00 FF 00 00 00 00 FF 00 00 FF 00 00 FF 00 FF 00 00 00 FF 00 FF 00 FF 00 FF 23 00 77 77 FF 08 00 77 77 FF 04 00 77 77 FF 08 00 77 77 00 00 00 FF 04 77 FF 06 00 FF 04 77 00 00 FF 04 77 FF 06 00 FF 04 77 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 00 FF 05 77 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 FF 05 77 FF 05 00 FF 0A 77 FF 06 00 FF 0A 77 FF 07 00 FF 08 77 FF 08 00 FF 08 77 FF 09 00 FF 06 77 FF 0A 00 FF 06 77 FF 0A 00 FF 06 77 FF 0A 00 FF 06 77 FF 09 00 FF 08 77 FF 08 00 FF 08 77 FF 07 00 FF 0A 77 FF 06 00 FF 0A 77 FF 05 00 FF 05 77 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 FF 05 77 00 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 FF 05 77 FF 04 00 FF 05 77 00 00 FF 04 77 FF 06 00 FF 04 77 00 00 FF 04 77 FF 06 00 FF 04 77 00 00 00 77 77 FF 08 00 77 77 FF 04 00 77 77 FF 08 00 77 77 FF 22 00 |
BMv·•··v···(··· ··· ······•····· •···•·•··•··•··· ••·•···•·•·••··• ••·•••···•···•·· ··•·•··•····•··• ··•·•···•·•·•·•# ·ww•··ww•··ww•·· ww···•·w•··•·w·· •·w•··•·w··•·w•· ·•·w··•·w•··•·w· ··•·w··•·w•··•·w ··•·w•··•·w•··•· w•··•·w•··•·w•·· •·w•··•·w•··•·w• ··•·w•··•·w•··•· w•··•·w•··•·w•·· •·w··•·w•··•·w·· •·w···•·w•··•·w· ·•·w•··•·w··•·w• ··•·w··•·w•··•·w ···ww•··ww•··ww• ··ww•"· |
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
000 016 032 048 064 080 096 112 128 144 160 176 192 208 224 240 256 272 288 304 320 336 352 368 384 400 416 432 448 464 480 496 512 528 544 560 576 592 608 624 640 656 672 688 704 720 736 |
61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 20 20 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 20 20 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 |
aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaa bb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb bbbbbbbbbb cccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccc |
| Zeile | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | Text |
|
00 |
FF DC 61 20 20 FF FE 62 FF 2E 62 20 20 FF DC 63 |
••a ••b•.b ••c |