plakativ/plakativ.py

1328 lines
48 KiB
Python
Raw Permalink Normal View History

2019-06-30 23:39:09 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
2019-07-04 10:32:04 +00:00
#
# Plakativ allows to create posters bigger than the page size one's own printer
# is able to print on by enlarging the input PDF, cutting it into smaller
# pieces and putting each of them onto a paper size that can be printed
# normally. The result can then be glued together into a bigger poster.
#
# Copyright (C) 2019 Johannes 'josch' Schauer
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 as published by the
# Free Software Foundation.
2019-06-30 23:39:09 +00:00
from collections import OrderedDict
import math
import fitz
import tkinter
import tkinter.filedialog
2019-06-30 23:39:09 +00:00
import sys
import argparse
import os.path
import platform
VERSION = "0.1"
PAGE_SIZES = OrderedDict(
[
("custom", (None, None)),
("A0 (84.1 cm × 118.9 cm)", (841, 1189)),
("A1 (59.4 cm × 84.1 cm)", (594, 841)),
("A2 (42.0 cm × 59.4 cm)", (420, 594)),
("A3 (29.7 cm × 42.0 cm)", (297, 420)),
("A4 (21.0 cm × 29.7 cm)", (210, 297)),
("A5 (14.8 cm × 21.0 cm)", (148, 210)),
("Letter (8.5 in × 11 in)", (215.9, 279.4)),
("Legal (8.5 in × 14 in)", (215.9, 355.6)),
("Tabloid (11 in × 17 in)", (279.4, 431.8)),
]
)
def mm_to_pt(length):
return (72.0 * length) / 25.4
def pt_to_mm(length):
return (25.4 * length) / 72.0
2019-07-02 09:55:27 +00:00
class PlakativException(Exception):
pass
class PageNrOutOfRangeException(PlakativException):
pass
class LayoutNotComputedException(PlakativException):
pass
2019-06-30 23:39:09 +00:00
2019-07-02 09:55:27 +00:00
class Plakativ:
2019-07-04 05:59:19 +00:00
def __init__(self, infile, pagenr=0):
2019-06-30 23:39:09 +00:00
self.doc = fitz.open(infile)
2019-07-02 09:55:27 +00:00
self.pagenr = pagenr
2019-06-30 23:39:09 +00:00
self.border_left = 20
self.border_right = 20
self.border_top = 20
self.border_bottom = 20
2019-07-04 05:59:19 +00:00
# set page number -- first page is 0
2019-07-02 09:55:27 +00:00
def set_input_pagenr(self, pagenr):
2019-07-04 05:59:19 +00:00
if pagenr < 0 or pagenr >= len(self.doc):
raise PageNrOutOfRangeException(
"%d is not between 0 and %d (inclusive)" % (pagenr, len(self.doc))
)
2019-06-30 23:39:09 +00:00
2019-07-02 09:55:27 +00:00
self.pagenr = pagenr
2019-07-04 05:59:19 +00:00
def get_input_pagenums(self):
return len(self.doc)
2019-07-02 09:55:27 +00:00
def get_input_page_size(self):
2019-07-04 05:59:19 +00:00
width = self.doc[self.pagenr].getDisplayList().rect.width
height = self.doc[self.pagenr].getDisplayList().rect.height
2019-07-02 09:55:27 +00:00
return (width, height)
def get_image(self, zoom):
mat_0 = fitz.Matrix(zoom, zoom)
pix = (
2019-07-04 05:59:19 +00:00
self.doc[self.pagenr].getDisplayList().getPixmap(matrix=mat_0, alpha=False)
2019-07-02 09:55:27 +00:00
)
return pix.getImageData("ppm")
2019-07-03 08:52:40 +00:00
def compute_layout(
2019-07-03 13:24:04 +00:00
self,
mode,
postersize=None,
mult=None,
npages=None,
pagesize=(210, 297),
border=(0, 0, 0, 0),
2019-07-03 08:52:40 +00:00
):
border_top, border_right, border_bottom, border_left = border
self.layout = {
2019-07-03 13:24:04 +00:00
"output_pagesize": pagesize,
2019-07-03 08:52:40 +00:00
"border_top": border_top,
"border_right": border_right,
"border_bottom": border_bottom,
"border_left": border_left,
}
2019-06-30 23:39:09 +00:00
2019-07-01 09:25:25 +00:00
printable_width = self.layout["output_pagesize"][0] - (
2019-07-03 08:52:40 +00:00
border_left + border_right
2019-06-30 23:39:09 +00:00
)
2019-07-01 09:25:25 +00:00
printable_height = self.layout["output_pagesize"][1] - (
2019-07-03 08:52:40 +00:00
border_top + border_bottom
2019-06-30 23:39:09 +00:00
)
2019-07-04 05:59:19 +00:00
inpage_width = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.width)
inpage_height = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.height)
2019-06-30 23:39:09 +00:00
if mode in ["size", "mult"]:
if mode == "size":
# fit the input page size into the selected postersize
2019-07-03 13:24:04 +00:00
poster_width = postersize[0]
2019-07-02 09:55:27 +00:00
poster_height = (poster_width * inpage_height) / inpage_width
2019-07-03 13:24:04 +00:00
if poster_height > postersize[1]:
poster_height = postersize[1]
2019-07-02 09:55:27 +00:00
poster_width = (poster_height * inpage_width) / inpage_height
2019-06-30 23:39:09 +00:00
elif mode == "mult":
2019-07-02 09:55:27 +00:00
area = inpage_width * inpage_height * mult
poster_width = math.sqrt(area * inpage_width / inpage_height)
poster_height = math.sqrt(area * inpage_height / inpage_width)
2019-06-30 23:39:09 +00:00
else:
raise Exception("unsupported mode: %s" % mode)
pages_x_portrait = math.ceil(poster_width / printable_width)
pages_y_portrait = math.ceil(poster_height / printable_height)
pages_x_landscape = math.ceil(poster_width / printable_height)
pages_y_landscape = math.ceil(poster_height / printable_width)
portrait = True
if (
pages_x_portrait * pages_y_portrait
> pages_x_landscape * pages_y_landscape
):
portrait = False
if portrait:
pages_x = pages_x_portrait
pages_y = pages_y_portrait
else:
pages_x = pages_x_landscape
pages_y = pages_y_landscape
elif mode == "npages":
# stupid bruteforce algorithm to determine the largest printable
# postersize with N pages
best_area = 0
best = None
2019-07-02 09:55:27 +00:00
for x in range(1, npages + 1):
for y in range(1, npages + 1):
if x * y > npages:
2019-06-30 23:39:09 +00:00
continue
width_portrait = x * printable_width
height_portrait = y * printable_height
poster_width = width_portrait
2019-07-02 09:55:27 +00:00
poster_height = (poster_width * inpage_height) / inpage_width
2019-06-30 23:39:09 +00:00
if poster_height > height_portrait:
poster_height = height_portrait
2019-07-02 09:55:27 +00:00
poster_width = (poster_height * inpage_width) / inpage_height
2019-06-30 23:39:09 +00:00
area_portrait = poster_width * poster_height
if area_portrait > best_area:
best_area = area_portrait
best = (x, y, True, poster_width, poster_height)
width_landscape = x * printable_height
height_landscape = y * printable_width
poster_width = width_landscape
2019-07-02 09:55:27 +00:00
poster_height = (poster_width * inpage_height) / inpage_width
2019-06-30 23:39:09 +00:00
if poster_height > height_landscape:
poster_height = height_landscape
2019-07-02 09:55:27 +00:00
poster_width = (poster_height * inpage_width) / inpage_height
2019-06-30 23:39:09 +00:00
area_landscape = poster_width * poster_height
if area_landscape > best_area:
best_area = area_landscape
best = (x, y, False, poster_width, poster_height)
pages_x, pages_y, portrait, poster_width, poster_height = best
else:
raise Exception("unsupported mode: %s" % mode)
2019-07-03 08:52:40 +00:00
# size of the bounding box of all pages after they have been glued together
if portrait:
self.layout["overallsize"] = (
pages_x * printable_width + (border_right + border_left),
pages_y * printable_height + (border_top + border_bottom),
)
else:
self.layout["overallsize"] = (
pages_x * printable_height + (border_top + border_bottom),
pages_y * printable_width + (border_right + border_left),
)
# size of output poster is always proportional to size of input page
self.layout["postersize"] = poster_width, poster_height
# position of the poster relative to upper left corner of layout["overallsize"]
if portrait:
self.layout["posterpos"] = (
border_left + (pages_x * printable_width - poster_width) / 2,
border_top + (pages_y * printable_height - poster_height) / 2,
)
else:
self.layout["posterpos"] = (
border_bottom + (pages_x * printable_height - poster_width) / 2,
border_right + (pages_y * printable_width - poster_height) / 2,
)
# positions are relative to upper left corner of poster
2019-06-30 23:39:09 +00:00
self.layout["positions"] = []
for y in range(pages_y):
for x in range(pages_x):
if portrait:
posx = x * printable_width
posy = y * printable_height
else:
posx = x * printable_height
posy = y * printable_width
self.layout["positions"].append((posx, posy, portrait))
if mode == "size":
2019-07-02 09:55:27 +00:00
mult = (poster_width * poster_height) / (inpage_width * inpage_height)
npages = pages_x * pages_y
2019-06-30 23:39:09 +00:00
elif mode == "mult":
2019-07-03 13:24:04 +00:00
postersize = poster_width, poster_height
2019-07-02 09:55:27 +00:00
npages = pages_x * pages_y
2019-06-30 23:39:09 +00:00
elif mode == "npages":
2019-07-03 13:24:04 +00:00
postersize = poster_width, poster_height
2019-07-02 09:55:27 +00:00
mult = (poster_width * poster_height) / (inpage_width * inpage_height)
2019-06-30 23:39:09 +00:00
else:
raise Exception("unsupported mode: %s" % mode)
2019-07-03 13:24:04 +00:00
return postersize, mult, npages
2019-06-30 23:39:09 +00:00
def render(self, outfile):
2019-07-02 09:55:27 +00:00
if not hasattr(self, "layout"):
raise LayoutNotComputedException()
2019-06-30 23:39:09 +00:00
2019-07-04 05:59:19 +00:00
inpage_width = pt_to_mm(self.doc[self.pagenr].getDisplayList().rect.width)
2019-07-02 09:55:27 +00:00
outdoc = fitz.open()
2019-06-30 23:39:09 +00:00
for (x, y, portrait) in self.layout["positions"]:
if portrait:
2019-07-02 09:55:27 +00:00
page_width = mm_to_pt(self.layout["output_pagesize"][0])
page_height = mm_to_pt(self.layout["output_pagesize"][1])
2019-06-30 23:39:09 +00:00
else:
2019-07-02 09:55:27 +00:00
page_width = mm_to_pt(self.layout["output_pagesize"][1])
page_height = mm_to_pt(self.layout["output_pagesize"][0])
2019-06-30 23:39:09 +00:00
page = outdoc.newPage(
2019-07-02 09:55:27 +00:00
-1, width=page_width, height=page_height # insert after last page
)
2019-06-30 23:39:09 +00:00
2019-07-03 08:52:40 +00:00
target_x = x - self.layout["posterpos"][0]
target_y = y - self.layout["posterpos"][1]
2019-06-30 23:39:09 +00:00
target_xoffset = 0
target_yoffset = 0
if portrait:
2019-07-01 09:25:25 +00:00
target_width = self.layout["output_pagesize"][0]
target_height = self.layout["output_pagesize"][1]
2019-06-30 23:39:09 +00:00
else:
2019-07-01 09:25:25 +00:00
target_width = self.layout["output_pagesize"][1]
target_height = self.layout["output_pagesize"][0]
2019-06-30 23:39:09 +00:00
if target_x < 0:
target_xoffset = -target_x
target_width += target_x
target_x = 0
if target_y < 0:
target_yoffset = -target_y
target_height += target_y
target_y = 0
if target_x + target_width > self.layout["postersize"][0]:
target_width = self.layout["postersize"][0] - target_x
if target_y + target_height > self.layout["postersize"][1]:
target_height = self.layout["postersize"][1] - target_y
targetrect = fitz.Rect(
mm_to_pt(target_xoffset),
mm_to_pt(target_yoffset),
mm_to_pt(target_xoffset + target_width),
mm_to_pt(target_yoffset + target_height),
)
2019-07-02 09:55:27 +00:00
factor = inpage_width / self.layout["postersize"][0]
2019-06-30 23:39:09 +00:00
sourcerect = fitz.Rect(
mm_to_pt(factor * target_x),
mm_to_pt(factor * target_y),
mm_to_pt(factor * (target_x + target_width)),
mm_to_pt(factor * (target_y + target_height)),
)
2019-07-02 09:55:27 +00:00
page.showPDFpage(
2019-06-30 23:39:09 +00:00
targetrect, # fill the whole page
self.doc, # input document
2019-07-04 05:59:19 +00:00
self.pagenr, # input page number
2019-06-30 23:39:09 +00:00
clip=sourcerect, # part of the input page to use
)
outdoc.save(outfile, garbage=4, deflate=True)
# from Python 3.7 Lib/idlelib/configdialog.py
# Copyright 2015-2017 Terry Jan Reedy
# Python License
class VerticalScrolledFrame(tkinter.Frame):
"""A pure Tkinter vertically scrollable frame.
* Use the 'interior' attribute to place widgets inside the scrollable frame
* Construct and pack/place/grid normally
* This frame only allows vertical scrolling
"""
def __init__(self, parent, *args, **kw):
tkinter.Frame.__init__(self, parent, *args, **kw)
# Create a canvas object and a vertical scrollbar for scrolling it.
vscrollbar = tkinter.Scrollbar(self, orient=tkinter.VERTICAL)
vscrollbar.pack(fill=tkinter.Y, side=tkinter.RIGHT, expand=tkinter.FALSE)
canvas = tkinter.Canvas(
self,
borderwidth=0,
highlightthickness=0,
yscrollcommand=vscrollbar.set,
width=240,
)
canvas.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=tkinter.TRUE)
vscrollbar.config(command=canvas.yview)
# Reset the view.
canvas.xview_moveto(0)
canvas.yview_moveto(0)
# Create a frame inside the canvas which will be scrolled with it.
self.interior = interior = tkinter.Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior, anchor=tkinter.NW)
# Track changes to the canvas and frame width and sync them,
# also updating the scrollbar.
def _configure_interior(event):
# Update the scrollbars to match the size of the inner frame.
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
interior.bind("<Configure>", _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
# Update the inner frame's width to fill the canvas.
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind("<Configure>", _configure_canvas)
return
# From Python 3.7 Lib/tkinter/__init__.py
# Copyright 2000 Fredrik Lundh
# Python License
#
# add support for 'state' and 'name' kwargs
2019-07-04 05:59:19 +00:00
# add support for updating list of options
2019-06-30 23:39:09 +00:00
class OptionMenu(tkinter.Menubutton):
"""OptionMenu which allows the user to select a value from a menu."""
def __init__(self, master, variable, value, *values, **kwargs):
"""Construct an optionmenu widget with the parent MASTER, with
the resource textvariable set to VARIABLE, the initially selected
value VALUE, the other menu values VALUES and an additional
keyword argument command."""
kw = {
"borderwidth": 2,
"textvariable": variable,
"indicatoron": 1,
"relief": tkinter.RAISED,
"anchor": "c",
"highlightthickness": 2,
}
if "state" in kwargs:
kw["state"] = kwargs["state"]
del kwargs["state"]
if "name" in kwargs:
kw["name"] = kwargs["name"]
del kwargs["name"]
tkinter.Widget.__init__(self, master, "menubutton", kw)
self.widgetName = "tk_optionMenu"
2019-07-04 05:59:19 +00:00
self.callback = kwargs.get("command")
self.variable = variable
2019-06-30 23:39:09 +00:00
if "command" in kwargs:
del kwargs["command"]
if kwargs:
raise tkinter.TclError("unknown option -" + list(kwargs.keys())[0])
2019-07-04 05:59:19 +00:00
self.set_values([value] + list(values))
2019-06-30 23:39:09 +00:00
def __getitem__(self, name):
if name == "menu":
return self.__menu
return tkinter.Widget.__getitem__(self, name)
2019-07-04 05:59:19 +00:00
def set_values(self, values):
menu = self.__menu = tkinter.Menu(self, name="menu", tearoff=0)
self.menuname = menu._w
for v in values:
menu.add_command(
label=v, command=tkinter._setit(self.variable, v, self.callback)
)
self["menu"] = menu
2019-06-30 23:39:09 +00:00
def destroy(self):
"""Destroy this widget and the associated menu."""
tkinter.Menubutton.destroy(self)
self.__menu = None
class Application(tkinter.Frame):
def __init__(self, master=None, plakativ=None):
super().__init__(master)
self.master = master
self.master.title("plakativ")
self.pack(fill=tkinter.BOTH, expand=tkinter.TRUE)
2019-07-02 09:55:27 +00:00
if plakativ is not None:
2019-06-30 23:39:09 +00:00
self.plakativ = plakativ
self.canvas = tkinter.Canvas(self, bg="black")
self.canvas.pack(fill=tkinter.BOTH, side=tkinter.LEFT, expand=tkinter.TRUE)
self.canvas_size = self.canvas.winfo_width(), self.canvas.winfo_height()
self.canvas.bind("<Configure>", self.on_resize)
2019-07-04 05:59:19 +00:00
frame_right = tkinter.Frame(self)
frame_right.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.Y)
2019-06-30 23:39:09 +00:00
2019-07-04 05:59:19 +00:00
top_frame = tkinter.Frame(frame_right)
2019-06-30 23:39:09 +00:00
top_frame.pack(fill=tkinter.X)
open_button = tkinter.Button(
top_frame, text="Open PDF", command=self.on_open_button
)
open_button.pack(side=tkinter.LEFT, expand=tkinter.TRUE, fill=tkinter.X)
help_button = tkinter.Button(top_frame, text="Help", state=tkinter.DISABLED)
help_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X)
2019-07-04 05:59:19 +00:00
frame1 = VerticalScrolledFrame(frame_right)
frame1.pack(side=tkinter.TOP, expand=tkinter.TRUE, fill=tkinter.Y)
self.input = InputWidget(frame1.interior)
self.input.pack(fill=tkinter.X)
self.input.set(1, (0, 0))
if hasattr(self, "plakativ"):
self.input.callback = self.on_input
2019-06-30 23:39:09 +00:00
2019-07-03 13:24:04 +00:00
self.pagesize = PageSizeWidget(frame1.interior)
self.pagesize.pack(fill=tkinter.X)
self.pagesize.set(False, (210, 297))
if hasattr(self, "plakativ"):
self.postersize.callback = self.on_pagesize
2019-06-30 23:39:09 +00:00
2019-07-03 13:24:04 +00:00
self.bordersize = BorderSizeWidget(frame1.interior)
self.bordersize.pack(fill=tkinter.X)
self.bordersize.set(20.0, 20.0, 20.0, 20.0)
2019-07-03 08:52:40 +00:00
if hasattr(self, "plakativ"):
2019-07-03 13:24:04 +00:00
self.postersize.callback = self.on_bordersize
2019-06-30 23:39:09 +00:00
self.postersize = PostersizeWidget(frame1.interior)
self.postersize.pack(fill=tkinter.X)
self.postersize.set("size", (False, (594, 841)), 1.0, 1)
2019-07-02 09:55:27 +00:00
if hasattr(self, "plakativ"):
2019-06-30 23:39:09 +00:00
self.postersize.callback = self.on_postersize
layouter_group = tkinter.LabelFrame(frame1.interior, text="Layouter")
layouter_group.pack(fill=tkinter.X)
self.layouter = tkinter.IntVar()
self.layouter.set(1)
layouter1 = tkinter.Radiobutton(
layouter_group, text="Simple", variable=self.layouter, value=1
)
layouter1.pack(anchor=tkinter.W)
layouter2 = tkinter.Radiobutton(
layouter_group,
text="Advanced",
variable=self.layouter,
value=2,
state=tkinter.DISABLED,
)
layouter2.pack(anchor=tkinter.W)
layouter3 = tkinter.Radiobutton(
layouter_group,
text="Complex",
variable=self.layouter,
value=3,
state=tkinter.DISABLED,
)
layouter3.pack(anchor=tkinter.W)
output_group = tkinter.LabelFrame(frame1.interior, text="Output options")
output_group.pack(fill=tkinter.X)
tkinter.Checkbutton(
output_group, text="Print cutting guides", state=tkinter.DISABLED
).pack(anchor=tkinter.W)
tkinter.Checkbutton(
output_group, text="Print poster border", state=tkinter.DISABLED
).pack(anchor=tkinter.W)
2019-07-04 05:59:19 +00:00
option_group = tkinter.LabelFrame(frame1.interior, text="Program options")
option_group.pack(fill=tkinter.X)
tkinter.Label(option_group, text="Unit:", state=tkinter.DISABLED).grid(
row=0, column=0, sticky=tkinter.W
)
unit = tkinter.StringVar()
unit.set("mm")
OptionMenu(option_group, unit, ["mm"], state=tkinter.DISABLED).grid(
row=0, column=1, sticky=tkinter.W
)
tkinter.Label(option_group, text="Language:", state=tkinter.DISABLED).grid(
row=1, column=0, sticky=tkinter.W
)
language = tkinter.StringVar()
language.set("English")
OptionMenu(option_group, language, ["English"], state=tkinter.DISABLED).grid(
row=1, column=1, sticky=tkinter.W
)
bottom_frame = tkinter.Frame(frame_right)
2019-06-30 23:39:09 +00:00
bottom_frame.pack(fill=tkinter.X)
self.save_button = tkinter.Button(
bottom_frame,
text="Save PDF",
command=self.on_save_button,
state=tkinter.DISABLED,
)
self.save_button.pack(side=tkinter.LEFT, expand=tkinter.TRUE, fill=tkinter.X)
quit_button = tkinter.Button(
bottom_frame, text="Exit", command=self.master.destroy
)
quit_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE, fill=tkinter.X)
2019-07-04 05:59:19 +00:00
def on_input(self, value):
_, pagesize = self.pagesize.value
pagenum, _ = value
mode, (custom_size, size), mult, npages = self.postersize.value
bordersize = self.bordersize.value
self.plakativ.set_input_pagenr(pagenum - 1)
size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, bordersize
)
self.postersize.set(mode, (custom_size, size), mult, npages)
self.draw()
width, height = self.plakativ.get_input_page_size()
return "%.02f" % pt_to_mm(width), "%.02f" % pt_to_mm(height)
2019-07-03 13:24:04 +00:00
def on_pagesize(self, value):
_, pagesize = value
2019-07-04 05:59:19 +00:00
pagenum, _ = self.input.value
2019-07-03 13:24:04 +00:00
mode, (custom_size, size), mult, npages = self.postersize.value
bordersize = self.bordersize.value
2019-07-04 05:59:19 +00:00
self.plakativ.set_input_pagenr(pagenum - 1)
2019-07-03 08:52:40 +00:00
size, mult, npages = self.plakativ.compute_layout(
2019-07-03 13:24:04 +00:00
mode, size, mult, npages, pagesize, bordersize
2019-07-03 08:52:40 +00:00
)
2019-07-03 13:24:04 +00:00
self.postersize.set(mode, (custom_size, size), mult, npages)
2019-06-30 23:39:09 +00:00
self.draw()
2019-07-03 13:24:04 +00:00
def on_bordersize(self, value):
_, pagesize = self.pagesize.value
2019-07-04 05:59:19 +00:00
pagenum, _ = self.input.value
2019-07-03 08:52:40 +00:00
mode, (custom_size, size), mult, npages = self.postersize.value
2019-07-04 05:59:19 +00:00
self.plakativ.set_input_pagenr(pagenum - 1)
2019-07-03 08:52:40 +00:00
size, mult, npages = self.plakativ.compute_layout(
2019-07-03 13:24:04 +00:00
mode, size, mult, npages, pagesize, value
2019-07-03 08:52:40 +00:00
)
self.postersize.set(mode, (custom_size, size), mult, npages)
2019-06-30 23:39:09 +00:00
self.draw()
2019-07-03 13:24:04 +00:00
def on_postersize(self, value):
mode, (custom_size, size), mult, npages = value
2019-07-04 05:59:19 +00:00
pagenum, _ = self.input.value
2019-07-03 13:24:04 +00:00
_, pagesize = self.pagesize.value
border = self.bordersize.value
2019-07-04 05:59:19 +00:00
self.plakativ.set_input_pagenr(pagenum - 1)
2019-07-03 13:24:04 +00:00
size, mult, npages = self.plakativ.compute_layout(
mode, size, mult, npages, pagesize, border
)
2019-06-30 23:39:09 +00:00
self.draw()
2019-07-03 13:24:04 +00:00
return (mode, (custom_size, size), mult, npages)
2019-06-30 23:39:09 +00:00
def on_resize(self, event):
self.canvas_size = (event.width, event.height)
self.draw()
def draw(self):
# clean canvas
self.canvas.delete(tkinter.ALL)
2019-07-02 09:55:27 +00:00
if not hasattr(self, "plakativ"):
2019-07-03 13:24:04 +00:00
self.canvas.create_text(
self.canvas_size[0] / 2,
self.canvas_size[1] / 2,
2019-07-04 05:59:19 +00:00
text='Click on the "Open PDF" button in the upper right.',
2019-07-03 13:24:04 +00:00
fill="white",
)
2019-06-30 23:39:09 +00:00
return
canvas_padding = 10
2019-07-02 09:55:27 +00:00
width, height = self.plakativ.get_input_page_size()
2019-07-03 08:52:40 +00:00
# factor to convert from input page dimensions (given in pt) into
# canvas dimensions (given in pixels)
2019-06-30 23:39:09 +00:00
zoom_0 = min(
self.canvas_size[0]
2019-07-02 09:55:27 +00:00
/ width
2019-06-30 23:39:09 +00:00
* self.plakativ.layout["postersize"][0]
/ (self.plakativ.layout["overallsize"][0] + canvas_padding),
self.canvas_size[1]
2019-07-02 09:55:27 +00:00
/ height
2019-06-30 23:39:09 +00:00
* self.plakativ.layout["postersize"][1]
/ (self.plakativ.layout["overallsize"][1] + canvas_padding),
)
2019-07-03 08:52:40 +00:00
img = self.plakativ.get_image(zoom_0)
tkimg = tkinter.PhotoImage(data=img)
# factor to convert from output poster dimensions (given in mm) into
# canvas dimensions (given in pixels)
2019-06-30 23:39:09 +00:00
zoom_1 = min(
self.canvas_size[0]
/ (self.plakativ.layout["overallsize"][0] + canvas_padding),
self.canvas_size[1]
/ (self.plakativ.layout["overallsize"][1] + canvas_padding),
)
2019-07-03 08:52:40 +00:00
# draw image on canvas
2019-06-30 23:39:09 +00:00
self.canvas.create_image(
2019-07-03 08:52:40 +00:00
(self.canvas_size[0] - zoom_1 * self.plakativ.layout["overallsize"][0]) / 2
+ zoom_1 * self.plakativ.layout["posterpos"][0],
(self.canvas_size[1] - zoom_1 * self.plakativ.layout["overallsize"][1]) / 2
+ zoom_1 * self.plakativ.layout["posterpos"][1],
2019-06-30 23:39:09 +00:00
anchor=tkinter.NW,
image=tkimg,
)
self.canvas.image = tkimg
# draw rectangles
for (x, y, portrait) in self.plakativ.layout["positions"]:
x0 = (
x * zoom_1
2019-07-03 08:52:40 +00:00
+ (
self.canvas_size[0]
- zoom_1 * self.plakativ.layout["overallsize"][0]
)
/ 2
2019-06-30 23:39:09 +00:00
)
y0 = (
y * zoom_1
2019-07-03 08:52:40 +00:00
+ (
self.canvas_size[1]
- zoom_1 * self.plakativ.layout["overallsize"][1]
)
/ 2
2019-06-30 23:39:09 +00:00
)
if portrait:
2019-07-01 09:25:25 +00:00
x1 = x0 + self.plakativ.layout["output_pagesize"][0] * zoom_1
y1 = y0 + self.plakativ.layout["output_pagesize"][1] * zoom_1
2019-06-30 23:39:09 +00:00
else:
2019-07-01 09:25:25 +00:00
x1 = x0 + self.plakativ.layout["output_pagesize"][1] * zoom_1
y1 = y0 + self.plakativ.layout["output_pagesize"][0] * zoom_1
2019-06-30 23:39:09 +00:00
self.canvas.create_rectangle(x0, y0, x1, y1, outline="red")
2019-07-03 08:52:40 +00:00
if portrait:
top = self.plakativ.layout["border_top"]
right = self.plakativ.layout["border_right"]
bottom = self.plakativ.layout["border_bottom"]
left = self.plakativ.layout["border_left"]
else:
top = self.plakativ.layout["border_left"]
right = self.plakativ.layout["border_top"]
bottom = self.plakativ.layout["border_right"]
left = self.plakativ.layout["border_bottom"]
2019-06-30 23:39:09 +00:00
self.canvas.create_rectangle(
2019-07-03 08:52:40 +00:00
x0 + zoom_1 * left,
y0 + zoom_1 * top,
x1 - zoom_1 * right,
y1 - zoom_1 * bottom,
2019-06-30 23:39:09 +00:00
outline="blue",
)
def on_open_button(self):
filename = tkinter.filedialog.askopenfilename(
parent=self.master,
title="foobar",
filetypes=[("pdf documents", "*.pdf"), ("all files", "*")],
initialdir="/home/josch/git/plakativ",
initialfile="test.pdf",
)
if filename == ():
return
self.filename = filename
2019-07-02 09:55:27 +00:00
self.plakativ = Plakativ(self.filename)
2019-06-30 23:39:09 +00:00
# compute the splitting with the current values
2019-07-03 08:52:40 +00:00
mode, (custom_size, size), mult, npages = self.postersize.value
2019-07-03 13:24:04 +00:00
_, pagesize = self.pagesize.value
border = self.bordersize.value
2019-07-03 08:52:40 +00:00
size, mult, npages = self.plakativ.compute_layout(
2019-07-03 13:24:04 +00:00
mode, size, mult, npages, pagesize, border
2019-07-03 08:52:40 +00:00
)
2019-07-04 05:59:19 +00:00
# update input widget
width, height = self.plakativ.get_input_page_size()
self.input.set(1, ("%.02f" % pt_to_mm(width), "%.02f" % pt_to_mm(height)))
self.input.nametowidget("spinbox_pagenum").configure(
to=self.plakativ.get_input_pagenums()
)
self.input.nametowidget("label_of_pagenum").configure(
text="of %d" % self.plakativ.get_input_pagenums()
)
2019-06-30 23:39:09 +00:00
# update postersize widget
2019-07-03 08:52:40 +00:00
self.postersize.set(mode, (custom_size, size), mult, npages)
2019-06-30 23:39:09 +00:00
# draw preview in canvas
self.draw()
# enable save button
self.save_button.configure(state=tkinter.NORMAL)
# set callback function
2019-07-04 05:59:19 +00:00
self.input.callback = self.on_input
2019-07-03 13:24:04 +00:00
self.pagesize.callback = self.on_pagesize
self.bordersize.callback = self.on_bordersize
2019-06-30 23:39:09 +00:00
self.postersize.callback = self.on_postersize
def on_save_button(self):
base, ext = os.path.splitext(os.path.basename(self.filename))
filename = tkinter.filedialog.asksaveasfilename(
parent=self.master,
title="foobar",
defaultextension=".pdf",
filetypes=[("pdf documents", "*.pdf"), ("all files", "*")],
initialdir="/home/josch/git/plakativ",
initialfile=base + "_poster" + ext,
)
if filename == "":
return
self.plakativ.render(filename)
2019-07-04 05:59:19 +00:00
class InputWidget(tkinter.LabelFrame):
def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__(self, parent, text="Input properties", *args, **kw)
self.callback = None
self.variables = {
"pagenum": tkinter.IntVar(),
"width": tkinter.StringVar(),
"height": tkinter.StringVar(),
}
def callback(varname, idx, op):
assert op == "w"
self.on_pagenum(self.variables["pagenum"].get())
self.variables["pagenum"].trace("w", callback)
tkinter.Label(self, text="Use page").grid(row=0, column=0, sticky=tkinter.W)
tkinter.Spinbox(
self,
increment=1,
from_=1,
to=100,
width=3,
name="spinbox_pagenum",
textvariable=self.variables["pagenum"],
).grid(row=0, column=1, sticky=tkinter.W)
tkinter.Label(self, text="of 1", name="label_of_pagenum").grid(
row=0, column=2, sticky=tkinter.W
)
tkinter.Label(self, text="Width:").grid(row=1, column=0, sticky=tkinter.W)
tkinter.Label(self, textvariable=self.variables["width"]).grid(
row=1, column=1, sticky=tkinter.W
)
tkinter.Label(self, text="mm", name="size_label_width_mm").grid(
row=1, column=2, sticky=tkinter.W
)
tkinter.Label(self, text="Height:").grid(row=2, column=0, sticky=tkinter.W)
tkinter.Label(self, textvariable=self.variables["height"]).grid(
row=2, column=1, sticky=tkinter.W
)
tkinter.Label(self, text="mm", name="size_label_height_mm").grid(
row=2, column=2, sticky=tkinter.W
)
def on_pagenum(self, value):
if getattr(self, "value", None) is None:
return
_, size = self.value
self.set(value, size)
def set(self, pagenum, pagesize):
# before setting self.value, check if the effective value is different
# from before or otherwise we do not need to execute the callback in
# the end
state_changed = True
if getattr(self, "value", None) is not None:
state_changed = self.value != (pagenum, pagesize)
# execute callback if necessary
if state_changed and self.callback is not None:
pagesize = self.callback((pagenum, pagesize))
self.value = (pagenum, pagesize)
width, height = pagesize
if self.variables["pagenum"].get() != pagenum:
self.variables["pagenum"].set(pagenum)
if self.variables["width"].get() != width:
self.variables["width"].set(width)
if self.variables["height"].get() != height:
self.variables["height"].set(height)
2019-07-03 13:24:04 +00:00
class PageSizeWidget(tkinter.LabelFrame):
def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__(
self, parent, text="Size of output pages", *args, **kw
)
self.callback = None
self.variables = {
"dropdown": tkinter.StringVar(),
"width": tkinter.DoubleVar(),
"height": tkinter.DoubleVar(),
}
for k, v in self.variables.items():
# need to pass k and v as function arguments so that their value
# does not get overwritten each loop iteration
def callback(varname, idx, op, k_copy=k, v_copy=v):
assert op == "w"
getattr(self, "on_" + k_copy)(v_copy.get())
v.trace("w", callback)
OptionMenu(self, self.variables["dropdown"], *PAGE_SIZES.keys()).grid(
row=1, column=0, columnspan=3, sticky=tkinter.W
)
tkinter.Label(
self, text="Width:", state=tkinter.DISABLED, name="size_label_width"
).grid(row=2, column=0, sticky=tkinter.W)
tkinter.Spinbox(
self,
format="%.2f",
increment=0.01,
from_=0,
to=100,
width=5,
state=tkinter.DISABLED,
name="spinbox_width",
textvariable=self.variables["width"],
).grid(row=2, column=1, sticky=tkinter.W)
tkinter.Label(
self, text="mm", state=tkinter.DISABLED, name="size_label_width_mm"
).grid(row=2, column=2, sticky=tkinter.W)
tkinter.Label(
self, text="Height:", state=tkinter.DISABLED, name="size_label_height"
).grid(row=3, column=0, sticky=tkinter.W)
tkinter.Spinbox(
self,
format="%.2f",
increment=0.01,
from_=0,
to=100,
width=5,
state=tkinter.DISABLED,
name="spinbox_height",
textvariable=self.variables["height"],
).grid(row=3, column=1, sticky=tkinter.W)
tkinter.Label(
self, text="mm", state=tkinter.DISABLED, name="size_label_height_mm"
).grid(row=3, column=2, sticky=tkinter.W)
def on_dropdown(self, value):
custom_size, size = self.value
if value == "custom":
custom_size = True
else:
custom_size = False
size = PAGE_SIZES[value]
self.set(custom_size, size)
def on_width(self, value):
if getattr(self, "value", None) is None:
return
custom_size, (_, height) = self.value
self.set(custom_size, (value, height))
def on_height(self, value):
if getattr(self, "value", None) is None:
return
custom_size, (width, _) = self.value
self.set(custom_size, (width, value))
def set(self, custom_size, pagesize):
# before setting self.value, check if the effective value is different
# from before or otherwise we do not need to execute the callback in
# the end
state_changed = True
if getattr(self, "value", None) is not None:
state_changed = self.value != (custom_size, pagesize)
# execute callback if necessary
if state_changed and self.callback is not None:
self.callback((custom_size, pagesize))
self.value = (custom_size, pagesize)
width, height = pagesize
if custom_size:
self.nametowidget("size_label_width").configure(state=tkinter.NORMAL)
self.nametowidget("spinbox_width").configure(state=tkinter.NORMAL)
self.nametowidget("size_label_width_mm").configure(state=tkinter.NORMAL)
self.nametowidget("size_label_height").configure(state=tkinter.NORMAL)
self.nametowidget("spinbox_height").configure(state=tkinter.NORMAL)
self.nametowidget("size_label_height_mm").configure(state=tkinter.NORMAL)
else:
self.nametowidget("size_label_width").configure(state=tkinter.DISABLED)
self.nametowidget("spinbox_width").configure(state=tkinter.DISABLED)
self.nametowidget("size_label_width_mm").configure(state=tkinter.DISABLED)
self.nametowidget("size_label_height").configure(state=tkinter.DISABLED)
self.nametowidget("spinbox_height").configure(state=tkinter.DISABLED)
self.nametowidget("size_label_height_mm").configure(state=tkinter.DISABLED)
# only set variables that changed to not trigger multiple variable tracers
if custom_size:
if self.variables["dropdown"].get() != "custom":
self.variables["dropdown"].set("custom")
else:
val = dict(zip(PAGE_SIZES.values(), PAGE_SIZES.keys()))[(width, height)]
if self.variables["dropdown"].get() != val:
self.variables["dropdown"].set(val)
if self.variables["width"].get() != width:
self.variables["width"].set(width)
if self.variables["height"].get() != height:
self.variables["height"].set(height)
class BorderSizeWidget(tkinter.LabelFrame):
2019-07-03 08:52:40 +00:00
def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__(
self, parent, text="Output Borders/Overlap", *args, **kw
)
self.callback = None
self.variables = dict()
for i, (n, label) in enumerate(
[
("top", "Top:"),
("right", "Right:"),
("bottom", "Bottom:"),
("left", "Left:"),
]
):
self.variables[n] = tkinter.DoubleVar()
# need to pass k and v as function arguments so that their value
# does not get overwritten each loop iteration
def callback(varname, idx, op, k_copy=n, v_copy=self.variables[n]):
assert op == "w"
getattr(self, "on_" + k_copy)(v_copy.get())
self.variables[n].trace("w", callback)
tkinter.Label(self, text=label).grid(row=i, column=0, sticky=tkinter.W)
tkinter.Spinbox(
self,
format="%.2f",
increment=1.0,
from_=0,
to=100,
width=5,
textvariable=self.variables[n],
).grid(row=i, column=1)
tkinter.Label(self, text="mm").grid(row=i, column=2)
def on_top(self, value):
if getattr(self, "value", None) is None:
return
_, right, bottom, left = self.value
self.set(value, right, bottom, left)
def on_right(self, value):
if getattr(self, "value", None) is None:
return
top, _, bottom, left = self.value
self.set(top, value, bottom, left)
def on_bottom(self, value):
if getattr(self, "value", None) is None:
return
top, right, _, left = self.value
self.set(top, right, value, left)
def on_left(self, value):
if getattr(self, "value", None) is None:
return
top, right, bottom, _ = self.value
self.set(top, right, bottom, value)
def set(self, top, right, bottom, left):
# before setting self.value, check if the effective value is different
# from before or otherwise we do not need to execute the callback in
# the end
state_changed = True
if getattr(self, "value", None) is not None:
state_changed = self.value != (top, right, bottom, left)
# execute callback if necessary
if state_changed and self.callback is not None:
self.callback((top, right, bottom, left))
self.value = top, right, bottom, left
# only set variables that changed to not trigger multiple variable tracers
if self.variables["top"].get() != top:
self.variables["top"].set(top)
if self.variables["right"].get() != right:
self.variables["right"].set(right)
if self.variables["bottom"].get() != bottom:
self.variables["bottom"].set(bottom)
if self.variables["left"].get() != left:
self.variables["left"].set(left)
2019-06-30 23:39:09 +00:00
class PostersizeWidget(tkinter.LabelFrame):
def __init__(self, parent, *args, **kw):
tkinter.LabelFrame.__init__(self, parent, text="Poster Size", *args, **kw)
self.callback = None
self.variables = {
"radio": tkinter.StringVar(),
"dropdown": tkinter.StringVar(),
"width": tkinter.DoubleVar(),
"height": tkinter.DoubleVar(),
"multiplier": tkinter.DoubleVar(),
"pages": tkinter.IntVar(),
}
for k, v in self.variables.items():
# need to pass k and v as function arguments so that their value
# does not get overwritten each loop iteration
def callback(varname, idx, op, k_copy=k, v_copy=v):
assert op == "w"
getattr(self, "on_" + k_copy)(v_copy.get())
v.trace("w", callback)
tkinter.Radiobutton(
self,
text="Fit into width/height",
variable=self.variables["radio"],
value="size",
state=tkinter.DISABLED,
name="size_radio",
).grid(row=0, column=0, columnspan=3, sticky=tkinter.W)
OptionMenu(
self,
self.variables["dropdown"],
*PAGE_SIZES.keys(),
# state=tkinter.DISABLED,
2019-07-03 13:24:04 +00:00
name="size_dropdown",
2019-06-30 23:39:09 +00:00
).grid(row=1, column=0, columnspan=3, sticky=tkinter.W, padx=(27, 0))
tkinter.Label(
self, text="Width:", state=tkinter.DISABLED, name="size_label_width"
).grid(row=2, column=0, sticky=tkinter.W, padx=(27, 0))
tkinter.Spinbox(
self,
format="%.2f",
increment=0.1,
from_=0,
to=10000,
width=5,
textvariable=self.variables["width"],
state=tkinter.DISABLED,
name="size_spinbox_width",
).grid(row=2, column=1, sticky=tkinter.W)
tkinter.Label(
self, text="mm", state=tkinter.DISABLED, name="size_label_width_mm"
).grid(row=2, column=2, sticky=tkinter.W)
tkinter.Label(
self, text="Height:", state=tkinter.DISABLED, name="size_label_height"
).grid(row=3, column=0, sticky=tkinter.W, padx=(27, 0))
tkinter.Spinbox(
self,
format="%.2f",
increment=0.1,
from_=0,
to=10000,
width=5,
textvariable=self.variables["height"],
state=tkinter.DISABLED,
name="size_spinbox_height",
).grid(row=3, column=1, sticky=tkinter.W)
tkinter.Label(
self, text="mm", state=tkinter.DISABLED, name="size_label_height_mm"
).grid(row=3, column=2, sticky=tkinter.W)
tkinter.Radiobutton(
self,
text="Factor of input page size",
variable=self.variables["radio"],
value="mult",
state=tkinter.DISABLED,
name="mult_radio",
).grid(row=4, column=0, columnspan=3, sticky=tkinter.W)
tkinter.Label(
self,
text="Multipler:",
state=tkinter.DISABLED,
name="mult_label_multiplier",
).grid(row=5, column=0, sticky=tkinter.W, padx=(27, 0))
tkinter.Spinbox(
self,
format="%.2f",
increment=0.01,
from_=0,
to=10000,
width=6,
textvariable=self.variables["multiplier"],
state=tkinter.DISABLED,
name="mult_spinbox_multiplier",
).grid(row=5, column=1, sticky=tkinter.W)
tkinter.Label(
self, text="%", state=tkinter.DISABLED, name="mult_label_perc"
).grid(row=5, column=2, sticky=tkinter.W)
tkinter.Radiobutton(
self,
text="Fit into X output pages",
variable=self.variables["radio"],
value="npages",
state=tkinter.DISABLED,
name="npages_radio",
).grid(row=6, column=0, columnspan=3, sticky=tkinter.W)
tkinter.Label(
self, text="# of pages:", state=tkinter.DISABLED, name="npages_label"
).grid(row=7, column=0, sticky=tkinter.W, padx=(27, 0))
tkinter.Spinbox(
self,
increment=1,
from_=1,
to=10000,
width=6,
textvariable=self.variables["pages"],
state=tkinter.DISABLED,
name="npages_spinbox",
).grid(row=7, column=1, sticky=tkinter.W)
def on_radio(self, value):
_, size, mult, npages = self.value
self.set(value, size, mult, npages)
def on_dropdown(self, value):
mode, (custom_size, size), mult, npages = self.value
if value == "custom":
custom_size = True
else:
custom_size = False
size = PAGE_SIZES[value]
self.set(mode, (custom_size, size), mult, npages)
def on_width(self, value):
if getattr(self, "value", None) is None:
return
mode, (custom_size, (_, height)), mult, npages = self.value
self.set(mode, (custom_size, (value, height)), mult, npages)
def on_height(self, value):
if getattr(self, "value", None) is None:
return
mode, (custom_size, (width, _)), mult, npages = self.value
self.set(mode, (custom_size, (width, value)), mult, npages)
def on_multiplier(self, value):
if getattr(self, "value", None) is None:
return
mode, size, _, npages = self.value
self.set(mode, size, value, npages)
def on_pages(self, value):
if getattr(self, "value", None) is None:
return
mode, size, mult, _ = self.value
self.set(mode, size, mult, value)
def set(self, mode, size, mult, npages):
# before setting self.value, check if the effective value is different
# from before or otherwise we do not need to execute the callback in
# the end
state_changed = True
if getattr(self, "value", None) is not None:
if mode == self.value[0] == "size":
state_changed = self.value[1][1] != size[1]
elif mode == self.value[0] == "mult":
state_changed = self.value[2] != mult
elif mode == self.value[0] == "npages":
state_changed = self.value[3] != npages
# execute callback if necessary
if state_changed and self.callback is not None:
mode, size, mult, npages = self.callback((mode, size, mult, npages))
self.value = (mode, size, mult, npages)
custom_size, (width, height) = size
# cycle through all widgets and set the state accordingly
for k, v in self.children.items():
if k.endswith("_radio"):
v.configure(state=tkinter.NORMAL)
continue
if not k.startswith(mode + "_"):
v.configure(state=tkinter.DISABLED)
continue
if k in ["size_dropdown", "size_radio"]:
v.configure(state=tkinter.NORMAL)
continue
if mode != "size":
v.configure(state=tkinter.NORMAL)
continue
if custom_size:
v.configure(state=tkinter.NORMAL)
continue
v.configure(state=tkinter.DISABLED)
# only set variables that changed to not trigger multiple variable tracers
if custom_size or mode != "size":
if self.variables["dropdown"].get() != "custom":
self.variables["dropdown"].set("custom")
else:
val = dict(zip(PAGE_SIZES.values(), PAGE_SIZES.keys()))[(width, height)]
if self.variables["dropdown"].get() != val:
self.variables["dropdown"].set(val)
if self.variables["radio"].get() != mode:
self.variables["radio"].set(mode)
if self.variables["width"].get() != width:
self.variables["width"].set(width)
if self.variables["height"].get() != height:
self.variables["height"].set(height)
if self.variables["multiplier"].get() != mult:
self.variables["multiplier"].set(mult)
if self.variables["pages"].get() != npages:
self.variables["pages"].set(npages)
2019-07-03 08:52:40 +00:00
def compute_layout(
2019-07-03 13:24:04 +00:00
infile,
outfile,
mode,
size=None,
mult=None,
npages=None,
2019-07-04 05:59:19 +00:00
pagenr=0,
2019-07-03 13:24:04 +00:00
pagesize=(210, 297),
border=(0, 0, 0, 0),
2019-07-03 08:52:40 +00:00
):
2019-07-04 05:59:19 +00:00
plakativ = Plakativ(infile, pagenr)
2019-07-03 13:24:04 +00:00
plakativ.compute_layout(mode, size, mult, npages, pagesize, border)
2019-06-30 23:39:09 +00:00
plakativ.render(outfile)
def gui():
root = tkinter.Tk()
app = Application(master=root)
app.mainloop()
def main():
parser = argparse.ArgumentParser()
gui_group = parser.add_mutually_exclusive_group(required=False)
gui_group.add_argument(
"--gui",
dest="gui",
action="store_true",
help="run tkinter gui (default on Windows)",
)
gui_group.add_argument(
"--nogui",
dest="gui",
action="store_false",
help="don't run tkinter gui (default elsewhere)",
)
if platform.system() == "Windows":
parser.set_defaults(gui=True)
else:
parser.set_defaults(gui=False)
2019-07-03 08:52:40 +00:00
parser.add_argument(
"--mode", choices=["size", "mult", "npages"], help="select poster size"
)
2019-06-30 23:39:09 +00:00
parser.add_argument("-o", "--output", help="output file")
parser.add_argument("input", nargs="?", help="input file")
args = parser.parse_args()
if args.gui:
gui()
sys.exit(0)
2019-06-30 23:39:09 +00:00
2019-07-03 08:52:40 +00:00
compute_layout(args.input, args.output, mode=args.mode, size=(297, 420))
2019-06-30 23:39:09 +00:00
2019-07-02 09:55:27 +00:00
2019-06-30 23:39:09 +00:00
if __name__ == "__main__":
main()
__all__ = ["Plakativ", "compute_layout"]