Merge pull request #3 from laurierloi/pdf-support-weasyprint

Pdf support weasyprint
This commit is contained in:
Laurier Loiselle 2023-04-11 18:54:13 -04:00 committed by GitHub
commit 7d61f0e6da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 64 additions and 29 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ __pycache__
# Built examples # Built examples
examples/* examples/*
tutorial/* tutorial/*
outputs/*
!examples/*.yml !examples/*.yml
!tutorial/*.yml !tutorial/*.yml
!tutorial/*.md !tutorial/*.md

View File

@ -1,3 +1,4 @@
# need to install pango > 1.44.0
click click
graphviz graphviz
pillow pillow
@ -5,3 +6,4 @@ pyyaml
setuptools setuptools
tabulate tabulate
jinja2 jinja2
weasyprint

View File

@ -1,7 +1,7 @@
<style> <style>
.A4 #bom { /* BOM on top of title block */ .A4 #bom { /* BOM on top of title block */
position: absolute; position: absolute;
bottom: calc({{ titleblock_rows + 1 }} * 4.25mm); bottom: {{ (titleblock_rows + 1) * 4.25 }}mm;
right: 0; right: 0;
} }

View File

@ -38,7 +38,7 @@
position: relative; position: relative;
} }
.A4, .sheetsize_default { /* portrait */ .A4 { /* portrait */
width: 180mm; width: 180mm;
height: 277mm; height: 277mm;
} }
@ -62,12 +62,19 @@
{% set bottom_rows = [bom_rows, titleblock_rows]|max + 1 %} {% set bottom_rows = [bom_rows, titleblock_rows]|max + 1 %}
{% endif %} {% endif %}
.A4 #diagram, .A3 #diagram {
height: {{ 277 - bottom_rows * 4.25 }}mm;
}
.A2 #diagram {
height: {{ 400 - bottom_rows * 4.25 }}mm;
}
#diagram { #diagram {
position: relative; position: relative;
top: 0; top: 0;
left: 0; left: 0;
max-width: 100%; max-width: 100%;
height: calc(100% - {{ bottom_rows }} * 4.25mm);
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
} }
@ -85,14 +92,13 @@
<style type="text/css" media="print"> <style type="text/css" media="print">
@page { @page {
size: auto; size: {{ sheetsize }} {{ orientation }};
margin: 0; margin: 0;
} }
/* TODO: auto-adjust based on portrait (larger margin on left) or landscape (larger margin on top) */
#page { #page {
margin: 10mm; margin-top: 10mm;
margin-left: 20mm; margin-left: 15mm; /* TODO: maybe scale this value depending on sheetsize */
} }
</style> </style>

View File

@ -2,9 +2,9 @@
.A4 #notes { /* NOTES on top of BOM */ .A4 #notes { /* NOTES on top of BOM */
position: absolute; position: absolute;
{% if show_bom %} {% if show_bom %}
bottom: calc({{ titleblock_rows + bom_rows + 2 }} * 4.25mm); bottom: {{ (titleblock_rows + bom_rows + 2) * 4.25 }}mm;
{% else %} {% else %}
bottom: calc({{ titleblock_rows + 1 }} * 4.25mm); bottom: {{ (titleblock_rows + 1) * 4.25 }}mm;
{% endif %} {% endif %}
right: 0; right: 0;
} }
@ -12,11 +12,11 @@
.A3 #notes, .A2 #notes { /* NOTES on top of title block */ .A3 #notes, .A2 #notes { /* NOTES on top of title block */
position: absolute; position: absolute;
{% if notes_on_right %} {% if notes_on_right %}
bottom: calc({{ titleblock_rows + 1 }} * 4.25mm); bottom: {{ (titleblock_rows + 1) * 4.25 }}mm;
right: 0; right: 0;
{% else %} {% else %}
{% if show_bom %} {% if show_bom %}
bottom: calc({{ bom_rows + 1 }} * 4.25mm); bottom: {{ (bom_rows + 1) * 4.25 }}mm;
{% else %} {% else %}
bottom: 0; bottom: 0;
{% endif %} {% endif %}

View File

@ -1,13 +1,8 @@
<style> <style>
#titleblock { #titleblock {
position: absolute; position: absolute;
bottom: 0mm; bottom: 0;
right: -0mm; right: 0;
}
#titleblock {
width: 180mm;
height: calc({{ titleblock_rows }} * 4.25mm));
} }
#titleblock table, th, td { #titleblock table, th, td {
@ -108,7 +103,7 @@
<!-- START OF TEMPLATE --!> <!-- START OF TEMPLATE --!>
<div id="titleblock"> <div id="titleblock">
<table id="titleblock"> <table>
<tr> <!-- ROW 1 --!> <tr> <!-- ROW 1 --!>
<!-- REVISIONS Column 1 to 4 --!> <!-- REVISIONS Column 1 to 4 --!>
{{ revision(1) }} {{ revision(1) }}

View File

