TBitmap32.LoadFromStream()自动识别图像格式

时间:2013-06-20 08:27:40

标签: delphi image-formats graphics32

我正在使用Delphi XE2(Update 3)和GR32。我无法使用TBitmap32.LoadFromStream()加载图片数据。它引发了以下异常:

Project MyApp.exe raised exception class EInvalidGraphic with message 'Bitmap image is not valid'.

代码

uses GR32, GifImg, PngImage, Vcl.Graphics;

var
  pic: TBitmap32;
  bs: TBytesStream;
begin
  bs := TBytesStream.Create(TClientDataSet(cds).FieldByName('filedata').AsBytes);
  try
    pic := TBitmap32.Create;
    try
//      bs.SaveToFile('c:\delme.png');
//      pic.LoadFromFile('c:\delme.png');
      pic.LoadFromStream(bs); // <- EInvalidGraphic exception
      // do something with 'pic'
    finally
      FreeAndNil(pic);
    end;
  finally
    FreeAndNil(bs);
  end;
end;

解决方法(一个或多个)

如果我评论LoadFromStream()代码并取消注释前两行,它就可以工作 - 因此它可以在从文件加载时确定图像格式。在此示例中,bs包含有效的PNG图像。但是,有时它可能是GIF,JPG,BMP或其他图形格式。

我也知道我可以使用中间对象(例如TPNGImageTJPEGImage等),使用LoadFromStream()将图像数据加载到中间对象中,然后{ {1}}它Assign()。但是,如果TBitmap32可以处理没有中间对象的任何类型的图像会更好,我认为它可以...

问题

是否有人知道如何使用TBitmap32加载图片并让其自动识别图像格式而不将图像保存到HDD(即使是暂时的),或者使用中间图像对象

2 个答案:

答案 0 :(得分:4)

Delphi XE2在Vcl.Graphics中包含一个名为TWICImage的类,用于处理Windows Imaging Component支持的图像,包括 BMP,GIF,ICO,JPEG,PNG,TIF和Windows Media照片即可。这意味着您可以直接从流中加载任何支持的图像类型,它将自动检测图像类型并加载它。然后,可以将加载的图像分配给TBitmap32组件(或TImageTImage32等。)

uses GR32, Vcl.Graphics;

var
  pic: TBitmap32;
  wic: TWICImage;
  bs: TBytesStream;
begin
  bs := TBytesStream.Create(TClientDataSet(cds).FieldByName('filedata').AsBytes);
  try
    pic := TBitmap32.Create;
    try
      wic := TWICImage.Create;
      try
        bs.Position := 0;
        wic.LoadFromStream(bs);
        pic.Assign(wic);
      finally
        FreeAndNil(wic);
      end;
    finally
      FreeAndNil(pic);
    end;
  finally
    FreeAndNil(bs);
  end;
end;

无需在PNGImage声明中添加GIFImgJPEGuses即可。

答案 1 :(得分:3)

这是LoadFromFile的代码:

procedure TCustomBitmap32.LoadFromFile(const FileName: string);
var
  FileStream: TFileStream;
  Header: TBmpHeader;
  P: TPicture;
begin
  FileStream := TFileStream.Create(Filename, fmOpenRead);
  try
    FileStream.ReadBuffer(Header, SizeOf(TBmpHeader));

    // Check for Windows bitmap magic bytes...
    if Header.bfType = $4D42 then
    begin
      // if it is, use our stream read method...
      FileStream.Seek(-SizeOf(TBmpHeader), soFromCurrent);
      LoadFromStream(FileStream);
      Exit;
    end
  finally
    FileStream.Free;
  end;

  // if we got here, use the fallback approach via TPicture...
  P := TPicture.Create;
  try
    P.LoadFromFile(FileName);
    Assign(P);
  finally
    P.Free;
  end;
end;

如您所见,代码会检查文件是否为Windows位图。如果是,则通过调用LoadFromStream直接加载它。

如果没有,则加载到TPicture然后分配给此实例。

关键是LoadFromStream只能理解Windows位图。它不了解任何其他文件格式。而你正在尝试加载PNG。因此,如果不使用中间对象,就无法做到所需。

您的解决方案是:

  1. 实例化TPNGImage对象。
  2. 在该实例上调用LoadFromStream
  3. 在通过Assign实例的TBitmap32实例上调用TPNGImage