Metadata-Version: 2.5
Name: vec_io
Version: 0.2.0
Summary: Create PDFs in Python: drawing APIs, SVG conversion, rasterization and more
Project-URL: Repository, https://github.com/ajgouhier/vec_io
Author-email: Arthur Gouhier <ajgouhier@gmail.com>
License-Expression: BSD-3-Clause
License-File: LICENSE
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: flake8; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: ziglang==0.15.1; extra == 'dev'
Description-Content-Type: text/markdown

# vec_io

Create PDF files in Python: convert SVG, draw pages, plot data, render PNG or JPEG.
No dependencies: a bundled C library does the heavy lifting.

![showcase](examples/showcase.png)

* **Fonts**: installed fonts, font files and `@font-face`, variable fonts at any axis
  position; a family that is not installed is downloaded once and cached, from Google
  Fonts, the URW base 35 fonts, CTAN (TeX Gyre, Latin Modern, CMU), Fontsource or
  Fontshare (`font_downloads=False` or `VEC_IO_FONT_DOWNLOADS=0` turns that off).
* **Convert** SVG to PDF: shapes, paths, text with embedded font subsets,
  gradients, patterns, clipping, masks, markers, images (PNG, JPEG, and
  JPEG XL when libjxl is installed) and CSS.  With libjxl, images can also
  be written as JPEG XL (`/JXLDecode`, as PDFium reads it).
* **Draw on pages** with `Document` and its pages (HTML-canvas-style), in the unit of
  your choice: multiple pages, links, bookmarks, metadata, placed SVG files, markers and
  text along paths, SVG's filter effects on any group.
* **Build drawings** of elements with `vec_io.draw` (drawsvg-style names): they draw onto
  any page, and save as PDF, SVG, EPS, PNG, JPEG, JPEG XL or AVIF.
* **Read PDF**: `vec_io.open_pdf` reads PDF (and Illustrator `.ai`) files into documents,
  `draw_pdf` places a page on a canvas: text stays text, every font kind, encrypted and
  damaged files, all shadings; then write PDF, SVG, EPS or images (`vec_io in.pdf out.png`).
* **Write SVG** of what any page draws, and **EPS** (PostScript Level 3) of any page:
  transparency flattened, fonts embedded as Type 42 or CFF.
* **Lay out text**: paragraphs in boxes, justified or not, greedy or
  Knuth–Plass line breaking, kerning, ligatures, rich text with links,
  overflow into further boxes; shape and measure text without a page (`vec_io.text`).
* **Print and archive**: CMYK output, spot colors (Separation), ink limit,
  ICC output intent; PDF/A-2b, 2u and 3b with file attachments; transparency flattened
  into opaque vectors (`flatten_transparency=True`), with an image fallback for what
  vectors cannot express.
* **Plot**: markers at many points, each with its own shape, size, colors
  and opacity; lines of millions of points; many bars and polygons; grids of cells
  (heatmaps) from colors, palette indices or positions along a color table.  Coordinates
  are sequences or any buffer (`array`, numpy arrays, ...).  `simplify` leaves out what
  later points hide (within half a level per pixel) and decimates long lines.  Statistics
  and color maps are plot_io's, built on vec_io.
* **Rasterize** groups, filters and whole pages (PNG, JPEG, JPEG XL, AVIF) with the same
  rendering as the PDF.
* **Compress well, in formats every reader takes**: PNG in its smallest lossless layout, or a
  lossy palette that halves plots; progressive JPEG with trellis quantization, deringing
  and sharp 4:2:0 color (20–36% smaller at equal SSIM); `compression="best"`: Deflate with
  near-optimal parsing for every PDF stream.

## Install

```sh
pip install .
```

Python 3.11+. No dependencies. Copying the `vec_io/` directory into a project
also works.

The C library is bundled, prebuilt for Linux (x86_64, aarch64), Windows
(x86_64, arm64) and macOS (arm64); pip compiles nothing.  On other platforms,
build it with `tools/build_native.py` and point `VEC_IO_NATIVE_LIB` at it;
without it, plain vector drawing still works and the bulk features (markers,
lines, cells, rasterization, PNG, image decoding) raise
`NativeLibraryError`.

