📄 gif_myrxgraph.pas
字号:
{*******************************************************}
{ }
{ Delphi VCL Extensions (MyRx) }
{ }
{ Copyright (c) 1997, 1998 Master-Bank }
{ }
{*******************************************************}
Unit Gif_MyRxGraph;
interface
uses Windows, SysUtils, Classes, Graphics, Gif_Unit;
type
TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf24bit);
TMappingMethod = (mmHistogram, mmQuantize, mmTrunc784, mmTrunc666,
mmTripel, mmGrayscale);
function GetBitmapPixelFormat(Bitmap: TBitmap): TPixelFormat;
function GetPaletteBitmapFormat(Bitmap: TBitmap): TPixelFormat;
procedure SetBitmapPixelFormat(Bitmap: TBitmap; PixelFormat: TPixelFormat;
Method: TMappingMethod);
function BitmapToMemoryStream(Bitmap: TBitmap; PixelFormat: TPixelFormat;
Method: TMappingMethod): TMemoryStream;
procedure GrayscaleBitmap(Bitmap: TBitmap);
function BitmapToMemory(Bitmap: TBitmap; Colors: Integer): TStream;
procedure SaveBitmapToFile(const Filename: string; Bitmap: TBitmap;
Colors: Integer);
function ScreenPixelFormat: TPixelFormat;
function ScreenColorCount: Integer;
procedure TileImage(Canvas: TCanvas; Rect: TRect; Image: TGraphic);
function ZoomImage(ImageW, ImageH, MaxW, MaxH: Integer; Stretch: Boolean): TPoint;
const
DefaultMappingMethod: TMappingMethod = mmHistogram;
{ TMyRxGradient class }
type
TMyRxGradient = class(TPersistent)
private
FStartColor: TColor;
FEndColor: TColor;
FDirection: TFillDirection;
FStepCount: Byte;
FVisible: Boolean;
FOnChange: TNotifyEvent;
procedure SetStartColor(Value: TColor);
procedure SetEndColor(Value: TColor);
procedure SetDirection(Value: TFillDirection);
procedure SetStepCount(Value: Byte);
procedure SetVisible(Value: Boolean);
protected
procedure Changed; dynamic;
public
constructor Create;
procedure Assign(Source: TPersistent); override;
procedure Draw(Canvas: TCanvas; Rect: TRect);
published
property Direction: TFillDirection read FDirection write SetDirection
default fdTopToBottom;
property EndColor: TColor read FEndColor write SetEndColor default clGray;
property StartColor: TColor read FStartColor write SetStartColor default clSilver;
property StepCount: Byte read FStepCount write SetStepCount default 64;
property Visible: Boolean read FVisible write SetVisible default False;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
implementation
{$R-}
uses Consts;
procedure InvalidBitmap; near;
begin
raise EInvalidGraphic.Create(ResStr(SInvalidBitmap));
end;
type
PRGBPalette = ^TRGBPalette;
TRGBPalette = array [Byte] of TRGBQuad;
function WidthBytes(I: Longint): Longint;
begin
Result := ((I + 31) div 32) * 4;
end;
function PixelFormatToColors(PixelFormat: TPixelFormat): Integer;
begin
case PixelFormat of
pf1bit: Result := 2;
pf4bit: Result := 16;
pf8bit: Result := 256;
else Result := 0;
end;
end;
function ScreenPixelFormat: TPixelFormat;
var
DC: HDC;
begin
DC := GetDC(0);
try
case (GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL)) of
1: Result := pf1bit;
4: Result := pf4bit;
8: Result := pf8bit;
24: Result := pf24bit;
else Result := pfDevice;
end;
finally
ReleaseDC(0, DC);
end;
end;
function ScreenColorCount: Integer;
begin
Result := PixelFormatToColors(ScreenPixelFormat);
end;
{ Quantizing }
{ Quantizing ptocedures based on free C source code written by
Joe C. Oliphant, CompuServe 71742, 1451, joe_oliphant@csufresno.edu }
const
MAX_COLORS = 4096;
type
PQColor = ^TQColor;
TQColor = record
RGB: array[0..2] of Byte;
NewColorIndex: Byte;
Count: Longint;
PNext: PQColor;
end;
PQColorArray = ^TQColorArray;
TQColorArray = array[0..MAX_COLORS - 1] of TQColor;
PQColorList = ^TQColorList;
TQColorList = array[0..MaxListSize - 1] of PQColor;
PNewColor = ^TNewColor;
TNewColor = record
RGBMin, RGBWidth: array[0..2] of Byte;
NumEntries: Longint;
Count: Longint;
QuantizedColors: PQColor;
end;
PNewColorArray = ^TNewColorArray;
TNewColorArray = array[Byte] of TNewColor;
procedure PInsert(ColorList: PQColorList; Number: Integer;
SortRGBAxis: Integer);
var
Q1, Q2: PQColor;
I, J: Integer;
Temp: PQColor;
begin
for I := 1 to Number - 1 do begin
Temp := ColorList^[I];
J := I - 1;
while (J >= 0) do begin
Q1 := Temp;
Q2 := ColorList^[J];
if (Q1^.RGB[SortRGBAxis] - Q2^.RGB[SortRGBAxis] > 0) then Break;
ColorList^[J + 1] := ColorList^[J];
Dec(J);
end;
ColorList^[J + 1] := Temp;
end;
end;
procedure PSort(ColorList: PQColorList; Number: Integer;
SortRGBAxis: Integer);
var
Q1, Q2: PQColor;
I, J, N, Nr: Integer;
Temp, Part: PQColor;
begin
if Number < 8 then begin
PInsert(ColorList, Number, SortRGBAxis);
Exit;
end;
Part := ColorList^[Number div 2];
I := -1;
J := Number;
repeat
repeat
Inc(I);
Q1 := ColorList^[I];
Q2 := Part;
N := Q1^.RGB[SortRGBAxis] - Q2^.RGB[SortRGBAxis];
until (N >= 0);
repeat
Dec(J);
Q1 := ColorList^[J];
Q2 := Part;
N := Q1^.RGB[SortRGBAxis] - Q2^.RGB[SortRGBAxis];
until (N <= 0);
if (I >= J) then Break;
Temp := ColorList^[I];
ColorList^[I] := ColorList^[J];
ColorList^[J] := Temp;
until False;
Nr := Number - I;
if (I < Number div 2) then begin
PSort(ColorList, I, SortRGBAxis);
PSort(PQColorList(@ColorList^[I]), Nr, SortRGBAxis);
end
else begin
PSort(PQColorList(@ColorList^[I]), Nr, SortRGBAxis);
PSort(ColorList, I, SortRGBAxis);
end;
end;
function DivideMap(NewColorSubdiv: PNewColorArray; ColorMapSize: Integer;
var NewColormapSize: Integer; lpStr: Pointer): Integer;
var
I, J: Integer;
MaxSize, Index: Integer;
NumEntries, MinColor,
MaxColor: Integer;
Sum, Count: Longint;
QuantizedColor: PQColor;
SortArray: PQColorList;
SortRGBAxis: Integer;
begin
Index := 0; SortRGBAxis := 0;
while (colormapsize > NewColormapSize) do begin
MaxSize := -1;
for I := 0 to NewColormapSize - 1 do begin
for J := 0 to 2 do begin
if (NewColorSubdiv^[I].RGBwidth[J] > MaxSize) and
(NewColorSubdiv^[I].NumEntries > 1) then
begin
MaxSize := NewColorSubdiv^[I].RGBwidth[J];
Index := I;
SortRGBAxis := J;
end;
end;
end;
if (MaxSize = -1) then begin
Result := 1;
Exit;
end;
SortArray := PQColorList(lpStr);
J := 0;
QuantizedColor := NewColorSubdiv^[Index].QuantizedColors;
while (J < NewColorSubdiv^[Index].NumEntries) and
(QuantizedColor <> nil) do
begin
SortArray^[J] := QuantizedColor;
Inc(J);
QuantizedColor := QuantizedColor^.pnext;
end;
PSort(SortArray, NewColorSubdiv^[Index].NumEntries, SortRGBAxis);
for J := 0 to NewColorSubdiv^[Index].NumEntries - 2 do
SortArray^[J]^.pnext := SortArray^[J + 1];
SortArray^[NewColorSubdiv^[Index].NumEntries - 1]^.pnext := nil;
NewColorSubdiv^[Index].QuantizedColors := SortArray^[0];
QuantizedColor := SortArray^[0];
Sum := NewColorSubdiv^[Index].Count div 2 - QuantizedColor^.Count;
NumEntries := 1;
Count := QuantizedColor^.Count;
Dec(Sum, QuantizedColor^.pnext^.Count);
while (Sum >= 0) and (QuantizedColor^.pnext <> nil) and
(QuantizedColor^.pnext^.pnext <> nil) do
begin
QuantizedColor := QuantizedColor^.pnext;
Inc(NumEntries);
Inc(Count, QuantizedColor^.Count);
Dec(Sum, QuantizedColor^.pnext^.Count);
end;
MaxColor := (QuantizedColor^.RGB[SortRGBAxis]) shl 4;
MinColor := (QuantizedColor^.pnext^.RGB[SortRGBAxis]) shl 4;
NewColorSubdiv^[NewColormapSize].QuantizedColors := QuantizedColor^.pnext;
QuantizedColor^.pnext := nil;
NewColorSubdiv^[NewColormapSize].Count := Count;
Dec(NewColorSubdiv^[Index].Count, Count);
NewColorSubdiv^[NewColormapSize].NumEntries :=
NewColorSubdiv^[Index].NumEntries - NumEntries;
NewColorSubdiv^[Index].NumEntries := NumEntries;
for J := 0 to 2 do begin
NewColorSubdiv^[NewColormapSize].RGBmin[J] :=
NewColorSubdiv^[Index].RGBmin[J];
NewColorSubdiv^[NewColormapSize].RGBwidth[J] :=
NewColorSubdiv^[Index].RGBwidth[J];
end;
NewColorSubdiv^[NewColormapSize].RGBwidth[SortRGBAxis] :=
NewColorSubdiv^[NewColormapSize].RGBmin[SortRGBAxis] +
NewColorSubdiv^[NewColormapSize].RGBwidth[SortRGBAxis] -
MinColor;
NewColorSubdiv^[NewColormapSize].RGBmin[SortRGBAxis] := MinColor;
NewColorSubdiv^[Index].RGBwidth[SortRGBAxis] :=
MaxColor - NewColorSubdiv^[Index].RGBmin[SortRGBAxis];
Inc(NewColormapSize);
end;
Result := 1;
end;
function Quantize(const bmp: TBitmapInfoHeader; gptr, Data8: Pointer;
var ColorCount: Integer; var OutputColormap: TRGBPalette): Integer;
type
PWord = ^Word;
var
P: PByteArray;
LineBuffer, Data: Pointer;
LineWidth: Longint;
TmpLineWidth, NewLineWidth: Longint;
I, J: Longint;
Index: Word;
NewColormapSize, NumOfEntries: Integer;
Mems: Longint;
cRed, cGreen, cBlue: Longint;
lpStr, Temp, Tmp: Pointer;
NewColorSubdiv: PNewColorArray;
ColorArrayEntries: PQColorArray;
QuantizedColor: PQColor;
begin
LineWidth := WidthBytes(Longint(bmp.biWidth) * bmp.biBitCount);
Mems := (Longint(SizeOf(TQColor)) * (MAX_COLORS)) +
(Longint(SizeOf(TNewColor)) * 256) + LineWidth +
(Longint(sizeof(PQCOLOR)) * (MAX_COLORS));
lpStr := AllocMemo(Mems);
try
Temp := AllocMemo(Longint(bmp.biWidth) * Longint(bmp.biHeight) *
SizeOf(Word));
try
ColorArrayEntries := PQColorArray(lpStr);
NewColorSubdiv := PNewColorArray(HugeOffset(lpStr,
Longint(sizeof(TQColor)) * (MAX_COLORS)));
LineBuffer := HugeOffset(lpStr, (Longint(sizeof(TQColor)) * (MAX_COLORS)) +
(Longint(sizeof(TNewColor)) * 256));
for I := 0 to MAX_COLORS - 1 do begin
ColorArrayEntries^[I].RGB[0] := I shr 8;
ColorArrayEntries^[I].RGB[1] := (I shr 4) and $0F;
ColorArrayEntries^[I].RGB[2] := I and $0F;
ColorArrayEntries^[I].Count := 0;
end;
Tmp := Temp;
for I := 0 to bmp.biHeight - 1 do begin
HMemCpy(LineBuffer, HugeOffset(gptr, (bmp.biHeight - 1 - I) *
LineWidth), LineWidth);
P := LineBuffer;
for J := 0 to bmp.biWidth - 1 do begin
Index := (Longint(P^[2] and $F0) shl 4) +
Longint(P^[1] and $F0) + (Longint(P^[0] and $F0) shr 4);
Inc(ColorArrayEntries^[Index].Count);
P := HugeOffset(P, 3);
PWord(Tmp)^ := Index;
Tmp := HugeOffset(Tmp, 2);
end;
end;
for I := 0 to 255 do begin
NewColorSubdiv^[I].QuantizedColors := nil;
NewColorSubdiv^[I].Count := 0;
NewColorSubdiv^[I].NumEntries := 0;
for J := 0 to 2 do begin
NewColorSubdiv^[I].RGBmin[J] := 0;
NewColorSubdiv^[I].RGBwidth[J] := 255;
end;
end;
I := 0;
while I < MAX_COLORS do begin
if ColorArrayEntries^[I].Count > 0 then Break;
Inc(I);
end;
QuantizedColor := @ColorArrayEntries^[I];
NewColorSubdiv^[0].QuantizedColors := @ColorArrayEntries^[I];
NumOfEntries := 1;
Inc(I);
while I < MAX_COLORS do begin
if ColorArrayEntries^[I].Count > 0 then begin
QuantizedColor^.pnext := @ColorArrayEntries^[I];
QuantizedColor := @ColorArrayEntries^[I];
Inc(NumOfEntries);
end;
Inc(I);
end;
QuantizedColor^.pnext := nil;
NewColorSubdiv^[0].NumEntries := NumOfEntries;
NewColorSubdiv^[0].Count := Longint(bmp.biWidth) * Longint(bmp.biHeight);
NewColormapSize := 1;
DivideMap(NewColorSubdiv, ColorCount, NewColormapSize,
HugeOffset(lpStr, Longint(SizeOf(TQColor)) * (MAX_COLORS) +
Longint(SizeOf(TNewColor)) * 256 + LineWidth));
if (NewColormapSize < ColorCount) then begin
for I := NewColormapSize to ColorCount - 1 do
FillChar(OutputColormap[I], SizeOf(TRGBQuad), 0);
end;
for I := 0 to NewColormapSize - 1 do begin
J := NewColorSubdiv^[I].NumEntries;
if J > 0 then begin
QuantizedColor := NewColorSubdiv^[I].QuantizedColors;
cRed := 0;
cGreen := 0;
cBlue := 0;
while (QuantizedColor <> nil) do begin
QuantizedColor^.NewColorIndex := I;
Inc(cRed, QuantizedColor^.RGB[0]);
Inc(cGreen, QuantizedColor^.RGB[1]);
Inc(cBlue, QuantizedColor^.RGB[2]);
QuantizedColor := QuantizedColor^.pnext;
end;
with OutputColormap[I] do begin
rgbRed := (Longint(cRed shl 4) or $0F) div J;
rgbGreen := (Longint(cGreen shl 4) or $0F) div J;
rgbBlue := (Longint(cBlue shl 4) or $0F) div J;
rgbReserved := 0;
if (rgbRed <= $10) and (rgbGreen <= $10) and (rgbBlue <= $10) then
FillChar(OutputColormap[I], SizeOf(TRGBQuad), 0); { clBlack }
end;
end;
end;
TmpLineWidth := Longint(bmp.biWidth) * SizeOf(Word);
NewLineWidth := WidthBytes(Longint(bmp.biWidth) * 8);
ZeroMemory(Data8, NewLineWidth * bmp.biHeight);
for I := 0 to bmp.biHeight - 1 do begin
LineBuffer := HugeOffset(Temp, (bmp.biHeight - 1 - I) * TmpLineWidth);
Data := HugeOffset(Data8, I * NewLineWidth);
for J := 0 to bmp.biWidth - 1 do begin
PByte(Data)^ := ColorArrayEntries^[PWord(LineBuffer)^].NewColorIndex;
LineBuffer := HugeOffset(LineBuffer, 2);
Data := HugeOffset(Data, 1);
end;
end;
finally
FreeMemo(Temp);
end;
finally
FreeMemo(lpStr);
end;
ColorCount := NewColormapSize;
Result := 0;
end;
{
Procedures to truncate to lower bits-per-pixel, grayscale, tripel and
histogram conversion based on freeware C source code of GBM package by
Andy Key (nyangau@interalpha.co.uk). The home page of GBM author is
at http://www.interalpha.net/customer/nyangau/.
}
{ Truncate to lower bits per pixel }
type
TTruncLine = procedure(Src, Dest: Pointer; CX: Integer);
{ For 6MyRx6Gx6B, 7MyRx8Gx4B palettes etc. }
const
Scale04: array[0..3] of Byte = (0, 85, 170, 255);
Scale06: array[0..5] of Byte = (0, 51, 102, 153, 204, 255);
Scale07: array[0..6] of Byte = (0, 43, 85, 128, 170, 213, 255);
Scale08: array[0..7] of Byte = (0, 36, 73, 109, 146, 182, 219, 255);
{ For 6MyRx6Gx6B, 7MyRx8Gx4B palettes etc. }
var
TruncIndex04: array[Byte] of byte;
TruncIndex06: array[Byte] of byte;
TruncIndex07: array[Byte] of byte;
TruncIndex08: array[Byte] of byte;
{ These functions initialises this module }
procedure InitTruncTables;
function NearestIndex(Value: Byte; const Bytes: array of Byte): Byte;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -