diff --git a/src/calibre/ebooks/conversion/config.py b/src/calibre/ebooks/conversion/config.py
index 8ec90b9481..530dc04177 100644
--- a/src/calibre/ebooks/conversion/config.py
+++ b/src/calibre/ebooks/conversion/config.py
@@ -304,7 +304,7 @@ OPTIONS = {
'pdf_footer_template', 'pdf_header_template', 'pdf_add_toc',
'toc_title', 'pdf_page_margin_left', 'pdf_page_margin_top',
'pdf_page_margin_right', 'pdf_page_margin_bottom',
- 'pdf_use_document_margins', 'pdf_page_number_map',),
+ 'pdf_use_document_margins', 'pdf_page_number_map', 'pdf_odd_even_offset'),
'pml': ('inline_toc', 'full_image_depth', 'pml_output_encoding'),
diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py
index 72a4e0994f..81971289dc 100644
--- a/src/calibre/ebooks/conversion/plugins/pdf_output.py
+++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py
@@ -130,6 +130,18 @@ class PDFOutput(OutputFormatPlugin):
recommended_value=False, help=_(
'Generate an uncompressed PDF, useful for debugging.')
),
+ OptionRecommendation(name='pdf_odd_even_offset', recommended_value=0.0,
+ level=OptionRecommendation.LOW,
+ help=_(
+ 'Shift the text horizontally by the specified offset (in pts).'
+ ' On odd numbered pages, it is shifted to the right and on even'
+ ' numbered pages to the left. Use negative numbers for the opposite'
+ ' effect. Note that this setting is ignored on pages where the margins'
+ ' are smaller than the specified offset. Shifting is done by setting'
+ ' the PDF CropBox, not all software respects the CropBox.'
+ )
+ ),
+
}
def specialize_options(self, log, opts, input_fmt):
diff --git a/src/calibre/ebooks/pdf/html_writer.py b/src/calibre/ebooks/pdf/html_writer.py
index b386b48f7c..dc4d0a40c3 100644
--- a/src/calibre/ebooks/pdf/html_writer.py
+++ b/src/calibre/ebooks/pdf/html_writer.py
@@ -1213,6 +1213,16 @@ def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, co
if num_removed:
log('Removed', num_removed, 'duplicate images')
+ if opts.pdf_odd_even_offset:
+ for i in range(1, pdf_doc.page_count()):
+ margins = page_margins_map[i]
+ mult = -1 if i % 2 else 1
+ val = opts.pdf_odd_even_offset
+ if abs(val) < min(margins.left, margins.right):
+ box = list(pdf_doc.get_page_box("CropBox", i))
+ box[0] += val * mult
+ pdf_doc.set_page_box("CropBox", i, *box)
+
if cover_data:
add_cover(pdf_doc, cover_data, page_layout, opts)
diff --git a/src/calibre/gui2/convert/pdf_output.ui b/src/calibre/gui2/convert/pdf_output.ui
index 95a92a2344..0af14e0d15 100644
--- a/src/calibre/gui2/convert/pdf_output.ui
+++ b/src/calibre/gui2/convert/pdf_output.ui
@@ -7,7 +7,7 @@
0
0
638
- 634
+ 665
@@ -210,14 +210,14 @@
-
- -
+
-
Page margins
- -
+
-
Page headers and footers
@@ -272,6 +272,32 @@
+ -
+
+
+ Odd/even &offset:
+
+
+ opt_pdf_odd_even_offset
+
+
+
+ -
+
+
+ pt
+
+
+ 1
+
+
+ -100000.000000000000000
+
+
+ 100000.000000000000000
+
+
+
diff --git a/src/pyj/book_list/conversion_widgets.pyj b/src/pyj/book_list/conversion_widgets.pyj
index ef6068ef21..d4a482435c 100644
--- a/src/pyj/book_list/conversion_widgets.pyj
+++ b/src/pyj/book_list/conversion_widgets.pyj
@@ -664,6 +664,7 @@ def pdf_output(container):
g.appendChild(float_spin('pdf_page_margin_top', indent + _('Top page margin'), unit='pt', min=-100, max=500))
g.appendChild(float_spin('pdf_page_margin_right', indent + _('Right page margin'), unit='pt', min=-100, max=500))
g.appendChild(float_spin('pdf_page_margin_bottom', indent + _('Bottom page margin'), unit='pt', min=-100, max=500))
+ g.appendChild(float_spin('pdf_odd_even_offset', indent + _('Odd/event offset'), unit='pt', min=-500, max=500))
g.appendChild(lineedit('pdf_header_template', _('&Header template:')))
g.appendChild(lineedit('pdf_footer_template', _('&Footer template:')))
# }}}