Erster Commit: nativer Linux-Port aus macOS-Bytecode
Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .common import *
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Test environment
|
||||
|
||||
import common
|
||||
|
||||
def main():
|
||||
common.log("CHECK")
|
||||
|
||||
try:
|
||||
from fpdf import FPDF_VERSION
|
||||
except ImportError:
|
||||
FPDF_VERSION = None
|
||||
common.log("VER =", FPDF_VERSION)
|
||||
|
||||
try:
|
||||
try:
|
||||
import Image
|
||||
except:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
if Image:
|
||||
common.log("PIL = yes")
|
||||
else:
|
||||
common.log("PIL = no")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,284 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# common utilities for pyfpdf tests
|
||||
# Note: 1) this file imported from both 2 and 3 version of python
|
||||
# 2) import this file before import fpdf
|
||||
# 3) assert this file in tests/cover folder
|
||||
|
||||
import sys, os, subprocess
|
||||
|
||||
PY3K = sys.version_info >= (3, 0)
|
||||
|
||||
basepath = os.path.abspath(os.path.join(__file__, "..", ".."))
|
||||
|
||||
RESHASH = "38db8db76e80a2e75f94d1df9eda307e"
|
||||
|
||||
# if PYFPDFTESTLOCAL is not set - use instaled pyfpdf version
|
||||
PYFPDFTESTLOCAL = ("PYFPDFTESTLOCAL" in os.environ)
|
||||
if PYFPDFTESTLOCAL:
|
||||
sys.path = [os.path.join(basepath, "fpdf_local")] + sys.path
|
||||
|
||||
|
||||
if PY3K:
|
||||
#import common3 as _common
|
||||
def tobytes(value):
|
||||
return value.encode("latin1")
|
||||
def frombytes(value):
|
||||
return value.decode("latin1")
|
||||
from hashlib import md5
|
||||
unicode = str
|
||||
|
||||
else:
|
||||
#import common2 as _common
|
||||
def tobytes(value):
|
||||
return value
|
||||
def frombytes(value):
|
||||
return value
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
import md5
|
||||
|
||||
def exec_cmd(cmd):
|
||||
"Execute command and return console output (stdout, stderr)"
|
||||
obj = subprocess.Popen(cmd, \
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE)
|
||||
std, err = obj.communicate()
|
||||
return (frombytes(std), frombytes(err))
|
||||
|
||||
def start_by_ext(fn):
|
||||
"Open file in associated progrom"
|
||||
try:
|
||||
try:
|
||||
os.startfile(fn)
|
||||
except WindowsError:
|
||||
os.system("start " + fn)
|
||||
except:
|
||||
subprocess.call(["xdg-open", fn])
|
||||
|
||||
def writer(stream, items):
|
||||
sep = ""
|
||||
for item in items:
|
||||
stream.write(sep)
|
||||
sep = " "
|
||||
if not isinstance(item, str):
|
||||
item = str(item)
|
||||
if not PY3K:
|
||||
if not isinstance(item, unicode):
|
||||
item = str(item)
|
||||
stream.write(item)
|
||||
stream.write("\n")
|
||||
|
||||
def log(*kw):
|
||||
writer(sys.stdout, kw)
|
||||
|
||||
def err(*kw):
|
||||
writer(sys.stderr, kw)
|
||||
|
||||
def test_putinfo(self):
|
||||
"Replace info stamp with defaults for all automated test objects"
|
||||
self._out('/Producer '+self._textstring('PyFPDF TEST http://pyfpdf.googlecode.com/'))
|
||||
if hasattr(self,'title'):
|
||||
self._out('/Title '+self._textstring(self.title))
|
||||
if hasattr(self,'subject'):
|
||||
self._out('/Subject '+self._textstring(self.subject))
|
||||
if hasattr(self,'author'):
|
||||
self._out('/Author '+self._textstring(self.author))
|
||||
if hasattr (self,'keywords'):
|
||||
self._out('/Keywords '+self._textstring(self.keywords))
|
||||
if hasattr(self,'creator'):
|
||||
self._out('/Creator '+self._textstring(self.creator))
|
||||
self._out('/CreationDate '+self._textstring('D:19700101000000'))
|
||||
|
||||
def file_hash(fn):
|
||||
"Calc MD5 hash for file"
|
||||
md = md5()
|
||||
f = open(fn, "rb")
|
||||
try:
|
||||
md.update(f.read())
|
||||
finally:
|
||||
f.close()
|
||||
return md.hexdigest()
|
||||
|
||||
def read_cover_info(fn):
|
||||
"Read cover test info"
|
||||
f = open(fn, "rb")
|
||||
da = {"res": []}
|
||||
mark = "#PyFPDF-cover-test:"
|
||||
encmark = "# -*- coding:"
|
||||
enc = None
|
||||
try:
|
||||
hdr = False
|
||||
for line in f.readlines():
|
||||
if enc is None:
|
||||
if line.decode("latin-1")[:len(encmark)] == unicode(encmark):
|
||||
enc = line.decode("latin-1")[len(encmark):].strip()
|
||||
if enc[-3:] == unicode("-*-"):
|
||||
enc = enc[:-3].strip()
|
||||
try:
|
||||
line.decode(enc)
|
||||
except:
|
||||
enc = None
|
||||
line = line.decode(enc or "UTF-8").strip()
|
||||
if line[:len(mark)] == mark:
|
||||
hdr = True
|
||||
kv = line[len(mark):].split("=", 1)
|
||||
if len(kv) == 2:
|
||||
if kv[0] == "res":
|
||||
da["res"].append(kv[1])
|
||||
else:
|
||||
da[kv[0]] = kv[1]
|
||||
else:
|
||||
if hdr and len(line) == 0:
|
||||
break
|
||||
|
||||
finally:
|
||||
f.close()
|
||||
return da
|
||||
|
||||
def parse_test_args(args, deffn):
|
||||
"Parse test args, return (fn, autotest)"
|
||||
args = args[1:]
|
||||
da = {}
|
||||
da["fn"] = deffn
|
||||
da["autotest"] = False
|
||||
da["check"] = False
|
||||
while len(args) > 0:
|
||||
arg = args[0]
|
||||
if arg == "--help":
|
||||
log("Test usage: [--auto] [--check] [<outputname>]")
|
||||
log(" --auto - no version and timestamp in file, do not open")
|
||||
log(" --check - compare new file with stock")
|
||||
log(" <outputname> - output filename, default \"%s\"" % deffn)
|
||||
sys.exit(0)
|
||||
if arg == "--auto":
|
||||
da["autotest"] = True
|
||||
elif arg == "--check":
|
||||
da["check"] = True
|
||||
else:
|
||||
da["fn"] = arg
|
||||
args = args[1:]
|
||||
return da
|
||||
|
||||
def load_res_file(path):
|
||||
items = {}
|
||||
res = None
|
||||
for line in open(path):
|
||||
line = line.strip()
|
||||
if line[:1] == "#":
|
||||
continue
|
||||
kv = line.split("=", 1)
|
||||
if len(kv) != 2:
|
||||
continue
|
||||
if kv[0] == "res":
|
||||
res = kv[1]
|
||||
if res not in items:
|
||||
items[res] = ["", []]
|
||||
elif res is None:
|
||||
continue
|
||||
elif kv[0] == "hash":
|
||||
items[res][0] = kv[1]
|
||||
elif kv[0] == "tags":
|
||||
items[res][1] += [kv[1].split(",")]
|
||||
return items
|
||||
|
||||
def check_env(settings, args):
|
||||
"Check test environment"
|
||||
verbose = not args["autotest"]
|
||||
# check python version
|
||||
if PY3K:
|
||||
if settings.get("python3", "yes") == "no":
|
||||
# python 3 inacceptable
|
||||
if verbose:
|
||||
err("Python 3.x unsupported %s" % repr(sys.version_info))
|
||||
else:
|
||||
log("NOTFORPY3")
|
||||
return False
|
||||
else:
|
||||
if settings.get("python2", "yes") == "no":
|
||||
# python 2 inacceptable
|
||||
if verbose:
|
||||
err("Python 2.x unsupported %s" % repr(sys.version_info))
|
||||
else:
|
||||
log("NOTFORPY2")
|
||||
return False
|
||||
if settings.get("pil", "no") == "yes":
|
||||
# import PIL
|
||||
try:
|
||||
try:
|
||||
import Image
|
||||
except:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
if Image is None:
|
||||
if verbose:
|
||||
err("PIL or Pillow module is required")
|
||||
else:
|
||||
log("NOPIL")
|
||||
return False
|
||||
# check res
|
||||
reslst = None
|
||||
for res in settings.get("res", []):
|
||||
if reslst is None:
|
||||
# check
|
||||
respath = os.path.join(basepath, "resources.txt")
|
||||
if file_hash(respath) != RESHASH:
|
||||
if verbose:
|
||||
err("File resources.txt damaged (hash mismatch)")
|
||||
else:
|
||||
log("RESHASH")
|
||||
return False
|
||||
# load data
|
||||
reslst = load_res_file(respath)
|
||||
if res not in reslst:
|
||||
err("Resource \"" + res + "\" not found")
|
||||
if not verbose:
|
||||
log("NORES")
|
||||
return False
|
||||
# check hash
|
||||
respath = os.path.join(basepath, res)
|
||||
hs = file_hash(respath)
|
||||
if hs != reslst[res][0]:
|
||||
err("Resource \"" + res + "\" damaged")
|
||||
err(" read = %s" % hs)
|
||||
err(" required = %s" % reslst[res][0])
|
||||
if not verbose:
|
||||
log("RESERR")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def check_result(settings, args):
|
||||
check = True
|
||||
if settings.get("fn"):
|
||||
if args["check"]:
|
||||
# compare with hash
|
||||
hs = file_hash(args["fn"])
|
||||
fhs = settings.get("hash", "")
|
||||
if fhs != "" and hs != fhs:
|
||||
check = False
|
||||
err("Hash mismatch:")
|
||||
err(" new = %s" % hs)
|
||||
err(" required = %s" % fhs)
|
||||
|
||||
if args["autotest"]:
|
||||
if check:
|
||||
log("OK")
|
||||
else:
|
||||
log("HASHERROR")
|
||||
else:
|
||||
if settings.get("fn"):
|
||||
start_by_ext(args["fn"])
|
||||
else:
|
||||
log("Test passed")
|
||||
|
||||
def testmain(fn, testfunc):
|
||||
si = read_cover_info(fn)
|
||||
da = parse_test_args(sys.argv, si.get("fn"))
|
||||
if not check_env(si, da):
|
||||
return
|
||||
testfunc(da["fn"], da["autotest"] or da["check"])
|
||||
check_result(si, da)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Test caching"
|
||||
|
||||
#PyFPDF-cover-test:res=font/DejaVuSansCondensed.ttf
|
||||
#PyFPDF-cover-test:res=font/DejaVuSans.ttf
|
||||
|
||||
import common
|
||||
import fpdf
|
||||
|
||||
import os, shutil, time
|
||||
|
||||
def testfile(f1, f2):
|
||||
# create pdf
|
||||
pdf = fpdf.FPDF()
|
||||
if f1:
|
||||
pdf.add_font('DejaVuSansCondensed', '', f1, uni = True)
|
||||
if f2:
|
||||
pdf.add_font('DejaVuSans', '', f2, uni = True)
|
||||
pdf.set_font('DejaVuSans', "", 10)
|
||||
return pdf
|
||||
|
||||
def trashfile(fn):
|
||||
f = open(fn, "w")
|
||||
f.write("1234567890")
|
||||
f.close()
|
||||
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
try:
|
||||
from md5 import md5
|
||||
except ImportError:
|
||||
md5 = None
|
||||
def hashfn(fn):
|
||||
h = md5()
|
||||
if common.PY3K:
|
||||
h.update(fn.encode("UTF-8"))
|
||||
else:
|
||||
h.update(fn)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
cachepath = os.path.join(os.path.dirname(__file__), "cache")
|
||||
if os.path.exists(cachepath):
|
||||
# cleanup dest
|
||||
for item in os.listdir(cachepath):
|
||||
os.remove(os.path.join(cachepath, item))
|
||||
else:
|
||||
# create font dir
|
||||
os.makedirs(cachepath)
|
||||
hashpath = os.path.join(os.path.dirname(__file__), "hash")
|
||||
if os.path.exists(hashpath):
|
||||
# cleanup dest
|
||||
for item in os.listdir(hashpath):
|
||||
os.remove(os.path.join(hashpath, item))
|
||||
else:
|
||||
# create font dir
|
||||
os.makedirs(hashpath)
|
||||
# copy font files
|
||||
shutil.copy(os.path.join(common.basepath, "font", "DejaVuSansCondensed.ttf"), cachepath)
|
||||
shutil.copy(os.path.join(common.basepath, "font", "DejaVuSans.ttf"), cachepath)
|
||||
f1 = os.path.join(cachepath, "DejaVuSansCondensed.ttf")
|
||||
f2 = os.path.join(cachepath, "DejaVuSans.ttf")
|
||||
|
||||
# --- normal cache mode ---
|
||||
fpdf.set_global("FPDF_CACHE_MODE", 0)
|
||||
# first load
|
||||
t0 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t1 = time.time()
|
||||
assert os.path.exists(f1[:-3] + "pkl")
|
||||
assert os.path.exists(f2[:-3] + "pkl")
|
||||
# load cached
|
||||
t2 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t3 = time.time()
|
||||
if not nostamp:
|
||||
common.log("Cache fonts: ", t1 - t0)
|
||||
common.log("Reload fonts: ", t3 - t2)
|
||||
pdf.add_page()
|
||||
# trigger cw127
|
||||
#pdf.write(5, "Γειά σου κόσμος")
|
||||
pdf.write(5, "Привет!")
|
||||
pdf.write(10, "Hello")
|
||||
pdf.output(os.path.join(cachepath, "pdf0.pdf"), "F")
|
||||
# check cw127
|
||||
assert not os.path.exists(f1[:-3] + "cw127.pkl")
|
||||
assert os.path.exists(f2[:-3] + "cw127.pkl")
|
||||
|
||||
# --- disable cache reading ---
|
||||
fpdf.set_global("FPDF_CACHE_MODE", 1)
|
||||
# put garbage data to cache files - fpdf should not read pkl
|
||||
trashfile(f1[:-3] + "pkl")
|
||||
trashfile(f2[:-3] + "pkl")
|
||||
trashfile(f2[:-3] + "cw127.pkl")
|
||||
# test same file
|
||||
t0 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t1 = time.time()
|
||||
# remove pkl files
|
||||
os.remove(f1[:-3] + "pkl")
|
||||
os.remove(f2[:-3] + "pkl")
|
||||
os.remove(f2[:-3] + "cw127.pkl")
|
||||
# test reload
|
||||
t2 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t3 = time.time()
|
||||
if not nostamp:
|
||||
common.log("No cache 1st: ", t1 - t0)
|
||||
common.log("No cache 2nd: ", t3 - t2)
|
||||
pdf.add_page()
|
||||
pdf.write(5, "Γειά σου κόσμος")
|
||||
pdf.write(10, "Hello")
|
||||
pdf.output(os.path.join(cachepath, "pdf1.pdf"), "F")
|
||||
# test no files created
|
||||
assert not os.path.exists(f1[:-3] + "pkl")
|
||||
assert not os.path.exists(f2[:-3] + "pkl")
|
||||
assert not os.path.exists(f1[:-3] + "cw127.pkl")
|
||||
assert not os.path.exists(f2[:-3] + "cw127.pkl")
|
||||
|
||||
# --- hash cache ---
|
||||
fpdf.set_global("FPDF_CACHE_MODE", 2)
|
||||
fpdf.set_global("FPDF_CACHE_DIR", hashpath)
|
||||
t0 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t1 = time.time()
|
||||
assert not os.path.exists(f1[:-3] + "pkl")
|
||||
assert not os.path.exists(f2[:-3] + "pkl")
|
||||
# load cached
|
||||
t2 = time.time()
|
||||
pdf = testfile(f1, f2)
|
||||
t3 = time.time()
|
||||
# test reload
|
||||
if not nostamp:
|
||||
common.log("Hash load 1st:", t1 - t0)
|
||||
common.log("Hash load 2nd:", t3 - t2)
|
||||
# check hash
|
||||
assert os.path.exists(os.path.join(hashpath, hashfn(f1) + ".pkl"))
|
||||
assert os.path.exists(os.path.join(hashpath, hashfn(f2) + ".pkl"))
|
||||
pdf.add_page()
|
||||
pdf.write(5, "Хешировали, хешировали, да выдохешиовали.")
|
||||
pdf.write(10, "Hello")
|
||||
pdf.output(os.path.join(cachepath, "pdf2.pdf"), "F")
|
||||
assert not os.path.exists(os.path.join(hashpath, hashfn(f1) + ".cw127.pkl"))
|
||||
assert os.path.exists(os.path.join(hashpath, hashfn(f2) + ".cw127.pkl"))
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"PDF Template Helper for FPDF.py"
|
||||
|
||||
__author__ = "Mariano Reingart <reingart@gmail.com>"
|
||||
__copyright__ = "Copyright (C) 2010 Mariano Reingart"
|
||||
__license__ = "LGPL 3.0"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=invoice.pdf
|
||||
#PyFPDF-cover-test:hash=5844bbebe3e33b0ac9cc15ac39327a81
|
||||
#PyFPDF-cover-test:res=invoice.csv
|
||||
|
||||
import common
|
||||
from fpdf import Template
|
||||
|
||||
import os
|
||||
|
||||
class randomfake:
|
||||
RINT1_10 = [8, 5, 7, 9, 10, 8, 1, 9, 1, 7, 6, 2, 3, 7, 8, 4, 6, 5, 7, 2, \
|
||||
5, 8, 6, 5, 5, 8, 7, 7, 6]
|
||||
RINT65_90 = [67, 67, 87, 78, 84, 67, 86, 75, 86, 89, 81, 69, 72, 71, 84, \
|
||||
80, 71 , 86 , 82 , 70 , 84 , 69 , 70]
|
||||
RFLT = [0.820710198665, 0.342854771472, 0.0238515965298, 0.177658111957, \
|
||||
0.422301628067, 0.701867781693, 0.168650983171, 0.329723498664, \
|
||||
0.490481106182, 0.892634029991, 0.994758791625, 0.998243714035, \
|
||||
0.596244312914 ,0.318601111178 ,0.321593673214 ,0.203486335469]
|
||||
def __init__(self):
|
||||
self.icnt1_10 = 0
|
||||
self.icnt65_90 = 0
|
||||
self.fcnt = 0
|
||||
|
||||
def randint(self, beg, end):
|
||||
if beg == 1 and end == 10:
|
||||
self.icnt1_10 += 1
|
||||
if self.icnt1_10 > len(self.RINT1_10):
|
||||
self.icnt1_10 = 1
|
||||
return self.RINT1_10[self.icnt1_10 - 1]
|
||||
if beg == 65 and end == 90:
|
||||
self.icnt65_90 += 1
|
||||
if self.icnt65_90 > len(self.RINT65_90):
|
||||
self.icnt65_90 = 1
|
||||
return self.RINT65_90[self.icnt65_90 - 1]
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def random(self):
|
||||
self.fcnt += 1
|
||||
if self.fcnt > len(self.RFLT):
|
||||
self.fcnt = 1
|
||||
return self.RFLT[self.fcnt - 1]
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
|
||||
# generate sample invoice (according Argentina's regulations)
|
||||
from decimal import Decimal
|
||||
|
||||
f = Template(format="A4",
|
||||
title="Sample Invoice", author="Sample Company",
|
||||
subject="Sample Customer", keywords="Electronic TAX Invoice")
|
||||
if nostamp:
|
||||
f.pdf._putinfo = lambda: common.test_putinfo(f.pdf)
|
||||
random = randomfake()
|
||||
else:
|
||||
import random
|
||||
|
||||
csvpath = os.path.join(common.basepath, "invoice.csv")
|
||||
f.parse_csv(infile=csvpath, delimiter=";", decimal_sep=",")
|
||||
|
||||
detail = "Lorem ipsum dolor sit amet, consectetur. " * 30
|
||||
items = []
|
||||
for i in range(1, 30):
|
||||
ds = "Sample product %s" % i
|
||||
qty = random.randint(1,10)
|
||||
price = round(random.random()*100,3)
|
||||
code = "%s%s%02d" % (chr(random.randint(65,90)), chr(random.randint(65,90)),i)
|
||||
items.append(dict(code=code, unit='u',
|
||||
qty=qty, price=price,
|
||||
amount=qty*price,
|
||||
ds="%s: %s" % (i,ds)))
|
||||
|
||||
# divide and count lines
|
||||
lines = 0
|
||||
li_items = []
|
||||
for it in items:
|
||||
qty = it['qty']
|
||||
code = it['code']
|
||||
unit = it['unit']
|
||||
for ds in f.split_multicell(it['ds'], 'item_description01'):
|
||||
# add item description line (without price nor amount)
|
||||
li_items.append(dict(code=code, ds=ds, qty=qty, unit=unit, price=None, amount=None))
|
||||
# clean qty and code (show only at first)
|
||||
unit = qty = code = None
|
||||
# set last item line price and amount
|
||||
li_items[-1].update(amount = it['amount'],
|
||||
price = it['price'])
|
||||
|
||||
obs="\n<U>Detail:</U>\n\n" + detail
|
||||
for ds in f.split_multicell(obs, 'item_description01'):
|
||||
li_items.append(dict(code=code, ds=ds, qty=qty, unit=unit, price=None, amount=None))
|
||||
|
||||
# calculate pages:
|
||||
lines = len(li_items)
|
||||
max_lines_per_page = 24
|
||||
pages = int(lines / (max_lines_per_page - 1))
|
||||
if lines % (max_lines_per_page - 1): pages = pages + 1
|
||||
|
||||
# completo campos y hojas
|
||||
for page in range(1, int(pages)+1):
|
||||
f.add_page()
|
||||
f['page'] = 'Page %s of %s' % (page, pages)
|
||||
if pages>1 and page<pages:
|
||||
s = 'Continues on page %s' % (page+1)
|
||||
else:
|
||||
s = ''
|
||||
f['item_description%02d' % (max_lines_per_page+1)] = s
|
||||
|
||||
f["company_name"] = "Sample Company"
|
||||
f["company_logo"] = os.path.join(common.basepath, "../tutorial/logo.png")
|
||||
f["company_header1"] = "Some Address - somewhere -"
|
||||
f["company_header2"] = "http://www.example.com"
|
||||
f["company_footer1"] = "Tax Code ..."
|
||||
f["company_footer2"] = "Tax/VAT ID ..."
|
||||
f['number'] = '0001-00001234'
|
||||
f['issue_date'] = '2010-09-10'
|
||||
f['due_date'] = '2099-09-10'
|
||||
f['customer_name'] = "Sample Client"
|
||||
f['customer_address'] = "Siempreviva 1234"
|
||||
|
||||
# print line item...
|
||||
li = 0
|
||||
k = 0
|
||||
total = Decimal("0.00")
|
||||
for it in li_items:
|
||||
k = k + 1
|
||||
if k > page * (max_lines_per_page - 1):
|
||||
break
|
||||
if it['amount']:
|
||||
total += Decimal("%.6f" % it['amount'])
|
||||
if k > (page - 1) * (max_lines_per_page - 1):
|
||||
li += 1
|
||||
if it['qty'] is not None:
|
||||
f['item_quantity%02d' % li] = it['qty']
|
||||
if it['code'] is not None:
|
||||
f['item_code%02d' % li] = it['code']
|
||||
if it['unit'] is not None:
|
||||
f['item_unit%02d' % li] = it['unit']
|
||||
f['item_description%02d' % li] = it['ds']
|
||||
if it['price'] is not None:
|
||||
f['item_price%02d' % li] = "%0.3f" % it['price']
|
||||
if it['amount'] is not None:
|
||||
f['item_amount%02d' % li] = "%0.2f" % it['amount']
|
||||
|
||||
if pages == page:
|
||||
f['net'] = "%0.2f" % (total/Decimal("1.21"))
|
||||
f['vat'] = "%0.2f" % (total*(1-1/Decimal("1.21")))
|
||||
f['total_label'] = 'Total:'
|
||||
else:
|
||||
f['total_label'] = 'SubTotal:'
|
||||
f['total'] = "%0.2f" % total
|
||||
|
||||
f.render(outputname)
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Test images flow mode (cell-like, trigger page breaks)"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=issue_14.pdf
|
||||
#PyFPDF-cover-test:hash=7e4a5b0a77c4eaefa475bb7db655fcd9
|
||||
#PyFPDF-cover-test:res=../tutorial/logo_pb.png
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
|
||||
for i in range(1,41):
|
||||
# for flow mode, do not pass x or y:
|
||||
pdf.image(os.path.join(common.basepath, '../tutorial/logo_pb.png'))
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Test issue 33 (Cannot import GIF files that don't have transparency)"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=issue_33.pdf
|
||||
#PyFPDF-cover-test:hash=be95c7ef3a5b14b5a54a52f7eaf3a9e4
|
||||
#PyFPDF-cover-test:2to3=no
|
||||
#PyFPDF-cover-test:pil=yes
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os, sys, tempfile
|
||||
try:
|
||||
try:
|
||||
import Image
|
||||
except:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
|
||||
def genbar():
|
||||
# bg
|
||||
bg = Image.new("L", (112, 1), 1)
|
||||
bg = bg.resize((112, 11))
|
||||
# stripes
|
||||
vbarnum = [0x4F43484B, 0xEE90D642, 0xF11A2735, 0xD71A]
|
||||
vbar = Image.new("L", (112, 1), 1)
|
||||
pix = vbar.load()
|
||||
pos = 0
|
||||
for b in vbarnum:
|
||||
for i in range(32):
|
||||
pix[pos, 0] = 0 if (b & 1) else 1
|
||||
b = b >> 1
|
||||
pos += 1
|
||||
if pos >= 112: break
|
||||
vbar = vbar.resize((112, 31), Image.NEAREST)
|
||||
# digit
|
||||
dignum = [0x398, 0x6dc, 0x61a, 0x31b, 0x1bf, 0x6d8, 0x7d8]
|
||||
dbar = Image.new("L", (16, 7), 1)
|
||||
pix = dbar.load()
|
||||
pos = 0
|
||||
ypos = 0
|
||||
for b in dignum:
|
||||
for i in range(16):
|
||||
pix[pos, ypos] = 0 if (b & 1) else 1
|
||||
b = b >> 1
|
||||
pos += 1
|
||||
ypos += 1
|
||||
pos = 0
|
||||
# result
|
||||
bar = Image.new("L", (114, 44), 2)
|
||||
bar.paste(vbar, (1, 1))
|
||||
bar.paste(bg, (1, 32))
|
||||
for i in range(4):
|
||||
bar.paste(dbar, (35 + i * 12, 34))
|
||||
return bar
|
||||
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
plane = genbar()
|
||||
palette = (0,0,0, 255,255,255) + (128,128,128)*254
|
||||
img = Image.fromstring("P", plane.size, plane.tostring())
|
||||
img.putpalette(palette)
|
||||
|
||||
f = tempfile.NamedTemporaryFile(delete = False, suffix = ".gif")
|
||||
gif1 = f.name
|
||||
f.close()
|
||||
f = tempfile.NamedTemporaryFile(delete = False, suffix = ".gif")
|
||||
gif2 = f.name
|
||||
f.close()
|
||||
|
||||
img.save(gif1, "GIF", optimize = 0)
|
||||
img.save(gif2, "GIF", transparency = 1, optimize = 0)
|
||||
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial', '', 16)
|
||||
pdf.write(8, "Transparency")
|
||||
pdf.ln()
|
||||
pdf.write(8, " Transparency")
|
||||
pdf.ln()
|
||||
pdf.write(8, " Transparency")
|
||||
pdf.ln()
|
||||
pdf.image(gif1, x = 15, y = 15)
|
||||
|
||||
pdf.write(8, "Transparency")
|
||||
pdf.ln()
|
||||
pdf.write(8, " Transparency")
|
||||
pdf.ln()
|
||||
pdf.write(8, " Transparency")
|
||||
pdf.ln()
|
||||
pdf.image(gif2, x = 15, y = 39)
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
os.unlink(gif1)
|
||||
os.unlink(gif2)
|
||||
|
||||
def main():
|
||||
si = common.read_cover_info(__file__)
|
||||
da = common.parse_test_args(sys.argv, si["fn"])
|
||||
if not common.check_env(si, da):
|
||||
return
|
||||
dotest(da["fn"], da["autotest"] or da["check"])
|
||||
common.check_result(si, da)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Tests new dashed line feature (issue 35)"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=issue_35.pdf
|
||||
#PyFPDF-cover-test:hash=e8f92b3210aea65caa72f70d0f898c04
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
|
||||
pdf.dashed_line(10, 10, 110, 10)
|
||||
pdf.dashed_line(10, 20, 110, 20, 5, 5)
|
||||
pdf.dashed_line(10, 30, 110, 30, 1, 10)
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Test issue 41 (escape CR char)"
|
||||
|
||||
#PyFPDF-cover-test:format=TXT
|
||||
#PyFPDF-cover-test:fn=issue_41.txt
|
||||
#PyFPDF-cover-test:hash=c576afec3362a7cc3b4b07a12feeefd3
|
||||
|
||||
import common # common set of utilities
|
||||
import fpdf
|
||||
|
||||
import sys
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
txt = "This is test string for issue41 with special symbols \n" +\
|
||||
"ln - \n\n" +\
|
||||
"cr - \r\n" +\
|
||||
"\\ ( ) abcdef..xyz 01234\n" +\
|
||||
"| [ ] ABCDEF..XYZ 56789\n"
|
||||
|
||||
pdf = fpdf.FPDF()
|
||||
f = open(outputname, "wb")
|
||||
f.write(pdf._escape(txt).encode("latin1"))
|
||||
f.close()
|
||||
|
||||
def main():
|
||||
si = common.read_cover_info(__file__)
|
||||
da = common.parse_test_args(sys.argv, si["fn"])
|
||||
if not common.check_env(si, da):
|
||||
return
|
||||
dotest(da["fn"], da["autotest"] or da["check"])
|
||||
common.check_result(si, da)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic test to reproduce issue 60: RTL languages (arabian, hebrew, etc.)"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=issue_60.pdf
|
||||
#PyFPDF-cover-test:hash=bc47380ca9511b96756d1066a3b494c1
|
||||
#PyFPDF-cover-test:res=font/DejaVuSans.ttf
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import sys, traceback, os
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.compress = False
|
||||
pdf.add_page()
|
||||
pdf.add_font('DejaVu', '', \
|
||||
os.path.join(common.basepath, 'font/DejaVuSans.ttf'), uni=True)
|
||||
pdf.set_font('DejaVu', '', 14)
|
||||
# this will be displayed wrong as actually it is stored LTR:
|
||||
text= u"این یک متن پارسی است. This is a Persian text !!"
|
||||
pdf.write(8, text)
|
||||
pdf.ln(8)
|
||||
# Reverse the RLT using the Bidirectional Algorithm to be displayed correctly:
|
||||
# (http://unicode.org/reports/tr9/)
|
||||
from bidi.algorithm import get_display
|
||||
rtl_text = get_display(text)
|
||||
pdf.write(8, rtl_text)
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
from bidi.algorithm import get_display
|
||||
except ImportError:
|
||||
traceback.print_exc(file = sys.stdout)
|
||||
common.err("This test requre PyBiDi (https://pypi.python.org/pypi/python-bidi)")
|
||||
common.log("SKIP")
|
||||
sys.exit(0)
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
|
||||
"Basic test to reproduce issue 63: warning in unicode get_char_width"
|
||||
|
||||
#PyFPDF-cover-test:res=font/DejaVuSans.ttf
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os, struct
|
||||
|
||||
if common.PY3K:
|
||||
def u(x):
|
||||
return x
|
||||
else:
|
||||
import codecs
|
||||
def u(x):
|
||||
return codecs.unicode_escape_decode(x)[0]
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
|
||||
pdf = FPDF()
|
||||
pdf.set_font('Arial','',14)
|
||||
s = 'Texto largo que no cabe en esta celda pero que será ajustado'
|
||||
w = pdf.get_string_width(s)
|
||||
if not nostamp:
|
||||
print (s, w)
|
||||
assert round(w, 2) == 135.90
|
||||
pdf.add_font('DejaVu', '', './font/DejaVuSans.ttf', uni=True)
|
||||
pdf.set_font('DejaVu', '', 14)
|
||||
s = u('Texto largo que no cabe en esta celda pero que será ajustado')
|
||||
w = pdf.get_string_width(s)
|
||||
if not nostamp:
|
||||
print (s, w)
|
||||
assert round(w, 2) == 153.64
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic test to check issue 70: raise an exception if add_page was not called"
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os, struct
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
try:
|
||||
# Portrait, millimeter units, A4 page size
|
||||
pdf = FPDF("P", "mm", "A4")
|
||||
# Set font: Times, normal, size 10
|
||||
pdf.set_font('Times','', 12)
|
||||
##pdf.add_page()
|
||||
# Layout cell: 0 x 5 mm, text, no border, Left
|
||||
pdf.cell(0,5,'Input 1 : ',border=0,align="L")
|
||||
pdf.cell(0,5,'Input 2 : ', border=0,align="L")
|
||||
pdf.cell(0,5,'Recomendation : ', border=0, align="L")
|
||||
pdf.cell(0,5,'Data 1 :', border=0, align="L" )
|
||||
pdf.cell(0,5,'Data 2 :', border=0, align="L" )
|
||||
pdf.output(outputname,'F')
|
||||
except RuntimeError as e:
|
||||
assert e.args[0] == "FPDF error: No page open, you need to call add_page() first"
|
||||
else:
|
||||
raise RuntimeError("Exception not raised!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic test to check issue 71: test Code39"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=issue_71.pdf
|
||||
#PyFPDF-cover-test:hash=1575947cac5b0a8cdceedf9b525ee6db
|
||||
# get res from http://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Code_3_of_9.svg/262px-Code_3_of_9.svg.png
|
||||
# PyFPDF-cover-test:res=.png
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
# Portrait, millimeter units, A4 page size
|
||||
pdf = FPDF("P", "mm", "A4")
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
# Set font: Times, normal, size 10
|
||||
pdf.add_page()
|
||||
if not nostamp:
|
||||
# do not show picture in batch
|
||||
url = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Code_3_of_9.svg/262px-Code_3_of_9.svg.png"
|
||||
pdf.image(url, 10, 10)
|
||||
|
||||
pdf.code39("*wikipedia*", 12.75, 7, 1.49)
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Test jpeg image embedding"
|
||||
|
||||
# Note: img_cmyk.jpg has no color profile, PDF rendering may vary
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=jpeg.pdf
|
||||
#PyFPDF-cover-test:hash=eb8db8f336226f6de671a3e515b9cc61
|
||||
#PyFPDF-cover-test:res=img_gray.jpg
|
||||
#PyFPDF-cover-test:res=img_rgb.jpg
|
||||
#PyFPDF-cover-test:res=img_cmyk.jpg
|
||||
|
||||
import common # test utilities
|
||||
from fpdf import FPDF
|
||||
|
||||
import sys
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial', '', 14)
|
||||
|
||||
pdf.text(10, 57, 'DeviceGray')
|
||||
pdf.image("img_gray.jpg", 55, 5)
|
||||
|
||||
pdf.text(10, 157, 'DeviceRGB')
|
||||
pdf.image("img_rgb.jpg", 55, 105)
|
||||
|
||||
pdf.text(10, 257, 'DeviceCMYK')
|
||||
pdf.image("img_cmyk.jpg", 55, 205)
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Simple test to check alias_nb_pages replacement under unicode fonts"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=nb_pages.pdf
|
||||
#PyFPDF-cover-test:hash=4f22df85e31007cb275fabdc9fa78f97
|
||||
#PyFPDF-cover-test:res=font/DejaVuSansCondensed.ttf
|
||||
|
||||
import common
|
||||
import fpdf
|
||||
|
||||
import os
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = fpdf.FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
fpdf.set_global("FPDF_CACHE_MODE", 1)
|
||||
# set default alias: {nb} that will be replaced with total page count
|
||||
pdf.alias_nb_pages()
|
||||
|
||||
# Add a Unicode font (uses UTF-8)
|
||||
pdf.add_font('DejaVu', '', \
|
||||
os.path.join(common.basepath, "font", 'DejaVuSansCondensed.ttf'), \
|
||||
uni = True)
|
||||
pdf.set_font('DejaVu', '', 14)
|
||||
|
||||
for i in range(5):
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial','B',16)
|
||||
pdf.cell(40,10,'Hello World! Page %d from {nb}' % (i + 1))
|
||||
pdf.set_font('DejaVu','',14)
|
||||
pdf.cell(40,30,'Hello World! unicode {nb}')
|
||||
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic example to test py3k conversion"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=py3k.pdf
|
||||
#PyFPDF-cover-test:hash=ecf5ec7b9a3bb6015b4c9f0546f62e84
|
||||
#PyFPDF-cover-test:python2=no
|
||||
|
||||
import common # test utilities
|
||||
from fpdf import FPDF
|
||||
|
||||
import sys
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial', '', 14)
|
||||
pdf.ln(10)
|
||||
if nostamp:
|
||||
data = "TEST-TEST-TEST"
|
||||
else:
|
||||
data = sys.version
|
||||
|
||||
#áéíóúüñ
|
||||
# This string converted with errors in py2.x
|
||||
pdf.write(5, ('hello world %s áéíóúüñ' % data))
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic example to test PyFPDF"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=simple.pdf
|
||||
#PyFPDF-cover-test:hash=1fd821a42cb5029a51727a6107b623ec
|
||||
#PyFPDF-cover-test:pil=yes
|
||||
#PyFPDF-cover-test:res=../tutorial/logo.png
|
||||
#PyFPDF-cover-test:res=flower2.jpg
|
||||
#PyFPDF-cover-test:res=lena.gif
|
||||
|
||||
import common # test utilities
|
||||
from fpdf import FPDF
|
||||
|
||||
import sys
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial', '', 14)
|
||||
pdf.ln(10)
|
||||
if nostamp:
|
||||
data = "TEST-TEST-TEST"
|
||||
else:
|
||||
data = sys.version
|
||||
|
||||
pdf.write(5, 'hello world %s' % data)
|
||||
pdf.image("../tutorial/logo.png", 50, 50)
|
||||
pdf.image("flower2.jpg", 100, 50)
|
||||
pdf.image("lena.gif", 50, 75)
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"This is test template"
|
||||
|
||||
# Lines below must not be separated by blank line
|
||||
# output formats PDF (can be auto-opened), TXT
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
# default filename
|
||||
#PyFPDF-cover-test:fn=template.pdf
|
||||
# hash stamp for compare in --check mode (insert your hash)
|
||||
#PyFPDF-cover-test:hash=b1812fffdcf175976e80317b3766a0f0
|
||||
# use 2to3 tool (default - no)
|
||||
#PyFPDF-cover-test:2to3=no
|
||||
# can be used in python2 (default - yes)
|
||||
#PyFPDF-cover-test:python2=yes
|
||||
# can be used in python3 (default - yes)
|
||||
#PyFPDF-cover-test:python3=yes
|
||||
# is PIL required (default - no)
|
||||
#PyFPDF-cover-test:pil=no
|
||||
# only for platform (default all - *)
|
||||
#PyFPDF-cover-test:platform=*
|
||||
#...
|
||||
#...PyFPDF-cover-test:res=some_resource.ttf
|
||||
#...PyFPDF-cover-test:res=other_resource.txt
|
||||
#...
|
||||
|
||||
import common # common set of utilities
|
||||
from fpdf import FPDF
|
||||
|
||||
import sys
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
# filename - output filename
|
||||
# nostamp - do no use stamp in result file
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
pdf.add_page()
|
||||
pdf.set_font('Arial', '', 16)
|
||||
pdf.write(8, "Test template")
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Basic test of TrueType Unicode font handling"
|
||||
|
||||
#PyFPDF-cover-test:res=font/DejaVuSansCondensed.ttf
|
||||
#PyFPDF-cover-test:res=dejavusanscondensed.cw.dat
|
||||
|
||||
import common
|
||||
from fpdf.ttfonts import TTFontFile
|
||||
|
||||
import os, struct
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
ttf = TTFontFile()
|
||||
ttffile = os.path.join(common.basepath, "font", "DejaVuSansCondensed.ttf");
|
||||
ttf.getMetrics(ttffile)
|
||||
# test basic metrics:
|
||||
assert round(ttf.descent, 0) == -236
|
||||
assert round(ttf.capHeight, 0) == 928
|
||||
assert ttf.flags == 4
|
||||
assert [round(i, 0) for i in ttf.bbox] == [-918, -415, 1513, 1167]
|
||||
assert ttf.italicAngle == 0
|
||||
assert ttf.stemV == 87
|
||||
assert round(ttf.defaultWidth, 0) == 540
|
||||
assert round(ttf.underlinePosition, 0) == -63
|
||||
assert round(ttf.underlineThickness, 0) == 44
|
||||
# test char widths 8(against binary file generated by tfpdf.php):
|
||||
data = open(os.path.join(common.basepath, "dejavusanscondensed.cw.dat"),\
|
||||
"rb").read()
|
||||
char_widths = struct.unpack(">%dH" % int(len(data) / 2), data)
|
||||
assert len(ttf.charWidths) == len(char_widths)
|
||||
diff = []
|
||||
for i, (x, y) in enumerate(zip(char_widths, ttf.charWidths)):
|
||||
if x != y: # compare each char width
|
||||
diff.append(i)
|
||||
assert not diff
|
||||
# for checking assertion works ttf.charWidths[1] = 600
|
||||
assert tuple(ttf.charWidths) == tuple(char_widths)
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Example of unicode support based on tfPDF http://www.fpdf.org/en/script/script92.php"
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=ex.pdf
|
||||
#PyFPDF-cover-test:hash=f77f71491e1662a732212861a2d87928
|
||||
#PyFPDF-cover-test:res=font/DejaVuSansCondensed.ttf
|
||||
#PyFPDF-cover-test:res=HelloWorld.txt
|
||||
|
||||
import common
|
||||
from fpdf import FPDF
|
||||
|
||||
import os
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
pdf = FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
# Add a Unicode font (uses UTF-8)
|
||||
pdf.add_font('DejaVu', '', \
|
||||
os.path.join(common.basepath, "font", 'DejaVuSansCondensed.ttf'), \
|
||||
uni = True)
|
||||
pdf.set_font('DejaVu','',14)
|
||||
|
||||
# Load a UTF-8 string from a file and print it
|
||||
txt = open(os.path.join(common.basepath, "HelloWorld.txt"), "rb").\
|
||||
read().decode("UTF-8")
|
||||
pdf.write(8, txt)
|
||||
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"Example of unicode support winfonts based on tfPDF"
|
||||
# http://www.fpdf.org/en/script/script92.php
|
||||
|
||||
#PyFPDF-cover-test:format=PDF
|
||||
#PyFPDF-cover-test:fn=winfonts.pdf
|
||||
#PyFPDF-cover-test:platform=win32
|
||||
#PyFPDF-cover-test:res=HelloWorld.txt
|
||||
|
||||
# This test can't calc hash because TTF fonts can vary on systems
|
||||
|
||||
import common
|
||||
import fpdf
|
||||
|
||||
import os, time
|
||||
|
||||
def dotest(outputname, nostamp):
|
||||
fpdf.set_global('SYSTEM_TTFONTS', "c:\\WINDOWS\\Fonts")
|
||||
|
||||
pdf = fpdf.FPDF()
|
||||
if nostamp:
|
||||
pdf._putinfo = lambda: common.test_putinfo(pdf)
|
||||
|
||||
pdf.add_page()
|
||||
# Add a Windows System font (uses UTF-8)
|
||||
t0 = time.time()
|
||||
pdf.add_font('sysfont','','arial.ttf',uni=True)
|
||||
pdf.set_font('sysfont','',14)
|
||||
t1 = time.time()
|
||||
if not nostamp:
|
||||
common.log("ttf loading time", t1-t0)
|
||||
|
||||
# Load a UTF-8 string from a file and print it
|
||||
txt = open(os.path.join(common.basepath, "HelloWorld.txt"), "rb").\
|
||||
read().decode("UTF-8")
|
||||
pdf.multi_cell(25, 5, txt)
|
||||
|
||||
pdf.text(100, 5, '1234')
|
||||
|
||||
pdf.write(5,'To find out what\'s new in self tutorial, click ')
|
||||
pdf.set_font('','U')
|
||||
link=pdf.add_link()
|
||||
pdf.write(5,'here',link)
|
||||
|
||||
# Select a standard font (uses windows-1252)
|
||||
pdf.set_font('Arial','',14)
|
||||
pdf.ln(10)
|
||||
pdf.write(5, 'The file size of this PDF is only 12 KB.')
|
||||
|
||||
pdf.output(outputname, 'F')
|
||||
|
||||
if __name__ == "__main__":
|
||||
common.testmain(__file__, dotest)
|
||||
|
||||
Reference in New Issue
Block a user