From 4fc69ef7c620cbaefa5569ef8ccdc3f480dfbb2b Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:17:54 +0100 Subject: [PATCH 1/6] Replace printer with Qt's PDF writer --- novelwriter/formats/toqdoc.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index bd9b3cb1..f427aa79 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -29,10 +29,9 @@ from pathlib import Path from PyQt5.QtCore import QMarginsF, QSizeF from PyQt5.QtGui import ( - QColor, QFont, QFontMetricsF, QPageSize, QTextBlockFormat, QTextCharFormat, - QTextCursor, QTextDocument + QColor, QFont, QFontMetricsF, QPageLayout, QPageSize, QPdfWriter, + QTextBlockFormat, QTextCharFormat, QTextCursor, QTextDocument ) -from PyQt5.QtPrintSupport import QPrinter from novelwriter.constants import nwStyles, nwUnicode from novelwriter.core.project import NWProject @@ -67,7 +66,7 @@ class ToQTextDocument(Tokenizer): super().__init__(project) self._document = QTextDocument() self._document.setUndoRedoEnabled(False) - self._document.setDocumentMargin(0) + self._document.setDocumentMargin(0.0) self._usedNotes: dict[str, int] = {} self._usedFields: list[tuple[int, str]] = [] @@ -241,17 +240,14 @@ class ToQTextDocument(Tokenizer): def saveDocument(self, path: Path) -> None: """Save the document as a PDF file.""" - m = self._pageMargins - - printer = QPrinter(QPrinter.PrinterMode.PrinterResolution) - printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat) - printer.setPageSize(self._pageSize) - printer.setPageMargins(m.left(), m.top(), m.right(), m.bottom(), QPrinter.Unit.Millimeter) - printer.setOutputFileName(str(path)) - - self._document.setPageSize(self._pageSize.size(QPageSize.Unit.Point)) - self._document.print(printer) - + writer = QPdfWriter(str(path)) + writer.setTitle(self._project.data.name) + writer.setPageSize(self._pageSize) + writer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter) + writer.setResolution(1200) + self._document.setDocumentMargin(0.0) + self._document.setPageSize(QSizeF(writer.pageLayout().paintRectPoints().size())*16/12) + self._document.print(writer) return def closeDocument(self) -> None: From 7c0a6f1d0234abac1d6000e205e8933d22f13e33 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:18:22 +0100 Subject: [PATCH 2/6] Use correct em calculation in qdoc class --- novelwriter/formats/toqdoc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index f427aa79..065b9842 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -29,8 +29,8 @@ from pathlib import Path from PyQt5.QtCore import QMarginsF, QSizeF from PyQt5.QtGui import ( - QColor, QFont, QFontMetricsF, QPageLayout, QPageSize, QPdfWriter, - QTextBlockFormat, QTextCharFormat, QTextCursor, QTextDocument + QColor, QFont, QPageLayout, QPageSize, QPdfWriter, QTextBlockFormat, + QTextCharFormat, QTextCursor, QTextDocument ) from novelwriter.constants import nwStyles, nwUnicode @@ -120,9 +120,8 @@ class ToQTextDocument(Tokenizer): self._document.clear() self._document.setDefaultFont(self._textFont) - qMetric = QFontMetricsF(self._textFont) - mPx = qMetric.ascent() # 1 em in pixels fPt = self._textFont.pointSizeF() + mPx = fPt*90.0/72.0 # 1 em in pixels # Scaled Sizes # ============ From 22ca0045bcc1ad10aac810dca7fd23772a22108d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:40:58 +0100 Subject: [PATCH 3/6] Correct font scaling on PDF output --- novelwriter/formats/toqdoc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index 065b9842..a5c67743 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -244,9 +244,15 @@ class ToQTextDocument(Tokenizer): writer.setPageSize(self._pageSize) writer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter) writer.setResolution(1200) + + # We need to correct for a discrepancy between screen resolution + # (96 DPI) and the one used for font size (72 DPI). See #2100. + adjustedSize = writer.pageLayout().paintRect(QPageLayout.Unit.Point).size()*96.0/72.0 + self._document.setDocumentMargin(0.0) - self._document.setPageSize(QSizeF(writer.pageLayout().paintRectPoints().size())*16/12) + self._document.setPageSize(adjustedSize) self._document.print(writer) + return def closeDocument(self) -> None: From 69147c2480b6b29853604bab2e43299600115f4d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 15 Nov 2024 01:27:49 +0100 Subject: [PATCH 4/6] Correct pixel units --- novelwriter/formats/toqdoc.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index a5c67743..407943d7 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -121,17 +121,17 @@ class ToQTextDocument(Tokenizer): self._document.setDefaultFont(self._textFont) fPt = self._textFont.pointSizeF() - mPx = fPt*90.0/72.0 # 1 em in pixels + fPx = fPt*96.0/72.0 # 1 em in pixels # Scaled Sizes # ============ self._mHead = { - BlockTyp.TITLE: (mPx * self._marginTitle[0], mPx * self._marginTitle[1]), - BlockTyp.HEAD1: (mPx * self._marginHead1[0], mPx * self._marginHead1[1]), - BlockTyp.HEAD2: (mPx * self._marginHead2[0], mPx * self._marginHead2[1]), - BlockTyp.HEAD3: (mPx * self._marginHead3[0], mPx * self._marginHead3[1]), - BlockTyp.HEAD4: (mPx * self._marginHead4[0], mPx * self._marginHead4[1]), + BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]), + BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]), + BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]), + BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]), + BlockTyp.HEAD4: (fPx * self._marginHead4[0], fPx * self._marginHead4[1]), } hScale = self._scaleHeads @@ -143,12 +143,12 @@ class ToQTextDocument(Tokenizer): BlockTyp.HEAD4: (nwStyles.H_SIZES.get(4, 1.0) * fPt) if hScale else fPt, } - self._mText = (mPx * self._marginText[0], mPx * self._marginText[1]) - self._mMeta = (mPx * self._marginMeta[0], mPx * self._marginMeta[1]) - self._mSep = (mPx * self._marginSep[0], mPx * self._marginSep[1]) + self._mText = (fPx * self._marginText[0], fPx * self._marginText[1]) + self._mMeta = (fPx * self._marginMeta[0], fPx * self._marginMeta[1]) + self._mSep = (fPx * self._marginSep[0], fPx * self._marginSep[1]) - self._mIndent = mPx * 2.0 - self._tIndent = mPx * self._firstWidth + self._mIndent = fPx * 2.0 + self._tIndent = fPx * self._firstWidth # Text Formats # ============ @@ -245,12 +245,8 @@ class ToQTextDocument(Tokenizer): writer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter) writer.setResolution(1200) - # We need to correct for a discrepancy between screen resolution - # (96 DPI) and the one used for font size (72 DPI). See #2100. - adjustedSize = writer.pageLayout().paintRect(QPageLayout.Unit.Point).size()*96.0/72.0 - - self._document.setDocumentMargin(0.0) - self._document.setPageSize(adjustedSize) + # The document needs size in pixels. See #2100. + self._document.setPageSize(QSizeF(writer.pageLayout().paintRectPixels(96).size())) self._document.print(writer) return From 2c031bc093dcad3c2255c1e74748fa132078ff5d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 15 Nov 2024 01:34:02 +0100 Subject: [PATCH 5/6] Skip anchors when generating PDF --- novelwriter/core/docbuild.py | 1 + novelwriter/formats/toqdoc.py | 30 ++++++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py index 96d88145..5cbdfc0a 100644 --- a/novelwriter/core/docbuild.py +++ b/novelwriter/core/docbuild.py @@ -176,6 +176,7 @@ class NWBuildDocument: elif bFormat == nwBuildFmt.PDF: makeObj = ToQTextDocument(self._project) + makeObj.disableAnchors() filtered = self._setupBuild(makeObj) makeObj.initDocument() yield from self._iterBuild(makeObj, filtered) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index 407943d7..eb5592b5 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -75,6 +75,7 @@ class ToQTextDocument(Tokenizer): self._bold = QFont.Weight.Bold self._normal = QFont.Weight.Normal self._newPage = False + self._anchors = True self._pageSize = QPageSize(QPageSize.PageSizeId.A4) self._pageMargins = QMarginsF(20.0, 20.0, 20.0, 20.0) @@ -107,6 +108,11 @@ class ToQTextDocument(Tokenizer): self._newPage = state return + def disableAnchors(self) -> None: + """Disable anchors for when writing to file.""" + self._anchors = False + return + ## # Class Methods ## @@ -341,18 +347,22 @@ class ToQTextDocument(Tokenizer): cFmt.setForeground(self._theme.text) primary = None elif fmt == TextFmt.ANM_B: - cFmt.setAnchor(True) - cFmt.setAnchorNames([data]) + if self._anchors: + cFmt.setAnchor(True) + cFmt.setAnchorNames([data]) elif fmt == TextFmt.ANM_E: - cFmt.setAnchor(False) + if self._anchors: + cFmt.setAnchor(False) elif fmt == TextFmt.ARF_B: - cFmt.setFontUnderline(True) - cFmt.setAnchor(True) - cFmt.setAnchorHref(data) + if self._anchors: + cFmt.setFontUnderline(True) + cFmt.setAnchor(True) + cFmt.setAnchorHref(data) elif fmt == TextFmt.ARF_E: - cFmt.setFontUnderline(False) - cFmt.setAnchor(False) - cFmt.setAnchorHref("") + if self._anchors: + cFmt.setFontUnderline(False) + cFmt.setAnchor(False) + cFmt.setAnchorHref("") elif fmt == TextFmt.HRF_B: cFmt.setForeground(self._theme.link) cFmt.setFontUnderline(True) @@ -426,7 +436,7 @@ class ToQTextDocument(Tokenizer): cFmt.setForeground(self._theme.head if hCol else self._theme.text) cFmt.setFontWeight(self._bold if self._boldHeads else self._normal) cFmt.setFontPointSize(self._sHead.get(hType, 1.0)) - if hKey: + if hKey and self._anchors: cFmt.setAnchorNames([hKey]) cFmt.setAnchor(True) From f3c9a7798967e480b2ae482d06700a9325b3563d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 15 Nov 2024 19:31:55 +0100 Subject: [PATCH 6/6] Revert to QPrinter, but update paint device --- novelwriter/formats/toqdoc.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index eb5592b5..1787413e 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -29,10 +29,12 @@ from pathlib import Path from PyQt5.QtCore import QMarginsF, QSizeF from PyQt5.QtGui import ( - QColor, QFont, QPageLayout, QPageSize, QPdfWriter, QTextBlockFormat, - QTextCharFormat, QTextCursor, QTextDocument + QColor, QFont, QPageSize, QTextBlockFormat, QTextCharFormat, QTextCursor, + QTextDocument ) +from PyQt5.QtPrintSupport import QPrinter +from novelwriter import __version__ from novelwriter.constants import nwStyles, nwUnicode from novelwriter.core.project import NWProject from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt @@ -245,15 +247,19 @@ class ToQTextDocument(Tokenizer): def saveDocument(self, path: Path) -> None: """Save the document as a PDF file.""" - writer = QPdfWriter(str(path)) - writer.setTitle(self._project.data.name) - writer.setPageSize(self._pageSize) - writer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter) - writer.setResolution(1200) + m = self._pageMargins - # The document needs size in pixels. See #2100. - self._document.setPageSize(QSizeF(writer.pageLayout().paintRectPixels(96).size())) - self._document.print(writer) + printer = QPrinter(QPrinter.PrinterMode.HighResolution) + printer.setDocName(self._project.data.name) + printer.setCreator(f"novelWriter/{__version__}") + printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat) + printer.setPageSize(self._pageSize) + printer.setPageMargins(m.left(), m.top(), m.right(), m.bottom(), QPrinter.Unit.Millimeter) + printer.setOutputFileName(str(path)) + + self._document.documentLayout().setPaintDevice(printer) + self._document.setPageSize(QSizeF(printer.pageRect().size())) + self._document.print(printer) return