Page 1 of 1

Save images to disk with WebView4Delphi

Posted: Tue Sep 17, 2024 6:41 pm
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?

Re: Save images to disk with WebView4Delphi

Posted: Wed Sep 18, 2024 8:48 am
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.

Re: Save images to disk with WebView4Delphi

Posted: Thu Sep 19, 2024 11:34 am
by jtremlett
That's very helpful. Thank you. I'll have a go.

Re: Save images to disk with WebView4Delphi

Posted: Tue Sep 24, 2024 2:58 pm
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;