【问题标题】:Load a png image from the web (delphi fmx)从网络加载 png 图像 (delphi fmx)
【发布时间】:2021-08-17 16:25:24
【问题描述】:

我想从网络加载 png 图像,但使用下面的代码,并非所有图像都能正确进入流(在 web 浏览器中发布 url 时,例如 edge,确实给出了正确的图像)。例如,代码中的第一个 url 给出了加载位图失败的错误(在流中 FSize 只有 14?),而第二个 url 没有给出问题。有谁知道如何正确下载第一个网址?

为了让这段代码工作,一个 TButton 和一个 TImage 被放在一个表单上。
System.Net.HttpClientComponent 被添加到使用中。我正在使用德尔福 10.3.3。调频。

谢谢, 杰拉德

    procedure TForm1.Button1Click(Sender: TObject);
    var ms: TmemoryStream;
        httpCli: TNetHTTPClient;
        url: string;
    begin
      httpCli := TNetHTTPClient.Create(nil);
      ms := TMemoryStream.Create();
    
      url := 'https://a.tile.openstreetmap.org/11/1050/674.png';
  //  url := 'https://upload.wikimedia.org/wikipedia/commons/d/d5/Japan_small_icon.png';
    
      httpCli.Get(url,ms);
      ms.Position := 0;
      Image1.Bitmap.LoadFromStream(ms);
    
      ms.free;
      httpCli.free;
    end;

【问题讨论】:

  • 你说有一些数据被加载到第一个url的流中,如果它不是一个有效的图像那么它到底是什么数据?
  • 这是一个有效的图像,可以通过在浏览器中复制 url 来查看。
  • 14 字节可能不足以生成有效图像。字节实际上是什么样的?
  • 问题是服务器阻塞了用户代理。有关详细信息,请参阅here

标签: delphi firemonkey


【解决方案1】:

在 HTTP 上操作时,您必须检查 HTTP 服务器是否可以满足您的请求(status code 200,根据 RFC7231, § 6.3.1)或发生任何错误。在您的情况下,请求该 URI 并确保查看来自服务器的内容可以通过 wget 来完成:

wget -S --content-on-error https://a.tile.openstreetmap.org/11/1050/674.png

这将打印服务器的响应标头,并在任何情况下创建一个保存有效负载的文件。响应标头是(摘录):

HTTP/1.1 403 Forbidden
Content-Length: 14

这意味着:不允许您查询该资源(HTTP 状态代码 403)。有效负载保存在一个大小为 14 字节的文件中,其中包含 14 个 ASCII 字符的文本:

Access denied.

琐事:最小的有效 PNG 文件大小至少 67 字节(阅读"Smallest possible transparent PNG" by Gareth Rees

【讨论】:

    【解决方案2】:

    OpenStreetMap 瓦片服务器的问题在于 UserAgent。您必须将默认值更改为服务器可接受的值。我检查了许多可能性,除了TNetHTTPClient 的默认值之外,它看起来几乎没有任何效果。有关详细信息,请参阅此Wikipedia article

    为此,您需要添加该行

    httpCli.UserAgent := 'Delphi/4.0 (compatible; Delphi; HttpClient)';
    

    我的代码版本包括 HTTP 状态代码检查如下:

    procedure TForm1.Button1Click(Sender: TObject);
    var
        ms       : TMemoryStream;
        httpCli  : TNetHTTPClient;
        resp     : IHTTPResponse;
        url      : String;
    begin
        httpCli := TNetHTTPClient.Create(nil);
        try
            httpCli.UserAgent := 'Delphi/4.0 (compatible; Delphi; HttpClient)';
            ms := TMemoryStream.Create();
            try
                url  := 'https://a.tile.openstreetmap.org/11/1050/674.png';
                resp := httpCli.Get(url, ms);
                if resp.StatusCode <> 200 then
                    Memo1.Lines.Add(Format('HTTP Error=%d %s',
                                           [resp.StatusCode, resp.StatusText]))
                else begin
                    ms.Position := 0;
                    Image1.Bitmap.LoadFromStream(ms);
                end;
            finally
                ms.Free;
            end;
        finally
            httpCli.Free;
        end;
    end;
    

    【讨论】:

    • “你必须改变它,这样你才能伪装成一个知名的浏览器,比如Mozilla”这是policy禁止的:“有效的HTTP用户- 代理识别应用程序。伪造另一个应用程序的用户代理将使您被阻止。"您应该选择自己的用户代理,特定于您的应用程序。
    • 谢谢大家。通过添加您自己的 UserAgent 字符串,以便 OSM 服务器可以识别您的应用程序(而不是使用另一个应用程序的确切 useragent 字符串),它将能够正确下载并且服务器可以验证您是否在策略中使用它。
    • @fpiette:缺少两个非可选的try..finally 块。
    • @AndreasRejbrand 当然。我刚刚为 OP 问题添加了所需的修复程序。这不是如何使用 Delphi 编程的完整示例。但是为了您的快乐,我会添加它。
    • 谢谢。一般来说,我担心新的 Delphi 开发人员可能会观察到有经验的开发人员在 SO 上忽略了这些块,然后得出错误的结论,即它们在实际代码中也不是必需的。
    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    相关资源
    最近更新 更多