Ich habe erst vor kurzem eine sehr einfache aber effiziente Methode der Übertragung von Bildschirminhalt geschrieben.
Das Prinzip war folgendermaßen:
-> Mit Scanline letzten und nächten Frame vom Bildschirm pixelweise durchgehen.
---> Wenn ein (außreichend großer?) Unterschied von beiden Pixeln festgestellt wird, werden in den Stream die Pixelnummer (zeile*width+x) und ein Platzhalter für die Anzahl an Pixeln geschrieben
---> Solange die folgenden Pixel sich von dem Original unterscheiden (+ lookahead von 2 Pixeln) wird jeder weitere Pixel in den Stream geschrieben.
---> Wenn 3 aufeinanderfolgende Pixel wieder gleich sind, wird mit dem schreiben aufgehört.
---> Wenn der Schreibvorgang beendet wird, wird noch die Anzahl geschriebener Pixel an den Platzhalter geschrieben
---> Bei durchgehen aller Pixel werden dabei Zeilenenden ignoriert.
-> Der Finale Stream wird noch mit
ZLib gepackt.
-> Das Wiederherstellen des Bildes beim Zielrechner geschieht analog.
Hier mal die beiden Funktionen dafür:
Delphi-Quellcode:
procedure compressStream(input, output: TStream);
var
xx: TCompressionStream;
begin
xx := TCompressionStream.Create(clmax, output);
try
input.Position := 0;
xx.CopyFrom(input, input.Size);
finally
xx.Free;
output.position := 0;
end;
end;
procedure TForm1.WriteDiffPkg(last, next: TBitmap; zipPkg: TMemoryStream);
var
w, h : Integer;
ix, iy : Integer;
pixpos : Cardinal;
cnt : Cardinal;
addr : Int64;
pl, pn : PRGBTriple;
diff : Boolean;
pkg : TMemoryStream;
type
PLongWord = ^LongWord;
begin
pkg := TMemoryStream.Create;
try
w := last.Width;
h := last.Height;
pixpos := 0;
diff := false;
for iy := 0
to h - 1
do
begin
pl := last.ScanLine[iy];
pn := next.ScanLine[iy];
for ix := 0
to w - 1
do
begin
If ((PLongWord(pl)^
and $F0F0F0) = (PLongWord(pn)^
and $F0F0F0))
then
begin
If diff
then
begin
inc(pl); inc(pn);
If ((PLongWord(pl)^
and $F0F0F0) = (PLongWord(pn)^
and $F0F0F0))
then
begin
inc(pl); inc(pn);
If ((PLongWord(pl)^
and $F0F0F0) = (PLongWord(pn)^
and $F0F0F0))
then
begin
PCardinal(Integer(Pkg.Memory) + addr)^ := cnt;
diff := false;
end;
dec(pl);
dec(pn);
end;
dec(pl);
dec(pn);
If diff
then
begin
Pkg.
Write(pn^, 3);
// pl^.rgbtRed := 0;
// pl^.rgbtGreen := 0;
// pl^.rgbtBlue := 0;
inc(cnt);
end;
end;
end
else
begin
If not diff
then
begin
cnt := 0;
addr := Pkg.Size;
Pkg.WriteCardinal(0);
Pkg.WriteCardinal(pixpos);
diff := true;
end;
Pkg.
Write(pn^, 3);
// pl^.rgbtRed := 0;
// pl^.rgbtGreen := 0;
// pl^.rgbtBlue := 0;
inc(cnt);
end;
inc(pixpos);
inc(pl);
inc(pn);
end;
end;
Pkg.WriteCardinal(0);
finally
zipPkg.Clear;
pkg.Position := 0;
compressStream(pkg, zipPkg);
pkg.Free;
end;
end;
procedure TForm1.ReadDiffPkg(last: TBitmap; zipPkg: TStream);
var
w, h : Integer;
ix, iy : Integer;
pixpos : Cardinal;
cnt : Cardinal;
addr : Cardinal;
ssize : Int64;
pix : PRGBTriple;
pkg : TDecompressionStream;
type
PLongWord = ^LongWord;
begin
zipPkg.Position := 0;
pkg := TDecompressionStream.Create(zipPkg);
try
w := last.Width;
h := last.Height;
ix := 0;
iy := 0;
pixpos := 0;
pix := last.ScanLine[iy];
//while Pkg.Position < Pkg.Size do
while true
do
begin
cnt := Pkg.ReadCardinal;
If cnt = 0
then break;
addr := Pkg.ReadCardinal;
// Fast-forward to address
ix := addr
mod w;
iy := addr
div w;
pix := last.ScanLine[iy];
inc(pix, ix);
// Write data
while cnt > 0
do
If (ix < w)
then
begin
Pkg.
Read(pix^, 3);
inc(ix);
inc(pixpos);
dec(cnt);
inc(pix);
end
else
begin
inc(iy);
pix := last.ScanLine[iy];
ix := 0;
end;
end;
finally
pkg.Free;
end;
end;
Bei Interesse kann ich auch noch eine Variation der Funktion posten, welche per Flag nur jede gerade/ungerade Zeile verarbeitet, um schnellere Updates zu ermöglichen.
Diese Technik hat sich im Praxistest als unglaublich schnell für die Übertragung von Textinhalten erwiesen.
Man kann bestimmt das ganze durch Bittiefenreduzierung noch optimieren...