Weasyprint: Can I print the output without creating a pdf in Gtk3?

Created on 17 Mar 2018  Â·  3Comments  Â·  Source: Kozea/WeasyPrint

Is there any way to print the rendered html without creating a file? Something like using pycairo to integrate with GTKs printing dialog (I couldn't find out how should I do this)?

Most helpful comment

Can you help me to make the two Cairo backend compatible (if it's the problem)?

Yes, that's the problem. And seriously, converting a cairocffi context into a cairo-with-introspection is crazy, nobody would ever want to do this… Oh, wait! Here's what we want!

Nice!

import cairocffi

[…]

    def draw_page(self, operation, print_ctx, page_num, document):
        page = document.pages[page_num]
        cairo_context = print_ctx.get_cairo_context()
        cairocffi_context = cairocffi.Context._from_pointer(
            cairocffi.ffi.cast(
                'cairo_t **', id(cairo_context) + object.__basicsize__)[0],
            incref=True)
        page.paint(cairocffi_context, left_x=0, top_y=0, scale=0.75)

It works!

You'll have to play with left_x, top_y and scale in order to make the document size fit into the printable area (that depends on the printer settings). The current scale should work when the document has the same size as the paper (0.75 = 72 PDF point (cairo units) per inch / 96 CSS pixel per inch).

But that's your part of the work! You'll probably need to read Gtk PrintSettings documentation.

All 3 comments

Good question!

I've tried, but it seems to be hard: WeasyPrint uses CairoCFFI objects while GTK uses Cairo's introspection objects. Here's what I wrote, I think that it would work if the two Cairo backends were compatible:

import sys

from gi.repository import Gtk, GLib
from weasyprint import HTML


class Printo:
    def __init__(self, url):
        self.operation = Gtk.PrintOperation()

        document = HTML(url).render()

        self.operation.connect('begin-print', self.begin_print, document)
        self.operation.connect('draw-page', self.draw_page, document)

        self.operation.set_use_full_page(False)
        self.operation.set_unit(Gtk.Unit.POINTS)
        self.operation.set_embed_page_setup(True)

        settings = Gtk.PrintSettings()

        directory = GLib.get_user_special_dir(
            GLib.UserDirectory.DIRECTORY_DOCUMENTS) or GLib.get_home_dir()
        ext = settings.get(Gtk.PRINT_SETTINGS_OUTPUT_FILE_FORMAT) or 'pdf'
        uri = 'file://%s/weasyprint.%s' % (directory, ext)
        settings.set(Gtk.PRINT_SETTINGS_OUTPUT_URI, uri)
        self.operation.set_print_settings(settings)

    def run(self):
        self.operation.run(Gtk.PrintOperationAction.PRINT_DIALOG)
        Gtk.main_quit()

    def begin_print(self, operation, print_ctx, document):
        operation.set_n_pages(len(document.pages))

    def draw_page(self, operation, print_ctx, page_num, document):
        page = document.pages[page_num]
        context = print_ctx.get_cairo_context()
        page.paint(context)


def main():
    url = sys.argv[1] if len(sys.argv) > 1 else 'https://weasyprint.org'
    Printo(url).run()


if __name__ == '__main__':
    main()

(Highly inspired by https://gitlab.gnome.org/GNOME/pygobject/blob/3.13.3/demos/gtk-demo/demos/printing.py)

I'd be happy to have a solution!

Thanks for your solution and your great engine.
When I run this code the following error occurred:
Traceback (most recent call last): File "tt.py", line 39, in draw_page page.paint(context) File "/usr/local/lib/python2.7/dist-packages/weasyprint/document.py", line 238, in paint draw_page(self._page_box, cairo_context, self._enable_hinting) File "/usr/local/lib/python2.7/dist-packages/weasyprint/draw.py", line 158, in draw_page clip_box=False, bleed=bleed, marks=marks) File "/usr/local/lib/python2.7/dist-packages/weasyprint/draw.py", line 405, in draw_background draw_background_image(context, layer, bg.image_rendering) File "/usr/local/lib/python2.7/dist-packages/weasyprint/draw.py", line 481, in draw_background_image context.set_source(pattern) TypeError: Context.set_source() argument 1 must be cairo.Pattern, not SurfacePattern
And a blank pdf created. Can you help me to make the two Cairo backend compatible (if it's the problem)?
Anyway, we are working on https://github.com/Jooyeshgar/amir/tree/gtk3 and your engine saved our life!

Can you help me to make the two Cairo backend compatible (if it's the problem)?

Yes, that's the problem. And seriously, converting a cairocffi context into a cairo-with-introspection is crazy, nobody would ever want to do this… Oh, wait! Here's what we want!

Nice!

import cairocffi

[…]

    def draw_page(self, operation, print_ctx, page_num, document):
        page = document.pages[page_num]
        cairo_context = print_ctx.get_cairo_context()
        cairocffi_context = cairocffi.Context._from_pointer(
            cairocffi.ffi.cast(
                'cairo_t **', id(cairo_context) + object.__basicsize__)[0],
            incref=True)
        page.paint(cairocffi_context, left_x=0, top_y=0, scale=0.75)

It works!

You'll have to play with left_x, top_y and scale in order to make the document size fit into the printable area (that depends on the printer settings). The current scale should work when the document has the same size as the paper (0.75 = 72 PDF point (cairo units) per inch / 96 CSS pixel per inch).

But that's your part of the work! You'll probably need to read Gtk PrintSettings documentation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

schettino72 picture schettino72  Â·  5Comments

elyak123 picture elyak123  Â·  3Comments

mjbeyeler picture mjbeyeler  Â·  4Comments

assuntaw picture assuntaw  Â·  3Comments

amarnav picture amarnav  Â·  5Comments