cefpython icon indicating copy to clipboard operation
cefpython copied to clipboard

PDF printing support

Open cztomczak opened this issue 7 years ago • 12 comments

Printing to PDF can be performed in two ways:

  1. When print dialog appears you should see "Print to PDF" option (printer). This is already available.

  2. There is a new method CefBrowserHost::PrintToPDF(), but this wasn't yet exposed in CEF Python.

See these commits by cuijinbao for reference: https://github.com/cztomczak/cefpython/commit/aec34742a71662dae21cfa3b2102fba28b1952f4 and https://github.com/cztomczak/cefpython/commit/7dc6d7d9d8b2a9c2662a196c5ccb3b1a135867f7 .

Below is the code from CEF header files that would need to be exposed:

PrintToPDF function

///
  // Print the current browser contents to the PDF file specified by |path| and
  // execute |callback| on completion. The caller is responsible for deleting
  // |path| when done. For PDF printing to work on Linux you must implement the
  // CefPrintHandler::GetPdfPaperSize method.
  ///
  /*--cef(optional_param=callback)--*/
  virtual void PrintToPDF(const CefString& path,
                          const CefPdfPrintSettings& settings,
                          CefRefPtr<CefPdfPrintCallback> callback) =0;

Print settings

///
// Structure representing PDF print settings.
///
typedef struct _cef_pdf_print_settings_t {
  ///
  // Page title to display in the header. Only used if |header_footer_enabled|
  // is set to true (1).
  ///
  cef_string_t header_footer_title;

  ///
  // URL to display in the footer. Only used if |header_footer_enabled| is set
  // to true (1).
  ///
  cef_string_t header_footer_url;

  ///
  // Output page size in microns. If either of these values is less than or
  // equal to zero then the default paper size (A4) will be used.
  ///
  int page_width;
  int page_height;

  ///
  // The percentage to scale the PDF by before printing (e.g. 50 is 50%).
  // If this value is less than or equal to zero the default value of 100
  // will be used.
  ///
  int scale_factor;

  ///
  // Margins in millimeters. Only used if |margin_type| is set to
  // PDF_PRINT_MARGIN_CUSTOM.
  ///
  double margin_top;
  double margin_right;
  double margin_bottom;
  double margin_left;

  ///
  // Margin type.
  ///
  cef_pdf_print_margin_type_t margin_type;

  ///
  // Set to true (1) to print headers and footers or false (0) to not print
  // headers and footers.
  ///
  int header_footer_enabled;

  ///
  // Set to true (1) to print the selection only or false (0) to print all.
  ///
  int selection_only;

  ///
  // Set to true (1) for landscape mode or false (0) for portrait mode.
  ///
  int landscape;

  ///
  // Set to true (1) to print background graphics or false (0) to not print
  // background graphics.
  ///
  int backgrounds_enabled;

} cef_pdf_print_settings_t;

Print callback

///
// Callback interface for CefBrowserHost::PrintToPDF. The methods of this class
// will be called on the browser process UI thread.
///
/*--cef(source=client)--*/
class CefPdfPrintCallback : public virtual CefBaseRefCounted {
 public:
  ///
  // Method that will be executed when the PDF printing has completed. |path|
  // is the output path. |ok| will be true if the printing completed
  // successfully or false otherwise.
  ///
  /*--cef()--*/
  virtual void OnPdfPrintFinished(const CefString& path, bool ok) =0;
};

cztomczak avatar May 15 '17 09:05 cztomczak

I'm interested in this. I'm using both chromium (custom hacked with a couple of weird features) and cefpython but still using phantomjs for rendering docs as PDF.

How hard is it to implement something like this? I've had a look through cefpython previously and it seems that much of the work is in mapping all the datatypes and function calls between cefpython and cef (though I'm not very familiar with pyx) - is that correct?

aidos avatar Jun 02 '17 09:06 aidos

@aidos It's a matter of exposing the API above, so it's pretty easy:

  1. PrintToPDF - add wrapper method in browser.pyx and signatures in cef_browser.pxd
  2. Print settings - add wrapper in settings.pyx and signatures in cef_types.pxd. Preferably settings should be exposed as classes to provide auto completion/checking in IDE's. See Issue #205.
  3. Print callback - this can be a bit harder as it requires writing some C++ code as well. See for example string_visitor.cpp, string_visitor.h and string_visitor.pyx.

cztomczak avatar Jun 02 '17 10:06 cztomczak

Also when adding new functions you should update API docs - the api/ directory. PR is welcome.

cztomczak avatar Jun 02 '17 10:06 cztomczak

For editing cefpython code I recommend PyCharm - see config in Issue #232.

cztomczak avatar Jun 02 '17 10:06 cztomczak

Ok great! I'll take a look when I get a moment. First I'll get the build running locally and then I can take a stab at adding the functionality.

Ultimately I want to run my custom chromium build via cefpython so this was already on my list (I know there are a couple of patches to cef required to make them play nice).

aidos avatar Jun 02 '17 11:06 aidos

For adding custom Chromium/CEF patches to CEF Python see patches/patch.py and Build instructions doc > How to patch. It's best to send them upstream.

cztomczak avatar Jun 02 '17 11:06 cztomczak

https://github.com/qq18436558/cefpython Update to cef 3.3325.1756.g6d8faa4 Add CefFileDialogCallback Add CefFastPdfPrintCallback

Test OnFileDialog and OnPdfPrintFinished on Mac and Win10 in wxpython.py

qq18436558 avatar Apr 13 '18 06:04 qq18436558

This commit from @qq18436558 be added?

williamgeraldo avatar Jul 02 '18 13:07 williamgeraldo

It needs to go through a PR review process. PDF printing and file dialog callback should be sent as separate PRs, unless they depend on each other.

cztomczak avatar Jul 02 '18 14:07 cztomczak

@cztomczak I'm also very interested in this feature. I'd posted a question on SO a while back about this very function and just came across your work here.

Do you have any projection of a timeline for this? I don't see a PR from @qq18436558 with the changes they made - does one need to be opened?

bsplosion avatar Feb 18 '21 17:02 bsplosion

See https://github.com/cztomczak/cefpython/pull/422

cztomczak avatar Feb 18 '21 17:02 cztomczak

How to use it in Python?

54huige avatar Jun 28 '21 16:06 54huige