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:
maik
2026-08-20 19:57:01 +02:00
co-authored by Claude Opus 4.8
commit a7c93fa266
654 changed files with 478133 additions and 0 deletions
@@ -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)