FireMonkey GIF处理的更新

盒子上人才济济,很快就有兄弟发现在Android中有问题。

经过调试,发现Android中TCanvas.DrawBitmap对透明处理跟Windows不太一样,而是把透明部分也覆盖上去了,于是自己处理了一下帧的叠加,自己复制Bitmap的Scanline颜色,跳过透明即可。

2017.4.19加入对FMX for Linux的支持
http://www.raysoftware.cn/?p=559

此条目发表在Delphi分类目录,贴了, , 标签。将固定链接加入收藏夹。

FireMonkey GIF处理的更新》有 154 条评论

  1. 匿名说:

    我测试第一版,透明 GIF 在 Androi 并没问题, 可否将您测试有问题的透明 GIF 放入压缩包里,给我试试

    另外在 iOS 64 下编译会出错:
    需将 Stream.Seek(SkipByte, soFromCurrent);
    改成 Stream.Seek(Int64(SkipByte), soFromCurrent);
    就可编译并运行成功

    谢谢!

  2. dgbread说:

    编译运行Demo,显示Demo中带的两张GIF图。在Windows下显示正常,在Android下图片偏色严重。“100206.gif”应该是黄色而显示出来却变为蓝色。用Demo中的TImage加载该GIF,颜色为正常的黄色。请问如何处理?

  3. Alitrun说:

    Please update your GIF unit, our community fixed some bugs:
    http://fire-monkey.ru/topic/5093-производительность-отрисовки-текста-на-мобильных-платформах/?page=2#comment-32397
    Thank you.

    https://drive.google.com/file/d/1WV-eRWRjfMdYJ9y9y2H8EMypvgCUM1hH/view?usp=sharing

    unit FMX.GifUtils;

    interface

    uses
    System.Classes, System.SysUtils, System.Types, System.UITypes,
    FMX.Types, FMX.Objects, FMX.Graphics, System.Generics.Collections;

    const
    alphaTransparent = $00;
    GifSignature: array [0 .. 2] of Byte = ($47, $49, $46); // GIF
    VerSignature87a: array [0 .. 2] of Byte = ($38, $37, $61); // 87a
    VerSignature89a: array [0 .. 2] of Byte = ($38, $39, $61); // 89a

    GIF_DISPOSAL_UNSPECIFIED = 0;
    GIF_DISPOSAL_LEAVE = 1;
    GIF_DISPOSAL_BACKGROUND = 2;
    GIF_DISPOSAL_PREVIOUS = 3;

    type
    TGifVer = (verUnknow, ver87a, ver89a);

    TInternalColor = packed record
    case Integer of
    0:
    (

    {$IFDEF BIGENDIAN}
    R, G, B, A: Byte;
    {$ELSE}
    B, G, R, A: Byte;
    {$ENDIF}
    );
    1:
    (Color: TAlphaColor;
    );
    end;

    {$POINTERMATH ON}

    PInternalColor = ^TInternalColor;
    {$POINTERMATH OFF}

    TGifRGB = packed record
    R: Byte;
    G: Byte;
    B: Byte;
    end;

    TGIFHeader = packed record
    Signature: array [0 .. 2] of Byte; // * Header Signature (always “GIF”) */
    Version: array [0 .. 2] of Byte; // * GIF format version(“87a” or “89a”) */
    // Logical Screen Descriptor
    ScreenWidth: word; // * Width of Display Screen in Pixels */
    ScreenHeight: word; // * Height of Display Screen in Pixels */
    Packedbit: Byte; // * Screen and Color Map Information */
    BackgroundColor: Byte; // * Background Color Index */
    AspectRatio: Byte; // * Pixel Aspect Ratio */
    end;

    TGifImageDescriptor = packed record
    Left: word; // * X position of image on the display */
    Top: word; // * Y position of image on the display */
    Width: word; // * Width of the image in pixels */
    Height: word; // * Height of the image in pixels */
    Packedbit: Byte; // * Image and Color Table Data Information */
    end;

    TGifGraphicsControlExtension = packed record
    BlockSize: Byte; // * Size of remaining fields (always 04h) */
    Packedbit: Byte; // * Method of graphics disposal to use */
    DelayTime: word; // * Hundredths of seconds to wait */
    ColorIndex: Byte; // * Transparent Color Index */
    Terminator: Byte; // * Block Terminator (always 0) */
    end;

    TGifReader = class;

    TPalette = TArray;

    TGifFrameItem = class;

    TGifFrameList = TObjectList;
    { TGifReader }

    TGifReader = class(TObject)
    protected
    FHeader: TGIFHeader;
    FPalette: TPalette;
    FScreenWidth: Integer;
    FScreenHeight: Integer;
    FInterlace: Boolean;
    FBitsPerPixel: Byte;
    FBackgroundColorIndex: Byte;
    FResolution: Byte;
    FGifVer: TGifVer;

    public
    function Read(Stream: TStream; var AFrameList: TGifFrameList): Boolean;
    overload; virtual;
    function Read(FileName: string; var AFrameList: TGifFrameList): Boolean;
    overload; virtual;
    function ReadRes(Instance: THandle; ResName: string; ResType: PChar;
    var AFrameList: TGifFrameList): Boolean; overload; virtual;
    function ReadRes(Instance: THandle; ResId: Integer; ResType: PChar;
    var AFrameList: TGifFrameList): Boolean; overload; virtual;

    function Check(Stream: TStream): Boolean; overload; virtual;
    function Check(FileName: string): Boolean; overload; virtual;
    public
    constructor Create; virtual;
    destructor Destroy; override;

    property Header: TGIFHeader read FHeader;
    property ScreenWidth: Integer read FScreenWidth;
    property ScreenHeight: Integer read FScreenHeight;
    property Interlace: Boolean read FInterlace;
    property BitsPerPixel: Byte read FBitsPerPixel;
    property Background: Byte read FBackgroundColorIndex;
    property Resolution: Byte read FResolution;
    property GifVer: TGifVer read FGifVer;
    end;

    TGifFrameItem = class
    FDisposalMethod: Integer;
    FPos: TPoint;
    FTime: Integer;
    FDisbitmap: TBitmap;
    fBackColor : TalphaColor;
    public
    destructor Destroy; override;
    property Bitmap : TBitmap read FDisbitmap;
    end;

    implementation

    uses
    Math;

    function swap16(x: UInt16): UInt16; inline;
    begin
    Result := ((x and $FF) shl 8) or ((x and $FF00) shr 8);
    end;

    function swap32(x: UInt32): UInt32; inline;
    begin
    Result := ((x and $FF) shl 24) or ((x and $FF00) shl 8) or
    ((x and $FF0000) shr 8) or ((x and $FF000000) shr 24);
    end;

    function LEtoN(Value: word): word; overload;
    begin
    Result := swap16(Value);
    end;

    function LEtoN(Value: Dword): Dword; overload;
    begin
    Result := swap32(Value);
    end;

    procedure MergeBitmap(const Source, Dest: TBitmap; SrcRect: TRect;
    DestX, DestY: Integer);
    var
    I, J, MoveBytes: Integer;
    SrcData, DestData: TBitmapData;
    lpColorSrc, lpColorDst: PInternalColor;
    begin

    With Dest do
    begin
    if Map(TMapAccess.Write, DestData) then
    try
    if Source.Map(TMapAccess.Read, SrcData) then
    try
    if SrcRect.Left < 0 then
    begin
    Dec(DestX, SrcRect.Left);
    SrcRect.Left := 0;
    end;
    if SrcRect.Top < 0 then
    begin
    Dec(DestY, SrcRect.Top);
    SrcRect.Top := 0;
    end;
    SrcRect.Right := Min(SrcRect.Right, Source.Width);
    SrcRect.Bottom := Min(SrcRect.Bottom, Source.Height);
    if DestX < 0 then
    begin
    Dec(SrcRect.Left, DestX);
    DestX := 0;
    end;
    if DestY Width then
    SrcRect.Width := Width – DestX;
    if DestY + SrcRect.Height > Height then
    SrcRect.Height := Height – DestY;

    if (SrcRect.Left < SrcRect.Right) and (SrcRect.Top < SrcRect.Bottom)
    then
    begin
    MoveBytes := SrcRect.Width * SrcData.BytesPerPixel;
    for I := 0 to SrcRect.Height – 1 do
    begin
    lpColorSrc := SrcData.GetPixelAddr(SrcRect.Left,
    SrcRect.Top + I);
    lpColorDst := DestData.GetPixelAddr(DestX, DestY + I);
    for J := 0 to SrcRect.Width – 1 do
    if lpColorSrc[J].A 0 then
    begin
    lpColorDst[J] := lpColorSrc[J];
    end;
    end;
    end;
    finally
    Source.Unmap(SrcData);
    end;
    finally
    Unmap(DestData);
    end;
    end;

    end;

    { TGifReader }

    function TGifReader.Read(FileName: string;
    var AFrameList: TGifFrameList): Boolean;
    var
    fs: TFileStream;
    begin
    Result := False;
    fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
    Result := Read(fs, AFrameList);
    except

    end;
    fs.DisposeOf;
    end;

    function TGifReader.ReadRes(Instance: THandle; ResName: string; ResType: PChar;
    var AFrameList: TGifFrameList): Boolean;
    var
    res: TResourceStream;
    begin
    res := TResourceStream.Create(HInstance, ResName, ResType);
    Result := Read(res, AFrameList);
    res.DisposeOf;
    end;

    function TGifReader.ReadRes(Instance: THandle; ResId: Integer; ResType: PChar;
    var AFrameList: TGifFrameList): Boolean;
    var
    res: TResourceStream;
    begin
    res := TResourceStream.CreateFromID(HInstance, ResId, ResType);
    Result := Read(res, AFrameList);
    res.DisposeOf;
    end;

    function TGifReader.Read(Stream: TStream;
    var AFrameList: TGifFrameList): Boolean;
    var
    LDescriptor: TGifImageDescriptor;
    LGraphicsCtrlExt: TGifGraphicsControlExtension;
    LIsTransparent: Boolean;
    LGraphCtrlExt: Boolean;
    LFrameWidth: Integer;
    LFrameHeight: Integer;
    LLocalPalette: TPalette;
    LScanLineBuf: TBytes;

    procedure ReadPalette(Stream: TStream; Size: Integer; var APalette: TPalette);
    Var
    RGBEntry: TGifRGB;
    I: Integer;
    c: TInternalColor;
    begin
    SetLength(APalette, Size);
    For I := 0 To Size – 1 Do
    Begin
    Stream.Read(RGBEntry, SizeOf(RGBEntry));
    With APalette[I] do
    begin
    R := RGBEntry.R or (RGBEntry.R shl 8);
    G := RGBEntry.G or (RGBEntry.G shl 8);
    B := RGBEntry.B or (RGBEntry.B shl 8);
    A := $FF;
    end;
    End;
    end;

    function ProcHeader: Boolean;
    var
    c: TInternalColor;
    begin
    Result := False;
    With FHeader do
    begin
    if (CompareMem(@Signature, @GifSignature, 3)) and
    (CompareMem(@Version, @VerSignature87a, 3)) or
    (CompareMem(@Version, @VerSignature89a, 3)) then
    begin
    FScreenWidth := FHeader.ScreenWidth;
    FScreenHeight := FHeader.ScreenHeight;

    FResolution := Packedbit and $70 shr 5 + 1;
    FBitsPerPixel := Packedbit and 7 + 1;
    FBackgroundColorIndex := BackgroundColor;
    if CompareMem(@Version, @VerSignature87a, 3) then
    FGifVer := ver87a
    else if CompareMem(@Version, @VerSignature89a, 3) then
    FGifVer := ver89a;
    Result := True;
    end
    else
    Raise Exception.Create(‘Unknown GIF image format’);
    end;

    end;

    function ProcFrame: Boolean;
    var
    LineSize: Integer;
    LBackColorIndex: Integer;
    begin
    Result := False;
    With LDescriptor do
    begin
    LFrameWidth := Width;
    LFrameHeight := Height;
    FInterlace := ((Packedbit and $40) = $40);
    end;

    if LGraphCtrlExt then
    begin
    LIsTransparent := (LGraphicsCtrlExt.Packedbit and $01) 0;
    If LIsTransparent then
    LBackColorIndex := LGraphicsCtrlExt.ColorIndex;
    end
    else
    begin
    LIsTransparent := FBackgroundColorIndex 0;
    LBackColorIndex := FBackgroundColorIndex;
    end;
    LineSize := LFrameWidth * (LFrameHeight + 1);
    SetLength(LScanLineBuf, LineSize);

    If LIsTransparent then
    begin
    LLocalPalette[LBackColorIndex].A := alphaTransparent;
    end;

    Result := True;
    end;

    function ReadAndProcBlock(Stream: TStream): Byte;
    var
    Introducer, Labels, SkipByte: Byte;
    begin
    Stream.Read(Introducer, 1);
    if Introducer = $21 then
    begin
    Stream.Read(Labels, 1);
    Case Labels of
    $FE, $FF:
    // Comment Extension block or Application Extension block
    while True do
    begin
    Stream.Read(SkipByte, 1);
    if SkipByte = 0 then
    Break;
    Stream.Seek(Int64( SkipByte), soFromCurrent);
    end;
    $F9: // Graphics Control Extension block
    begin
    Stream.Read(LGraphicsCtrlExt, SizeOf(LGraphicsCtrlExt));
    LGraphCtrlExt := True;
    end;
    $01: // Plain Text Extension block
    begin
    Stream.Read(SkipByte, 1);
    Stream.Seek(Int64( SkipByte), soFromCurrent);
    while True do
    begin
    Stream.Read(SkipByte, 1);
    if SkipByte = 0 then
    Break;
    Stream.Seek(Int64( SkipByte), soFromCurrent);
    end;
    end;
    end;
    end;
    Result := Introducer;
    end;

    function ReadScanLine(Stream: TStream; AScanLine: PByte): Boolean;
    var
    OldPos, UnpackedSize, PackedSize: longint;
    I: Integer;
    Data, Bits, Code: Cardinal;
    SourcePtr: PByte;
    InCode: Cardinal;

    CodeSize: Cardinal;
    CodeMask: Cardinal;
    FreeCode: Cardinal;
    OldCode: Cardinal;
    Prefix: array [0 .. 4095] of Cardinal;
    Suffix, Stack: array [0 .. 4095] of Byte;
    StackPointer: PByte;
    Target: PByte;
    DataComp: TBytes;
    B, FInitialCodeSize, FirstChar: Byte;
    ClearCode, EOICode: word;
    begin
    DataComp := nil;
    try
    try
    Stream.Read(FInitialCodeSize, 1);
    OldPos := Stream.Position;
    PackedSize := 0;
    Repeat
    Stream.Read(B, 1);
    if B > 0 then
    begin
    Inc(PackedSize, B);
    Stream.Seek(Int64(B), soFromCurrent);
    CodeMask := (1 shl CodeSize) – 1;
    end;
    until B = 0;
    SetLength(DataComp, 2 * PackedSize);
    SourcePtr := @DataComp[0];
    Stream.Position := OldPos;
    Repeat
    Stream.Read(B, 1);
    if B > 0 then
    begin
    Stream.ReadBuffer(SourcePtr^, B);
    Inc(SourcePtr, B);
    end;
    until B = 0;

    SourcePtr := @DataComp[0];
    Target := AScanLine;
    CodeSize := FInitialCodeSize + 1;
    ClearCode := 1 shl FInitialCodeSize;
    EOICode := ClearCode + 1;
    FreeCode := ClearCode + 2;
    OldCode := 4096;
    CodeMask := (1 shl CodeSize) – 1;
    UnpackedSize := LFrameWidth * LFrameHeight;
    for I := 0 to ClearCode – 1 do
    begin
    Prefix[I] := 4096;
    Suffix[I] := I;
    end;
    StackPointer := @Stack;
    FirstChar := 0;
    Data := 0;
    Bits := 0;
    while (UnpackedSize > 0) and (PackedSize > 0) do
    begin
    Inc(Data, SourcePtr^ shl Bits);
    Inc(Bits, 8);
    while Bits >= CodeSize do
    begin
    Code := Data and CodeMask;
    Data := Data shr CodeSize;
    Dec(Bits, CodeSize);
    if Code = EOICode then
    Break;
    if Code = ClearCode then
    begin
    CodeSize := FInitialCodeSize + 1;
    CodeMask := (1 shl CodeSize) – 1;
    FreeCode := ClearCode + 2;
    OldCode := 4096;
    Continue;
    end;
    if Code > FreeCode then
    Break;
    if OldCode = 4096 then
    begin
    FirstChar := Suffix[Code];
    Target^ := FirstChar;
    Inc(Target);
    Dec(UnpackedSize);
    OldCode := Code;
    Continue;
    end;
    InCode := Code;
    if Code = FreeCode then
    begin
    StackPointer^ := FirstChar;
    Inc(StackPointer);
    Code := OldCode;
    end;
    while Code > ClearCode do
    begin
    StackPointer^ := Suffix[Code];
    Inc(StackPointer);
    Code := Prefix[Code];
    end;
    FirstChar := Suffix[Code];
    StackPointer^ := FirstChar;
    Inc(StackPointer);
    Prefix[FreeCode] := OldCode;
    Suffix[FreeCode] := FirstChar;
    if (FreeCode = CodeMask) and (CodeSize < 12) then
    begin
    Inc(CodeSize);
    CodeMask := (1 shl CodeSize) – 1;
    end;
    if FreeCode = NumberB) and (NumberB > 0) and
    (NumberA mod NumberB = 0);
    end;

    var
    PLine: PInternalColor;
    Data: TBitmapData;
    begin
    Result := False;
    P := AScanLine;
    if Img.Map(TMapAccess.Write, Data) then
    begin
    try
    If FInterlace then
    begin
    For Pass := 1 to 4 do
    begin
    Case Pass of
    1:
    begin
    Row := 0;
    Every := 8;
    end;
    2:
    begin
    Row := 4;
    Every := 8;
    end;
    3:
    begin
    Row := 2;
    Every := 4;
    end;
    4:
    begin
    Row := 1;
    Every := 2;
    end;
    end;

    Repeat
    PLine := Data.GetScanline(Row);
    for Col := 0 to Img.Width – 1 do
    begin
    PLine[Col] := LLocalPalette[P^];
    Inc(P);
    end;
    Inc(Row, Every);
    until Row >= Img.Height;
    end;
    end
    else
    begin
    for Row := 0 to Img.Height – 1 do
    begin
    PLine := Data.GetScanline(Row);
    for Col := 0 to Img.Width – 1 do
    begin
    PLine[Col] := LLocalPalette[P^];
    Inc(P);
    end;
    end;
    end;
    Result := True;
    finally
    Img.Unmap(Data);
    end;
    end;
    end;

    procedure RenderFrame(const Index : integer; const aFrames : array of TGifFrameItem; const aDisplay : TBitmap);
    var
    I, First, Last: Integer;
    begin
    Last := Index;
    First := Max(0, Last);
    aDisplay.Clear(aFrames[Index].fBackColor);
    while First > 0 do
    begin
    if (fScreenWidth = aFrames[First].Bitmap.Width) and (fScreenHeight = aFrames[First].Bitmap.Height) then
    begin
    if (aFrames[First].FDisposalMethod = GIF_DISPOSAL_BACKGROUND) and (First First) then
    begin
    // Restore background color
    aDisplay.ClearRect(TRectF.Create(aFrames[i].FPos.X, aFrames[i].FPos.Y,
    aFrames[i].FPos.X + aFrames[i].Bitmap.Width,
    aFrames[i].FPos.Y + aFrames[i].Bitmap.Height),
    aFrames[i].fBackColor);
    end;
    GIF_DISPOSAL_PREVIOUS: ; // Do nothing – previous state is already on screen
    end;
    end;
    MergeBitmap(aFrames[Index].Bitmap, aDisplay, aFrames[Index].Bitmap.Bounds, aFrames[Index].FPos.X, aFrames[Index].FPos.Y);
    end;

    var
    Introducer: Byte;
    ColorTableSize: Integer;
    tmp: TBitmap;
    LFrame: TGifFrameItem;
    FrameIndex: Integer;
    I: Integer;
    LBC : integer;
    LFrames : array of TGifFrameItem;
    rendered : array of TBitmap;
    begin
    Result := False;
    if not Check(Stream) then
    Exit;
    AFrameList.Clear;
    FGifVer := verUnknow;
    FPalette := nil;
    LScanLineBuf := nil;
    try

    Stream.Position := 0;
    Stream.Read(FHeader, SizeOf(FHeader));

    {$IFDEF BIGENDIAN}
    with FHeader do
    begin
    ScreenWidth := LEtoN(ScreenWidth);
    ScreenHeight := LEtoN(ScreenHeight);
    end;
    {$ENDIF}
    if (FHeader.Packedbit and $80) = $80 then
    begin
    ColorTableSize := FHeader.Packedbit and 7 + 1;
    ReadPalette(Stream, 1 shl ColorTableSize, FPalette);
    end;
    if not ProcHeader then
    Exit;

    FrameIndex := 0;
    SetLength(LFrames, 0);
    while True do
    begin
    LLocalPalette := nil;
    Repeat
    Introducer := ReadAndProcBlock(Stream);
    until (Introducer in [$2C, $3B]);
    if Introducer = $3B then
    Break;

    Stream.Read(LDescriptor, SizeOf(LDescriptor));
    {$IFDEF BIGENDIAN}
    with FDescriptor do
    begin
    Left := LEtoN(Left);
    Top := LEtoN(Top);
    Width := LEtoN(Width);
    Height := LEtoN(Height);
    end;
    {$ENDIF}
    if (LDescriptor.Packedbit and $80) 0 then
    begin
    ColorTableSize := LDescriptor.Packedbit and 7 + 1;
    ReadPalette(Stream, 1 shl ColorTableSize, LLocalPalette);
    end
    else
    begin
    LLocalPalette := Copy(FPalette, 0, Length(FPalette));
    end;

    if not ProcFrame then
    Exit;
    LFrame := TGifFrameItem.Create;
    LFrame.FTime := 10 * LGraphicsCtrlExt.DelayTime;
    LFrame.FDisbitmap := TBitmap.Create(LFrameWidth, LFrameHeight);
    LFrame.FPos := Point(LDescriptor.Left, LDescriptor.Top);
    LFrame.FDisposalMethod := 7 and (LGraphicsCtrlExt.Packedbit shr 2);
    if not ReadScanLine(Stream, @LScanLineBuf[0]) then
    Exit;
    if not WriteScanLine(LFrame.FDisbitmap, @LScanLineBuf[0]) then
    Exit;
    if LGraphCtrlExt then
    begin
    LIsTransparent := (LGraphicsCtrlExt.Packedbit and $01) 0;
    If LIsTransparent then
    LBC := LGraphicsCtrlExt.ColorIndex
    else
    LBC := FBackgroundColorIndex;
    end
    else
    LBC := FBackgroundColorIndex;
    LFrame.fBackColor := LLocalPalette[LBC].Color;
    Inc(FrameIndex);
    SetLength(LFrames, FrameIndex);
    LFrames[FrameIndex - 1] := LFrame;
    end;
    SetLength(rendered, Length(LFrames));
    for I := 0 to Length(LFrames) – 1 do
    begin
    tmp := TBitmap.Create(FScreenWidth, FScreenHeight);
    RenderFrame(I, LFrames, tmp);
    rendered[i] := tmp;
    end;
    for I := 0 to Length(LFrames) – 1 do
    begin
    LFrames[i].Bitmap.Assign(rendered[i]);
    FreeAndNil(rendered[i]);
    AFrameList.Add(LFrames[i]);
    end;

    Result := True;
    finally
    LLocalPalette := nil;
    LScanLineBuf := nil;
    rendered := nil;
    LFrames := nil;
    end;
    end;

    function TGifReader.Check(Stream: TStream): Boolean;
    var
    OldPos: Int64;
    begin
    try
    OldPos := Stream.Position;
    Stream.Read(FHeader, SizeOf(FHeader));
    Result := (CompareMem(@FHeader.Signature, @GifSignature, 3)) and
    (CompareMem(@FHeader.Version, @VerSignature87a, 3)) or
    (CompareMem(@FHeader.Version, @VerSignature89a, 3));
    Stream.Position := OldPos;
    except
    Result := False;
    end;
    end;

    function TGifReader.Check(FileName: string): Boolean;
    var
    fs: TFileStream;
    begin
    Result := False;
    fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
    Result := Check(fs);
    except

    end;
    fs.DisposeOf;
    end;

    constructor TGifReader.Create;
    begin
    inherited Create;

    end;

    destructor TGifReader.Destroy;
    begin

    inherited Destroy;
    end;

    { TGifFrameItem }

    destructor TGifFrameItem.Destroy;
    begin
    if FDisbitmap nil then
    begin
    FDisbitmap.DisposeOf;
    FDisbitmap := nil;
    end;
    inherited Destroy;
    end;

    end.

  4. Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí

  5. Pingback引用通告: abisko.ru

  6. Pingback引用通告: Mstiteli: Final (2019)

  7. Pingback引用通告: watch online

  8. Pingback引用通告: tureckie_serialy_na_russkom_jazyke

  9. Pingback引用通告: 00-tv.com

  10. Pingback引用通告: Ñìîòðåòü ñåðèàëû îíëàéí âñå ñåðèè ïîäðÿä

  11. Pingback引用通告: watch

  12. Pingback引用通告: Video

  13. Pingback引用通告: +1+

  14. Pingback引用通告: 1 2 3 4 5 6 7 8 9 10

  15. Pingback引用通告: wwin-tv.com

  16. Pingback引用通告: Watch TV Shows

  17. Pingback引用通告: casino

  18. Pingback引用通告: Kinokrad 2019 Kinokrad Hd

  19. Pingback引用通告: Kinokrad

  20. Pingback引用通告: filmy-kinokrad

  21. Pingback引用通告: kinokrad-2019

  22. Pingback引用通告: filmy-2019-kinokrad

  23. Pingback引用通告: serial

  24. Pingback引用通告: cerialest.ru

  25. Pingback引用通告: youtube2019.ru

  26. Pingback引用通告: dorama hdrezka

  27. Pingback引用通告: movies hdrezka

  28. Pingback引用通告: HDrezka

  29. Pingback引用通告: kinosmotretonline

  30. Pingback引用通告: LostFilm HD 720

  31. Pingback引用通告: trustedmdstorefy.com

  32. Pingback引用通告: bofilm ñåðèàë

  33. Pingback引用通告: bofilm

  34. Pingback引用通告: 1 seriya

  35. Pingback引用通告: Êîíñóëüòàöèÿ ïñèõîëîãà

  36. Pingback引用通告: topedstoreusa.com

  37. Pingback引用通告: hqcialismht.com

  38. Pingback引用通告: viagramdtrustser.com

  39. Pingback引用通告: rick and morty season 3

  40. Pingback引用通告: See-Season-1

  41. Pingback引用通告: Evil-Season-1

  42. Pingback引用通告: Evil-Season-2

  43. Pingback引用通告: Evil-Season-3

  44. Pingback引用通告: Evil-Season-4

  45. Pingback引用通告: Dollface-Season-1

  46. Pingback引用通告: Queer-Eye-We-re-in-Japan-Season-1

  47. Pingback引用通告: serial 2020

  48. Pingback引用通告: Dailymotion

  49. Pingback引用通告: Watch+movies+2020

  50. Pingback引用通告: Netflix Original Movies

  51. Pingback引用通告: serial-video-film-online

  52. Pingback引用通告: tvrv.ru

  53. Pingback引用通告: 1plus1serial.site

  54. Pingback引用通告: #1plus1

  55. Pingback引用通告: 1plus1

  56. Pingback引用通告: 2020

  57. Pingback引用通告: Watch Movies Online

  58. Pingback引用通告: Film

  59. Pingback引用通告: Film 2020

  60. Pingback引用通告: Film 2021

  61. Pingback引用通告: watch online TV LIVE

  62. Pingback引用通告: parazity-oskar-2020

  63. Pingback引用通告: human design

  64. Pingback引用通告: DSmlka

  65. Pingback引用通告: viagra

  66. Pingback引用通告: viagra online

  67. Pingback引用通告: +

  68. Pingback引用通告: ¯jak Son³k

  69. Pingback引用通告: astrolog

  70. Pingback引用通告: film-kalashnikov-watch

  71. Pingback引用通告: generic cialis

  72. Pingback引用通告: cialis 20mg

  73. Pingback引用通告: kinoxaxru.ru

  74. Pingback引用通告: pobachennya u vegas

  75. Pingback引用通告: Proshanie so Stalinym

  76. Pingback引用通告: strelcov 2020

  77. Pingback引用通告: film t-34

  78. Pingback引用通告: online pharmacy

  79. Pingback引用通告: canadian pharmacy

  80. Pingback引用通告: Beograd film 2020

  81. Pingback引用通告: psiholog

  82. Pingback引用通告: pomoshh-psihologa-online

  83. Pingback引用通告: psixolog

  84. Pingback引用通告: psyhelp_on_line

  85. Pingback引用通告: coronavirus

  86. Pingback引用通告: PSYCHOSOCIAL

  87. Pingback引用通告: rasstanovka hellinger

  88. Pingback引用通告: Cherekasi film 2020

  89. Pingback引用通告: film doktor_liza

  90. Pingback引用通告: djoker film

  91. Pingback引用通告: t.me/psyhell

  92. Pingback引用通告: Ïñèõîëîã îíëàéí

  93. Pingback引用通告: bitly.com

  94. Pingback引用通告: viagra 100mg

  95. Pingback引用通告: viagra price

  96. Pingback引用通告: viagra generic

  97. Pingback引用通告: viagra coupon

  98. Pingback引用通告: cheap viagra

  99. Pingback引用通告: cialis

  100. Pingback引用通告: cialis coupon

  101. Pingback引用通告: canadian pharmacy cialis

  102. Pingback引用通告: cialis 5mg

  103. Pingback引用通告: rlowcostmd.com

  104. Pingback引用通告: bitly

  105. Pingback引用通告: movies-tekstmovies-tekst

  106. Pingback引用通告: Zemlyane 2005 smotret onlajn

  107. Pingback引用通告: smotret onlajn besplatno v kachestve hd 1080

  108. Pingback引用通告: gusmeasu.com

  109. Pingback引用通告: movies-unhinged-film

  110. Pingback引用通告: malenkie-zhenshhiny-2020

  111. Pingback引用通告: dom 2

  112. Pingback引用通告: zoom-psykholog

  113. Pingback引用通告: zoom-viber-skype

  114. Pingback引用通告: Vratar Galaktiki Film, 2020

  115. Pingback引用通告: Vratar

  116. Pingback引用通告: Cherkassy 2020

  117. Pingback引用通告: chernobyl-hbo-2019-1-sezon

  118. Pingback引用通告: moskva-psiholog

  119. Pingback引用通告: batmanapollo.ru

  120. Pingback引用通告: 323

  121. Pingback引用通告: 525

  122. Pingback引用通告: dom2-ru

  123. Pingback引用通告: Tenet Online

  124. Pingback引用通告: psy psy psy psy

  125. Pingback引用通告: krsmi.ru

  126. Pingback引用通告: like-v.ru

  127. Pingback引用通告: CFOSPUK

  128. Pingback引用通告: MAMprEj

  129. Pingback引用通告: fgu0ygW

  130. Pingback引用通告: batmanapollo

  131. Pingback引用通告: tsoy

  132. Pingback引用通告: 44548

  133. Pingback引用通告: 44549

  134. Pingback引用通告: hod-korolevy-2020

  135. Pingback引用通告: HD

  136. Pingback引用通告: 158444

  137. Pingback引用通告: groznyy-serial-2020

  138. Pingback引用通告: 38QvPmk

  139. Pingback引用通告: bitly.com/doctor-strange-hd

  140. Pingback引用通告: bitly.com/eternals-online

  141. Pingback引用通告: bitly.com/maior-grom

  142. Pingback引用通告: matrica-film

  143. Pingback引用通告: dzhonuikfilm4

  144. Pingback引用通告: bitly.com/batman20212022

  145. Pingback引用通告: bitly.com/venom-2-smotret-onlajn

  146. Pingback引用通告: bitly.com/nevremyaumirat

  147. Pingback引用通告: bitly.com/kingsmankingsman

  148. Pingback引用通告: bitly.com/3zaklyatie3

  149. Pingback引用通告: bitly.com/1dreykfilm

  150. Pingback引用通告: bitly.com/topgunmavericktopgun

  151. Pingback引用通告: bitly.com/flash2022

  152. Pingback引用通告: bitly.com/fantasticheskietvari3

  153. Pingback引用通告: bitly.com/wonderwoman1984hd

发表评论

电子邮件地址不会被公开。

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

你必须启用JavaScript