📄 gif_myrxgraph.pas
字号:
var
B, I: Byte;
Diff, DiffMin: Word;
begin
Result := 0;
B := Bytes[0];
DiffMin := Abs(Value - B);
for I := 1 to High(Bytes) do begin
B := Bytes[I];
Diff := Abs(Value - B);
if Diff < DiffMin then begin
DiffMin := Diff;
Result := I;
end;
end;
end;
var
I: Integer;
begin
{ For 7 Red X 8 Green X 4 Blue palettes etc. }
for I := 0 to 255 do begin
TruncIndex04[I] := NearestIndex(Byte(I), Scale04);
TruncIndex06[I] := NearestIndex(Byte(I), Scale06);
TruncIndex07[I] := NearestIndex(Byte(I), Scale07);
TruncIndex08[I] := NearestIndex(Byte(I), Scale08);
end;
end;
procedure Trunc(const Header: TBitmapInfoHeader; Src, Dest: Pointer;
DstBitsPerPixel: Integer; TruncLineProc: TTruncLine);
var
SrcScanline, DstScanline: Longint;
Y: Integer;
begin
SrcScanline := (Header.biWidth * 3 + 3) and not 3;
DstScanline := ((Header.biWidth * DstBitsPerPixel + 31) div 32) * 4;
for Y := 0 to Header.biHeight - 1 do
TruncLineProc(HugeOffset(Src, Y * SrcScanline),
HugeOffset(Dest, Y * DstScanline), Header.biWidth);
end;
{ return 6MyRx6Gx6B palette
This function makes the palette for the 6 red X 6 green X 6 blue palette.
216 palette entrys used. Remaining 40 Left blank.
}
procedure TruncPal6R6G6B(var Colors: TRGBPalette);
var
I, R, G, B: Byte;
begin
FillChar(Colors, SizeOf(TRGBPalette), $80);
I := 0;
for R := 0 to 5 do
for G := 0 to 5 do
for B := 0 to 5 do begin
Colors[I].rgbRed := Scale06[R];
Colors[I].rgbGreen := Scale06[G];
Colors[I].rgbBlue := Scale06[B];
Colors[I].rgbReserved := 0;
Inc(I);
end;
end;
{ truncate to 6MyRx6Gx6B one line }
procedure TruncLine6R6G6B(Src, Dest: Pointer; CX: Integer); far;
var
X: Integer;
R, G, B: Byte;
begin
for X := 0 to CX - 1 do begin
B := TruncIndex06[Byte(Src^)]; Src := HugeOffset(Src, 1);
G := TruncIndex06[Byte(Src^)]; Src := HugeOffset(Src, 1);
R := TruncIndex06[Byte(Src^)]; Src := HugeOffset(Src, 1);
PByte(Dest)^ := 6 * (6 * R + G) + B;
Dest := HugeOffset(Dest, 1);
end;
end;
{ truncate to 6MyRx6Gx6B }
procedure Trunc6R6G6B(const Header: TBitmapInfoHeader;
const Data24, Data8: Pointer);
begin
Trunc(Header, Data24, Data8, 8, TruncLine6R6G6B);
end;
{ return 7MyRx8Gx4B palette
This function makes the palette for the 7 red X 8 green X 4 blue palette.
224 palette entrys used. Remaining 32 Left blank.
Colours calculated to match those used by 8514/A PM driver.
}
procedure TruncPal7R8G4B(var Colors: TRGBPalette);
var
I, R, G, B: Byte;
begin
FillChar(Colors, SizeOf(TRGBPalette), $80);
I := 0;
for R := 0 to 6 do
for G := 0 to 7 do
for B := 0 to 3 do begin
Colors[I].rgbRed := Scale07[R];
Colors[I].rgbGreen := Scale08[G];
Colors[I].rgbBlue := Scale04[B];
Colors[I].rgbReserved := 0;
Inc(I);
end;
end;
{ truncate to 7MyRx8Gx4B one line }
procedure TruncLine7R8G4B(Src, Dest: Pointer; CX: Integer); far;
var
X: Integer;
R, G, B: Byte;
begin
for X := 0 to CX - 1 do begin
B := TruncIndex04[Byte(Src^)]; Src := HugeOffset(Src, 1);
G := TruncIndex08[Byte(Src^)]; Src := HugeOffset(Src, 1);
R := TruncIndex07[Byte(Src^)]; Src := HugeOffset(Src, 1);
PByte(Dest)^ := 4 * (8 * R + G) + B;
Dest := HugeOffset(Dest, 1);
end;
end;
{ truncate to 7MyRx8Gx4B }
procedure Trunc7R8G4B(const Header: TBitmapInfoHeader;
const Data24, Data8: Pointer);
begin
Trunc(Header, Data24, Data8, 8, TruncLine7R8G4B);
end;
{ Grayscale support }
procedure GrayPal(var Colors: TRGBPalette);
var
I: Byte;
begin
FillChar(Colors, SizeOf(TRGBPalette), 0);
for I := 0 to 255 do FillChar(Colors[I], 3, I);
end;
procedure Grayscale(const Header: TBitmapInfoHeader; Data24, Data8: Pointer);
var
SrcScanline, DstScanline: Longint;
Y, X: Integer;
Src, Dest: PByte;
R, G, B: Byte;
begin
SrcScanline := (Header.biWidth * 3 + 3) and not 3;
DstScanline := (Header.biWidth + 3) and not 3;
for Y := 0 to Header.biHeight - 1 do begin
Src := Data24;
Dest := Data8;
for X := 0 to Header.biWidth - 1 do begin
B := Src^; Src := HugeOffset(Src, 1);
G := Src^; Src := HugeOffset(Src, 1);
R := Src^; Src := HugeOffset(Src, 1);
Dest^ := Byte(Longint(Word(R) * 77 + Word(G) * 150 + Word(B) * 29) shr 8);
Dest := HugeOffset(Dest, 1);
end;
Data24 := HugeOffset(Data24, SrcScanline);
Data8 := HugeOffset(Data8, DstScanline);
end;
end;
{ Tripel conversion }
procedure TripelPal(var Colors: TRGBPalette);
var
I: Byte;
begin
FillChar(Colors, SizeOf(TRGBPalette), 0);
for I := 0 to $40 do begin
Colors[I].rgbRed := I shl 2;
Colors[I + $40].rgbGreen := I shl 2;
Colors[I + $80].rgbBlue := I shl 2;
end;
end;
procedure Tripel(const Header: TBitmapInfoHeader; Data24, Data8: Pointer);
var
SrcScanline, DstScanline: Longint;
Y, X: Integer;
Src, Dest: PByte;
R, G, B: Byte;
begin
SrcScanline := (Header.biWidth * 3 + 3) and not 3;
DstScanline := (Header.biWidth + 3) and not 3;
for Y := 0 to Header.biHeight - 1 do begin
Src := Data24;
Dest := Data8;
for X := 0 to Header.biWidth - 1 do begin
B := Src^; Src := HugeOffset(Src, 1);
G := Src^; Src := HugeOffset(Src, 1);
R := Src^; Src := HugeOffset(Src, 1);
case ((X + Y) mod 3) of
0: Dest^ := Byte(R shr 2);
1: Dest^ := Byte($40 + (G shr 2));
2: Dest^ := Byte($80 + (B shr 2));
end;
Dest := HugeOffset(Dest, 1);
end;
Data24 := HugeOffset(Data24, SrcScanline);
Data8 := HugeOffset(Data8, DstScanline);
end;
end;
{ Histogram/Frequency-of-use method of color reduction }
const
MAX_N_COLS = 2049;
MAX_N_HASH = 5191;
function Hash(R, G, B: Byte): Word;
begin
Result := Word(Longint(Longint(R + G) * Longint(G + B) *
Longint(B + R)) mod MAX_N_HASH);
end;
type
PFreqRecord = ^TFreqRecord;
TFreqRecord = record
B, G, R: Byte;
Frequency: Longint;
Nearest: Byte;
end;
PHist = ^THist;
THist = record
ColCount: Longint;
Rm, Gm, Bm: Byte;
Freqs: array[0..MAX_N_COLS - 1] of TFreqRecord;
HashTable: array[0..MAX_N_HASH - 1] of Word;
end;
function CreateHistogram(R, G, B: Byte): PHist;
{ create empty histogram }
begin
GetMem(Result, SizeOf(THist));
with Result^ do begin
Rm := R;
Gm := G;
Bm := B;
ColCount := 0;
end;
FillChar(Result^.HashTable, MAX_N_HASH * SizeOf(Word), 255);
end;
procedure ClearHistogram(var Hist: PHist; R, G, B: Byte);
begin
with Hist^ do begin
Rm := R;
Gm := G;
Bm := B;
ColCount := 0;
end;
FillChar(Hist^.HashTable, MAX_N_HASH * SizeOf(Word), 255);
end;
procedure DeleteHistogram(var Hist: PHist);
begin
FreeMem(Hist, SizeOf(THist));
Hist := nil;
end;
function AddToHistogram(var Hist: THist; const Header: TBitmapInfoHeader;
Data24: Pointer): Boolean;
{ add bitmap data to histogram }
var
Step24: Integer;
HashColor, Index: Word;
Rm, Gm, Bm, R, G, B: Byte;
X, Y, ColCount: Longint;
begin
Step24 := ((Header.biWidth * 3 + 3) and not 3) - Header.biWidth * 3;
Rm := Hist.Rm;
Gm := Hist.Gm;
Bm := Hist.Bm;
ColCount := Hist.ColCount;
for Y := 0 to Header.biHeight - 1 do begin
for X := 0 to Header.biWidth - 1 do begin
B := Byte(Data24^) and Bm; Data24 := HugeOffset(Data24, 1);
G := Byte(Data24^) and Gm; Data24 := HugeOffset(Data24, 1);
R := Byte(Data24^) and Rm; Data24 := HugeOffset(Data24, 1);
HashColor := Hash(R, G, B);
repeat
Index := Hist.HashTable[HashColor];
if (Index = $FFFF) or ((Hist.Freqs[Index].R = R) and
(Hist.Freqs[Index].G = G) and (Hist.Freqs[Index].B = B)) then Break;
Inc(HashColor);
if (HashColor = MAX_N_HASH) then HashColor := 0;
until False;
{ Note: loop will always be broken out of }
{ We don't allow HashTable to fill up above half full }
if (Index = $FFFF) then begin
{ Not found in Hash table }
if (ColCount = MAX_N_COLS) then begin
Result := False;
Exit;
end;
Hist.Freqs[ColCount].Frequency := 1;
Hist.Freqs[ColCount].B := B;
Hist.Freqs[ColCount].G := G;
Hist.Freqs[ColCount].R := R;
Hist.HashTable[HashColor] := ColCount;
Inc(ColCount);
end
else begin
{ Found in Hash table, update index }
Inc(Hist.Freqs[Index].Frequency);
end;
end;
Data24 := HugeOffset(Data24, Step24);
end;
Hist.ColCount := ColCount;
Result := True;
end;
procedure PalHistogram(var Hist: THist; var Colors: TRGBPalette;
ColorsWanted: Integer);
{ work out a palette from Hist }
var
I, J: Longint;
MinDist, Dist: Longint;
MaxJ, MinJ: Longint;
DeltaB, DeltaG, DeltaR: Longint;
MaxFreq: Longint;
begin
I := 0; MaxJ := 0; MinJ := 0;
{ Now find the ColorsWanted most frequently used ones }
while (I < ColorsWanted) and (I < Hist.ColCount) do begin
MaxFreq := 0;
for J := 0 to Hist.ColCount - 1 do
if (Hist.Freqs[J].Frequency > MaxFreq) then begin
MaxJ := J;
MaxFreq := Hist.Freqs[J].Frequency;
end;
Hist.Freqs[MaxJ].Nearest := Byte(I);
Hist.Freqs[MaxJ].Frequency := 0; { Prevent later use of Freqs[MaxJ] }
Colors[I].rgbBlue := Hist.Freqs[MaxJ].B;
Colors[I].rgbGreen := Hist.Freqs[MaxJ].G;
Colors[I].rgbRed := Hist.Freqs[MaxJ].R;
Colors[I].rgbReserved := 0;
Inc(I);
end;
{ Unused palette entries will be medium grey }
while I <= 255 do begin
Colors[I].rgbRed := $80;
Colors[I].rgbGreen := $80;
Colors[I].rgbBlue := $80;
Colors[I].rgbReserved := 0;
Inc(I);
end;
{ For the rest, find the closest one in the first ColorsWanted }
for I := 0 to Hist.ColCount - 1 do begin
if Hist.Freqs[I].Frequency <> 0 then begin
MinDist := 3 * 256 * 256;
for J := 0 to ColorsWanted - 1 do begin
DeltaB := Hist.Freqs[I].B - Colors[J].rgbBlue;
DeltaG := Hist.Freqs[I].G - Colors[J].rgbGreen;
DeltaR := Hist.Freqs[I].R - Colors[J].rgbRed;
Dist := Longint(DeltaR * DeltaR) + Longint(DeltaG * DeltaG) +
Longint(DeltaB * DeltaB);
if (Dist < MinDist) then begin
MinDist := Dist;
MinJ := J;
end;
end;
Hist.Freqs[I].Nearest := Byte(MinJ);
end;
end;
end;
procedure MapHistogram(var Hist: THist; const Header: TBitmapInfoHeader;
Data24, Data8: Pointer);
{ map bitmap data to Hist palette }
var
Step24: Integer;
Step8: Integer;
HashColor, Index: Longint;
Rm, Gm, Bm, R, G, B: Byte;
X, Y: Longint;
begin
Step24 := ((Header.biWidth * 3 + 3) and not 3) - Header.biWidth * 3;
Step8 := ((Header.biWidth + 3) and not 3) - Header.biWidth;
Rm := Hist.Rm;
Gm := Hist.Gm;
Bm := Hist.Bm;
for Y := 0 to Header.biHeight - 1 do begin
for X := 0 to Header.biWidth - 1 do begin
B := Byte(Data24^) and Bm; Data24 := HugeOffset(Data24, 1);
G := Byte(Data24^) and Gm; Data24 := HugeOffset(Data24, 1);
R := Byte(Data24^) and Rm; Data24 := HugeOffset(Data24, 1);
HashColor := Hash(R, G, B);
repeat
Index := Hist.HashTable[HashColor];
if (Hist.Freqs[Index].R = R) and (Hist.Freqs[Index].G = G) and
(Hist.Freqs[Index].B = B) then Break;
Inc(HashColor);
if (HashColor = MAX_N_HASH) then HashColor := 0;
until False;
PByte(Data8)^ := Hist.Freqs[Index].Nearest;
Data8 := HugeOffset(Data8, 1);
end;
Data24 := HugeOffset(Data24, Step24);
Data8 := HugeOffset(Data8, Step8);
end;
end;
procedure Histogram(const Header: TBitmapInfoHeader; var Colors: TRGBPalette;
Data24, Data8: Pointer; ColorsWanted: Integer; Rm, Gm, Bm: Byte);
{ map single bitmap to frequency optimised palette }
var
Hist: PHist;
begin
Hist := CreateHistogram(Rm, Gm, Bm);
try
repeat
if AddToHistogram(Hist^, Header, Data24) then Break
else begin
if (Gm > Rm) then Gm := Gm shl 1
else if (Rm > Bm) then Rm := Rm shl 1
else Bm := Bm shl 1;
ClearHistogram(Hist, Rm, Gm, Bm);
end;
until False;
{ Above loop will always be exited as if masks get rough }
{ enough, ultimately number of unique colours < MAX_N_COLS }
PalHistogram(Hist^, Colors, ColorsWanted);
MapHistogram(Hist^, Header, Data24, Data8);
finally
DeleteHistogram(Hist);
end;
end;
{ expand to 24 bits-per-pixel }
(*
procedure ExpandTo24Bit(const Header: TBitmapInfoHeader; Colors: TRGBPalette;
Data, NewData: Pointer);
var
Scanline, NewScanline: Longint;
Y, X: Integer;
Src, Dest: Pointer;
C: Byte;
begin
if Header.biBitCount = 24 then begin
Exit;
end;
Scanline := ((Header.biWidth * Header.biBitCount + 31) div 32) * 4;
NewScanline := ((Header.biWidth * 3 + 3) and not 3);
for Y := 0 to Header.biHeight - 1 do begin
Src := HugeOffset(Data, Y * Scanline);
Dest := HugeOffset(NewData, Y * NewScanline);
case Header.biBitCount of
1:
begin
C := 0;
for X := 0 to Header.biWidth - 1 do begin
if (X and 7) = 0 then begin
C := Byte(Src^);
Src := HugeOffset(Src, 1);
end
else C := C shl 1;
PByte(Dest)^ := Colors[C shr 7].rgbBlue;
Dest := HugeOffset(Dest, 1);
PByte(Dest)^ := Colors[C shr 7].rgbGreen;
Dest := HugeOffset(Dest, 1);
PByte(Dest)^ := Colors[C shr 7].rgbRed;
Dest := HugeOffset(Dest, 1);
end;
end;
4:
begin
X := 0;
while X < Header.biWidth - 1 do begin
C := Byte(Src^);
Src := HugeOffset(Src, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -