def make_pdf_from_html(
        # Mandatory parameters:
        on_disk: bool,
        html: str,
        # Disk options:
        output_path: str = None,
        # Shared options:
        header_html: str = None,
        footer_html: str = None,
        wkhtmltopdf_filename: str = _WKHTMLTOPDF_FILENAME,
        wkhtmltopdf_options: Dict[str, Any] = None,
        file_encoding: str = "utf-8",
        debug_options: bool = False,
        debug_content: bool = False,
        debug_wkhtmltopdf_args: bool = True,
        fix_pdfkit_encoding_bug: bool = None,
        processor: str = _DEFAULT_PROCESSOR) -> Union[bytes, bool]:
    """
    Takes HTML and either returns a PDF in memory or makes one on disk.

    For preference, uses ``wkhtmltopdf`` (with ``pdfkit``):

    - faster than ``xhtml2pdf``
    - tables not buggy like ``Weasyprint``
    - however, doesn't support CSS Paged Media, so we have the
      ``header_html`` and ``footer_html`` options to allow you to pass
      appropriate HTML content to serve as the header/footer (rather than
      passing it within the main HTML).

    Args:
        on_disk: make file on disk (rather than returning it in memory)?

        html: main HTML

        output_path: if ``on_disk``, the output filename

        header_html: optional page header, as HTML

        footer_html: optional page footer, as HTML

        wkhtmltopdf_filename: filename of the ``wkhtmltopdf`` executable

        wkhtmltopdf_options: options for ``wkhtmltopdf``

        file_encoding: encoding to use when writing the header/footer to disk

        debug_options: log ``wkhtmltopdf`` config/options passed to ``pdfkit``?

        debug_content: log the main/header/footer HTML?

        debug_wkhtmltopdf_args: log the final command-line arguments to
            that will be used by ``pdfkit`` when it calls ``wkhtmltopdf``?

        fix_pdfkit_encoding_bug: attempt to work around bug in e.g.
            ``pdfkit==0.5.0`` by encoding ``wkhtmltopdf_filename`` to UTF-8
            before passing it to ``pdfkit``? If you pass ``None`` here, then
            a default value is used, from
            :func:`get_default_fix_pdfkit_encoding_bug`.

        processor: a PDF processor type from :class:`Processors`

    Returns:
        the PDF binary as a ``bytes`` object

    Raises:
        AssertionError: if bad ``processor``
        RuntimeError: if requested processor is unavailable

    """
    wkhtmltopdf_options = wkhtmltopdf_options or {}  # type: Dict[str, Any]
    assert_processor_available(processor)

    if debug_content:
        log.debug("html: {}", html)
        log.debug("header_html: {}", header_html)
        log.debug("footer_html: {}", footer_html)

    if fix_pdfkit_encoding_bug is None:
        fix_pdfkit_encoding_bug = get_default_fix_pdfkit_encoding_bug()

    if processor == Processors.XHTML2PDF:

        if on_disk:
            with open(output_path, mode='wb') as outfile:
                # noinspection PyUnresolvedReferences
                xhtml2pdf.document.pisaDocument(html, outfile)
            return True
        else:
            memfile = io.BytesIO()
            # noinspection PyUnresolvedReferences
            xhtml2pdf.document.pisaDocument(html, memfile)
            # ... returns a document, but we don't use it, so we don't store it
            # to stop pychecker complaining
            # http://xhtml2pdf.appspot.com/static/pisa-en.html
            memfile.seek(0)
            return memfile.read()
            # http://stackoverflow.com/questions/3310584

    elif processor == Processors.WEASYPRINT:

        if on_disk:
            return weasyprint.HTML(string=html).write_pdf(output_path)
        else:
            # http://ampad.de/blog/generating-pdfs-django/
            return weasyprint.HTML(string=html).write_pdf()

    elif processor == Processors.PDFKIT:

        # Config:
        if not wkhtmltopdf_filename:
            config = None
        else:
            if fix_pdfkit_encoding_bug:  # needs to be True for pdfkit==0.5.0
                log.debug("Attempting to fix bug in pdfkit (e.g. version 0.5.0)"
                          " by encoding wkhtmltopdf_filename to UTF-8")
                config = pdfkit.configuration(
                    wkhtmltopdf=wkhtmltopdf_filename.encode('utf-8'))
                # the bug is that pdfkit.pdfkit.PDFKit.__init__ will attempt to
                # decode the string in its configuration object;
                # https://github.com/JazzCore/python-pdfkit/issues/32
            else:
                config = pdfkit.configuration(wkhtmltopdf=wkhtmltopdf_filename)

        # Temporary files that a subprocess can read:
        #   http://stackoverflow.com/questions/15169101
        # wkhtmltopdf requires its HTML files to have ".html" extensions:
        #   http://stackoverflow.com/questions/5776125
        h_filename = None
        f_filename = None
        try:
            if header_html:
                h_fd, h_filename = tempfile.mkstemp(suffix='.html')
                os.write(h_fd, header_html.encode(file_encoding))
                os.close(h_fd)
                wkhtmltopdf_options["header-html"] = h_filename
            if footer_html:
                f_fd, f_filename = tempfile.mkstemp(suffix='.html')
                os.write(f_fd, footer_html.encode(file_encoding))
                os.close(f_fd)
                wkhtmltopdf_options["footer-html"] = f_filename
            if debug_options:
                log.debug("wkhtmltopdf config: {!r}", config)
                log.debug("wkhtmltopdf_options: {}",
                          pformat(wkhtmltopdf_options))
            kit = pdfkit.pdfkit.PDFKit(html, 'string', configuration=config,
                                       options=wkhtmltopdf_options)

            if on_disk:
                path = output_path
            else:
                path = None
                # With "path=None", the to_pdf() function directly returns
                # stdout from a subprocess.Popen().communicate() call (see
                # pdfkit.py). Since universal_newlines is not set, stdout will
                # be bytes in Python 3.

            if debug_wkhtmltopdf_args:
                log.debug("Probable current user: {!r}", getpass.getuser())
                log.debug("wkhtmltopdf arguments will be: {!r}",
                          kit.command(path=path))

            return kit.to_pdf(path=path)

        finally:
            if h_filename:
                os.remove(h_filename)
            if f_filename:
                os.remove(f_filename)

    else:
        raise AssertionError("Unknown PDF engine")