## Quick start

```python
import vec_io

vec_io.convert("drawing.svg", "drawing.pdf")
png = vec_io.convert(svg_text, format="png", dpi=192)
```

```sh
vec_io drawing.svg out.pdf
```

```python
import vec_io.draw as draw

d = draw.Drawing(400, 300)                         # CSS pixels, origin top-left
d.append(draw.Circle(200, 150, 80, fill="#e30613"))
d.append(draw.Text("Hello", 32, 200, 160, text_anchor="middle", fill="white"))
d.save("hello.pdf")
d.save("hello.svg")
```

```python
import vec_io

doc = vec_io.Document(unit="mm", title="Report")   # one unit for pages, calls and fonts
page = doc.add_page(size="A4")                     # 210 x 297 mm, origin top-left
page.font_size = 8
page.fill_text("Report", 20, 30)
page.draw_markers(xs, ys, size=1.5, fill="#111111", stroke=None)
page.draw_cells(x_edges, y_edges, indices, ["#440154", "#21918c", "#fde725"])   # a grid
doc.save("report.pdf")                             # write it, as often as needed
doc.save("small.pdf", compression="best", images=vec_io.ImagePolicy(quality=85))
page.render(dpi=150, background="white").save("report.png")   # or render a page
```

A document records what is drawn; each output (`save`, `render`) is made from the record
with its own options, in any order, and drawing may go on after a save.

## Documentation

* [API.md](API.md): the complete API, supported SVG features, fonts,
  rasterization and limits.
* [EXAMPLES.md](EXAMPLES.md): worked examples (scatter plot, bubble chart,
  heatmap, multi-page document, rasterization, filters, PNG).

## Limits

* Text: no complex-script shaping or bidirectional reordering. Pairs are kerned in all
  text; ligatures apply to laid-out paragraphs only.
* Text needs an outline font: fonts are always embedded (the standard 14 PDF fonts only
  when named with `embed=False`), and with no font installed, supplied or downloaded,
  text raises `NoFontError`.
* Filters can only be reproduced as pixels, so they are opt-in.
* Animation and scripting are ignored: the initial state is drawn.

## Development

```sh
python -m unittest discover -s tests -t tests
```

Tests generate their own fonts and images and ignore installed fonts: their default
font, PioTest, is built by `tests/testfont.py` into `tests/fonts`. They never download
fonts: download tests run against a local server, and `VEC_IO_LIVE_TESTS=1` adds one test
against each source itself.

```sh
mypy                                       # type check (configured in pyproject.toml)
```

The package ships type annotations (`py.typed`); mypy is a development tool
only.

```sh
python tools/regress.py --render --check   # output vs. HEAD on tests/corpus
python tools/regress.py --base main --system
python tools/bench.py                      # timings quoted in API.md
```

`regress.py` converts every SVG of the corpus with the working tree and with
a git revision and compares the page content streams and rasterized images
byte for byte; `--render` reports pixel differences of changed files and
`--check` reports files poppler warns about; `--eps` renders the working tree's EPS of
every file with Ghostscript against the flattened PDF.

```sh
pip install ziglang==0.15.1                # or: pip install -e .[dev]
python tools/build_native.py               # rebuild vec_io/native/bin/*
python tools/build_native.py --check       # binaries match the sources, byte for byte
python tools/crosscheck.py --qemu qemu-aarch64-static   # same pixels on x86_64 and aarch64
```

The C library and its rules (no libc, no imports, deterministic floating
point) are described in [vec_io/native/README.md](vec_io/native/README.md),
with the sanitizer build and the fuzzers (`tests/fuzz_native.py`).

```sh
python tools/verapdf.py                    # PDF/A validation of the corpus
```

`verapdf.py` converts the corpus at each PDF/A level and validates the files
with [veraPDF](https://verapdf.org) (on `PATH` or `--verapdf`); the PDF/A
unit tests also run veraPDF when it is on `PATH`.
