Creating print job in gtk3/python

2019-05-28 00:00发布

问题:

I have some information (a list of participants to an event) which I want to print out easily. No need for fancy layout, just a table with several columns, and if possible a drawn line in between the lines of text for better readability. Will need to print landscape to make it all fit (can be done via a GtkPageSetup).

I'm using Python, and I'm on Linux so will have to use the GtkPrintUnixDialog interface. I've been searching on Internet but can't find any example on how this could possibly be achieved.

To simplify the problem: it's for my own use only, so known paper size (A4).

The problem that I have is basically two-fold: 1) create a properly formatted text, suitable for printing, and 2) send this to the printer.

Any suggestions on where to start? Or better, complete examples?

回答1:

I search for my old print examples, but for a start:

You could write to pdf surface, and print pdf, or put the drawing code on on_print function. Note, it does not print what you see, but what you draw on print surface. Draw the context like a regular cairo context, but a few methods are not available(don't fit in print context) while others, like new page, are added. If I find the example, I will come with a answer more self-explanatory. Edit: find an ex:

def on_button_clicked(self, widget):
    ps = Gtk.PaperSize.new_custom("cc", "cc", 210, 297, Gtk.Unit.MM)
    st = Gtk.PrintSettings()
    s = Gtk.PageSetup()
    s.set_paper_size(ps)
    s.set_bottom_margin(4.3, Gtk.Unit.MM)
    s.set_left_margin(4.3, Gtk.Unit.MM)
    s.set_right_margin(4.3, Gtk.Unit.MM)
    s.set_top_margin(4.3, Gtk.Unit.MM)
    s.set_orientation(Gtk.PageOrientation.LANDSCAPE)
    # ret =  Gtk.print_run_page_setup_dialog(self, s, st)
    pd = Gtk.PrintOperation()
    pd.set_n_pages(1)
    pd.set_default_page_setup(s)
    pd.connect("begin_print", self.bg)
    pd.connect("draw_page", self.draw_page)
    # print(ret, s, st)
    pd.set_export_filename("test.pdf")
    result = pd.run(Gtk.PrintOperationAction.EXPORT, None) #play with action, but for test export first; if it's ok, then action.PRINT
    print (result)  # handle errors etc.
    # Gtk.PaperSize.free(ps) - not needed in py

the above may be on button press or whatever

def draw_page (self, operation, context, page_number):
    end = self.layout.get_line_count()
    cr = context.get_cairo_context()
    cr.set_source_rgb(0, 0, 0)
    i = 0
    start = 0
    start_pos = 0
    iter = self.layout.get_iter()
    while 1:
        if i >= start:
            line = iter.get_line()
            print(line)
            _, logical_rect = iter.get_line_extents()
            # x_bearing, y_bearing, lwidth, lheight = logical_rect
            baseline = iter.get_baseline()
            if i == start:
                start_pos = 12000 / 1024.0  # 1024.0 is float(pango.SCALE)
            cr.move_to(0 / 1024.0, baseline / 1024.0 - start_pos)
            PangoCairo.show_layout_line(cr, line)
        i += 1
        if not (i < end and iter.next_line()):
            break

That's just a basic example. Note that layout is a pango layout:

self.layout = cx.create_pango_layout()
    self.layout.set_width(int(w / 4 * Pango.SCALE))
    self.layout.set_text(text, len(text))
    num_lines = self.layout.get_line_count()
    page_height = 0
    self.layout.set_font_description(Pango.FontDescription("Georgia Bold 12"))
    k = 0
    for line in range(num_lines):
        if k == 4:
            self.layout.set_font_description(Pango.FontDescription("Georgia 10"))
        layout_line = self.layout.get_line(line)
        ink_rect, logical_rect = layout_line.get_extents()
        lheight = 1200
        line_height = lheight / 1024.0  # 1024.0 is float(pango.SCALE)
        page_height += line_height
        k += 1
        print ("page_height ", page_height)

copy/paste functional example:

    #!/usr/bin/python
from gi.repository import Gtk, Pango, PangoCairo
import cairo

text = '''
Text.
I have some information (a list of participants to an event) which I 
want to print out easily.
No need for fancy layout,
just a table with several columns,
and if possible a drawn line in between the lines of
 text for better readability.
'''


class MyWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Hello World Printing")
        self.button = Gtk.Button(label="Print A Rectangle")
        self.button.connect("clicked", self.on_button_clicked)
        self.add(self.button)

    def on_button_clicked(self, widget):
        ps = Gtk.PaperSize.new_custom("cc", "cc", 210, 297, Gtk.Unit.MM)
        st = Gtk.PrintSettings()
        s = Gtk.PageSetup()
        s.set_paper_size(ps)
        s.set_bottom_margin(4.3, Gtk.Unit.MM)
        s.set_left_margin(4.3, Gtk.Unit.MM)
        s.set_right_margin(4.3, Gtk.Unit.MM)
        s.set_top_margin(4.3, Gtk.Unit.MM)
        s.set_orientation(Gtk.PageOrientation.LANDSCAPE)
        # ret =  Gtk.print_run_page_setup_dialog(self, s, st)
        pd = Gtk.PrintOperation()
        pd.set_n_pages(1)
        pd.set_default_page_setup(s)
        pd.connect("begin_print", self.bg)
        pd.connect("draw_page", self.draw_page)
        # print(ret, s, st)
        pd.set_export_filename("test.pdf")
        result = pd.run(Gtk.PrintOperationAction.EXPORT, None)
        print (result)  # handle errors etc.
        # Gtk.PaperSize.free(ps)

    def bg(self, op, cx):
        w = cx.get_width()
        h = cx.get_height()
        self.layout = cx.create_pango_layout()
        self.layout.set_width(int(w / 4 * Pango.SCALE))
        self.layout.set_text(text, len(text))
        num_lines = self.layout.get_line_count()
        page_height = 0
        self.layout.set_font_description(Pango.FontDescription("Georgia Bold 12"))
        k = 0
        for line in range(num_lines):
            if k == 4:
                self.layout.set_font_description(Pango.FontDescription("Georgia 10"))
            layout_line = self.layout.get_line(line)
            ink_rect, logical_rect = layout_line.get_extents()
            # print(logical_rect, ink_rect)
            # x_bearing, y_bearing, lwidth, lheight = logical_rect
            lheight = 1200
            line_height = lheight / 1024.0  # 1024.0 is float(pango.SCALE)
            page_height += line_height
            # page_height is the current location on a page.
            # It adds the the line height on each pass through the loop
            # Once it is greater then the height supplied by context.get_height
            # it marks the line and sets the current page height back to 0
            k += 1
            print ("page_height ", page_height)


    def box(self, w, h, x, y, cx):
        w, h = int(w), int(h)
        cx.set_font_size(100)
        cx.set_source_rgb(0, 0, 0)
        cx.rectangle(x, y, w, h)
        cx.stroke()
        yy = 120
        cx.select_font_face("Times", 0, 1)
        ex = cx.text_extents("TEGOLA ROMÂNIA SRL")[2]
        cx.move_to(w / 2 - ex / 2 + x, 105 + y)
        cx.show_text("TEGOLA ROMÂNIA SRL")
        ex = cx.text_extents("Str. Plevnei, nr. 5, Buzău")[2]
        cx.move_to(w / 2 - ex / 2 + x, 210 + y)
        cx.show_text("Str. Plevnei, nr. 5, Buzău")
        ex = cx.text_extents("Tel.: 0238/710.280")[2]
        cx.move_to(w / 2 - ex / 2 + x, 320 + y)
        cx.show_text("Tel.: 0238/710.280")
        ex = cx.text_extents("Fax : 0238/710021")[2]
        cx.move_to(w / 2 - ex / 2 + x, 415 + y)
        cx.show_text("Fax : 0238/710021")
        cx.set_font_size(90)
        cx.move_to(x + 120, 520 + y)
        ex = cx.text_extents("Compoziție:")[2]
        cx.show_text("Compoziție:")
        cx.select_font_face("Times", 0, 0)
        cx.move_to(x + 125 + ex, 520 + y)
        cx.show_text("Polimer bituminos, liant și")
        cx.move_to(x + 5, 620 + y)
        cx.show_text("material de umplutură de înaltă calitate.")
        cx.move_to(x + 5, 720 + y)
        cx.show_text("Nu conține gudron.")
        cx.move_to(x + 5, 800 + y)
        cx.select_font_face("Times", 0, 1)
        ex = cx.text_extents("Instrucțiuni de utilizare:")[2]
        cx.show_text("Instrucțiuni de utilizare:")
        cx.select_font_face("Times", 0, 0)
        cx.move_to(x + 10 + ex, 800 + y)
        cx.show_text("Suprafețele se")


    def draw_page1(self, operation, context, page_nr=None):
        ctx = context.get_cairo_context()
        w = context.get_width()
        h = context.get_height()
        ww, hh = int(w / 4), int(h / 2)
        self.k = 0
        for x in range(2):
            for y in range(4):
                self.box(ww, hh, y * ww, x * hh, ctx)
                self.k += 1
        print(ctx.get_font_matrix())

    def draw_page (self, operation, context, page_number):
        end = self.layout.get_line_count()
        cr = context.get_cairo_context()
        cr.set_source_rgb(0, 0, 0)
        i = 0
        start = 0
        start_pos = 0
        iter = self.layout.get_iter()
        while 1:
            if i >= start:
                line = iter.get_line()
                print(line)
                _, logical_rect = iter.get_line_extents()
                # x_bearing, y_bearing, lwidth, lheight = logical_rect
                baseline = iter.get_baseline()
                if i == start:
                    start_pos = 12000 / 1024.0  # 1024.0 is float(pango.SCALE)
                cr.move_to(0 / 1024.0, baseline / 1024.0 - start_pos)
                PangoCairo.show_layout_line(cr, line)
            i += 1
            if not (i < end and iter.next_line()):
                break



win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Don't forget to change action to Gtk.PrintOperationAction.PRINT for real printing.