def make_pdf_from_html ( on_disk : bool , html : str , output_path : str = None , header_html : str = None , footer_html : str = None , wkhtmltopdf_filename : str = _WKHTMLTOPDF_FILENAME , wkhtmltopdf_options : Dict [ str , Any ] = None , file_encoding : str = "utf-8" , debug_options : bool = False , debug_content : bool = False , debug_wkhtmltopdf_args : bool = True , fix_pdfkit_encoding_bug : bool = None , processor : str = _DEFAULT_PROCESSOR ) -> Union [ bytes , bool ] : wkhtmltopdf_options = wkhtmltopdf_options or { } assert_processor_available ( processor ) if debug_content : log . debug ( "html: {}" , html ) log . debug ( "header_html: {}" , header_html ) log . debug ( "footer_html: {}" , footer_html ) if fix_pdfkit_encoding_bug is None : fix_pdfkit_encoding_bug = get_default_fix_pdfkit_encoding_bug ( ) if processor == Processors . XHTML2PDF : if on_disk : with open ( output_path , mode = 'wb' ) as outfile : xhtml2pdf . document . pisaDocument ( html , outfile ) return True else : memfile = io . BytesIO ( ) xhtml2pdf . document . pisaDocument ( html , memfile ) memfile . seek ( 0 ) return memfile . read ( ) elif processor == Processors . WEASYPRINT : if on_disk : return weasyprint . HTML ( string = html ) . write_pdf ( output_path ) else : return weasyprint . HTML ( string = html ) . write_pdf ( ) elif processor == Processors . PDFKIT : if not wkhtmltopdf_filename : config = None else : if fix_pdfkit_encoding_bug : log . debug ( "Attempting to fix bug in pdfkit (e.g. version 0.5.0)" " by encoding wkhtmltopdf_filename to UTF-8" ) config = pdfkit . configuration ( wkhtmltopdf = wkhtmltopdf_filename . encode ( 'utf-8' ) ) else : config = pdfkit . configuration ( wkhtmltopdf = wkhtmltopdf_filename ) h_filename = None f_filename = None try : if header_html : h_fd , h_filename = tempfile . mkstemp ( suffix = '.html' ) os . write ( h_fd , header_html . encode ( file_encoding ) ) os . close ( h_fd ) wkhtmltopdf_options [ "header-html" ] = h_filename if footer_html : f_fd , f_filename = tempfile . mkstemp ( suffix = '.html' ) os . write ( f_fd , footer_html . encode ( file_encoding ) ) os . close ( f_fd ) wkhtmltopdf_options [ "footer-html" ] = f_filename if debug_options : log . debug ( "wkhtmltopdf config: {!r}" , config ) log . debug ( "wkhtmltopdf_options: {}" , pformat ( wkhtmltopdf_options ) ) kit = pdfkit . pdfkit . PDFKit ( html , 'string' , configuration = config , options = wkhtmltopdf_options ) if on_disk : path = output_path else : path = None if debug_wkhtmltopdf_args : log . debug ( "Probable current user: {!r}" , getpass . getuser ( ) ) log . debug ( "wkhtmltopdf arguments will be: {!r}" , kit . command ( path = path ) ) return kit . to_pdf ( path = path ) finally : if h_filename : os . remove ( h_filename ) if f_filename : os . remove ( f_filename ) else : raise AssertionError ( "Unknown PDF engine" )
Takes HTML and either returns a PDF in memory or makes one on disk.

    For preference, uses ``wkhtmltopdf`` (with ``pdfkit``):

    - faster than ``xhtml2pdf``
    - tables not buggy like ``Weasyprint``
    - however, doesn't support CSS Paged Media, so we have the
      ``header_html`` and ``footer_html`` options to allow you to pass
      appropriate HTML content to serve as the header/footer (rather than
      passing it within the main HTML).

    Args:
        on_disk: make file on disk (rather than returning it in memory)?

        html: main HTML

        output_path: if ``on_disk``, the output filename

        header_html: optional page header, as HTML

        footer_html: optional page footer, as HTML

        wkhtmltopdf_filename: filename of the ``wkhtmltopdf`` executable

        wkhtmltopdf_options: options for ``wkhtmltopdf``

        file_encoding: encoding to use when writing the header/footer to disk

        debug_options: log ``wkhtmltopdf`` config/options passed to ``pdfkit``?

        debug_content: log the main/header/footer HTML?

        debug_wkhtmltopdf_args: log the final command-line arguments to
            that will be used by ``pdfkit`` when it calls ``wkhtmltopdf``?

        fix_pdfkit_encoding_bug: attempt to work around bug in e.g.
            ``pdfkit==0.5.0`` by encoding ``wkhtmltopdf_filename`` to UTF-8
            before passing it to ``pdfkit``? If you pass ``None`` here, then
            a default value is used, from
            :func:`get_default_fix_pdfkit_encoding_bug`.

        processor: a PDF processor type from :class:`Processors`

    Returns:
        the PDF binary as a ``bytes`` object

    Raises:
        AssertionError: if bad ``processor``
        RuntimeError: if requested processor is unavailable