如何使用python将gtk中的textview内容保存为pdf?

问题描述 投票:1回答:1

我想以PDF格式保存textview的缓冲区。如果只是简单的文本,我可以使用reportlab进行操作。但是,如果我想保存所有内容,包括带有标签的文本以及图像,怎么办?

from gi.repository import Gtk, GdkPixbuf
import pango
from reportlab.pdfgen import canvas

class gui():
    def __init__(self):
        self.window = Gtk.Window()
        self.window.connect('delete-event', Gtk.main_quit)

        self.box = Gtk.Box()
        self.window.add(self.box)

        self.textview = Gtk.TextView()
        self.textbuffer = self.textview.get_buffer()

        self.tag_bold = self.textbuffer.create_tag("bold",
                                                    weight=pango.WEIGHT_BOLD)
        self.tag_italic = self.textbuffer.create_tag("italic",
                                                     style=pango.STYLE_ITALIC)

        pix = GdkPixbuf.Pixbuf.new_from_file_at_size('baby.jpg', 50, 50)

        tag = [self.tag_bold,
               self.tag_italic]

        self.textbuffer.insert_pixbuf(self.textbuffer.get_end_iter(), pix)
        for i in range(20):
            self.textbuffer.insert_with_tags(self.textbuffer.get_end_iter(),
                                                     'line%d\n' % (i+1),
                                                     tag[i % 2])

        self.box.pack_start(self.textview, True, True, 0)

        self.button = Gtk.Button(label='Start')
        self.button.connect('clicked', self.on_button_clicked)
        self.box.pack_start(self.button, True, True, 0)

        self.window.show_all()
        Gtk.main()

    def on_button_clicked(self, widget):
        canv = canvas.Canvas('tes.pdf')

        for i in range(self.textbuffer.get_line_count()):
            a = self.textbuffer.get_iter_at_line(i)
            b = self.textbuffer.get_iter_at_line(i+1).get_offset()
            c = self.textbuffer.get_iter_at_offset(b - 1)
            t = self.textbuffer.get_text(a, b, True)
            line = 750 - (15 * l)
            canv.drawString(40, line, t)

        canv.save()

if __name__ == '__main__':
    gui = gui()

编辑:Drahnr建议改用cairo。好的,我认为这是一个更好的主意,因为reportlab坐标从左下开始,而cairo坐标从左上开始。下面是我使用cairo的代码。

from gi.repository import Gtk, GdkPixbuf, Gdk
import pango
import cairo


class gui():
    def __init__(self):
        self.window = Gtk.Window()
        self.window.connect('delete-event', Gtk.main_quit)
        self.textview = Gtk.TextView()
        self.window.add(self.textview)

        self.initText()
        self.createPDF()

        self.window.show_all()
        Gtk.main()

    def initText(self):
        self.tag_bold = self.textview.get_buffer().create_tag("bold", weight=pango.WEIGHT_BOLD)
        self.tag_italic = self.textview.get_buffer().create_tag("italic", style=pango.STYLE_ITALIC)

        pix = GdkPixbuf.Pixbuf.new_from_file_at_size('baby.png', 50, 50)

        tag = [self.tag_bold, self.tag_italic]

        self.textview.get_buffer().insert_pixbuf(self.textview.get_buffer().get_end_iter(), pix)
        self.textview.get_buffer().insert(self.textview.get_buffer().get_end_iter(), '\n')
        for i in range(20):
            self.textview.get_buffer().insert_with_tags(self.textview.get_buffer().get_end_iter(), 'line%d' % (i+1), tag[i % 2])
            self.textview.get_buffer().insert(self.textview.get_buffer().get_end_iter(), '\n')

    def createPDF(self):
        line = 30
        row = 5
        pos = 0
        ps = cairo.PDFSurface('tes.pdf', 600, 770)
        cr = cairo.Context(ps)  

        while pos != self.textview.get_buffer().get_end_iter().get_offset():
            if self.textview.get_buffer().get_iter_at_offset(pos).has_tag(self.tag_bold):
                cr.select_font_face('Times', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
            elif self.textview.get_buffer().get_iter_at_offset(pos).has_tag(self.tag_italic):
                cr.select_font_face('Times', cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL)
            else:
                cr.select_font_face('Times', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)

            t = self.textview.get_buffer().get_slice(self.textview.get_buffer().get_iter_at_offset(pos), self.textview.get_buffer().get_iter_at_offset(pos+1), False)
            if t == '\n':
                line += 12
                row = 5
            elif t == unichr(0xFFFC):
                pix = self.textview.get_buffer().get_iter_at_offset(pos).get_pixbuf()
                Gdk.cairo_set_source_pixbuf(cr, pix, 8 * row, line)
                line += pix.get_width()
                cr.paint()
            else:
                cr.move_to(8 * row, line)
                cr.show_text(t)

            pos=pos+1
            row += 1

if __name__ == '__main__':
    gui()

从字面上看还是一样。我应该对其进行硬编码以绘制所有内容。并且drahnr建议使用gtk_widget_draw将其渲染到开罗表面。

python pdf textview gtk reportlab
1个回答
0
投票

这不是python的答案,但它也可能适用于您的问题:

[渲染为cairo_surface_t并使用pdf表面API-呈现文本的方式由您决定,一种简单的方法是完全通过gtk_widget_draw呈现textview。

https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-drawhttp://cairographics.org/manual/cairo-PDF-Surfaces.html

更新#2:

以下内容不完整,需要一个可为您进行渲染的小部件,因此不能替换gtk_widget_draw调用。您需要创建ctype扩展名或手动绘制。

来源:http://www.stuartaxon.com/2010/02/03/using-cairo-to-generate-svg-in-django/

更新#1:

此功能将图像渲染到表面(PDF,SVG,无论您的已编译的cairo库支持什么),并将其存储到文件dest-有关详细信息,请参见特定功能的手册

def draw_render_to_file(dest, Widget, Surface = PDFSurface, width = 100, height = 100)
  widget = Widget(Surface)
  surface = widget.Surface(dest, width, height)
  widget.draw(Context(surface), width, height)
  surface.finish()

0
投票

我有同样的问题

我试图找到如何从文本视图(带有标签)创建pdf / rtf文件的方法

谢谢

© www.soinside.com 2019 - 2024. All rights reserved.