An mdBook single PDF generator using pure Rust and some Node.js

Overview

mdbook-compress

crate.io version badge

An mdBook backend renderer to generate a single PDF file for a full book.

There are other similar projects, but most rely on chrome in some way to generate a PDF. This project only optionally requires Node.js to be installed for code block syntax highlighting. If you don't want highlighting you can specify that with highlight = "none" in the config (or set highlight = "no-node" to use the built-in highlighter).

Usage

To use this backend, you'll need to add the following to your book.toml file:

[output.compress]

and install this project

cargo install mdbook-compress

If you want to keep the default HTML output, you'll also need to add in [output.html] if it's not already there

The resulting PDF will end up in /book/compress/<book-title>.pdf. If you want to have a look at an example PDF, you can have a look at this one which is the whole reason this project exists in the first place.

Config options

There are a few config options. They're all below and have a few comments to explain things. All the values are the default values.

[output.compress]
# You can optionally specify a subtitle. If you don't the PDF
# won't include a subtitle
subtitle = ""
# If you want to use custom fonts, specify them here.
# The value is a path relative to 'theme/fonts' under your book root
font.regular = ""
font.bold = ""
font.italic = ""
font.bold-italic = ""
font.monospace = ""
# Font sizes. Any heading after H6 will use the H6 font size
# All font sizes will become a u8
font_size.title = 12
font_size.h1 = 11
font_size.h2 = 10
# H3 is also used for the subtitle
font_size.h3 = 8
font_size.h4 = 7
font_size.h5 = 6
font_size.h6 = 6
font_size.text = 5
# Page configs
# Page size. One of: A4, US letter, US legal (see below for custom sizes)
page.size = "A4"
page.landscape = false
# Insert a page break between chapters (markdown files)
page.new_pages = false
# Line and margin spacing. Both measured in millimeters (f64 internally)
page.spacing.line = 1.5
page.spacing.heading = 2.0
page.spacing.margin = [20.0, 20.0]
# See the highlighting section below
highlight = "all"

Custom page sizes

If you need a custom page size, you can give the width and height (x and y) dimensions in millimeters like this

page.size = { x = "width", y = "height" }

Highlighting

Code highlighting with highlight.js (what mdbook uses for the HTML) is pretty slow because it requires calling a node command. To fix this, this project uses syntect to do any highlighting. However, if you specify a custom highlight.js script in the themes directory of your book, the code will use that.

You can change this though. The highlight value of the config can be one of:

  • "all" (default)
    Use highlight.js file when given otherwise use syntect
  • "no-node"
    Always use syntect even if a highlight.js file is given. In this case you can give .sublime-syntax files in your theme folder that will be used for highlighting. This way you can have a faster alternative to Node whilst keeping custom highlighting
  • "none"
    Don't do any highlighting

It's worth noting that the highlighting colours for syntect and highlight.js are different because they're different programs

If you use syntect, you can provide a custom theme.tmtheme file in your theme directory. If this is a valid theme, that'll get used for highlighting. If not, the theme base16-ocean.light is used instead.

Why does it take so long?

If you're using a custom highlight.js file, this might make the renderer a bit slow. This is due to having to call Node.js for each code block. You should only use this if you require highlighting a language not supported by syntect.

Things still to add

  • Images (This is not possible with genpdf... at the moment)
  • Custom highlight.js theme application (Can have a custom syntect theme)

Dependencies

If you want to know what different dependencies are used for, here you go. The descriptions are all a bit general, because anything more specific would make the table too big.

Dependency Version Use
serde 1.0.152 Config struct deserialisation
mdbook 0.4.25 Getting mdbook config and some error printing
genpdf 0.2.0 PDF building (really nice library btw)
anyhow 1.0.68 Error handling
scraper 0.14.0 Parsing HTML outputs
ego-tree 0.6.2 Required for function call types when highlighting
pulldown-cmark 0.9.2 Markdown parsing
syntect 0.5.0 Built-in code highlighting
You might also like...
Single-side boolean deserializers.

serde-bool Single value, true or false, boolean deserializers. Examples Supporting serde untagged enums where only one boolean value is valid, allowin

