📄 rxgif.pas
字号:
FImage.Release;
FImage := TGIFFrame(Source).FImage;
if TGIFFrame(Source).FOwner <> FOwner then FLocalColors := True
else FLocalColors := TGIFFrame(Source).FLocalColors;
FImage.Reference;
FTopLeft := TGIFFrame(Source).FTopLeft;
FInterlaced := TGIFFrame(Source).FInterlaced;
if TGIFFrame(Source).FBitmap <> nil then begin
NewBitmap;
FBitmap.Assign(TGIFFrame(Source).FBitmap);
end;
FTransparentColor := TGIFFrame(Source).FTransparentColor;
FAnimateInterval := TGIFFrame(Source).FAnimateInterval;
FDisposal := TGIFFrame(Source).FDisposal;
FGrayscale := TGIFFrame(Source).FGrayscale;
FCorrupted := TGIFFrame(Source).FCorrupted;
AComment := TGIFFrame(Source).FindComment(False);
if (AComment <> nil) and (AComment.Count > 0) then
SetComment(AComment);
end;
end
else if Source is TGIFImage then begin
if (TGIFImage(Source).Count > 0) then begin
if (TGIFImage(Source).FrameIndex >= 0) then
Assign(TGIFImage(Source).Frames[TGIFImage(Source).FrameIndex])
else
Assign(TGIFImage(Source).Frames[0]);
end
else Assign(nil);
end
else if Source is TGraphic then begin
{ TBitmap, TJPEGImage... }
if TGraphic(Source).Empty then begin
Assign(nil);
Exit;
end;
NewImage;
NewBitmap;
try
FBitmap.Assign(Source);
if Source is TBitmap then
FBitmap.Monochrome := TBitmap(Source).Monochrome;
except
FBitmap.Canvas.Brush.Color := clFuchsia;
FBitmap.Width := TGraphic(Source).Width;
FBitmap.Height := TGraphic(Source).Height;
FBitmap.Canvas.Draw(0, 0, TGraphic(Source));
end;
{$IFDEF RX_D3}
if TGraphic(Source).Transparent then begin
if Source is TBitmap then
FTransparentColor := TBitmap(Source).TransparentColor
else FTransparentColor := GetNearestColor(FBitmap.Canvas.Handle,
ColorToRGB(FBitmap.Canvas.Brush.Color));
end;
{$ELSE}
if (Source is TIcon) or (Source is TMetafile) then
FTransparentColor := GetNearestColor(FBitmap.Canvas.Handle,
ColorToRGB(FBitmap.Canvas.Brush.Color));
{$ENDIF}
end
else inherited Assign(Source);
if FOwner <> nil then FOwner.UpdateScreenSize;
end;
procedure TGIFFrame.AssignTo(Dest: TPersistent);
begin
if (Dest is TGIFFrame) or (Dest is TGIFImage) then Dest.Assign(Self)
else if Dest is TGraphic then begin
Dest.Assign(Bitmap);
{$IFDEF RX_D3}
if (Dest is TBitmap) and (FTransparentColor <> clNone) then begin
TBitmap(Dest).TransparentColor := GetNearestColor(
TBitmap(Dest).Canvas.Handle, ColorToRGB(FTransparentColor));
TBitmap(Dest).Transparent := True;
end;
{$ENDIF}
end
else inherited AssignTo(Dest);
end;
procedure TGIFFrame.NewBitmap;
begin
FBitmap.Free;
FBitmap := TBitmap.Create;
end;
procedure TGIFFrame.NewImage;
begin
if FImage <> nil then FImage.Release;
FImage := TGIFItem.Create;
FImage.Reference;
FGrayscale := False;
FCorrupted := False;
FTransparentColor := clNone;
FTopLeft := Point(0, 0);
FInterlaced := False;
FLocalColors := False;
FAnimateInterval := 0;
FDisposal := dmUndefined;
end;
function TGIFFrame.FindComment(ForceCreate: Boolean): TStrings;
var
Ext: TExtension;
begin
Ext := FindExtension(FExtensions, etComment);
if (Ext = nil) and ForceCreate then begin
Ext := TExtension.Create;
try
Ext.FExtType := etComment;
if FExtensions = nil then FExtensions := TList.Create;
FExtensions.Add(Ext);
except
Ext.Free;
raise;
end;
end;
if (Ext <> nil) then begin
if (Ext.FData = nil) and ForceCreate then
Ext.FData := TStringList.Create;
Result := Ext.FData;
end
else Result := nil;
end;
function TGIFFrame.GetComment: TStrings;
begin
Result := FindComment(True);
end;
procedure TGIFFrame.SetComment(Value: TStrings);
begin
GetComment.Assign(Value);
end;
procedure TGIFFrame.UpdateExtensions;
var
Ext: TExtension;
I: Integer;
begin
Ext := FindExtension(FExtensions, etGraphic);
if (FAnimateInterval > 0) or (FTransparentColor <> clNone) or
(FDisposal <> dmUndefined) then
begin
if Ext = nil then begin
Ext := TExtension.Create;
Ext.FExtType := etGraphic;
if FExtensions = nil then FExtensions := TList.Create;
FExtensions.Add(Ext);
with Ext.FExtRec.GCE do begin
BlockSize := 4;
PackedFields := 0;
Terminator := 0;
end;
end;
end;
if Ext <> nil then
with Ext.FExtRec.GCE do begin
DelayTime := FAnimateInterval div 10;
I := FindColorIndex(FImage.FColorMap, FTransparentColor);
if I >= 0 then begin
TransparentColorIndex := I;
PackedFields := PackedFields or GCE_TRANSPARENT;
end
else PackedFields := PackedFields and not GCE_TRANSPARENT;
PackedFields := (PackedFields and not GCE_DISPOSAL_METHOD) or
(Ord(FDisposal) shl 2);
end;
if FExtensions <> nil then
for I := FExtensions.Count - 1 downto 0 do begin
Ext := TExtension(FExtensions[I]);
if (Ext <> nil) and (Ext.FExtType = etComment) and
((Ext.FData = nil) or (Ext.FData.Count = 0)) then
begin
Ext.Free;
FExtensions.Delete(I);
end;
end;
if (FExtensions <> nil) and (FExtensions.Count > 0) then
FOwner.FVersion := gv89a;
end;
procedure TGIFFrame.EncodeBitmapStream(Stream: TMemoryStream);
var
BI: PBitmapInfoHeader;
ColorCount, W, H: Integer;
Bits, Pal: Pointer;
begin
ColorCount := 0;
Stream.Position := 0;
BI := PBitmapInfoHeader(Longint(Stream.Memory) + SizeOf(TBitmapFileHeader));
W := BI^.biWidth; H := BI^.biHeight;
Pal := PRGBPalette(Longint(BI) + SizeOf(TBitmapInfoHeader));
Bits := Pointer(Longword(Stream.Memory) + PBitmapFileHeader(Stream.Memory)^.bfOffBits);
case BI^.biBitCount of
1: ColorCount := 2;
4: ColorCount := 16;
8: ColorCount := 256;
else GifError(LoadStr(SGIFEncodeError));
end;
FInterlaced := False;
FillColorTable(FImage.FColorMap, PRGBPalette(Pal)^, ColorCount);
if FImage.FImageData = nil then FImage.FImageData := TMemoryStream.Create
else FImage.FImageData.SetSize(0);
try
WriteGIFData(FImage.FImageData, BI^, FInterlaced, Bits, FOwner.DoProgress);
except
on EAbort do begin
NewImage; { OnProgress can raise EAbort to cancel image save }
raise;
end
else raise;
end;
FImage.FBitsPerPixel := 1;
while FImage.FColorMap.Count > 1 shl FImage.FBitsPerPixel do
Inc(FImage.FBitsPerPixel);
if FOwner.FImage.FColorMap.Count = 0 then begin
FOwner.FImage.FColorMap := FImage.FColorMap;
FOwner.FImage.FBitsPerPixel := FImage.FBitsPerPixel;
FLocalColors := False;
end
else FLocalColors := True;
FImage.FSize.X := W; FImage.FSize.Y := H;
FOwner.FScreenWidth := Max(FOwner.FScreenWidth, FImage.FSize.X + FTopLeft.X);
FOwner.FScreenHeight := Max(FOwner.FScreenHeight, FImage.FSize.Y + FTopLeft.Y);
end;
procedure TGIFFrame.EncodeRasterData;
var
Method: TMappingMethod;
Mem: TMemoryStream;
begin
if not Assigned(FBitmap) or FBitmap.Empty then GifError(LoadStr(SNoGIFData));
if not (GetBitmapPixelFormat(FBitmap) in [pf1bit, pf4bit, pf8bit]) then
begin
if FGrayscale then Method := mmGrayscale
else Method := DefaultMappingMethod;
Mem := BitmapToMemoryStream(FBitmap, pf8bit, Method);
if (Method = mmGrayscale) then FGrayscale := True;
end
else Mem := TMemoryStream.Create;
try
if Mem.Size = 0 then FBitmap.SaveToStream(Mem);
EncodeBitmapStream(Mem);
finally
Mem.Free;
end;
end;
procedure TGIFFrame.WriteImageDescriptor(Stream: TStream);
var
ImageDesc: TImageDescriptor;
begin
with ImageDesc do begin
PackedFields := 0;
if FLocalColors then begin
FImage.FBitsPerPixel := 1;
while FImage.FColorMap.Count > 1 shl FImage.FBitsPerPixel do
Inc(FImage.FBitsPerPixel);
PackedFields := (PackedFields or ID_LOCAL_COLOR_TABLE) +
(FImage.FBitsPerPixel - 1);
end;
if FInterlaced then PackedFields := PackedFields or ID_INTERLACED;
ImageLeftPos := FTopLeft.X;
ImageTopPos := FTopLeft.Y;
ImageWidth := FImage.FSize.X;
ImageHeight := FImage.FSize.Y;
end;
Stream.Write(ImageDesc, SizeOf(TImageDescriptor));
end;
procedure TGIFFrame.WriteLocalColorMap(Stream: TStream);
begin
if FLocalColors then
with FImage.FColorMap do
Stream.Write(Colors[0], Count * SizeOf(TGIFColorItem));
end;
procedure TGIFFrame.WriteRasterData(Stream: TStream);
begin
Stream.WriteBuffer(FImage.FImageData.Memory^, FImage.FImageData.Size);
end;
procedure TGIFFrame.SaveToBitmapStream(Stream: TMemoryStream);
function ConvertBitsPerPixel: TPixelFormat;
begin
Result := pfDevice;
case FImage.FBitsPerPixel of
1: Result := pf1bit;
2..4: Result := pf4bit;
5..8: Result := pf8bit;
else GifError(LoadStr(SWrongGIFColors));
end;
end;
var
HeaderSize: Longword;
Length: Longword;
BI: TBitmapInfoHeader;
BitFile: TBitmapFileHeader;
Colors: TRGBPalette;
Bits: Pointer;
Corrupt: Boolean;
begin
with BI do begin
biSize := Sizeof(TBitmapInfoHeader);
biWidth := FImage.FSize.X;
biHeight := FImage.FSize.Y;
biPlanes := 1;
biBitCount := 0;
case ConvertBitsPerPixel of
pf1bit: biBitCount := 1;
pf4bit: biBitCount := 4;
pf8bit: biBitCount := 8;
end;
biCompression := BI_RGB;
biSizeImage := (((biWidth * biBitCount + 31) div 32) * 4) * biHeight;
biXPelsPerMeter := 0;
biYPelsPerMeter := 0;
biClrUsed := 0;
biClrImportant := 0;
end;
HeaderSize := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader) +
SizeOf(TRGBQuad) * (1 shl BI.biBitCount);
Length := HeaderSize + BI.biSizeImage;
Stream.SetSize(0);
Stream.Position := 0;
with BitFile do begin
bfType := $4D42; { BM }
bfSize := Length;
bfOffBits := HeaderSize;
end;
Stream.Write(BitFile, SizeOf(TBitmapFileHeader));
Stream.Write(BI, SizeOf(TBitmapInfoHeader));
FillRGBPalette(FImage.FColorMap, Colors);
Stream.Write(Colors, SizeOf(TRGBQuad) * (1 shl BI.biBitCount));
Bits := AllocMemo(BI.biSizeImage);
try
ZeroMemory(Bits, BI.biSizeImage);
FImage.FImageData.Position := 0;
ReadGIFData(FImage.FImageData, BI, FInterlaced, GIFLoadCorrupted,
FImage.FBitsPerPixel, Bits, Corrupt, FOwner.DoProgress);
FCorrupted := FCorrupted or Corrupt;
Stream.WriteBuffer(Bits^, BI.biSizeImage);
finally
FreeMemo(Bits);
end;
Stream.Position := 0;
end;
procedure TGIFFrame.LoadFromStream(Stream: TStream);
var
ImageDesc: TImageDescriptor;
I, TransIndex: Integer;
begin
FImage.FImageData := TMemoryStream.Create;
try
ReadImageStream(Stream, FImage.FImageData, ImageDesc, FInterlaced,
FLocalColors, FCorrupted, FImage.FBitsPerPixel, FImage.FColorMap);
if FCorrupted and not GIFLoadCorrupted then GifError(ResStr(SReadError));
FImage.FImageData.Position := 0;
with ImageDesc do begin
if ImageHeight = 0 then ImageHeight := FOwner.FScreenHeight;
if ImageWidth = 0 then ImageWidth := FOwner.FScreenWidth;
FTopLeft := Point(ImageLeftPos, ImageTopPos);
FImage.FSize := Point(ImageWidth, ImageHeight);
FImage.FPackedFields := PackedFields;
end;
if not FLocalColors then FImage.FColorMap := FOwner.FImage.FColorMap;
FAnimateInterval := 0;
if FExtensions <> nil then begin
for I := 0 to FExtensions.Count - 1 do
with TExtension(FExtensions[I]) do
if FExtType = etGraphic then begin
if (FExtRec.GCE.PackedFields and GCE_TRANSPARENT) <> 0 then
begin
TransIndex := FExtRec.GCE.TransparentColorIndex;
if FImage.FColorMap.Count > TransIndex then
FTransparentColor := ItemToRGB(FImage.FColorMap.Colors[TransIndex]);
end
else FTransparentColor := clNone;
FAnimateInterval := Max(FExtRec.GCE.DelayTime * 10,
FAnimateInterval);
FDisposal := TDisposalMethod((FExtRec.GCE.PackedFields and
GCE_DISPOSAL_METHOD) shr 2);
end;
end;
except
FImage.FImageData.Free;
FImage.FImageData := nil;
raise;
end;
end;
procedure TGIFFrame.Draw(ACanvas: TCanvas; const ARect: TRect;
Transparent: Boolean);
begin
if (FTransparentColor <> clNone) and Transparent then begin
with ARect do
StretchBitmapRectTransparent(ACanvas, Left, Top, Right - Left,
Bottom - Top, Bounds(0, 0, Bitmap.Width, Bitmap.Height), Bitmap,
FTransparentColor);
end
else ACanvas.StretchDraw(ARect, Bitmap);
end;
{ TGIFImage }
constructor TGIFImage.Create;
begin
inherited Create;
NewImage;
{$IFDEF RX_D3}
inherited SetTransparent(True);
{$ENDIF}
end;
destructor TGIFImage.Destroy;
begin
OnChange := nil;
FImage.Release;
ClearItems;
FItems.Free;
inherited Destroy;
end;
procedure TGIFImage.Clear;
begin
Assign(nil);
end;
procedure TGIFImage.ClearItems;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -