Update ODT handling of font

This commit is contained in:
Veronica Berglyd Olsen
2024-05-22 17:28:29 +02:00
parent 76e786d961
commit 7f3da655c0
2 changed files with 59 additions and 40 deletions
+1 -2
View File
@@ -36,7 +36,6 @@ from time import time
from PyQt5.QtCore import QCoreApplication, QRegularExpression from PyQt5.QtCore import QCoreApplication, QRegularExpression
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from novelwriter import CONFIG
from novelwriter.common import checkInt, formatTimeStamp, numberToRoman from novelwriter.common import checkInt, formatTimeStamp, numberToRoman
from novelwriter.constants import ( from novelwriter.constants import (
nwHeadFmt, nwKeyWords, nwLabels, nwRegEx, nwShortcode, nwUnicode, trConst nwHeadFmt, nwKeyWords, nwLabels, nwRegEx, nwShortcode, nwUnicode, trConst
@@ -141,7 +140,7 @@ class Tokenizer(ABC):
self._markdown: list[str] = [] self._markdown: list[str] = []
# User Settings # User Settings
self._textFont = CONFIG.textFont # Output text font self._textFont = QFont("Serif", 11) # Output text font
self._lineHeight = 1.15 # Line height in units of em self._lineHeight = 1.15 # Line height in units of em
self._blockIndent = 4.00 # Block indent in units of em self._blockIndent = 4.00 # Block indent in units of em
self._firstIndent = False # Enable first line indent self._firstIndent = False # Enable first line indent
+58 -38
View File
@@ -35,11 +35,14 @@ from hashlib import sha256
from pathlib import Path from pathlib import Path
from zipfile import ZipFile from zipfile import ZipFile
from PyQt5.QtGui import QFont
from novelwriter import __version__ from novelwriter import __version__
from novelwriter.common import xmlIndent from novelwriter.common import xmlIndent
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import T_Formats, Tokenizer, stripEscape from novelwriter.core.tokenizer import T_Formats, Tokenizer, stripEscape
from novelwriter.types import FONT_WEIGHTS
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -108,6 +111,10 @@ S_TEXT = "Text_20_body"
S_META = "Text_20_Meta" S_META = "Text_20_Meta"
S_HNF = "Header_20_and_20_Footer" S_HNF = "Header_20_and_20_Footer"
# Font Data
FONT_WEIGHT_NUM = ["100", "200", "300", "400", "500", "600", "700", "800", "900"]
FONT_WEIGHT_MAP = {"400": "normal", "700": "bold"}
class ToOdt(Tokenizer): class ToOdt(Tokenizer):
"""Core: Open Document Writer """Core: Open Document Writer
@@ -149,16 +156,17 @@ class ToOdt(Tokenizer):
self._errData = [] # List of errors encountered self._errData = [] # List of errors encountered
# Properties # Properties
self._textFont = "Liberation Serif" self._textFont = QFont("Liberation Serif", 12)
self._textSize = 12
self._textFixed = False
self._colourHead = False self._colourHead = False
self._headerFormat = "" self._headerFormat = ""
self._pageOffset = 0 self._pageOffset = 0
# Internal # Internal
self._fontFamily = "'Liberation Serif'" self._fontFamily = "Liberation Serif"
self._fontSize = 12
self._fontWeight = "normal"
self._fontPitch = "variable" self._fontPitch = "variable"
self._fontBold = "bold"
self._fSizeTitle = "30pt" self._fSizeTitle = "30pt"
self._fSizeHead1 = "24pt" self._fSizeHead1 = "24pt"
self._fSizeHead2 = "20pt" self._fSizeHead2 = "20pt"
@@ -260,19 +268,24 @@ class ToOdt(Tokenizer):
# Initialise Variables # Initialise Variables
# ==================== # ====================
self._fontFamily = self._textFont intWeight = FONT_WEIGHTS.get(self._textFont.weight(), 400)
if len(self._textFont.split()) > 1: fontWeight = str(intWeight)
self._fontFamily = f"'{self._textFont}'" fontBold = str(min(intWeight + 300, 900))
self._fontPitch = "fixed" if self._textFixed else "variable"
self._fSizeTitle = f"{round(2.50 * self._textSize):d}pt" self._fontFamily = self._textFont.family()
self._fSizeHead1 = f"{round(2.00 * self._textSize):d}pt" self._fontSize = self._textFont.pointSize()
self._fSizeHead2 = f"{round(1.60 * self._textSize):d}pt" self._fontWeight = FONT_WEIGHT_MAP.get(fontWeight, fontWeight)
self._fSizeHead3 = f"{round(1.30 * self._textSize):d}pt" self._fontPitch = "fixed" if self._textFont.fixedPitch() else "variable"
self._fSizeHead4 = f"{round(1.15 * self._textSize):d}pt" self._fontBold = FONT_WEIGHT_MAP.get(fontBold, fontBold)
self._fSizeHead = f"{round(1.15 * self._textSize):d}pt"
self._fSizeText = f"{self._textSize:d}pt" self._fSizeTitle = f"{round(2.50 * self._fontSize):d}pt"
self._fSizeFoot = f"{round(0.8*self._textSize):d}pt" self._fSizeHead1 = f"{round(2.00 * self._fontSize):d}pt"
self._fSizeHead2 = f"{round(1.60 * self._fontSize):d}pt"
self._fSizeHead3 = f"{round(1.30 * self._fontSize):d}pt"
self._fSizeHead4 = f"{round(1.15 * self._fontSize):d}pt"
self._fSizeHead = f"{round(1.15 * self._fontSize):d}pt"
self._fSizeText = f"{self._fontSize:d}pt"
self._fSizeFoot = f"{round(0.8*self._fontSize):d}pt"
mScale = self._lineHeight/1.15 mScale = self._lineHeight/1.15
@@ -320,8 +333,9 @@ class ToOdt(Tokenizer):
tAttr[_mkTag("office", "version")] = X_VERS tAttr[_mkTag("office", "version")] = X_VERS
fAttr = {} fAttr = {}
fAttr[_mkTag("style", "name")] = self._textFont fAttr[_mkTag("style", "name")] = self._fontFamily
fAttr[_mkTag("style", "font-pitch")] = self._fontPitch fAttr[_mkTag("style", "font-pitch")] = self._fontPitch
fAttr[_mkTag("style", "font-weight")] = self._fontWeight
if self._isFlat: if self._isFlat:
@@ -726,7 +740,7 @@ class ToOdt(Tokenizer):
style = ODTTextStyle(f"T{len(self._autoText)+1:d}") style = ODTTextStyle(f"T{len(self._autoText)+1:d}")
if hFmt & X_BLD: if hFmt & X_BLD:
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
if hFmt & X_ITA: if hFmt & X_ITA:
style.setFontStyle("italic") style.setFontStyle("italic")
if hFmt & X_DEL: if hFmt & X_DEL:
@@ -764,7 +778,7 @@ class ToOdt(Tokenizer):
def _emToCm(self, value: float) -> str: def _emToCm(self, value: float) -> str:
"""Converts an em value to centimetres.""" """Converts an em value to centimetres."""
return f"{value*2.54/72*self._textSize:.3f}cm" return f"{value*2.54/72*self._fontSize:.3f}cm"
## ##
# Style Elements # Style Elements
@@ -808,8 +822,9 @@ class ToOdt(Tokenizer):
_mkTag("style", "writing-mode"): "page", _mkTag("style", "writing-mode"): "page",
}) })
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
_mkTag("style", "font-name"): self._textFont, _mkTag("style", "font-name"): self._fontFamily,
_mkTag("fo", "font-family"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily,
_mkTag("fo", "font-weight"): self._fontWeight,
_mkTag("fo", "font-size"): self._fSizeText, _mkTag("fo", "font-size"): self._fSizeText,
_mkTag("fo", "language"): self._dLanguage, _mkTag("fo", "language"): self._dLanguage,
_mkTag("fo", "country"): self._dCountry, _mkTag("fo", "country"): self._dCountry,
@@ -822,8 +837,9 @@ class ToOdt(Tokenizer):
_mkTag("style", "class"): "text", _mkTag("style", "class"): "text",
}) })
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
_mkTag("style", "font-name"): self._textFont, _mkTag("style", "font-name"): self._fontFamily,
_mkTag("fo", "font-family"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily,
_mkTag("fo", "font-weight"): self._fontWeight,
_mkTag("fo", "font-size"): self._fSizeText, _mkTag("fo", "font-size"): self._fSizeText,
}) })
@@ -841,8 +857,9 @@ class ToOdt(Tokenizer):
_mkTag("fo", "keep-with-next"): "always", _mkTag("fo", "keep-with-next"): "always",
}) })
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={ ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
_mkTag("style", "font-name"): self._textFont, _mkTag("style", "font-name"): self._fontFamily,
_mkTag("fo", "font-family"): self._fontFamily, _mkTag("fo", "font-family"): self._fontFamily,
_mkTag("fo", "font-weight"): self._fontWeight,
_mkTag("fo", "font-size"): self._fSizeHead, _mkTag("fo", "font-size"): self._fSizeHead,
}) })
@@ -868,9 +885,10 @@ class ToOdt(Tokenizer):
style.setMarginBottom(self._mBotText) style.setMarginBottom(self._mBotText)
style.setLineHeight(self._fLineHeight) style.setLineHeight(self._fLineHeight)
style.setTextAlign(self._textAlign) style.setTextAlign(self._textAlign)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeText) style.setFontSize(self._fSizeText)
style.setFontWeight(self._fontWeight)
style.packXML(self._xStyl) style.packXML(self._xStyl)
self._mainPara[style.name] = style self._mainPara[style.name] = style
@@ -891,9 +909,10 @@ class ToOdt(Tokenizer):
style.setMarginTop(self._mTopMeta) style.setMarginTop(self._mTopMeta)
style.setMarginBottom(self._mBotMeta) style.setMarginBottom(self._mBotMeta)
style.setLineHeight(self._fLineHeight) style.setLineHeight(self._fLineHeight)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeText) style.setFontSize(self._fSizeText)
style.setFontWeight(self._fontWeight)
style.setColour(self._colMetaTx) style.setColour(self._colMetaTx)
style.setOpacity(self._opaMetaTx) style.setOpacity(self._opaMetaTx)
style.packXML(self._xStyl) style.packXML(self._xStyl)
@@ -908,10 +927,10 @@ class ToOdt(Tokenizer):
style.setMarginTop(self._mTopTitle) style.setMarginTop(self._mTopTitle)
style.setMarginBottom(self._mBotTitle) style.setMarginBottom(self._mBotTitle)
style.setTextAlign("center") style.setTextAlign("center")
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeTitle) style.setFontSize(self._fSizeTitle)
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
style.packXML(self._xStyl) style.packXML(self._xStyl)
self._mainPara[style.name] = style self._mainPara[style.name] = style
@@ -925,9 +944,10 @@ class ToOdt(Tokenizer):
style.setMarginBottom(self._mBotText) style.setMarginBottom(self._mBotText)
style.setLineHeight(self._fLineHeight) style.setLineHeight(self._fLineHeight)
style.setTextAlign("center") style.setTextAlign("center")
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeText) style.setFontSize(self._fSizeText)
style.setFontWeight(self._fontWeight)
style.packXML(self._xStyl) style.packXML(self._xStyl)
self._mainPara[style.name] = style self._mainPara[style.name] = style
@@ -940,10 +960,10 @@ class ToOdt(Tokenizer):
style.setClass("text") style.setClass("text")
style.setMarginTop(self._mTopHead1) style.setMarginTop(self._mTopHead1)
style.setMarginBottom(self._mBotHead1) style.setMarginBottom(self._mBotHead1)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeHead1) style.setFontSize(self._fSizeHead1)
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
style.setColour(self._colHead12) style.setColour(self._colHead12)
style.setOpacity(self._opaHead12) style.setOpacity(self._opaHead12)
style.packXML(self._xStyl) style.packXML(self._xStyl)
@@ -958,10 +978,10 @@ class ToOdt(Tokenizer):
style.setClass("text") style.setClass("text")
style.setMarginTop(self._mTopHead2) style.setMarginTop(self._mTopHead2)
style.setMarginBottom(self._mBotHead2) style.setMarginBottom(self._mBotHead2)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeHead2) style.setFontSize(self._fSizeHead2)
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
style.setColour(self._colHead12) style.setColour(self._colHead12)
style.setOpacity(self._opaHead12) style.setOpacity(self._opaHead12)
style.packXML(self._xStyl) style.packXML(self._xStyl)
@@ -976,10 +996,10 @@ class ToOdt(Tokenizer):
style.setClass("text") style.setClass("text")
style.setMarginTop(self._mTopHead3) style.setMarginTop(self._mTopHead3)
style.setMarginBottom(self._mBotHead3) style.setMarginBottom(self._mBotHead3)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeHead3) style.setFontSize(self._fSizeHead3)
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
style.setColour(self._colHead34) style.setColour(self._colHead34)
style.setOpacity(self._opaHead34) style.setOpacity(self._opaHead34)
style.packXML(self._xStyl) style.packXML(self._xStyl)
@@ -994,10 +1014,10 @@ class ToOdt(Tokenizer):
style.setClass("text") style.setClass("text")
style.setMarginTop(self._mTopHead4) style.setMarginTop(self._mTopHead4)
style.setMarginBottom(self._mBotHead4) style.setMarginBottom(self._mBotHead4)
style.setFontName(self._textFont) style.setFontName(self._fontFamily)
style.setFontFamily(self._fontFamily) style.setFontFamily(self._fontFamily)
style.setFontSize(self._fSizeHead4) style.setFontSize(self._fSizeHead4)
style.setFontWeight("bold") style.setFontWeight(self._fontBold)
style.setColour(self._colHead34) style.setColour(self._colHead34)
style.setOpacity(self._opaHead34) style.setOpacity(self._opaHead34)
style.packXML(self._xStyl) style.packXML(self._xStyl)
@@ -1077,7 +1097,7 @@ class ODTParagraphStyle:
VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"] VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"]
VALID_LEVEL = ["1", "2", "3", "4"] VALID_LEVEL = ["1", "2", "3", "4"]
VALID_CLASS = ["text", "chapter", "extra"] VALID_CLASS = ["text", "chapter", "extra"]
VALID_WEIGHT = ["normal", "inherit", "bold"] VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
def __init__(self, name: str) -> None: def __init__(self, name: str) -> None:
@@ -1320,8 +1340,8 @@ class ODTTextStyle:
Only the used settings are exposed here to keep the class minimal Only the used settings are exposed here to keep the class minimal
and fast. and fast.
""" """
VALID_WEIGHT = ["normal", "inherit", "bold"] VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
VALID_STYLE = ["normal", "inherit", "italic"] VALID_STYLE = ["normal", "italic", "oblique"]
VALID_POS = ["super", "sub"] VALID_POS = ["super", "sub"]
VALID_LSTYLE = ["none", "solid"] VALID_LSTYLE = ["none", "solid"]
VALID_LTYPE = ["single", "double"] VALID_LTYPE = ["single", "double"]