@ -37,7 +37,7 @@ groups = {
input_extensions = [".yml"] input_extensions = [".yml"]
extensions_not_containing_graphviz_output = [".gv", ".bom.tsv"] extensions_not_containing_graphviz_output = [".gv", ".bom.tsv"]
extensions_containing_graphviz_output = [".png", ".svg", ".html"] extensions_containing_graphviz_output = [".png", ".svg", ".html", ".pdf"]
generated_extensions = ( generated_extensions = (
extensions_not_containing_graphviz_output + extensions_containing_graphviz_output extensions_not_containing_graphviz_output + extensions_containing_graphviz_output
) )
@ -68,7 +68,7 @@ def build_generated(groupkeys):
try: try:
res = cli([ res = cli([
"--formats", "--formats",
"ghpst", "ghpstPb",
str(yaml_file), str(yaml_file),
"--prepend", "--prepend",
yaml_file.parent / "metadata.yml" yaml_file.parent / "metadata.yml"

View File

@ -14,6 +14,7 @@ from wireviz import APP_NAME, __version__
from wireviz.wv_bom import bom_list from wireviz.wv_bom import bom_list
from wireviz.wv_utils import bom2tsv from wireviz.wv_utils import bom2tsv
from wireviz.wv_harness_quantity import HarnessQuantity from wireviz.wv_harness_quantity import HarnessQuantity
from wireviz.wv_output import generate_pdf_output
format_codes = { format_codes = {
"c": "csv", "c": "csv",
@ -126,9 +127,11 @@ def cli(files, formats, prepend, output_dir, output_name, version, use_qty_multi
harness = None harness = None
shared_bom = {} shared_bom = {}
sheet_current = 1 sheet_current = 1
output_names = []
# run WireVIz on each input file # run WireVIz on each input file
for _file in files: for _file in files:
_output_name = _file.stem if not output_name else output_name _output_name = _file.stem if not output_name else output_name
output_names.append(_output_dir / _output_name)
print("Input file: ", _file) print("Input file: ", _file)
print( print(
@ -155,6 +158,9 @@ def cli(files, formats, prepend, output_dir, output_name, version, use_qty_multi
) )
shared_bom = ret["shared_bom"] shared_bom = ret["shared_bom"]
if 'pdf' in output_formats and 'html' in output_formats and len(output_names) > 1:
generate_pdf_output(output_names)
# TODO: move shared bom generation to a method? # TODO: move shared bom generation to a method?
if "shared_bom" in output_formats: if "shared_bom" in output_formats:
shared_bom_file = (_output_dir / "shared_bom").with_suffix(".tsv") shared_bom_file = (_output_dir / "shared_bom").with_suffix(".tsv")

View File

@ -30,7 +30,7 @@ from wireviz.wv_graphviz import (
parse_arrow_str, parse_arrow_str,
set_dot_basics, set_dot_basics,
) )
from wireviz.wv_output import embed_svg_images_file, generate_html_output from wireviz.wv_output import embed_svg_images_file, generate_html_output, generate_pdf_output
from wireviz.wv_utils import bom2tsv from wireviz.wv_utils import bom2tsv
@ -394,8 +394,7 @@ class Harness:
generate_html_output(filename, bomlist, self.metadata, self.options) generate_html_output(filename, bomlist, self.metadata, self.options)
# PDF output # PDF output
if "pdf" in fmt: if "pdf" in fmt:
# TODO: implement PDF output generate_pdf_output(filename)
print("PDF output is not yet supported")
# delete SVG if not needed # delete SVG if not needed
if "html" in fmt and not "svg" in fmt: if "html" in fmt and not "svg" in fmt:
# SVG file was just needed to generate HTML # SVG file was just needed to generate HTML

View File

@ -3,7 +3,10 @@
import base64 import base64
import re import re
from pathlib import Path from pathlib import Path
from typing import List, Union from typing import Dict, List, Union
import logging
from weasyprint import HTML
import wireviz # for doing wireviz.__file__ import wireviz # for doing wireviz.__file__
from wireviz.wv_dataclasses import Metadata, Options from wireviz.wv_dataclasses import Metadata, Options
@ -56,6 +59,28 @@ def embed_svg_images_file(
filename_out.replace(filename_in) filename_out.replace(filename_in)
def generate_pdf_output(
filename_list: List[Path],
options: Dict=None,
):
'''Generate a pdf output, options are ignored for now, expect the formatting
to be done within the html files
'''
if isinstance(filename_list, Path):
filename_list = [filename_list]
output_path = filename_list[0].with_suffix('.pdf')
else:
output_dir = filename_list[0].parent
output_path = (output_dir / output_dir.name).with_suffix('.pdf')
filepath_list = [f.with_suffix('.html') for f in filename_list]
print(f'Generating pdf output: {output_path}')
files_html = [HTML(path) for path in filepath_list]
documents = [f.render() for f in files_html]
all_pages = [p for doc in documents for p in doc.pages]
documents[0].copy(all_pages).write_pdf(output_path)
def generate_html_output( def generate_html_output(
filename: Path, filename: Path,
@ -117,7 +142,8 @@ def generate_html_output(
added_metadata = { added_metadata = {
"revisions": [], "revisions": [],
"authors": [], "authors": [],
"sheetsize": "sheetsize_default", "sheetsize": "A4",
"orientation": "portrait",
} }
if metadata: if metadata:
for item, contents in metadata.items(): for item, contents in metadata.items():
@ -132,9 +158,9 @@ def generate_html_output(
elif item == "pn": elif item == "pn":
added_metadata[item] = f'{contents}-{metadata.get("sheet_name")}' added_metadata[item] = f'{contents}-{metadata.get("sheet_name")}'
elif item == "template": elif item == "template":
added_metadata["sheetsize"] = contents.get( added_metadata["sheetsize"] = contents.get("sheetsize", "A4")
"sheetsize", "sheetsize_default" if added_metadata["sheetsize"] in ["A2", "A3"]:
) added_metadata["orientation"] = "landscape"
else: else:
added_metadata[item] = contents added_metadata[item] = contents