Added character portraits from @vincentmalloy.

Merge https://github.com/canismarko/dungeon-sheets/pull/100
This commit is contained in:
Mark Wolfman
2021-07-21 17:18:31 -05:00
parent ee7d5de601
commit 5183a6301d
10 changed files with 73 additions and 13 deletions
+14
View File
@@ -51,6 +51,20 @@ standard 5e rules, and are case-insensitive. Refer to the D&D
xp = 2190
hp_max = 16
Character Portrait
==================
.. code:: python
portrait = True
If this is set to True and a corresponding portrait file exists,
the portrait will be added to the character personality sheet.
For now, the file must have a .jpeg extension and be named exactly
the same as the character file. This might not work with every Image size.
ca 550 * 700px seems to be the right format. Anything smaller should work, too.
See the Bard1 example for a demonstration of this feature.
Ability Scores
==============
+1 -1
View File
@@ -97,7 +97,7 @@ class Character(Entity):
_proficiencies_text = list()
# Appearance
# portrait = placeholder not sure how to implement
portrait = False
age = 0
height = ""
weight = ""
View File
+49 -10
View File
@@ -2,9 +2,11 @@ import os
import subprocess
import logging
import warnings
import io
import pdfrw
from fdfgen import forge_fdf
from reportlab.pdfgen import canvas
from dungeonsheets.forms import mod_str
@@ -175,10 +177,10 @@ def create_character_pdf_template(character, basename, flatten=False):
# Prepare the actual PDF
dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/")
src_pdf = os.path.join(dirname, "blank-character-sheet-default.pdf")
return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten, portrait="")
def create_personality_pdf_template(character, basename, flatten=False):
def create_personality_pdf_template(character, basename, portrait_file="", flatten=False):
# Prepare the list of fields
fields = {
"CharacterName 2": character.name,
@@ -199,7 +201,7 @@ def create_personality_pdf_template(character, basename, flatten=False):
# Prepare the actual PDF
dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/")
src_pdf = os.path.join(dirname, "blank-personality-sheet-default.pdf")
return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten, portrait=portrait_file)
def create_spells_pdf_template(character, basename, flatten=False):
@@ -484,10 +486,10 @@ def create_spells_pdf_template(character, basename, flatten=False):
# Make the actual pdf
dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/")
src_pdf = os.path.join(dirname, "blank-spell-sheet-default.pdf")
make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten, portrait="")
def make_pdf(fields: dict, src_pdf: str, basename: str, flatten: bool = False):
def make_pdf(fields: dict, src_pdf: str, basename: str, flatten: bool = False, portrait = ""):
"""Create a new PDF by applying fields to a src PDF document.
Parameters
@@ -506,17 +508,17 @@ def make_pdf(fields: dict, src_pdf: str, basename: str, flatten: bool = False):
"""
try:
_make_pdf_pdftk(fields, src_pdf, basename, flatten)
_make_pdf_pdftk(fields, src_pdf, basename, flatten, portrait)
except FileNotFoundError:
# pdftk could not run, so alert the user and use pdfrw
warnings.warn(
f"Could not run `{PDFTK_CMD}`, using fallback; forcing `--editable`.",
RuntimeWarning,
)
_make_pdf_pdfrw(fields, src_pdf, basename, flatten)
_make_pdf_pdfrw(fields, src_pdf, basename, flatten, portrait)
def _make_pdf_pdfrw(fields: dict, src_pdf: str, basename: str, flatten: bool = False):
def _make_pdf_pdfrw(fields: dict, src_pdf: str, basename: str, flatten: bool = False, portrait = ""):
"""Backup make_pdf function in case pdftk is not available."""
template = pdfrw.PdfReader(src_pdf)
# Different types of PDF fields
@@ -575,7 +577,7 @@ def _make_pdf_pdfrw(fields: dict, src_pdf: str, basename: str, flatten: bool = F
pdfrw.PdfWriter().write(f"{basename}.pdf", template)
def _make_pdf_pdftk(fields, src_pdf, basename, flatten=False):
def _make_pdf_pdftk(fields, src_pdf, basename, flatten=False, portrait=""):
"""More robust way to make a PDF, but has a hard dependency."""
# Create the actual FDF file
fdfname = basename + ".fdf"
@@ -585,7 +587,12 @@ def _make_pdf_pdftk(fields, src_pdf, basename, flatten=False):
fdf_file.write(fdf)
fdf_file.close()
# Build the final flattened PDF documents
dest_pdf = basename + ".pdf"
if portrait != "":
dest_pdf = basename + "-temp.pdf"
image_pdf = basename + "_image_tmp.pdf"
make_image_pdf(portrait, image_pdf)
else:
dest_pdf = basename + ".pdf"
popenargs = [
PDFTK_CMD,
src_pdf,
@@ -597,5 +604,37 @@ def _make_pdf_pdftk(fields, src_pdf, basename, flatten=False):
if flatten:
popenargs.append("flatten")
subprocess.call(popenargs)
# stamp with image
if portrait != "":
src_pdf = dest_pdf
stamped_pdf = basename + ".pdf"
popenargs = [
PDFTK_CMD,
src_pdf,
"stamp",
image_pdf,
"output",
stamped_pdf,
]
popenargs.append("flatten")
subprocess.call(popenargs)
# Clean up
os.remove(image_pdf)
os.remove(dest_pdf)
# Clean up temporary files
os.remove(fdfname)
def make_image_pdf(src_img:str, dest_pdf:str):
packet = io.BytesIO()
can = canvas.Canvas(packet)
x_start = 10
y_start = 240
can.drawImage(src_img, x_start, y_start, width=175, preserveAspectRatio=True, mask='auto')
can.showPage()
can.save()
#move to the beginning of the StringIO buffer
packet.seek(0)
new_pdf = pdfrw.PdfReader(packet)
pdfrw.PdfWriter().write(dest_pdf, new_pdf)
Executable → Regular
+5 -1
View File
@@ -420,6 +420,10 @@ def make_character_sheet(
if character is None:
character_props = readers.read_sheet_file(char_file)
character = _char.Character.load(character_props)
# Load image file if present
portrait_file=""
if character.portrait:
portrait_file=char_file.stem + ".jpeg"
# Set the fields in the FDF
basename = char_file.stem
char_base = basename + "_char"
@@ -440,7 +444,7 @@ def make_character_sheet(
)
pages.append(char_pdf)
person_pdf = create_personality_pdf_template(
character=character, basename=person_base, flatten=flatten
character=character, basename=person_base, portrait_file=portrait_file, flatten=flatten
)
pages.append(person_pdf)
if character.is_spellcaster:
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+2
View File
@@ -107,3 +107,5 @@ flaws = """TODO: Describe your characters interesting flaws.
features_and_traits = """TODO: Describe other features and abilities your
character has."""
portrait = True
+1
View File
@@ -5,3 +5,4 @@ jinja2
sphinx
pdfrw
EbookLib
reportlab
+1 -1
View File
@@ -26,7 +26,7 @@ setup(name='dungeonsheets',
},
install_requires=[
'fdfgen', 'npyscreen', 'jinja2', 'pdfrw', 'sphinx',
'EbookLib',
'EbookLib', 'reportlab',
],
entry_points={
'console_scripts': [
Executable → Regular
View File