Python C API
24 Feb 2025 Languages fun projectPythonC/C++DjangosvgIt is usually easier to write and debug Python scripts than do it in C/C++, while for heavy computation tasks, C or C++ programs can run much faster. A common strategy to get the best of both worlds is writing the computation kernels in C/C++ and binding Python APIs to invoke the computation kernels in Python scripts. Python C API exists exactly for the purpose of binding Python with C/C++.
I learnt Python C API recently, and this post records my practice of creating a Python package, txt2qr, that uses C library libqrencode. Txt2QR generates the QR code (in SVG format) of a given text, and is easily integrated into a Django app.
Python C API
Python C API extends Python with C or C++. The tutorial on Python website covers:
- Create Python modules (
PyModule_Create(PyModuleDef)) - Register module methods (
PyMethodDefarray inPyModuleDef) - Extension function interface (convert arguments from
PyObjectand return result asPyObject) - Define exception (
PyErr_NewException) - Define object type (
PyType_Ready(PyTypeObject)to initilize the type thenPyModule_AddObjectRef()to add the type into a module) - Special object methods and attribute control (e.g., register accessors with
PyGetSetDef tp_getsetfield inPyTypeObject, register attributes withPyMemberDef tp_membersfield inPyTypeObjectwithREADONLYflags) - Reference count mechanism for dynamic memory management (
Py_INCREF()andPy_DECREF()) - Capsule approach for extension modules to be imported by other extension modules
- And many more
Following the tutorial, I was able to write some “hello world” Python extension modules. I brainstormed where this technique could be used, then there comes my Txt2QR project.
Txt2QR
QR code (quick-response code) is a widely used encoding method that represents information in a two dimentional grid of black/white dots. QR code makes it convenient to pass messages to devices with camera or scanner. I occationally want to generate QR codes for URLs (used in a presentation for example). For those commercial online tools. after the free trial, a subscription fee would be charged, or I need to sign up a new account. I have been longing to create my own free-forever solution: Txt2QR is such a project that converts any given string into a QR code and display it.
I do not want to test my understanding of QR code encoding algorithm by writing a C++ program to do so, especially the error correction part. This brings me to the libqrencode library, which is a C library that encodes information into QR codes. The APIs of libqrencode are well documented. After reading, I realize the APIs are very stright-forward that the inputs could be one of the following three:
- a C style string (
chararray ending withNULL); - a
QRinputstructure that holds not only thecharpointer but other meta info (e.g., minimal version, error correction level, hint on the character set); - a link list of
QRinputstructure;
And the output would be the QRcode structure holding QR code info in a bit mask array with version and width info.
Based on which encoding function is called, the output could be micro-QR code or QR code,
single QRcode structure or a linked list.
The most basic version of the encoding API is QRcode_encodeString(),
which encodes a string in a single QR code and it provides all the functionality my project needs.
So I write a Python extension module named pyqrencode to bind QRcode_encodeString() into Python.
Within pyqrencode module,
I registered:
- a Python type
QRcodewhich is one-to-one mapping to the C structQRcode, that has a bit mask array, version and width; - a Python method
enc()that takes a Python unicode string, feeds intoQRcode_encodeString()function with some default config, and return the encoding result in aQRcodePython object;
The inital version of pyqrencode module binding to libqrencode is as simple as this.
Later I added a Python type QRinput with more encoding configuration options for the improvement idea.
I want my Txt2QR Python package provides some visualization capability,
rather than simply staying at the level of binding libqrencode APIs.
So I also write a simple Python module file txt2qr.py,
that defines a svg() method,
where the bit mask array is iterated through to generate a SVG image.
By the way, SVG is a very nice way for visualization,
as it is essentially text-based XML document and most browsers can draw the figure described by the SVG,
with the capability of scaling and interactions.
To package the pyqrencode and txt2qr modules into one Python package,
I use setuptools
to configure the dependencies in a setup.py file.
Under the hood of the pip install . command,
it executes ./setup.py develop to get
the C extension module compiled,
and also build the package distribution to install.
So this is a pretty standard Python packaging flow.
With the txt2qr Python package installed,
a QR code SVG could be produced like the following:
import txt2qr
with open("qr.svg", "w") as fo:
fo.write(txt2qr.svg("txt2qr is amazing"))
To serve users who do not do Python programming, I also write a web page where users submit the text to a Django backend application, then the page loads the generated QR code for the given text.
Even though I did not dig deep into the error correction part of the QR code encoding algorithm, I got to know that QR code supports multiple levels of error correction, and at the highest level the information could be recovered even many bits in the QR code were wrong. So soon after I get the web page work, an improvement idea runs into my mind: what if I generate a SVG QR code that users can click on the cells to flip (black dot to white space, or vice versa)? Then users could make a little bit of pixel art on the QR code, with the message encoded in the QR code still can be delivered after error correction. For example, the following QR code encodes “LOVE”, and I augmented it with a heart shape drawn in pixels. You should be able to get the “LOVE” message from scanning, and further edit the QR code by clicking.
Closing
The Txt2QR project is a great practice of what I learnt about Python C extension, Python packaging, SVG and web development. Additionally, the outcome is a useful tool that I would definitly need it sometime. If you are interested in accessing Txt2QR repo please let me know.
Credits
- Python C API - Good tutorial where I learnt how to make Python C extension.
- Difference between attributes and properties in Python - Thanks for the great explanation to distinguish attributes and properties.
- setuptools - The setuptools for Python packaing.
- QR code - QR code wikipedia page covers many detailed informaiton about QR code.
- QR Code Model 2 Structure and Algorithms - Thanks for the nice illustration on the composition of QR codes.
- Encoding QR codes - QR code encoding explained in an interactive Observable note.
- SVG Tutorial - Tutorial on SVG.
