【问题标题】:Function to load PNG Image from ResourceStream returns nothing从 ResourceStream 加载 PNG 图像的函数不返回任何内容
【发布时间】:2020-02-27 04:42:28
【问题描述】:

在 Delphi 10.1 Berlin 中,我试图通过从资源加载 PNG 图像来更改表单上的图片。 我遵循了这个: Load image from embedded resource 并使用 TWICImage 自动处理不同的可能图像格式。 在这种情况下,我特别想使用 PNG 来实现透明度。

由于某种原因,我创建的函数什么都不返回。 但是,如果我在函数中调用result.savetofile('test.png'),则资源被成功保存,这将验证资源是否存在于EXE中并且已被找到。

function LoadImageResource(NativeInstance: NativeUInt; ImageResource: string): TWICImage;
var
   Strm: TResourceStream;
   WICImage: TWICImage;

begin

  Strm := TResourceStream.Create(NativeInstance, ImageResource, RT_RCDATA);
  try
    Strm.Position := 0;
    WICImage := TWICImage.Create;
    try
      WICImage.LoadFromStream(Strm);
      result :=  WICImage; //these return empty
      result.savetofile('test.png'); //this succesfully saves the resource to disk
    finally
      WICImage.Free;
    end;
  finally
    Strm.Free;
  end;

end;

在函数之外,如果我尝试通过调用 Image1.picture.assign(LoadFromResource(...))Image1.picture.graphic := LoadFromResource(...) 来分配图像,则不会分配任何内容。如果我再打电话给Image1.savetofile('test.png'),我会收到访问冲突错误。

我可能缺少什么?

【问题讨论】:

  • 您正在释放作为结果返回的 WICImage。我很惊讶您的应用没有因此崩溃。

标签: image delphi resources


【解决方案1】:

问题是您正在破坏您返回的图像。了解类是 Delphi 中的引用类型很重要。因此,在分配给Result 之后,在您的代码中,您仍然只有一个实例,但是对同一个实例的两个引用。

您需要删除对Free的调用。

function LoadImageResource(Module: NativeUInt; const ResName: string): TWICImage;
var
  Strm: TResourceStream;
begin
  Strm := TResourceStream.Create(Module, ResName, RT_RCDATA);
  try
    Result := TWICImage.Create;
    Result.LoadFromStream(Strm);
  finally
    Strm.Free;
  end;
end;

需要稍作调整才能使函数异常安全:

function LoadImageResource(Module: NativeUInt; const ResName: string): TWICImage;
var
  Strm: TResourceStream;
begin
  Strm := TResourceStream.Create(Module, ResName, RT_RCDATA);
  try
    Result := TWICImage.Create;
    try
      Result.LoadFromStream(Strm);
    except
      Result.Free;
      raise;
    end;
  finally
    Strm.Free;
  end;
end;

当您调用该函数时,它的行为类似于构造函数。它要么成功并返回一个新实例,将所有权移交给调用者。或者它会引发异常。因此,我将函数命名为CreateImageFromResource

【讨论】:

  • 还要注意Image1.Picture.Assign(LoadFromResource(...))Image1.Picture.Graphic := LoadFromResource(...) 都有内存泄漏。 TPicture 将制作分配给它的TWICImage副本。调用者必须Free LoadFromResource() 返回的原始TWICImageImg := LoadFromResource(...); try Image1.Picture.Assign(Img); {Image1.Picture.Graphic := Img;} finally Img.Free; 我建议将TPicture 传递给LoadImageResource() 并让它根据需要加载+分配图片,无需返回任何内容调用者。
  • 谢谢你们。尤其是你大卫对参考和副本的解释。这对我来说更有意义。我担心不在函数内调用 free 会导致内存泄漏。感谢 Remy 关于将 Tpicture 传递给函数的提示。我已经成功实现了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-18
  • 2023-01-23
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
相关资源
最近更新 更多