A relatively simple puzzle generator application written in Rust and used via Javascript
A relatively simple puzzle generator application written in Rust and used via Javascript

Puzzlip Basic Overview This is a relatively simple puzzle generator application written in Rust and used via Javascript in https://puzzlip.com. If you

An LR(1) parser generator and visualizer created for educational purposes.
An LR(1) parser generator and visualizer created for educational purposes.

.lr An LR(1) parser generator and visualizer created for educational purposes. Table of Contents What is an LR(1) parser? Why did you make this? How c

Local-first linkspage generator

weird.one Local-first linkspage generator Usage You'll need Perseus and SurrealDB. Start the SurrealDB instance. surreal start -u root -p root --log d

Uniswap V4 Hooks Salt Generator

A lightweight library designed to generate precise salt values with the correct bits prefix for V4 hooks. Simplify your hook development with targeted, easy-to-integrate salt generation.

An i386 operation system written in pure rust for fun and no profit.

OrustS An i386 operation system written in pure rust (for fun and no profit). This operation system is under active developing. Checklist implement a

An implementation of Olm and Megolm in pure Rust.

A Rust implementation of Olm and Megolm vodozemac is a Rust implementation of libolm, a cryptographic library used for end-to-end encryption in Matrix

High-order Virtual Machine (HVM) is a pure functional compile target that is lazy, non-garbage-collected and massively parallel
High-order Virtual Machine (HVM) is a pure functional compile target that is lazy, non-garbage-collected and massively parallel

High-order Virtual Machine (HVM) High-order Virtual Machine (HVM) is a pure functional compile target that is lazy, non-garbage-collected and massivel

Highly experimental, pure-Rust big integer library

grou-num (Pronounced "groo", from the Chiac meaning "big") This package is a highly experimental, unstable big integer library. I would not recommend

Releases(v0.2.1)
Owner
nxe
I make code, code sometime work, but don't ask me why. Okay bye x
nxe
An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous and blocking clients respectively.

eithers_rust An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous a

null 2 Oct 24, 2021
A fast uuid generator in Python using Rust

ruuid A fast UUID generator for Python built using Rust. Its a simple wrapper on top of Rust's UUID crate. How to use? Installation: pip3 install ruui

Rahul Nair 19 Jul 13, 2022
Some UwU and OwO for your Rust code

UwU Types Some UwU and OwO for your Rust code This is a Rust crate inspired by this tweet from @thingskatedid / @katef. Credits Some extra functionali

Evan Pratten 12 Feb 8, 2022
An attempt to start documenting the rust sdk for temporal and how to use it following some of the examples in typescript

This is an attempt to start documenting the rust sdk for temporal and how to use it following some of the examples in typescript.

Cosm 5 May 24, 2023
Print out some fibonacci numbers.

give-me-some-fibonacci A Rust library for some fibonacci. TL;DR: its just a joke. Usage To get started using give_me_some_fibonacci, just add this to

Leonardo Vieira 2 Mar 22, 2022
A collection (eventually) of examples that use some non-beginner things.

nannou examples A collection (eventually) of examples that use some non-beginner things. Right now the only example combines nannou's standard draw AP

Alexis Andre 22 Oct 21, 2022
Shows how to implement USB device on RP2040 in Rust, in a single file, with no hidden parts.

Rust RP2040 USB Device Example This is a worked example of implementing a USB device on the RP2040 microcontroller, in Rust. It is designed to be easy

Cliff L. Biffle 9 Dec 7, 2022
Download a single file from a Git repository.

git-download Microservices architecture requires sharing service definition files like in protocol buffer, for clients to access the server. To share

Akira Hayakawa 2 Jun 7, 2022
A crate for converting an ASCII text string or file to a single unicode character

A crate for converting an ASCII text string or file to a single unicode character. Also provides a macro to embed encoded source code into a Rust source file. Can also do the same to Python code while still letting the code run as before by wrapping it in a decoder.

Johanna Sörngård 17 Dec 31, 2022
Construct complex structures within single call + simple compile-time meta-inheritance model with mixins.

Introduction constructivism is a Rust sample-library designed to simplify the construction of structured data by defining and manipulating sequences o

polako.rs 5 Oct 24, 2023