mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +00:00
See #4690. User can now configure font and font-scaling in schedules.
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
* Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
*
|
||||||
|
* This file is part of BlenderBIM Add-on.
|
||||||
|
*
|
||||||
|
* BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You may copy this `schedule.css` template alongside your input schedule
|
||||||
|
* document with the same filename. For example if you have a schedule called
|
||||||
|
* `door_types.ods`, you can create a `door_types.css` in the same folder to
|
||||||
|
* style that schedule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you specify a font size in CSS, such as text { font-size: 5; }, all fonts
|
||||||
|
* will be overriden to match that size.
|
||||||
|
*
|
||||||
|
* If your CSS, ODS, XLSX does not specify a font size, the variables below
|
||||||
|
* will specify the default font size.
|
||||||
|
*
|
||||||
|
* If your ODS, XLSX does specify a font size, they will scale linearly based
|
||||||
|
* on the variables below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--font-size-pt: 12;
|
||||||
|
--font-size-px: 4.13;
|
||||||
|
--font-width: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
text, tspan { /* 2.5mm */ fill: black; stroke: none; font-family: 'OpenGost Type B TT', 'DejaVu Sans Condensed', 'Liberation Sans', 'Arial Narrow', 'Arial'; }
|
||||||
@@ -16,22 +16,21 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
import os
|
||||||
|
import re
|
||||||
|
import bpy
|
||||||
|
import string
|
||||||
import svgwrite
|
import svgwrite
|
||||||
import openpyxl
|
import openpyxl
|
||||||
|
|
||||||
|
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
||||||
from odf.opendocument import load as load_ods
|
from odf.opendocument import load as load_ods
|
||||||
from odf.table import Table, TableRow, TableColumn, TableCell
|
from odf.table import Table, TableRow, TableColumn, TableCell
|
||||||
from odf.text import P
|
from odf.text import P
|
||||||
from odf.style import Style
|
from odf.style import Style
|
||||||
from textwrap import wrap
|
from textwrap import wrap
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import string
|
|
||||||
|
|
||||||
FONT_SIZE = 4.13
|
|
||||||
FONT_WIDTH = lambda size: size * 0.45
|
|
||||||
FONT_SIZE_PT = 12
|
|
||||||
FONT_FAMILY = "OpenGost Type B TT"
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
|
||||||
@@ -63,11 +62,29 @@ class Scheduler:
|
|||||||
)
|
)
|
||||||
self.padding = 1
|
self.padding = 1
|
||||||
self.margin = 1
|
self.margin = 1
|
||||||
|
|
||||||
|
self.parse_css(infile)
|
||||||
if infile.endswith("ods"):
|
if infile.endswith("ods"):
|
||||||
self.schedule_ods(infile, outfile)
|
self.schedule_ods(infile, outfile)
|
||||||
elif infile.endswith("xlsx"):
|
elif infile.endswith("xlsx"):
|
||||||
self.schedule_xlsx(infile, outfile)
|
self.schedule_xlsx(infile, outfile)
|
||||||
|
|
||||||
|
def parse_css(self, infile):
|
||||||
|
stylesheet_path = os.path.splitext(infile)[0] + ".css"
|
||||||
|
if not os.path.exists(stylesheet_path):
|
||||||
|
stylesheet_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "assets", "schedule.css")
|
||||||
|
with open(stylesheet_path, "r") as stylesheet:
|
||||||
|
css = stylesheet.read()
|
||||||
|
|
||||||
|
matches = re.search("--font-size-pt:\s*([0-9.]+);", css)
|
||||||
|
self.font_size_pt = float(matches.groups()[0]) if matches else 12 # Default to 12pt
|
||||||
|
matches = re.search("--font-size-px:\s*([0-9.]+);", css)
|
||||||
|
self.font_size_px = float(matches.groups()[0]) if matches else 4.13 # Magic number 4.13px ~= 12pt
|
||||||
|
matches = re.search("--font-width:\s*([0-9.]+);", css)
|
||||||
|
self.font_width = float(matches.groups()[0]) if matches else 0.45 # A magic number for OpenGost
|
||||||
|
|
||||||
|
self.svg.defs.add(self.svg.style(css))
|
||||||
|
|
||||||
def schedule_xlsx(self, infile, outfile):
|
def schedule_xlsx(self, infile, outfile):
|
||||||
workbook = openpyxl.open(infile, data_only=True)
|
workbook = openpyxl.open(infile, data_only=True)
|
||||||
sheet = workbook.active
|
sheet = workbook.active
|
||||||
@@ -144,8 +161,8 @@ class Scheduler:
|
|||||||
x += unmerged_width
|
x += unmerged_width
|
||||||
continue
|
continue
|
||||||
|
|
||||||
font_size = cell.font.size or 11 # 11pt default
|
font_size = cell.font.size or self.font_size_pt # 12pt default
|
||||||
font_size = font_size / FONT_SIZE_PT * FONT_SIZE # Magic?
|
font_size = font_size / self.font_size_pt * self.font_size_px # Magic?
|
||||||
|
|
||||||
text_position = [0.0, 0.0]
|
text_position = [0.0, 0.0]
|
||||||
if cell.alignment.horizontal == "left":
|
if cell.alignment.horizontal == "left":
|
||||||
@@ -424,9 +441,9 @@ class Scheduler:
|
|||||||
italic_text = final_cell_style.get("font-style", None) == "italic"
|
italic_text = final_cell_style.get("font-style", None) == "italic"
|
||||||
# NOTE: very naive since we're scaling text proportionally
|
# NOTE: very naive since we're scaling text proportionally
|
||||||
font_size = (
|
font_size = (
|
||||||
float(final_cell_style.get("font-size", f"{FONT_SIZE_PT}pt")[:-2])
|
float(final_cell_style.get("font-size", f"{self.font_size_pt}pt")[:-2])
|
||||||
/ FONT_SIZE_PT
|
/ self.font_size_pt
|
||||||
* FONT_SIZE
|
* self.font_size_px
|
||||||
)
|
)
|
||||||
|
|
||||||
if p_tags:
|
if p_tags:
|
||||||
@@ -523,10 +540,7 @@ class Scheduler:
|
|||||||
"""
|
"""
|
||||||
text_lines = [str(p) for p in p_tags]
|
text_lines = [str(p) for p in p_tags]
|
||||||
box_alignment_params = SvgWriter.get_box_alignment_parameters(box_alignment)
|
box_alignment_params = SvgWriter.get_box_alignment_parameters(box_alignment)
|
||||||
text_params = {
|
text_params = {"font-size": font_size}
|
||||||
"font-size": font_size,
|
|
||||||
"font-family": FONT_FAMILY,
|
|
||||||
}
|
|
||||||
if bold:
|
if bold:
|
||||||
text_params["font-weight"] = "bold"
|
text_params["font-weight"] = "bold"
|
||||||
if italic:
|
if italic:
|
||||||
@@ -546,13 +560,13 @@ class Scheduler:
|
|||||||
|
|
||||||
text_tag = self.svg.text("", **(text_params | {"font-size": "0"} | box_alignment_params))
|
text_tag = self.svg.text("", **(text_params | {"font-size": "0"} | box_alignment_params))
|
||||||
|
|
||||||
# TODO: should be done in less naive way
|
# TODO: Should be done without using magic number for self.font_width
|
||||||
# without using magic number for FONT_WIDTH
|
|
||||||
# currently it might not work for all fonts and font sizes
|
|
||||||
if wrap_text:
|
if wrap_text:
|
||||||
wrapped_lines = []
|
wrapped_lines = []
|
||||||
for line in text_lines:
|
for line in text_lines:
|
||||||
wrapped_line = wrap(line, width=int(cell_width // FONT_WIDTH(font_size)), break_long_words=False)
|
wrapped_line = wrap(
|
||||||
|
line, width=int(cell_width // (font_size * self.font_width)), break_long_words=False
|
||||||
|
)
|
||||||
wrapped_lines.extend(wrapped_line)
|
wrapped_lines.extend(wrapped_line)
|
||||||
else:
|
else:
|
||||||
wrapped_lines = text_lines
|
wrapped_lines = text_lines
|
||||||
|
|||||||
Reference in New Issue
Block a user