Recent

Author Topic: Loading an image from an URL  (Read 769 times)

Dzandaa

  • Sr. Member
  • ****
  • Posts: 459
  • From C# to Lazarus
Loading an image from an URL
« on: June 18, 2025, 11:46:24 am »
Hi everybody,


for my CD database program, I'm trying to download this image from the web and save it either as a file, a TImage, or a BGRABitmap. :

But I don't know how...

https://i.discogs.com/7njgT1NmTkfwyDxTxQSHHwzqaR9x_oDuzPOAY6Lq2PQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwODk5/MzAtMTY1NjI0MTE5/NC0yNDk4LmpwZWc.jpeg

Code: Pascal  [Select][+][-]
  1.  Pict := TBGRABitmap.Create;
  2.  HTTP := THTTPSend.Create;
  3.  try
  4.   HTTP.Headers.Add('User-Agent: CDDatabase/1.0');
  5.   if HTTP.HTTPMethod('GET', URL) then
  6.   begin
  7.    Pict.LoadFromStream(HTTP.Document); // Error: The image format is unknown
  8.    end
  9.    else
  10.     TBStatus.Append('HTTP request failed.');
  11.     if(Pict <> nil) then FreeAndNil(Pict);  
  12.    finally
  13.     HTTP.Free;
  14.  end;
  15.  exit(Pict);
  16.  

Thank you.

B->
Regards,
Dzandaa

Thaddy

  • Hero Member
  • *****
  • Posts: 17396
  • Ceterum censeo Trump esse delendam
Re: Loading an image from an URL
« Reply #1 on: June 18, 2025, 12:39:01 pm »
Try this:
Code: Pascal  [Select][+][-]
  1. Pict := TBGRABitmap.Create;
  2. HTTP := THTTPSend.Create;
  3. try
  4.   HTTP.Headers.Add('User-Agent: CDDatabase/1.0');
  5.   if HTTP.HTTPMethod('GET', URL) then
  6.   begin
  7.     HTTP.Document.Position := 0;
  8.     try
  9.       Pict.LoadFromStream(HTTP.Document);
  10.     except
  11.       on E: Exception do
  12.       begin
  13.         FreeAndNil(Pict);
  14.         TBStatus.Append('Image format not supported or corrupted: ' + E.Message);
  15.       end;
  16.     end;
  17.   end
  18.   else
  19.   begin
  20.     FreeAndNil(Pict);
  21.     TBStatus.Append('HTTP request failed.');
  22.   end;
  23. finally
  24.   HTTP.Free;
  25. end;
  26. exit(Pict);
Untested, will test it later.
« Last Edit: June 18, 2025, 12:40:42 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Dzandaa

  • Sr. Member
  • ****
  • Posts: 459
  • From C# to Lazarus
Re: Loading an image from an URL
« Reply #2 on: June 18, 2025, 12:54:26 pm »
Hi,

@Thaddy:

Thank you, but I got the same error in the same call

Code: Pascal  [Select][+][-]
  1.  Pict.LoadFromStream(HTTP.Document); // Error: The image format is unknown

B->
Regards,
Dzandaa

etrusco

  • New Member
  • *
  • Posts: 17
Re: Loading an image from an URL
« Reply #3 on: June 18, 2025, 01:05:50 pm »
Did you check the image is fetched correctly (e.g tried saving the stream to file)?

Dzandaa

  • Sr. Member
  • ****
  • Posts: 459
  • From C# to Lazarus
Re: Loading an image from an URL
« Reply #4 on: June 18, 2025, 01:36:43 pm »
Hi,
@etrusco:

Yes i tried this:

Code: Pascal  [Select][+][-]
  1. HTTP.Document.SaveToFile('test');

And in the file, I have this:

Code: Text  [Select][+][-]
  1. <html>
  2.  <head><title>301 Moved Permanently</title></head>
  3.  <body>
  4.   <center><h1>301 Moved Permanently</h1></center>
  5.   <hr><center>cloudflare</center>
  6.  </body>
  7. </html>
  8.  

I can open the link with Firefox without problem, I can save it and it's O.K.
I'm not sure that is the good protocol to save an image from a link or I miss something.

B->


Regards,
Dzandaa

Thaddy

  • Hero Member
  • *****
  • Posts: 17396
  • Ceterum censeo Trump esse delendam
Re: Loading an image from an URL
« Reply #5 on: June 18, 2025, 01:45:03 pm »
Switch over to TFPHttpClient, which supports redirects. (afaik, ThttpSend too, but more cumbersome, hard to find)
The example I will add later will use that instead of THttpSend.
In a couple of hours I have the use of a real computer instead of a phone.
« Last Edit: June 18, 2025, 01:50:10 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

440bx

  • Hero Member
  • *****
  • Posts: 5575
Re: Loading an image from an URL
« Reply #6 on: June 18, 2025, 01:51:44 pm »
I have no idea how to use the HTTP class but, with "normal" (non-OOP) http (say WinHTTP on Windows), you need to tell the server which types your app can handle.

Normally, you see a call to WinHttpOpenRequest  that tells the server which types your app accepts.  If you don't tell the server you can accept pictures, the server will not send a picture.  That might be the problem in your code because  I don't see anywhere anything that informs the server what your code can accept. OTH, I have no idea what the equivalent of WinHttpOpenRequest is in the HTTP class but, that might the problem in your code.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v4.0rc3) on Windows 7 SP1 64bit.

Nimbus

  • Jr. Member
  • **
  • Posts: 61
Re: Loading an image from an URL
« Reply #7 on: June 18, 2025, 01:52:39 pm »
Quick guess (which can be incorrect) is that you might have a http:// scheme on the URL, to which Cloudflare responds with a 301 https redirection, that THTTPSend can't handle on its own. If this is the case, then changing http:// to https:// should help.

Dzandaa

  • Sr. Member
  • ****
  • Posts: 459
  • From C# to Lazarus
Re: Loading an image from an URL
« Reply #8 on: June 18, 2025, 03:15:15 pm »
Hi,

I also think there is a redirection problem.

Any help is welcome.

B->

Regards,
Dzandaa

Fred vS

  • Hero Member
  • *****
  • Posts: 3628
    • StrumPract is the musicians best friend
Re: Loading an image from an URL
« Reply #9 on: June 18, 2025, 03:34:40 pm »
Hi,

I also think there is a redirection problem.

Any help is welcome.

B->

Hello neighbor!.

Maybe you can take inspiration from Simple Web Player.

Take a look at: procedure twebstreamerfo.getpicture(aurl: string); line 1772 : this code.
« Last Edit: June 19, 2025, 05:12:15 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 17396
  • Ceterum censeo Trump esse delendam
Re: Loading an image from an URL
« Reply #10 on: June 18, 2025, 04:02:50 pm »
Good tip Fred!

BTW: the promised minimal example:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}{$ifdef windows}{$apptype console}{$endif}
  2. uses
  3.   classes,
  4.   fphttpclient,
  5.   openSSL,
  6.   opensslsockets;
  7. var
  8.   Client: TFPHttpClient;
  9. begin
  10.   Client := TFPHttpClient.Create(nil);
  11.   try
  12.     Client.RequestHeaders.Add('User-Agent: CDDatabase/1.0');
  13.     Client.AllowRedirect := true;
  14.     writeln(Client.Get('https://i.discogs.com/'));// your query goes here too
  15.   finally
  16.     Client.Free;
  17.   end;
  18. end.

You did not give us the right query, so I left that out, but at least: there's your connection with redirects.
I used OpenSSL 3.5 and FPC trunk at 64 bit.

My previous stream code should easily integrate.
I have no use for it, but this establishes a proven connection.
« Last Edit: June 19, 2025, 08:20:17 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 17396
  • Ceterum censeo Trump esse delendam
Re: Loading an image from an URL
« Reply #11 on: June 18, 2025, 04:14:46 pm »
Note this particular website it very sensitive to what it believes scraping attempts and may return a 403 if you test too many times.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Dzandaa

  • Sr. Member
  • ****
  • Posts: 459
  • From C# to Lazarus
Re: Loading an image from an URL
« Reply #12 on: June 18, 2025, 04:39:23 pm »
Hi,
@neighbor :)

Thank you Fred, it works finally !!!

Here is my code:

Code: Pascal  [Select][+][-]
  1. function GetURLPicture(URL: string): TBGRABitmap;
  2. var
  3.  amem: Tmemorystream;
  4.  Pict: TBGRABitmap;
  5. begin
  6.  TBStatus.Append('URL ' + URL);
  7.  
  8.  InitSSLInterface;
  9.  amem := Tmemorystream.Create;
  10.  
  11.  try
  12.   MyHTTPClient.Get(URL, amem);
  13.   amem.Position := 0;
  14.   Pict := TBGRAbitmap.Create(amem);
  15.   sleep(100);
  16.   except
  17.    on E: Exception do
  18.    begin
  19.     TBStatus.Append('image failed: ' + E.Message);
  20.     exit(nil);
  21.    end;
  22.  end;
  23.  
  24.  amem.Free;
  25.  Exit(Pict);
  26. end;
  27.  

MyHTTPClient is a TFPHTTPClient component

Also Thank you Thaddy, we arrived at the same result

Now doing the same with Musicbrainz :) :)

Thank you all.

B->
Regards,
Dzandaa

Thaddy

  • Hero Member
  • *****
  • Posts: 17396
  • Ceterum censeo Trump esse delendam
Re: Loading an image from an URL
« Reply #13 on: June 18, 2025, 04:42:00 pm »
Good news! 8)
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1536
    • Lebeau Software
Re: Loading an image from an URL
« Reply #14 on: June 18, 2025, 06:21:42 pm »
with "normal" (non-OOP) http (say WinHTTP on Windows), you need to tell the server which types your app can handle.

Normally, you see a call to WinHttpOpenRequest  that tells the server which types your app accepts.  If you don't tell the server you can accept pictures, the server will not send a picture.

That is not how HTTP works.  If a client does not specify what it accepts, the server must assume the client can accept everything.  This is explicitly stated in the HTTP specs:

RFC 2616:
Quote
The Accept request-header field can be used to specify certain media types which are acceptable for the response... If no Accept header field is present, then it is assumed that the client accepts all media types.

RFC 7231
Quote
The "Accept" header field can be used by user agents to specify response media types that are acceptable... A request without any Accept header field implies that the user agent will accept any media type in response.

It is advisable to tell the server what you want to accept, but it is not required to do so.  But, if you don't specify it, then you need to be prepared to handle other kinds of data that you don't want.
« Last Edit: June 18, 2025, 06:28:26 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018