Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.
If you find these projects useful please consider becoming a sponsor with Patreon, GitHub or Liberapay.

Save images to disk with WebView4Delphi

Post Reply
jtremlett
Posts: 3
Joined: Tue Sep 17, 2024 6:29 pm

Save images to disk with WebView4Delphi

Post by jtremlett »

I have just started using WebView4Delphi. Great work! I have managed to do everything I want to except one thing. I want to save the images on a webpage to disk programmatically. I can do it by hand in the browser by right-clicking on the image and selecting Save Image As but I can't work out how to do this with code and I've tried everything I can find from web searches. It is particularly annoying because I have done it before but I can't remember how, whether I wrote some code or used a tool or what. Either way, I can't find what I had before. I should mention that the webpages I want to take the images from is one I first login to. Has anyone done this and, if so, how?
User avatar
salvadordf
Posts: 4620
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Save images to disk with WebView4Delphi

Post by salvadordf »

Hi,

Most of the code you need is in the MiniBrowser demo.

If you only need the URLs then set a filter with a TWVBrowser.AddWebResourceRequestedFilterWithRequestSourceKinds call like this :
https://github.com/salvadordf/WebView4Delphi/blob/a7e05d986929abf05fda0a2001c82600723b006d/demos/Delphi_VCL/MiniBrowser/uMiniBrowser.pas#L512

Then use the TWVBrowser.OnWebResourceRequested event :
https://github.com/salvadordf/WebView4Delphi/blob/a7e05d986929abf05fda0a2001c82600723b006d/demos/Delphi_VCL/MiniBrowser/uMiniBrowser.pas#L990

If you want the resource contents then use the TWVBrowser.OnWebResourceResponseReceived event and call TCoreWebView2WebResourceResponseView.GetContent which will trigger the TWVBrowserBase.OnWebResourceResponseViewGetContentCompleted event with the contents of this resource.
https://github.com/salvadordf/WebView4Delphi/blob/a7e05d986929abf05fda0a2001c82600723b006d/demos/Delphi_VCL/MiniBrowser/uMiniBrowser.pas#L1008

The TWVBrowser.OnWebResourceRequested event has some issues and limitations :
https://github.com/MicrosoftEdge/WebView2Feedback/issues?q=is%3Aissue+is%3Aopen+WebResourceRequested

For more details read the code comments for all these events and functions.
jtremlett
Posts: 3
Joined: Tue Sep 17, 2024 6:29 pm

Re: Save images to disk with WebView4Delphi

Post by jtremlett »

That's very helpful. Thank you. I'll have a go.
jtremlett
Posts: 3
Joined: Tue Sep 17, 2024 6:29 pm

Re: Save images to disk with WebView4Delphi

Post by jtremlett »

An update to say that works perfectly. Very many thanks.

For anyone else looking to do the same thing, here are the relevant bits of the code lifted from the MiniBrowser demo with minimal additions (embarrassingly little, in fact - just a few lines in WebResourceResponseViewGetContentCompleted). What I am doing is navigating to a series of image URLs and saving each image to a local folder. I did find, for what I was doing, that if the image URL didn't end with '/' then it didn't work even though the image displayed in the browser correctly.

procedure TfrmMain.WVBrowser1AfterCreated(Sender: TObject);
begin
WVWindowParent1.UpdateSize;
WVWindowParent1.SetFocus;
WVBrowser1.AddWebResourceRequestedFilterWithRequestSourceKinds('*', COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE, COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL);
end;

procedure TfrmMain.WVBrowser1NavigationStarting(Sender: TObject;
const aWebView: ICoreWebView2;
const aArgs: ICoreWebView2NavigationStartingEventArgs);
begin
FGetHeaders := True;
end;

procedure TfrmMain.WVBrowser1WebResourceRequested(Sender: TObject;
const aWebView: ICoreWebView2;
const aArgs: ICoreWebView2WebResourceRequestedEventArgs);
var
TempArgs : TCoreWebView2WebResourceRequestedEventArgs;
TempResponse : ICoreWebView2WebResourceResponse;
begin
try
TempArgs := TCoreWebView2WebResourceRequestedEventArgs.Create(aArgs);
TempArgs.Response := TempResponse;
finally
FreeAndNil(TempArgs);
TempResponse := nil;
end;
end;

procedure TfrmMain.WVBrowser1WebResourceResponseReceived(Sender: TObject;
const aWebView: ICoreWebView2;
const aArgs: ICoreWebView2WebResourceResponseReceivedEventArgs);
var
TempArgs : TCoreWebView2WebResourceResponseReceivedEventArgs;
TempResponse : TCoreWebView2WebResourceResponseView;
TempName : wvstring;
TempValue : wvstring;
TempHandler : ICoreWebView2WebResourceResponseViewGetContentCompletedHandler;
begin
if FGetHeaders then
try
FGetHeaders := False;
TempArgs := TCoreWebView2WebResourceResponseReceivedEventArgs.Create(aArgs);
TempResponse := TCoreWebView2WebResourceResponseView.Create(TempArgs.Response);
TempHandler := TCoreWebView2WebResourceResponseViewGetContentCompletedHandler.Create(WVBrowser1);

TempResponse.GetContent(TempHandler);
finally
FreeAndNil(TempResponse);
FreeAndNil(TempArgs);
TempHandler := nil;
end;
end;

procedure TfrmMain.WVBrowser1WebResourceResponseViewGetContentCompleted(

Sender: TObject; aErrorCode: HRESULT; const aResult: IStream;
aResourceID: Integer);
var
TempOLEStream : TOLEStream;
TempStream : TFileStream;
SubstrJpg,
SubstrJpeg,
SubstrPng: String;
begin
// I've saved the URL of the image I've navigated to
// and I only want to process specific file types.
// Note that the substrings apply to the format of
// the URLs I am interrogating (which have a suffix
// after the file type
SubstrJpg := 'jpg.';
SubstrJpeg := 'jpeg.';
SubstrPng := 'png.';
if (Pos(SubstrJpg, FCurrentURL) > 0)
or (Pos(SubstrJpeg, FCurrentURL) > 0)
or (Pos(SubstrPng, FCurrentURL) > 0) then
begin
TempOLEStream := nil;
try
if succeeded(aErrorCode) and assigned(aResult) then
begin
TempOLEStream := TOLEStream.Create(aResult);
TempOLEStream.Position := 0;

// don't bother with anything too small
if (TempOLEStream.Size > 5) then
begin
try
// … I set Filename based on the URL here

// copy the TOLEStream to a TFileStream and write it to the specified folder
TempStream := TFileStream.Create(DownloadFolder + Filename, fmCreate);
TempStream.CopyFrom(TempOLEStream, TempOLEStream.Size);
TempStream.Write(TempOLEStream, TempOLEStream.Size);
finally
FreeAndNil(TempStream);
end;
end;
end;
finally
if assigned(TempOLEStream) then
FreeAndNil(TempOLEStream);
end;
end;
end;
Post Reply