📄 graphiccompression.pas
字号:
begin
RunLength := 1 + (SourcePtr^ and $7F);
if SourcePtr^ > $7F then
begin
Inc(SourcePtr);
SourceCardinal := PCardinalArray(SourcePtr)[0];
for I := 0 to RunLength - 1 do
PCardinalArray(TargetPtr)[I] := SourceCardinal;
Inc(TargetPtr, 4 * RunLength);
Inc(SourcePtr, 4);
end
else
begin
Inc(SourcePtr);
Move(SourcePtr^, TargetPtr^, 4 * RunLength);
Inc(SourcePtr, 4 * RunLength);
Inc(TargetPtr, 4 * RunLength);
end;
Dec(UnpackedSize, RunLength);
end;
end;
Source := SourcePtr;
end;
//----------------------------------------------------------------------------------------------------------------------
function GetPixel(P: PByte; BPP: Byte): Cardinal;
// Retrieves a pixel value from a Buffer. The actual size and order of the bytes is not important
// since we are only using the value for comparisons with other pixels.
begin
Result := P^;
Inc(P);
Dec(BPP);
while BPP > 0 do
begin
Result := Result shl 8;
Result := Result or P^;
Inc(P);
Dec(BPP);
end;
end;
//----------------------------------------------------------------------------------------------------------------------
function CountDiffPixels(P: PByte; BPP: Byte; Count: Integer): Integer;
// counts pixels in Buffer until two identical adjacent ones found
var
N: Integer;
Pixel,
NextPixel: Cardinal;
begin
N := 0;
NextPixel := 0; // shut up compiler
if Count = 1 then Result := Count
else
begin
Pixel := GetPixel(P, BPP);
while Count > 1 do
begin
Inc(P, BPP);
NextPixel := GetPixel(P, BPP);
if NextPixel = Pixel then Break;
Pixel := NextPixel;
Inc(N);
Dec(Count);
end;
if NextPixel = Pixel then Result := N
else Result := N + 1;
end;
end;
//----------------------------------------------------------------------------------------------------------------------
function CountSamePixels(P: PByte; BPP: Byte; Count: Integer): Integer;
var
Pixel,
NextPixel: Cardinal;
begin
Result := 1;
Pixel := GetPixel(P, BPP);
Dec(Count);
while Count > 0 do
begin
Inc(P, BPP);
NextPixel := GetPixel(P, BPP);
if NextPixel <> Pixel then Break;
Inc(Result);
Dec(Count);
end;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TTargaRLEDecoder.Encode(Source, Dest: Pointer; Count: Cardinal; var BytesStored: Cardinal);
// Encodes "Count" bytes pointed to by Source into the Buffer supplied with Target and returns the
// number of bytes stored in Target. BPP denotes bytes per pixel color depth.
// Note: The target Buffer must provide enough space to hold the compressed data. Using a size of
// twice the size of the input Buffer is sufficent.
var
DiffCount, // pixel count until two identical
SameCount: Integer; // number of identical adjacent pixels
SourcePtr,
TargetPtr: PByte;
BPP: Integer;
begin
BytesStored := 0;
SourcePtr := Source;
TargetPtr := Dest;
BytesStored := 0;
// +1 for 15 bits to get the correct 2 bytes per pixel
BPP := (FColorDepth + 1) div 8;
while Count > 0 do
begin
DiffCount := CountDiffPixels(SourcePtr, BPP, Count);
SameCount := CountSamePixels(SourcePtr, BPP, Count);
if DiffCount > 128 then DiffCount := 128;
if SameCount > 128 then SameCount := 128;
if DiffCount > 0 then
begin
// create a raw packet
TargetPtr^ := DiffCount - 1; Inc(TargetPtr);
Dec(Count, DiffCount);
Inc(BytesStored, (DiffCount * BPP) + 1);
while DiffCount > 0 do
begin
TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr);
if BPP > 1 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
if BPP > 2 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
if BPP > 3 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
Dec(DiffCount);
end;
end;
if SameCount > 1 then
begin
// create a RLE packet
TargetPtr^ := (SameCount - 1) or $80; Inc(TargetPtr);
Dec(Count, SameCount);
Inc(BytesStored, BPP + 1);
Inc(SourcePtr, (SameCount - 1) * BPP);
TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr);
if BPP > 1 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
if BPP > 2 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
if BPP > 3 then begin TargetPtr^ := SourcePtr^; Inc(SourcePtr); Inc(TargetPtr); end;
end;
end;
end;
//----------------- TTIFFLZWDecoder ------------------------------------------------------------------------------------
{$ifdef UseLZW}
procedure TTIFFLZWDecoder.Decode(var Source, Dest: Pointer; PackedSize, UnpackedSize: Integer);
var
I: Integer;
Data, // current data
Bits, // counter for bit management
Code: Cardinal; // current code value
SourcePtr: PByte;
InCode: Cardinal; // Buffer for passed code
CodeSize: Cardinal;
CodeMask: Cardinal;
FreeCode: Cardinal;
OldCode: Cardinal;
Prefix: array[0..4095] of Cardinal; // LZW prefix
Suffix, // LZW suffix
Stack: array [0..4095] of Byte; // stack
StackPointer: PByte;
Target: PByte;
FirstChar: Byte; // Buffer for decoded byte
ClearCode,
EOICode: Word;
begin
Target := Dest;
SourcePtr := Source;
// initialize parameter
ClearCode := 1 shl 8;
EOICode := ClearCode + 1;
FreeCode := ClearCode + 2;
OldCode := NoLZWCode;
CodeSize := 9;
CodeMask := (1 shl CodeSize) - 1;
// init code table
for I := 0 to ClearCode - 1 do
begin
Prefix[I] := NoLZWCode;
Suffix[I] := I;
end;
// initialize stack
StackPointer := @Stack;
FirstChar := 0;
Data := 0;
Bits := 0;
while (PackedSize > 0) and (UnpackedSize > 0) do
begin
// read code from bit stream
Inc(Data, Cardinal(SourcePtr^) shl (24 - Bits));
Inc(Bits, 8);
while Bits >= CodeSize do
begin
// current code
Code := (Data and ($FFFFFFFF - CodeMask)) shr (32 - CodeSize);
// mask it
Data := Data shl CodeSize;
Dec(Bits, CodeSize);
if Code = EOICode then Exit;
// handling of clear codes
if Code = ClearCode then
begin
// reset of all variables
CodeSize := 9;
CodeMask := (1 shl CodeSize) - 1;
FreeCode := ClearCode + 2;
OldCode := NoLZWCode;
Continue;
end;
// check whether it is a valid, already registered code
if Code > FreeCode then Break;
// handling for the first LZW code: print and keep it
if OldCode = NoLZWCode then
begin
FirstChar := Suffix[Code];
Target^ := FirstChar;
Inc(Target);
Dec(UnpackedSize);
OldCode := Code;
Continue;
end;
// keep the passed LZW code
InCode := Code;
// the first LZW code is always smaller than FFirstCode
if Code = FreeCode then
begin
StackPointer^ := FirstChar;
Inc(StackPointer);
Code := OldCode;
end;
// loop to put decoded bytes onto the stack
while Code > ClearCode do
begin
StackPointer^ := Suffix[Code];
Inc(StackPointer);
Code := Prefix[Code];
end;
// place new code into code table
FirstChar := Suffix[Code];
StackPointer^ := FirstChar;
Inc(StackPointer);
Prefix[FreeCode] := OldCode;
Suffix[FreeCode] := FirstChar;
if FreeCode < 4096 then Inc(FreeCode);
// increase code size if necessary
if (FreeCode = CodeMask) and
(CodeSize < 12) then
begin
Inc(CodeSize);
CodeMask := (1 shl CodeSize) - 1;
end;
// put decoded bytes (from the stack) into the target Buffer
OldCode := InCode;
repeat
Dec(StackPointer);
Target^ := StackPointer^;
Inc(Target);
Dec(UnpackedSize);
until Cardinal(StackPointer) <= Cardinal(@Stack);
end;
Inc(SourcePtr);
Dec(PackedSize);
end;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TTIFFLZWDecoder.Encode(Source, Dest: Pointer; Count: Cardinal; var BytesStored: Cardinal);
begin
end;
{$endif} // UseLZW
//----------------- TPackbitsRLEDecoder --------------------------------------------------------------------------------
procedure TPackbitsRLEDecoder.Decode(var Source, Dest: Pointer; PackedSize, UnpackedSize: Integer);
// decodes a simple run-length encoded strip of size PackedSize
var
SourcePtr,
TargetPtr: PByte;
N: Integer;
begin
TargetPtr := Dest;
SourcePtr := Source;
while (UnpackedSize > 0) and
(PackedSize > 0) do
begin
N := ShortInt(SourcePtr^);
Inc(SourcePtr);
Dec(PackedSize);
if N < 0 then // replicate next Byte -N + 1 times
begin
if N = -128 then Continue; // nop
N := -N + 1;
if N > UnpackedSize then N := UnpackedSize;
FillChar(TargetPtr^, N, SourcePtr^);
Inc(SourcePtr);
Dec(PackedSize);
Inc(TargetPtr, N);
Dec(UnpackedSize, N);
end
else
begin // copy next N + 1 bytes literally
Inc(N);
if N > UnpackedSize then N := UnpackedSize;
if N > PackedSize then N := PackedSize;
Move(SourcePtr^, TargetPtr^, N);
Inc(TargetPtr, N);
Inc(SourcePtr, N);
Dec(PackedSize, N);
Dec(UnpackedSize, N);
end;
end;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TPackbitsRLEDecoder.Encode(Source, Dest: Pointer; Count: Cardinal; var BytesStored: Cardinal);
begin
end;
//----------------- TPCXRLEDecoder -------------------------------------------------------------------------------------
procedure TPCXRLEDecoder.Decode(var Source, Dest: Pointer; PackedSize, UnpackedSize: Integer);
var
Count: Integer;
SourcePtr,
TargetPtr: PByte;
begin
SourcePtr := Source;
TargetPtr := Dest;
while UnpackedSize > 0 do
begin
if (SourcePtr^ and $C0) = $C0 then
begin
// RLE-Code
Count := SourcePtr^ and $3F;
Inc(SourcePtr);
if UnpackedSize < Count then Count := UnpackedSize;
FillChar(TargetPtr^, Count, SourcePtr^);
Inc(SourcePtr);
Inc(TargetPtr, Count);
Dec(UnpackedSize, Count);
end
else
begin
// not compressed
TargetPtr^ := SourcePtr^;
Inc(SourcePtr);
Inc(TargetPtr);
Dec(UnpackedSize);
end;
end;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TPCXRLEDecoder.Encode(Source, Dest: Pointer; Count: Cardinal; var BytesStored: Cardinal);
begin
end;
//----------------- TSGIRLEDecoder -------------------------------------------------------------------------------------
constructor TSGIRLEDecoder.Create(SampleSize: Byte);
begin
FSampleSize := SampleSize;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TSGIRLEDecoder.Decode(var Source, Dest: Pointer; PackedSize, UnpackedSize: Integer);
var
Source8,
Target8: PByte;
Source16,
Target16: PWord;
Pixel: Byte;
Pixel16: Word;
RunLength: Cardinal;
begin
if FSampleSize = 8 then
begin
Source8 := Source;
Target8 := Dest;
while True do
begin
Pixel := Source8^;
Inc(Source8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -