B4J Code Snippet [PyBridge] Create pdf with fpdf2


This is a console app, based on the console template: [PyBridge] Console (non-ui) project template

Dependency: pip install fpdf2
B4X:
'Html - html string
'img - Background image. Can be array of bytes or a string with the path to the image file.
Public Sub HtmlToPDF (Html As Object, img As Object) As PyWrapper
    Dim Code As String = $"
import fpdf

def HtmlToPDF (Html, img):
    pdf = fpdf.FPDF()
    pdf.add_page()
    if not img is None:
        pdf.image(img, x=0, y=0, w=210, h=297)
    pdf.write_html(Html)
    return pdf.output()
"$
    Return Py.RunCode("HtmlToPDF", Array(Html, img), Code)
End Sub

1742967903293.png
 

Attachments

  • fpdf2.zip
    14.5 KB · Views: 150

Theera

Expert
Licensed User
Longtime User
Hi Erel,
After I've downloaded example for learning,I clicked the global python linked for install fpdf (pip install fpdf2) and ran it. I've error message.
How do I solve it,please?

Server is listening on port: 51672
Python path: C:\Python\Python313\python.exe
connected
starting PyBridge v1.00
watchdog set to 30 seconds
Connecting to port: 51672
main._appstart (java line: 44)
java.lang.RuntimeException: java.lang.RuntimeException: (main._htmltopdf) - Python Error (TypeError) - Method: function.__call__: argument should be integer or bytes-like object, not 'str'
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at anywheresoftware.b4a.keywords.Common$3.run(Common.java:1172)
at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:181)
at b4j.example.main._appstart(main.java:44)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at b4j.example.main.main(main.java:28)
Caused by: java.lang.RuntimeException: (main._htmltopdf) - Python Error (TypeError) - Method: function.__call__: argument should be integer or bytes-like object, not 'str'
at b4j.example.pywrapper.raiseError(pywrapper.java:623)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
at b4j.example.pywrapper._getvalue(pywrapper.java:248)
at b4j.example.main$ResumableSub_Start.resume(main.java:204)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:156)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:105)
... 11 more
 

Theera

Expert
Licensed User
Longtime User
I'm sorry that I found my problem. I installed fpdf instead of fpdf2.
 

Pablo Torres

Active Member
Licensed User
Longtime User

This is a console app, based on the console template: [PyBridge] Console (non-ui) project template

Dependency: pip install fpdf2
B4X:
'Html - html string
'img - Background image. Can be array of bytes or a string with the path to the image file.
Public Sub HtmlToPDF (Html As Object, img As Object) As PyWrapper
    Dim Code As String = $"
import fpdf

def HtmlToPDF (Html, img):
    pdf = fpdf.FPDF()
    pdf.add_page()
    if not img is None:
        pdf.image(img, x=0, y=0, w=210, h=297)
    pdf.write_html(Html)
    return pdf.output()
"$
    Return Py.RunCode("HtmlToPDF", Array(Html, img), Code)
End Sub

View attachment 162922
Sorry Erel but when I run this code in my machine it throws an error, I have tried this for several days and I dont know what I'm doing wrong.
The code is exactly the one you posted, I did not made any changes and here is the logs:

<logs>
Waiting for debugger to connect...
Program started.
Server is listening on port: 52234
Python path: C:\Program Files\Anywhere Software\B4J\libraries\Python\python\python.exe
connected
starting PyBridge v1.00
watchdog set to 30 seconds
Connecting to port: 52234
Error occurred on line: 130 (PyWrapper)
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
at b4j.example.pywrapper._getvalue(pywrapper.java:106)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at anywheresoftware.b4a.shell.DebugResumableSub$RemoteResumableSub.resume(DebugResumableSub.java:21)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:156)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:105)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at anywheresoftware.b4a.keywords.Common$3.run(Common.java:1172)
at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
at anywheresoftware.b4a.shell.ShellBA.startMessageLoop(ShellBA.java:121)
at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:181)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:309)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at b4j.example.main.main(main.java:29)
Caused by: java.lang.RuntimeException: (main._htmltopdf) - Python Error (ModuleNotFoundError) - Method: module.exec: No module named 'fpdf'
at b4j.example.pywrapper.raiseError(pywrapper.java:1042)
... 39 more
</logs>
 

Pablo Torres

Active Member
Licensed User
Longtime User
Same error stands

(main._htmltopdf) - Python Error (ModuleNotFoundError) - Method: module.exec: No module named 'fpdf'
 

Theera

Expert
Licensed User
Longtime User
I'm sorry my mistake.

'After Click the global Python linked ,Type pip install fpdf2
'กรณี เผลอติดตั้ง fpdf แทน fpdf2 ต้องทำการยกเลิก แล้วติดตั้งไลบารี่ที่ถูกลงไปแทน ด้วย 2 ชุดคำสั่ง
'pip uninstall fpdf
'อย่าลืม กดปุ่ม y เพื่อยืนยันการยกเลิกติดตั้งก่อนติดตั้งอันใหม่
'pip install fpdf2
After you click the global Python linked ,you must type pip install fpdf2 ,so you must type pip uninstall fpdf before and then click "y" button ,the last you type pip install fpdf2 again. The result is within object folder.
 

BlueVision

Well-Known Member
Licensed User
Longtime User
To be honest, I'm a bit overwhelmed by how to integrate this wonderful extension into one of my B4J projects.
Primarily, it's about the correct setup of the PY-Bridge and the installation of fdpf2.
The articles on integrating PY-Bridge don't really help me (or I haven't found the right posts yet). Am I the only one who doesn't understand how to do this? Can someone please point me in the right direction?
 

Theera

Expert
Licensed User
Longtime User
1.Click local Python linked
2.In the DOS.prompt, install fpdf2 >pip install fpdf2
3. Run the example
 

BlueVision

Well-Known Member
Licensed User
Longtime User
Thanks Theera,

But local Python? Not the Global as described by Erel in the setup? I defined a Global Python here:
And this is not a cropped Image. It is the way it appears on my T430 (Lenovo). The buttons are hardly visible. Anyway. To complete this setup, you have to click the right button.
1756655500348.png


Next:
The downloaded fpdf2 file is 2times compressed. Do I have to uncompress it once or twice? How is PIP directed to the path with the downloaded file?
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Pip will find the file from trusted sources for you - it just needs the name fpdf2

PS C:\Users\User> pip install fpdf2
Collecting fpdf2
Downloading fpdf2-2.8.4-py2.py3-none-any.whl.metadata (72 kB)
Collecting defusedxml (from fpdf2)
Using cached defusedxml-0.7.1-py2.py3-none-any.whl.metadata (32 kB)
Collecting Pillow!=9.2.*,>=8.0.0 (from fpdf2)
Downloading pillow-11.3.0-cp313-cp313-win_amd64.whl.metadata (9.2 kB)
Collecting fonttools>=4.34.0 (from fpdf2)
Downloading fonttools-4.59.2-cp313-cp313-win_amd64.whl.metadata (111 kB)
Downloading fpdf2-2.8.4-py2.py3-none-any.whl (251 kB)
Downloading fonttools-4.59.2-cp313-cp313-win_amd64.whl (2.3 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.3/2.3 MB 21.3 MB/s 0:00:00
Downloading pillow-11.3.0-cp313-cp313-win_amd64.whl (7.0 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7.0/7.0 MB 33.4 MB/s 0:00:00
Using cached defusedxml-0.7.1-py2.py3-none-any.whl (25 kB)
Installing collected packages: Pillow, fonttools, defusedxml, fpdf2
Successfully installed Pillow defusedxml fonttools fpdf2
 

BlueVision

Well-Known Member
Licensed User
Longtime User
The question is: What do I have to start for submitting the pip command?
There is the WinPython Command Prompt.exe. Probably wrong.
Then a IDLE (Python GUI).exe. Probably also wrong.
Getting always a syntax error message when entering pip install fpdf2.
Sorry if this sounds totally stupid... My first attempts...

Feeling like having a key in my hands to open the door, but there is no hole in the door for the key...
 

Daestrum

Expert
Licensed User
Longtime User
What I do - change the pyoptions line to point to my global python. (I use my global version all the time not a local version)
Then just use a command prompt (pip knows where python is)

to test if your global python is set up ok

cmd prompt > pip --version ( this tells you 2 things , it can find pip and the version of it)
cmd prompt > python --version (like above but for python)

If you get not recognised as program.... - then your python is not set up correctly.
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
Check in environment settings that python has been added to the path (python and python/scripts) Your path will be different depending where you installed python.

1756659978557.png
 

BlueVision

Well-Known Member
Licensed User
Longtime User
Just switched to the local python, download and installation was done thanks to your advice.
I ran Erel's example and the PDF was created.
So next is to modifying his subroutine for running within my program.

I read that it might be better to work with a copy of the Python distribution available in B4X, so I copied the Python folder and changed the path specification in the B4J setup. I thought that would be all. Apparently not...
Does this now have a negative impact on the distribution of a B4J package to the end user? As I understand it, the corresponding Python files are then included in the distribution. The use of local Python files would only be disadvantageous for large Python libraries. Right?

Thank you Theera and Daestrum
 
Last edited:

BlueVision

Well-Known Member
Licensed User
Longtime User
Hi Erel, thanks for responding.
I read your article above already. However, after copying the local python folder to another place, making the changes in the setup of B4J for guiding the way to the copied global python, I was still unable to run the pip command with the global python. With local python it worked immediately. Use that now, also because you told about the thing with the standalone package somewhere else I think.
This beautiful snippet works fantastic, however I have to modify a little bit. Need no connection to the net for making a HTML to PDF. I have a local HTML to convert to PDF. Should not be a big problem.
Problem was my python setup, as Daestrum already told before. Thanks for clarifying.
 
Top