Skip to content

Commit

Permalink
⚙️ Complete text wrap/layout engine (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
ariebovenberg authored Apr 10, 2023
1 parent bd3b009 commit de77026
Show file tree
Hide file tree
Showing 82 changed files with 48,705 additions and 1,496 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v1
Expand All @@ -20,6 +20,6 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions poetry
pip install tox tox-gh-actions poetry==1.4.1
- name: Test with tox
run: tox
8 changes: 2 additions & 6 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ sphinx:
fail_on_warning: true

build:
os: ubuntu-20.04
os: ubuntu-22.04
tools:
python: "3.10"
python: "3.11"

python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
extra_requirements:
- docs
29 changes: 29 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
Changelog
=========

0.4.0 (2023-04-10)
------------------

A big release with lots of new features and improvements.
Most importantly, the page layout engine is now complete and
can be used to create multi-page/column documents.

**Added**

- ✂️ Automatic layout of multi-style text into lines, columns, and pages
- 🔬 Automatic kerning for supported fonts
- 🖌️ Support for drawing basic shapes
- 🎨 Additional text styling options
- 📦 Make fonttools dependency optional
- 📏 Horizontal rule element

**Documentation**

- 🧑‍🏫 Add a tutorial and examples
- 📋 Polished docstrings in public API

**Performance**

- ⛳️ Document pages and fonts are now written in one efficient pass

**Breaking**

- 🌅 Drop Python 3.7 support

0.3.0 (2022-12-02)
------------------

Expand Down
32 changes: 14 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
.PHONY: clean isort isort-check format format-check fix lint type-check pytest check test documentation docs



.PHONY: init
init:
poetry install
pip install -r docs/requirements.txt

.PHONY: clean
clean:
rm -rf .coverage .hypothesis .mypy_cache .pytest_cache .tox *.egg-info
rm -rf dist
find . | grep -E "(__pycache__|docs_.*$$|\.pyc|\.pyo$$)" | xargs rm -rf

.PHONY: isort
isort:
isort .

isort-check:
isort . --check-only --diff

.PHONY: format
format:
black .

format-check:
black --check --diff .

.PHONY: fix
fix: isort format

.PHONY: lint
lint:
flake8 --exclude=.tox,build

type-check:
mypy --pretty src tests
flake8 .

check: lint isort-check format-check type-check
.PHONY: mypy
mypy:
mypy --pretty src tests examples/

pytest:
.PHONY: test
test:
pytest --cov=pdfje

test: check pytest

.PHONY: docs
docs:
@touch docs/api.rst
make -C docs/ html

.PHONY: publish
publish:
rm -rf dist/*
poetry build
Expand Down
175 changes: 118 additions & 57 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
🖍 pdf'je
🌷 pdf'je
=========

.. image:: https://img.shields.io/pypi/v/pdfje.svg?style=flat-square
Expand All @@ -20,87 +20,148 @@

**pdf·je** [`🔉 <https://upload.wikimedia.org/wikipedia/commons/a/ac/Nl-pdf%27je.ogg>`_ PDF·yuh] (noun) Dutch for 'small PDF'

Tiny library for writing simple PDFs.
Write beautiful PDFs in declarative Python.

Currently under development.
The API may change significantly until the 1.x release.
Currently in active development. See the roadmap_ for supported features.
Leave a ⭐️ on GitHub if you're interested how this develops!

💁‍♂️ Why?
----------

The most popular Python libraries for writing PDFs are quite old
and inspired by Java and PHP. **pdf'je** is a modern, Pythonic library with
a more declarative API.
Why?
----

🚀 How does it work?
--------------------
There are many PDF libraries for Python, but none of them
have these features:

Getting text on paper is super easy:
🧩 Declarative API
~~~~~~~~~~~~~~~~~~

.. code-block:: python
from pdfje import Document
Document("Olá Mundo!").write('hello.pdf')
In most PDF writers, you first create various empty objects and
then mutate them with methods like ``addText()``,
all while changing the state of the writer with methods like ``setFont()``.
**Pdf'je** is different. You describe the document you want to write,
and the library takes care of the details. No state to manage, no mutations.
This makes your code easier to reuse and reason about.

but you can of course do more:
📐 Polished typography
~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python
Legibility counts. And `kerning <https://en.wikipedia.org/wiki/Kerning>`_
— i.e. adjusting the spacing between letters — is a key part of this.
Automatic kerning is supported everywhere, from web browsers to word processors.
However, most PDF writers don't support it.
By using font metrics to calculate the correct kerning,
**pdf'je** helps you write documents that look great.

from pdfje import Page, Text, Font
🎈 Small footprint
~~~~~~~~~~~~~~~~~~

Document([
Page("""Simple is better than complex.
Complex is better than complicated."""),
Page(),
Page(["The following text is",
Text("bigger and fancier!",
font=Font.from_path('path/to/MyFont.ttf'),
size=20)])
]).write('hello.pdf')
PDF supports many features, but most of the time you only need a few.
Why install many dependencies — just to write a simple document?
Not only is **pdf'je** pure-Python, it allows you to
install only the dependencies you need.


See `the docs <https://pdfje.rtfd.io>`_ for a complete overview.
Quickstart
----------

👩‍⚕️ Is pdf'je right for me?
------------------------------
Getting text onto paper is super easy:

Try it if you:
.. code-block:: python
- 🎯 Just want to get simple text into a PDF quickly
- 🪄 Prefer coding in a declarative and Pythonic style
- 🎁 Are looking for a lightweight, permissively licensed library
- 🔭 Enjoy experimenting and contributing to something new
from pdfje import Document
Document("Olá Mundo!").write("hello.pdf")
See `the tutorial <https://pdfje.rtfd.io/en/latest/tutorial.html>`_
for a complete overview of features, including:

- Styling text including font, size, and color
- Automatic layout of text into one or more columns
- Builtin and embedded fonts
- Drawing basic shapes

.. _roadmap:

Roadmap
-------

**Pdf'je** is still in active development,
so it is not yet feature-complete.
Until the 1.0 version, the API may change with minor releases.

Features:

✅ = implemented, 🚧 = planned, ❌ = not planned

- Typesetting
- ✅ Automatic kerning
- ✅ Wrapping text into lines, columns, and pages
- ✅ Page sizes
- 🚧 Centering text
- 🚧 Justification
- 🚧 Hyphenation
- 🚧 Avoiding orphaned lines
- Drawing operations
- ✅ Lines
- ✅ Rectangles
- ✅ Circles, ellipses
- 🚧 Arbitrary paths, fills, and strokes
- Text styling
- ✅ Font and size
- ✅ Embedded fonts
- ✅ Colors
- ✅ Bold, italic
- 🚧 Underline and strikethrough
- 🚧 Superscript and subscript
- ❌ Complex fill patterns
- 🚧 Images
- 🚧 Bookmarks and links
- 🚧 Tables
- 🚧 Inline markup with Markdown (Commonmark/MyST)
- ❌ Emoji
- ❌ Tables of contents
- ❌ Forms
- ❌ Annotations

Installation
------------

Look elsewhere if you:
It's available on PyPI.

- 🕸️ Want to turn HTML into PDF -- use ``wkhtmltopdf`` instead
- 🔬 Need perfectly typeset documents -- use LaTeX instead
- 🚚 Want lots of features -- use ``reportlab`` or ``fpdf2`` instead
- ✂️ Need to parse or edit -- use ``PyPDF2`` or ``pdfsyntax`` instead
.. code-block:: bash
🥘 So, what's cooking?
----------------------
pip install pdfje
The following features are planned:
By default, no additional dependencies are installed.
If you'd like to use custom fonts, you'll need ``fontTools``,
which is included in the ``[fonts]`` extras:

- 📑 Automatic line/page breaks
- 🎨 ``rich``-inspired styles and inline markup
- 🖼️ Support for images
- ✏️ Basic drawing operations
- 🔗 Bookmarks and links
.. code-block:: bash
🎁 Installation
---------------
pip install pdfje[fonts]
It's available on PyPI.
License
-------

.. code-block:: bash
This library is licensed under the terms of the MIT license.
It also includes short scripts from other projects (see ``pdfje/vendor``),
which are also MIT licensed.

pip install pdfje
Contributing
------------

🛠️ Development
--------------
Here are some useful tips for developing in the ``pdfje`` codebase itself:

- Install dependencies with ``poetry install``.
- To write output files during tests, use ``pytest --output-path=<outpur-dir>``
- To also run more comprehensive but 'slow' tests, use ``pytest --runslow``

Alternatives
------------

If pdf'je doesn't suit your needs, here are some other options:

- PyFPDF
- ReportLab
- WeasyPrint
- borb
- wkhtmltopdf
- pydyf
4 changes: 0 additions & 4 deletions dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,3 @@ updates:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
ignore:
- dependency-name: tox
versions:
- "< 3.6, >= 3.5.a"
4 changes: 4 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.. _api:

API reference
=============

Unless otherwise noted, all classes are immutable.

.. automodule:: pdfje
:members:
:exclude-members: __namedtuple_cls__, __hash__, __weakref__, __getnewargs__,
Expand Down
3 changes: 3 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.viewcode",
"sphinx_toolbox.collapse",
"sphinx_autodoc_typehints",
]
templates_path = ["_templates"]
source_suffix = ".rst"
Expand All @@ -43,6 +45,7 @@
autodoc_member_order = "bysource"
html_theme = "furo"
highlight_language = "python3"
pygments_style = "default"
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
}
Loading

0 comments on commit de77026

Please sign in to comment.