delphichromium-embeddedtchromium

TChromium : how to save a specific image to file?


I'm using TChromium and I need to navigate to a specific page and save a specific image of this page to a file.

I know how to navigate and extract the HTML source to get the image's address, but I don't know how to save the image to my local filesystem.

How can I do it using some TChromium method ?

I don't want to use another component (such TIdHTTP) to do it because the site requires login and the image relies on the active session.

Thanks in advance !


Solution

  • From CEF forums:

    "CEF does not currently support the extraction of cached resources. You can identify the request that originally returned the content by overriding CefRequestHandler::OnBeforeResourceLoad() and then execute the request yourself using CefWebURLRequest the retrieve and save the contents."

    Another approach is to add a context menu as asked here - TChromium how to add "Save Picture" item in Context Menu? and where TLama has made a code snippet:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtDlgs, IdHTTP, cefvcl, ceflib;
    
    const
      MENU_ID_SAVE_IMAGE_AS = Ord(MENU_ID_USER_FIRST) + 1;
    
    type
      TDownloader = class(TThread)
      private
        FURL: string;
        FFileName: string;
      protected
        procedure Execute; override;
      public
        constructor Create(const URL, FileName: string); reintroduce;
      end;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Chromium1: TChromium;
        SavePictureDialog1: TSavePictureDialog;
        procedure FormCreate(Sender: TObject);
        procedure Chromium1BeforeContextMenu(Sender: TObject; const browser: ICefBrowser;
          const frame: ICefFrame; const params: ICefContextMenuParams; const model: ICefMenuModel);
        procedure Chromium1ContextMenuCommand(Sender: TObject; const browser: ICefBrowser;
          const frame: ICefFrame; const params: ICefContextMenuParams; commandId: Integer;
          eventFlags: TCefEventFlags; out Result: Boolean);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TDownloader }
    
    constructor TDownloader.Create(const URL, FileName: string);
    begin
      inherited Create(False);
      FreeOnTerminate := True;
      FURL := URL;
      FFileName := FileName;
    end;
    
    procedure TDownloader.Execute;
    var
      HTTPClient: TIdHTTP;
      FileStream: TFileStream;
    begin
      try
        HTTPClient := TIdHTTP.Create;
        try
          FileStream := TFileStream.Create(FFileName, fmCreate);
          try
            HTTPClient.Get(FURL, FileStream);
          finally
            FileStream.Free;
          end;
        finally
          HTTPClient.Free;
        end;
      except
        // error handling ignored for this example
      end;
    end;
    
    { TForm1 }
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Chromium1.Load('http://www.google.com/');
    end;
    
    procedure TForm1.Chromium1BeforeContextMenu(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; const params: ICefContextMenuParams; const model: ICefMenuModel);
    begin
      if (CM_TYPEFLAG_MEDIA in params.TypeFlags) and (params.MediaType = CM_MEDIATYPE_IMAGE) then
        model.AddItem(MENU_ID_SAVE_IMAGE_AS, 'Save image as...');
    end;
    
    procedure TForm1.Chromium1ContextMenuCommand(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; const params: ICefContextMenuParams; commandId: Integer;
      eventFlags: TCefEventFlags; out Result: Boolean);
    var
      SaveDialog: TSavePictureDialog;
    begin
      if (commandId = MENU_ID_SAVE_IMAGE_AS) then
      begin
        SaveDialog := TSavePictureDialog.Create(nil);
        try
          // SaveDialog.FileName := <here you can extract file name from params.SourceUrl>;
          // SaveDialog.DefaultExt := <here you can extract file ext from params.SourceUrl>;
          if SaveDialog.Execute then
            TDownloader.Create(params.SourceUrl, SaveDialog.FileName);
        finally
          SaveDialog.Free;
        end;
      end;
    end;
    
    end.
    

    Another approach is to identify all the images from the page (take a look at How can I use Javascript to get a list of all picture URLs available on a site?) and download the image link by using CefBrowserHost.StartDownload.