【问题标题】:TBitmap32.LoadFromStream() Auto-Recognize Image FormatTBitmap32.LoadFromStream() 自动识别图像格式
【发布时间】:2013-06-17 00:33:31
【问题描述】:

我正在使用 Delphi XE2(更新 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()将图像数据加载到中间对象中,然后将Assign()加载到@ 987654331@。但是,如果TBitmap32 可以处理任何类型的图像而不需要中间对象,那就更好了,我认为它可以...

问题

有谁知道如何使用TBitmap32.LoadFromStream() 来加载图像并让它自动识别图像格式而不将图像保存到 HDD(即使是暂时的),或使用中间对象?

【问题讨论】:

  • 尝试 Vampyrу 成像。该项目旨在结合Graphics32的速度和GraphicEx的格式灵活性。不知道他们成功了多少,但有来自用户的热情报告。
  • @Arioch'The - 我会看看。谢谢。仅供参考 - 这是 SourceForge 链接:imaginglib.sourceforge.net

标签: delphi image-formats graphics32


【解决方案1】:

Delphi XE2 在Vcl.Graphics 中包含一个名为TWICImage 的类,用于处理Windows Imaging Component 支持的图像,包括BMP、GIF、ICO、JPEG、PNG、TIF 和Windows Media Photo。这意味着您可以直接从流中加载任何受支持的图像类型,它会自动检测图像类型并加载它。然后可以将加载的图像分配给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;

无需在您的 uses 语句中添加 PNGImageGIFImgJPEG 即可工作。

【讨论】:

    【解决方案2】:

    这是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. 在传递TPNGImage 实例的TBitmap32 实例上调用Assign

    【讨论】:

    • 很高兴知道LoadFromStream 特定于实例化对象类型——它不能自动检测数据流中的图像类型。谢谢大卫。
    • 刚刚也发现了这个,其中列出了一些不同的方法来完成这个:stackoverflow.com/questions/959160/…
    • 重点是你需要一个中间对象因为TBitmap32不能解码PNG
    • 是的 - 这是有道理的。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-10
    • 2016-02-09
    相关资源
    最近更新 更多