Skip to content

PDF printing support #362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
cztomczak opened this issue May 15, 2017 · 12 comments
Open

PDF printing support #362

cztomczak opened this issue May 15, 2017 · 12 comments

Comments

@cztomczak
Copy link
Owner

cztomczak commented May 15, 2017

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: aec3474 and 7dc6d7d .

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;
};
@aidos
Copy link

aidos commented Jun 2, 2017

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?

@cztomczak
Copy link
Owner Author

@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 ApplicationSettings and BrowserSettings as classes #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
Copy link
Owner Author

cztomczak commented Jun 2, 2017

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

@cztomczak
Copy link
Owner Author

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

@aidos
Copy link

aidos commented Jun 2, 2017

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).

@cztomczak
Copy link
Owner Author

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.

@qq18436558
Copy link

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

@williamgeraldo
Copy link

This commit from @qq18436558 be added?

@cztomczak
Copy link
Owner Author

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.

@bsplosion
Copy link

@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?

@cztomczak
Copy link
Owner Author

See #422

@54huige
Copy link

54huige commented Jun 28, 2021

How to use it in Python?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants