Commit 61d04078 authored by Alex Bramley's avatar Alex Bramley Committed by Kjo

Add an option to support long-edge flip printing.

Some printers (and Chrome, by default) use long-edge flip when
they print PDFs, because they assume the PDF is portrait even
when it's landscape. This patch allows you to choose long-edge
flip rendering, which rotates even-numbered output pages 180°.
When printed using long-edge flip these pages will be the right
way up \o/
parent 5e040c1b
......@@ -87,7 +87,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<object class="GtkTable" id="preferences_table">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">7</property>
<property name="n_rows">8</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">12</property>
......@@ -107,6 +107,21 @@ along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Two-sided _flip</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">output_paper_format_combobox</property>
</object>
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
......@@ -136,6 +151,20 @@ along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
</packing>
</child>
<child>
<object class="GtkComboBox" id="two_sided_flip_combobox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="cb_two_sided_flip_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
......@@ -145,8 +174,8 @@ along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
<property name="mnemonic_widget">output_file_chooser_button</property>
</object>
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
......@@ -220,8 +249,8 @@ along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
......
......@@ -61,11 +61,12 @@ class ConverterPreferences(object):
def __init__(self):
self._infile_name = None
self._conversion_type = None
self.copy_pages = None
self.layout = None
self.paper_format = None
self.paper_orientation = None
self.outfile_name = None
self._copy_pages = None
self._layout = None
self._two_sided_flip = None
self._paper_format = None
self._paper_orientation = None
self._outfile_name = None
self.__outfile_name_changed = False
@property
......@@ -169,6 +170,15 @@ class ConverterPreferences(object):
self.__outfile_name_changed = True
self._outfile_name = value
@property
def two_sided_flip(self):
return self._two_sided_flip
@two_sided_flip.setter
def two_sided_flip(self, value):
# XXX : verify value
self._two_sided_flip = value
def __str__(self):
string = "ConverterPreferences object:\n"
if self._infile_name:
......@@ -183,6 +193,8 @@ class ConverterPreferences(object):
string += " paper_format: %s\n" % self._paper_format
if self._paper_orientation:
string += " paper_orientation: %s\n" % self._paper_orientation
if self._two_sided_flip:
string += " two_sided_flip: %s\n" % self._two_sided_flip
if self._copy_pages:
string += " copy_pages: %s\n" % self._copy_pages
return string
......@@ -202,6 +214,8 @@ class ConverterPreferences(object):
if self._paper_format: converter.set_output_format(self._paper_format)
if self._paper_orientation:
converter._set_output_orientation(self._paper_orientation)
if self._two_sided_flip:
converter.set_two_sided_flip(self._two_sided_flip)
if self._copy_pages: converter.set_copy_pages(self._copy_pages)
return converter
......@@ -215,6 +229,7 @@ class TypedFileConverter(pdfimposer.FileConverter):
conversion_type=ConversionType.BOOKLETIZE,
layout='2x1',
format='A4',
flip=pdfimposer.TwoSidedFlip.SHORT_EDGE,
copy_pages=False,
overwrite_outfile_callback=None):
......@@ -230,13 +245,16 @@ class TypedFileConverter(pdfimposer.FileConverter):
- `layout`: The layout of input pages on one output page (see
set_layout).
- `format`: The format of the output paper (see set_output_format).
- `flip`: Whether the output paper will be flipped on the short edge
(default) or the long edge when printing (see set_two_sided_flip).
- `copy_pages`: Wether the same group of input pages shoud be copied
to fill the corresponding output page or not (see
set_copy_pages).
"""
pdfimposer.FileConverter.__init__(self, infile_name, outfile_name,
layout, format, copy_pages, overwrite_outfile_callback)
layout, format, flip, copy_pages,
overwrite_outfile_callback)
self._conversion_type = conversion_type
# CONVERSION FUNCTIONS
......
......@@ -93,6 +93,8 @@ class BookletImposerUI(object):
self.__pages_in_height_spinbutton = builder.get_object("pages_in_height_spinbutton")
self.__paper_format_combobox = \
builder.get_object("output_paper_format_combobox")
self.__two_sided_flip_combobox = \
builder.get_object("two_sided_flip_combobox")
self.__output_file_chooser_button = self.__create_output_file_chooser_button(builder)
self.__progressbar_conversion = builder.get_object("conversion_progressbar")
self.__about_button = builder.get_object("about_button")
......@@ -103,6 +105,7 @@ class BookletImposerUI(object):
self.__about_dialog = builder.get_object("about_dialog")
self.__fill_paper_formats()
self.__fill_two_sided_flip_options()
self.__add_keybindings()
def __add_keybindings(self):
......@@ -155,6 +158,13 @@ class BookletImposerUI(object):
liststore.append([format])
self.__paper_format_combobox.set_active(1)
def __fill_two_sided_flip_options(self):
liststore = self.set_liststore_for_combobox(
self.__two_sided_flip_combobox)
liststore.append([pdfimposer.TwoSidedFlip.SHORT_EDGE])
liststore.append([pdfimposer.TwoSidedFlip.LONG_EDGE])
self.__two_sided_flip_combobox.set_active(0)
@staticmethod
def combobox_select_row(widget, row_value):
def func(model, path, iter, widget):
......@@ -179,6 +189,9 @@ class BookletImposerUI(object):
if preferences.layout:
self.__pages_in_width_spinbutton.set_value(preferences.pages_in_width)
self.__pages_in_height_spinbutton.set_value(preferences.pages_in_height)
if preferences.two_sided_flip:
self.combobox_select_row(self.__two_sided_flip_combobox,
preferences.two_sided_flip)
if preferences.paper_format:
self.combobox_select_row(self.__paper_format_combobox,
preferences.paper_format)
......@@ -222,6 +235,10 @@ class BookletImposerUI(object):
self.__preferences.paper_format = widget.get_model().get_value(
widget.get_active_iter(), 0)
def cb_two_sided_flip_changed(self, widget, data=None):
self.__preferences.two_sided_flip = widget.get_model().get_value(
widget.get_active_iter(), 0)
def cb_outfile_clicked(self, widget, data=None):
fcdialog = Gtk.FileChooserDialog(
title=_("Choose file to save"),
......
......@@ -74,6 +74,13 @@ class PageOrientation:
LANDSCAPE = True
"""The lanscape orientation"""
class TwoSidedFlip:
"""Which paper edge will the flip occur on when printing?"""
SHORT_EDGE = "short-edge flip"
"""Pages will be flipped on the short edge"""
LONG_EDGE = "long-edge flip"
"""Pages will be flipped on the long edge"""
########################################################################
class PdfConvError(Exception):
......@@ -153,6 +160,7 @@ class AbstractConverter(object):
def __init__(self,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Create an AbstractConverter instance.
......@@ -162,6 +170,9 @@ class AbstractConverter(object):
(see set_layout).
- `format` The format of the output paper (see
set_output_format).
- `flip` Render the output booklet for two-sided printing with
flipping on the short (default) or long edge. Long-edge flip
will result in even-numbered output pages being upside-down.
- `copy_pages` Wether the same group of input pages
shoud be copied to fill the corresponding output page or not
(see set_copy_pages).
......@@ -173,6 +184,7 @@ class AbstractConverter(object):
self.set_layout(layout)
self.set_output_format(format)
self.set_copy_pages(copy_pages)
self.set_two_sided_flip(flip)
def default_progress_callback(msg, prog):
print "%s (%i%%)" % (msg, prog*100)
......@@ -307,6 +319,29 @@ class AbstractConverter(object):
"""
return self.__progress_callback
def set_two_sided_flip(self, flip):
"""
Set the edge which the paper will be flipped on when printed. Defaults
to TwoSidedFlip.SHORT_EDGE, where all the output pages are the right
way up. If your printer can only flip over the long edge, set this to
TwoSidedFlip.LONG_EDGE. The imposer will rotate all even output pages
180° to compensate.
:Parameters:
- `flip` Either TwoSidedFlip.SHORT_EDGE or TwoSidedFlip.LONG_EDGE.
"""
assert(flip in (TwoSidedFlip.SHORT_EDGE, TwoSidedFlip.LONG_EDGE))
self.__two_sided_flip = flip
def get_two_sided_flip(self):
"""
Get the edge which the paper will be flipped on when printed.
:Returns:
Either TwoSidedFlip.SHORT_EDGE or TwoSidedFlip.LONG_EDGE.
"""
return self.__two_sided_flip
# SOME GETTERS THAT CALCULATE THE VALUE THEY RETURN FROM OTHER VALUES
# ===================================================================
def get_input_size(self):
......@@ -558,6 +593,7 @@ class StreamConverter(AbstractConverter):
output_stream,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Create a StreamConverter.
......@@ -575,8 +611,9 @@ class StreamConverter(AbstractConverter):
set_copy_pages).
"""
AbstractConverter.__init__(self, layout, format,
copy_pages)
AbstractConverter.__init__(self, layout, format,
flip, copy_pages)
......@@ -771,6 +808,7 @@ class StreamConverter(AbstractConverter):
outpdf = pyPdf.PdfFileWriter()
current_page = 0
output_page = 0
while current_page < len(sequence):
self.get_progress_callback()(
_("creating page %i") %
......@@ -793,7 +831,10 @@ class StreamConverter(AbstractConverter):
self.get_pages_in_height())
)
current_page += 1
if self.get_two_sided_flip() == TwoSidedFlip.LONG_EDGE and output_page % 2:
page.rotateClockwise(180)
page.compressContentStreams()
output_page += 1
self.__write_output_stream(outpdf)
def bookletize(self):
......@@ -843,6 +884,7 @@ class FileConverter(StreamConverter):
outfile_name=None,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False,
overwrite_outfile_callback=None):
"""
......@@ -895,7 +937,7 @@ class FileConverter(StreamConverter):
raise UserInterruptError()
self._output_stream = open(outfile_name, 'wb')
StreamConverter.__init__(self, self._input_stream, self._output_stream,
layout, format, copy_pages)
layout, format, flip, copy_pages)
def __del__(self):
if self._input_stream:
......@@ -967,6 +1009,7 @@ def bookletize_on_stream(input_stream,
output_stream,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Convert a linear document to a booklet.
......@@ -984,17 +1027,20 @@ def bookletize_on_stream(input_stream,
- `layout` The layout of input pages on one output page (see
set_layout).
- `format` The format of the output paper (see set_output_format).
- `flip` Whether the output paper will be flipped on the short edge
(default) or the long edge when printing (see set_two_sided_flip).
- `copy_pages` Wether the same group of input pages shoud be copied
to fill the corresponding output page or not (see
set_copy_pages).
"""
StreamConverter(layout, format, copy_pages,
StreamConverter(layout, format, flip, copy_pages,
input_stream, output_stream()).bookletize()
def bookletize_on_file(input_file,
output_file=None,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Convert a linear PDF file to a booklet.
......@@ -1012,12 +1058,14 @@ def bookletize_on_file(input_file,
- `layout` The layout of input pages on one output page (see
set_layout).
- `format` The format of the output paper (see set_output_format).
- `flip` Whether the output paper will be flipped on the short edge
(default) or the long edge when printing (see set_two_sided_flip).
- `copy_pages` Wether the same group of input pages shoud be copied
to fill the corresponding output page or not (see
set_copy_pages).
"""
FileConverter(input_file, output_file, layout, format,
copy_pages).bookletize()
flip, copy_pages).bookletize()
def linearize_on_stream(input_stream,
output_stream,
......@@ -1045,7 +1093,7 @@ def linearize_on_stream(input_stream,
set_copy_pages).
"""
StreamConverter(input_stream, output_stream, layout,
format, copy_pages).linearize()
format, TwoSidedFlip.SHORT_EDGE, copy_pages).linearize()
def linearize_on_file(input_file,
output_file=None,
......@@ -1073,12 +1121,13 @@ def linearize_on_file(input_file,
set_copy_pages).
"""
FileConverter(input_file, output_file, layout, format,
copy_pages).linearize()
flip, TwoSidedFlip.SHORT_EDGE, copy_pages).linearize()
def reduce_on_stream(input_stream,
output_stream,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Put multiple input pages on one output page.
......@@ -1093,17 +1142,20 @@ def reduce_on_stream(input_stream,
- `layout` The layout of input pages on one output page (see
set_layout).
- `format` The format of the output paper (see set_output_format).
- `flip` Whether the output paper will be flipped on the short edge
(default) or the long edge when printing (see set_two_sided_flip).
- `copy_pages` Wether the same group of input pages shoud be copied
to fill the corresponding output page or not (see
set_copy_pages).
"""
StreamConverter(input_stream, output_stream, layout, format,
copy_pages).reduce()
StreamConverter(input_stream, output_stream, layout, format,
flip, copy_pages).reduce()
def reduce_on_file(input_file,
output_file=None,
layout='2x1',
format='A4',
flip=TwoSidedFlip.SHORT_EDGE,
copy_pages=False):
"""
Put multiple input pages on one output page.
......@@ -1118,9 +1170,11 @@ def reduce_on_file(input_file,
- `layout` The layout of input pages on one output page (see
set_layout).
- `format` The format of the output paper (see set_output_format).
- `flip` Whether the output paper will be flipped on the short edge
(default) or the long edge when printing (see set_two_sided_flip).
- `copy_pages` Wether the same group of input pages shoud be copied
to fill the corresponding output page or not (see
set_copy_pages).
"""
FileConverter(input_file, output_file, layout, format,
copy_pages).reduce()
flip, copy_pages).reduce()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment