📄 rxgif.pas
字号:
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1997, 1998 Master-Bank }
{ }
{*******************************************************}
unit RxGIF;
interface
{$I RX.INC}
uses Windows, RTLConsts, SysUtils, Classes, Graphics, RxGraph;
const
RT_GIF = 'GIF'; { GIF Resource Type }
type
{$IFNDEF RX_D3}
TProgressStage = (psStarting, psRunning, psEnding);
TProgressEvent = procedure (Sender: TObject; Stage: TProgressStage;
PercentDone: Byte; RedrawNow: Boolean; const R: TRect;
const Msg: string) of object;
{ TSharedImage }
TSharedImage = class
private
FRefCount: Integer;
protected
procedure Reference;
procedure Release;
procedure FreeHandle; virtual; abstract;
property RefCount: Integer read FRefCount;
end;
{$ENDIF RX_D3}
TGIFVersion = (gvUnknown, gv87a, gv89a);
TGIFBits = 1..8;
TDisposalMethod = (dmUndefined, dmLeave, dmRestoreBackground,
dmRestorePrevious, dmReserved4, dmReserved5, dmReserved6, dmReserved7);
TGIFColorItem = packed record
Red, Green, Blue: Byte;
end;
TGIFColorTable = packed record
Count: Integer;
Colors: packed array[Byte] of TGIFColorItem;
end;
TGIFFrame = class;
TGIFData = class;
TGIFItem = class;
{ TGIFImage }
TGIFImage = class(TGraphic)
private
FImage: TGIFData;
FVersion: TGIFVersion;
FItems: TList;
FFrameIndex: Integer;
FScreenWidth: Word;
FScreenHeight: Word;
FBackgroundColor: TColor;
FLooping: Boolean;
FCorrupted: Boolean;
FRepeatCount: Word;
{$IFNDEF RX_D3}
FOnProgress: TProgressEvent;
{$ENDIF}
function GetBitmap: TBitmap;
function GetCount: Integer;
function GetComment: TStrings;
function GetScreenWidth: Integer;
function GetScreenHeight: Integer;
function GetGlobalColorCount: Integer;
procedure UpdateScreenSize;
procedure SetComment(Value: TStrings);
function GetFrame(Index: Integer): TGIFFrame;
procedure SetFrameIndex(Value: Integer);
procedure SetBackgroundColor(Value: TColor);
procedure SetLooping(Value: Boolean);
procedure SetRepeatCount(Value: Word);
procedure ReadSignature(Stream: TStream);
procedure DoProgress(Stage: TProgressStage; PercentDone: Byte;
const Msg: string);
function GetCorrupted: Boolean;
function GetTransparentColor: TColor;
function GetBackgroundColor: TColor;
function GetPixelFormat: TPixelFormat;
procedure EncodeFrames(ReverseDecode: Boolean);
procedure ReadStream(Size: Longint; Stream: TStream; ForceDecode: Boolean);
procedure WriteStream(Stream: TStream; WriteSize: Boolean);
protected
procedure AssignTo(Dest: TPersistent); override;
procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
{$IFDEF WIN32}
function Equals(Graphic: TGraphic): Boolean; override;
{$ENDIF}
function GetEmpty: Boolean; override;
function GetHeight: Integer; override;
function GetWidth: Integer; override;
function GetPalette: HPALETTE; {$IFDEF RX_D3} override; {$ENDIF}
function GetTransparent: Boolean; {$IFDEF RX_D3} override; {$ENDIF}
procedure ClearItems;
procedure NewImage;
procedure UniqueImage;
{$IFNDEF RX_D3}
procedure Progress(Sender: TObject; Stage: TProgressStage;
PercentDone: Byte; RedrawNow: Boolean; const R: TRect;
const Msg: string); dynamic;
{$ENDIF}
procedure ReadData(Stream: TStream); override;
procedure SetHeight(Value: Integer); override;
procedure SetWidth(Value: Integer); override;
procedure WriteData(Stream: TStream); override;
property Bitmap: TBitmap read GetBitmap; { volatile }
public
constructor Create; override;
destructor Destroy; override;
procedure Clear;
procedure DecodeAllFrames;
procedure EncodeAllFrames;
procedure Assign(Source: TPersistent); override;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToStream(Stream: TStream); override;
procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
APalette: HPALETTE); override;
procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
var APalette: HPALETTE); override;
procedure LoadFromResourceName(Instance: THandle; const ResName: string;
ResType: PChar);
procedure LoadFromResourceID(Instance: THandle; ResID: Integer;
ResType: PChar);
function AddFrame(Value: TGraphic): Integer; virtual;
procedure DeleteFrame(Index: Integer);
procedure MoveFrame(CurIndex, NewIndex: Integer);
procedure Grayscale(ForceEncoding: Boolean);
property BackgroundColor: TColor read GetBackgroundColor write SetBackgroundColor;
property Comment: TStrings read GetComment write SetComment;
property Corrupted: Boolean read GetCorrupted;
property Count: Integer read GetCount;
property Frames[Index: Integer]: TGIFFrame read GetFrame; default;
property FrameIndex: Integer read FFrameIndex write SetFrameIndex;
property GlobalColorCount: Integer read GetGlobalColorCount;
property Looping: Boolean read FLooping write SetLooping;
property PixelFormat: TPixelFormat read GetPixelFormat;
property RepeatCount: Word read FRepeatCount write SetRepeatCount;
property ScreenWidth: Integer read GetScreenWidth;
property ScreenHeight: Integer read GetScreenHeight;
property TransparentColor: TColor read GetTransparentColor;
property Version: TGIFVersion read FVersion;
{$IFNDEF RX_D3}
property Palette: HPALETTE read GetPalette;
property Transparent: Boolean read GetTransparent;
property OnProgress: TProgressEvent read FOnProgress write FOnProgress;
{$ENDIF}
end;
{ TGIFFrame }
TGIFFrame = class(TPersistent)
private
FOwner: TGIFImage;
FBitmap: TBitmap;
FImage: TGIFItem;
FExtensions: TList;
FTopLeft: TPoint;
FInterlaced: Boolean;
FCorrupted: Boolean;
FGrayscale: Boolean;
FTransparentColor: TColor;
FAnimateInterval: Word;
FDisposal: TDisposalMethod;
FLocalColors: Boolean;
function GetBitmap: TBitmap;
function GetHeight: Integer;
function GetWidth: Integer;
function GetColorCount: Integer;
function FindComment(ForceCreate: Boolean): TStrings;
function GetComment: TStrings;
procedure SetComment(Value: TStrings);
procedure SetTransparentColor(Value: TColor);
procedure SetDisposalMethod(Value: TDisposalMethod);
procedure SetAnimateInterval(Value: Word);
procedure SetTopLeft(const Value: TPoint);
procedure NewBitmap;
procedure NewImage;
procedure SaveToBitmapStream(Stream: TMemoryStream);
procedure EncodeBitmapStream(Stream: TMemoryStream);
procedure EncodeRasterData;
procedure UpdateExtensions;
procedure WriteImageDescriptor(Stream: TStream);
procedure WriteLocalColorMap(Stream: TStream);
procedure WriteRasterData(Stream: TStream);
protected
constructor Create(AOwner: TGIFImage); virtual;
procedure LoadFromStream(Stream: TStream);
procedure AssignTo(Dest: TPersistent); override;
procedure GrayscaleImage(ForceEncoding: Boolean);
public
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure Draw(ACanvas: TCanvas; const ARect: TRect;
Transparent: Boolean);
property AnimateInterval: Word read FAnimateInterval write SetAnimateInterval;
property Bitmap: TBitmap read GetBitmap; { volatile }
property ColorCount: Integer read GetColorCount;
property Comment: TStrings read GetComment write SetComment;
property DisposalMethod: TDisposalMethod read FDisposal write SetDisposalMethod;
property Interlaced: Boolean read FInterlaced;
property Corrupted: Boolean read FCorrupted;
property TransparentColor: TColor read FTransparentColor write SetTransparentColor;
property Origin: TPoint read FTopLeft write SetTopLeft;
property Height: Integer read GetHeight;
property Width: Integer read GetWidth;
end;
{ TGIFData }
TGIFData = class(TSharedImage)
private
FComment: TStrings;
FAspectRatio: Byte;
FBitsPerPixel: Byte;
FColorResBits: Byte;
FColorMap: TGIFColorTable;
protected
procedure FreeHandle; override;
public
constructor Create;
destructor Destroy; override;
end;
{ TGIFItem }
TGIFItem = class(TSharedImage)
private
FImageData: TMemoryStream;
FSize: TPoint;
FPackedFields: Byte;
FBitsPerPixel: Byte;
FColorMap: TGIFColorTable;
protected
procedure FreeHandle; override;
public
destructor Destroy; override;
end;
{ Clipboard format for GIF image }
var
CF_GIF: Word;
{ Load incomplete or corrupted images without exceptions }
const
GIFLoadCorrupted: Boolean = True;
function GIFVersionName(Version: TGIFVersion): string;
procedure rxgif_dummy;
implementation
uses Consts, {$IFNDEF WIN32} Str16, {$ENDIF} VclUtils, AniFile, RxConst,
MaxMin, RxGConst;
{$R-}
procedure rxgif_dummy;
begin
end;
procedure GifError(const Msg: string);
{$IFDEF WIN32}
function ReturnAddr: Pointer;
asm
MOV EAX,[EBP+4]
end;
{$ELSE}
function ReturnAddr: Pointer; assembler;
asm
MOV AX,[BP].Word[2]
MOV DX,[BP].Word[4]
end;
{$ENDIF}
begin
raise EInvalidGraphicOperation.Create(Msg) at ReturnAddr;
end;
{$IFNDEF RX_D3}
{ TSharedImage }
procedure TSharedImage.Reference;
begin
Inc(FRefCount);
end;
procedure TSharedImage.Release;
begin
if Pointer(Self) <> nil then begin
Dec(FRefCount);
if FRefCount = 0 then begin
FreeHandle;
Free;
end;
end;
end;
{$ENDIF}
const
GIFSignature = 'GIF';
GIFVersionStr: array[TGIFVersion] of PChar = (#0#0#0, '87a', '89a');
function GIFVersionName(Version: TGIFVersion): string;
begin
Result := StrPas(GIFVersionStr[Version]);
end;
const
CODE_TABLE_SIZE = 4096;
{$IFDEF WIN32}
HASH_TABLE_SIZE = 17777;
{$ELSE}
HASH_TABLE_SIZE = MaxListSize - $10;
{$ENDIF}
MAX_LOOP_COUNT = 30000;
CHR_EXT_INTRODUCER = '!';
CHR_IMAGE_SEPARATOR = ',';
CHR_TRAILER = ';'; { indicates the end of the GIF Data stream }
{ Image descriptor bit masks }
ID_LOCAL_COLOR_TABLE = $80; { set if a local color table follows }
ID_INTERLACED = $40; { set if image is interlaced }
ID_SORT = $20; { set if color table is sorted }
ID_RESERVED = $0C; { reserved - must be set to $00 }
ID_COLOR_TABLE_SIZE = $07; { Size of color table as above }
{ Logical screen descriptor packed field masks }
LSD_GLOBAL_COLOR_TABLE = $80; { set if global color table follows L.S.D. }
LSD_COLOR_RESOLUTION = $70; { Color resolution - 3 bits }
LSD_SORT = $08; { set if global color table is sorted - 1 bit }
LSD_COLOR_TABLE_SIZE = $07; { Size of global color table - 3 bits }
{ Actual Size = 2^value+1 - value is 3 bits }
{ Graphic control extension packed field masks }
GCE_TRANSPARENT = $01; { whether a transparency Index is given }
GCE_USER_INPUT = $02; { whether or not user input is expected }
GCE_DISPOSAL_METHOD = $1C; { the way in which the graphic is to be treated after being displayed }
GCE_RESERVED = $E0; { reserved - must be set to $00 }
{ Application extension }
AE_LOOPING = $01; { looping Netscape extension }
GIFColors: array[TGIFBits] of Word = (2, 4, 8, 16, 32, 64, 128, 256);
function ColorsToBits(ColorCount: Word): Byte; near;
var
I: TGIFBits;
begin
Result := 0;
for I := Low(TGIFBits) to High(TGIFBits) do
if ColorCount = GIFColors[I] then begin
Result := I;
Exit;
end;
GifError(LoadStr(SWrongGIFColors));
end;
function ColorsToPixelFormat(Colors: Word): TPixelFormat;
begin
if Colors <= 2 then Result := pf1bit
else if Colors <= 16 then Result := pf4bit
else if Colors <= 256 then Result := pf8bit
else Result := pf24bit;
end;
function ItemToRGB(Item: TGIFColorItem): Longint; near;
begin
with Item do Result := RGB(Red, Green, Blue);
end;
function GrayColor(Color: TColor): TColor;
var
Index: Integer;
begin
Index := Byte(Longint(Word(GetRValue(Color)) * 77 +
Word(GetGValue(Color)) * 150 + Word(GetBValue(Color)) * 29) shr 8);
Result := RGB(Index, Index, Index);
end;
procedure GrayColorTable(var ColorTable: TGIFColorTable);
var
I: Byte;
Index: Integer;
begin
for I := 0 to ColorTable.Count - 1 do begin
with ColorTable.Colors[I] do begin
Index := Byte(Longint(Word(Red) * 77 + Word(Green) * 150 +
Word(Blue) * 29) shr 8);
Red := Index;
Green := Index;
Blue := Index;
end;
end;
end;
function FindColorIndex(const ColorTable: TGIFColorTable;
Color: TColor): Integer;
begin
if (Color <> clNone) then
for Result := 0 to ColorTable.Count - 1 do
if ItemToRGB(ColorTable.Colors[Result]) = ColorToRGB(Color) then Exit;
Result := -1;
end;
{ The following types and function declarations are used to call into
functions of the GIF implementation of the GIF image
compression/decompression standard. }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -