Gerard
Gerard

Reputation: 145

Load a png image from the web (delphi fmx)

I would like to load png images from the web, but with the code below not all images do get correctly into the stream (while posting the url in a webbrowser, e.g. edge, does give the image correctly). For example, the first url in the code gives a loading bitmap failed error (in the stream FSize is only 14?), while the second url does not give a problem. Does anyone know how to download the first url correctly?

For this piece of code to work, a TButton and a TImage was put on a form.
System.Net.HttpClientComponent was added in the uses. I am using Delphi 10.3.3. fmx.

Thanks, Gerard

    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;

Upvotes: 4

Views: 2029

Answers (3)

Leo
Leo

Reputation: 109

This is a variation of fpiete's answer. I found this way simpler, with no need to create the TMemoryStream object, for example.

You can use the RESTRequest4D library for the request. The usage is very simple and I find it more intuitive than the regular HTTP client.

procedure TQRCodeForm.LoadImageFromURL;
var
  LResponse: IResponse;
begin
  LResponse := TRequest
              .New
              .BaseURL(ImageURL)
              .Get;
  if LResponse.StatusCode = 200 then
  begin
    MyTImage.Bitmap.LoadFromStream(LResponse.ContentStream);
  end;
end;

Upvotes: 1

fpiette
fpiette

Reputation: 12292

The problem with the OpenStreetMap tile server is the UserAgent. You must change the default value to something acceptable by the server. I checked a number of possibilities and it looks like almost anything but default value of TNetHTTPClient works. See this Wikipedia article for details.

To do that, you need to add the line

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

My version of your code which includes HTTP status code checking is the following:

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;

Upvotes: 7

AmigoJack
AmigoJack

Reputation: 6099

When operating on HTTP you have to check if the HTTP server can satisfy your request (status code 200, as per RFC7231, § 6.3.1) or any error occured. In your case requesting that URI and making sure to see what comes from the server can be done with i.e. wget:

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

This will print the server's response headers and in any case create a file that will hold the payload. The response headers are (excerpt):

HTTP/1.1 403 Forbidden
Content-Length: 14

Which means: you are not allowed to query that resource (HTTP status code 403). The payload is saved in a file sizing 14 bytes, containing this text in 14 ASCII characters:

Access denied.

Trivia: the smallest valid PNG file sizes at least 67 bytes (read "Smallest possible transparent PNG" by Gareth Rees.

Upvotes: 1

Related Questions