加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

德尔福 – TGifImage透明度问题

发布时间:2020-12-15 04:12:08 所属栏目:大数据 来源:网络整理
导读:我正在使用Delphi XE附带的TGif Image. 我想要做的是从文件加载GIF并将所有帧提取到位图. 这是我到目前为止所做的: procedure ExtractGifFrames(FileName: string);var Gif: TGifImage; Bmp: TBitmap; i: Integer;begin Gif := TGifImage.Create; try Gif.L
我正在使用Delphi XE附带的TGif Image.

我想要做的是从文件加载GIF并将所有帧提取到位图.

这是我到目前为止所做的:

procedure ExtractGifFrames(FileName: string);
var
  Gif: TGifImage;
  Bmp: TBitmap;
  i: Integer;
begin
  Gif := TGifImage.Create;
  try
    Gif.LoadFromFile(FileName);

    Bmp := TBitmap.Create;
    try
      Bmp.SetSize(Gif.Width,Gif.Height);

      for i := 0 to Gif.Images.Count - 1 do
      begin
        if not Gif.Images[i].Empty then
        begin
          Bmp.Assign(Gif.Images[i]);
          Bmp.SaveToFile('C:testbitmap' + IntToStr(i) + '.bmp');
        end;
      end;
    finally
      Bmp.Free;
    end;
  finally
    Gif.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenPictureDialog1.Execute then
  begin
    ExtractGifFrames(OpenPictureDialog1.FileName);
  end;
end;

我面临的问题是存在许多不同Gif的透明度问题,以及尺寸问题.

以下是使用上面的代码保存的一些示例位图:

如您所见,结果不是很好,它们有大小和透明度问题.

我知道Gif文件本身没有损坏,因为我可以通过我的Web浏览器加载它们并且它们正确显示而没有错误.

如何从文件加载Gif,将每个帧分配给位图而不会丢失任何质量?

解决方法

对于较旧的Delphi版本(Pre 2009):看一下GIFImage单元的代码,您可能想要检查TGIFPainter如何根据每个Frame的Disposal方法呈现图像.

我用TGIFPainter.OnAfterPaint事件处理程序编写了一个小代码,将活动帧保存到BMP,并完成所有“辛勤工作”.

注:GIFImage单元版本2.2发布:5(1999年5月23日)

type
  TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    procedure Button1Click(Sender: TObject);
  public
    FBitmap: TBitmap;
    procedure AfterPaintGIF(Sender: TObject);
  end;

...

procedure TForm1.Button1Click(Sender: TObject);
var
  GIF: TGIFImage;
begin
  GIF := TGIFImage.Create;
  FBitmap := TBitmap.Create;
  Button1.Enabled := False;
  try
    GIF.LoadFromFile('c:testtest.gif');
    GIF.DrawOptions := GIF.DrawOptions - [goLoop,goLoopContinously,goAsync];
    GIF.AnimationSpeed := 1000; // Max - no delay
    FBitmap.Width := GIF.Width;
    FBitmap.Height := GIF.Height;
    GIF.OnAfterPaint := AfterPaintGIF;

    ProgressBar1.Max := Gif.Images.Count;
    ProgressBar1.Position := 0;
    ProgressBar1.Smooth := True;
    ProgressBar1.Step := 1;

    // Paint the GIF onto FBitmap,Let TGIFPainter do the painting logic
    // AfterPaintGIF will fire for each Frame
    GIF.Paint(FBitmap.Canvas,FBitmap.Canvas.ClipRect,GIF.DrawOptions);
    ShowMessage('Done!');
  finally
    FBitmap.Free;
    GIF.Free;
    Button1.Enabled := True;
  end;
end;

procedure TForm1.AfterPaintGIF(Sender: TObject);
begin
  if not (Sender is TGIFPainter) then Exit;
  if not Assigned(FBitmap) then Exit;
  // The event will ignore Empty frames      
  FBitmap.Canvas.Lock;
  try
    FBitmap.SaveToFile(Format('%.2d.bmp',[TGIFPainter(Sender).ActiveImage]));
  finally
    FBitmap.Canvas.Unlock;
  end;
  ProgressBar1.StepIt;
end;

注意:没有错误处理来简化代码.

对于较新的Delphi版本(2009):使用内置GIFImg单元,您可以使用TGIFRenderer(完全替换旧的TGIFPainter)轻松退出,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
  GIF: TGIFImage;
  Bitmap: TBitmap;
  I: Integer;
  GR: TGIFRenderer;
begin
  GIF := TGIFImage.Create;      
  Bitmap := TBitmap.Create;
  try
    GIF.LoadFromFile('c:testtest.gif');
    Bitmap.SetSize(GIF.Width,GIF.Height);
    GR := TGIFRenderer.Create(GIF);
    try
      for I := 0 to GIF.Images.Count - 1 do
      begin
        if GIF.Images[I].Empty then Break;
        GR.Draw(Bitmap.Canvas,Bitmap.Canvas.ClipRect);
        GR.NextFrame;
        Bitmap.SaveToFile(Format('%.2d.bmp',[I]));
      end;
    finally
      GR.Free;
    end;  
  finally
    GIF.Free;
    Bitmap.Free;
  end;
end;

使用GDI:

uses ...,GDIPAPI,GDIPOBJ,GDIPUTIL;

procedure ExtractGifFrames(const FileName: string);
var
  GPImage: TGPImage;
  encoderClsid: TGUID;
  BmpFrame: TBitmap;
  MemStream: TMemoryStream;
  FrameCount,FrameIndex: Integer;
begin
  GPImage := TGPImage.Create(FileName);
  try
    if GPImage.GetLastStatus = Ok then
    begin
      GetEncoderClsid('image/bmp',encoderClsid);
      FrameCount := GPImage.GetFrameCount(GDIPAPI.FrameDimensionTime);
      for FrameIndex := 0 to FrameCount - 1 do
      begin
        GPImage.SelectActiveFrame(GDIPAPI.FrameDimensionTime,FrameIndex);
        MemStream := TMemoryStream.Create;
        try
          if GPImage.Save(TStreamAdapter.Create(MemStream),encoderClsid) = Ok then
          begin
            MemStream.Position := 0;
            BmpFrame := TBitmap.Create;
            try
              BmpFrame.LoadFromStream(MemStream);
              BmpFrame.SaveToFile(Format('%.2d.bmp',[FrameIndex]));
            finally
              BmpFrame.Free;
            end;
          end;
        finally
          MemStream.Free;
        end;
      end;
    end;
  finally
    GPImage.Free;
  end;
end;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读