PrintCraft
v0.14.0, released this weekA free, open-source PDF workbench in the spirit of Acrobat.
FreeOpen sourceFree, no paid tier or account. Early alpha (v0.2)macOSUpdated yesterday
About
PrintCraft reads, organizes and combines PDFs. Pages can be rotated, deleted, inserted and reordered in a card view, and documents can be merged, split or extracted while links, form fields, layers and bookmarks survive. Rendering handles complex scripts, vertical Japanese, color emoji and transparency, search is instant, and text selection follows reading order. It opens files encrypted with RC4 up to AES-256 and respects the author's permissions. Saves are incremental with autosave and crash recovery, and a command palette reaches every tool. Written in Rust, with a command line version too. Early alpha.
- Price
- Free, Free, no paid tier or account. Early alpha (v0.2)
- License
- Apache-2.0
- Version
- 0.14.0 · Oct 25, 2026
- Platforms
- macOS
- Category
- Productivity
Featured badge
Make PrintCraft yours: show the badge on its site and the listing marks itself as linked back.
<a href="https://macgrove.app/apps/printcraft">
<img src="https://macgrove.app/badge/printcraft.svg" alt="Featured on MacGrove" width="263" height="32" />
</a>[](https://macgrove.app/apps/printcraft)What’s new
All 15 releases0.14.0LatestBig update · yesterday
- fix(cos): one decode budget per page walk, so repeated stream references cannot multiply decoding
- fix(cos, content, filters, crypt, model, render, print, a11y): bound the work that repeated keys, streams and page values multiply
- fix(limits): bound the decoding and listing work that repeated references and small inputs multiply
- fix(js, xfa): bound the text and work that form scripts and XFA data can multiply
- fix(edit,organize,create): bound the work hostile files cause in editing, page organizing and image import
- chore(sonar): exclude vendored crates and the spec-mandated MD5/RIPEMD-160 (SonarCloud rust:S4790)
Earlier
0.13.0> [!NOTE] > FreeBSD aarch64 is dropped from this release. We had to cut releases, and we cannot build this target within the 5-hour CI limit for any of the Craft apps, so we are dropping it for now. This is a known blocker, flagged for a future fix in storytold/craft-common-actions#39. FreeBSD x86_64 and every other platform are included.
> [!NOTE] > FreeBSD aarch64 is dropped from this release. We had to cut releases, and we cannot build this target within the 5-hour CI limit for any of the Craft apps, so we are dropping it for now. This is a known blocker, flagged for a future fix in storytold/craft-common-actions#39. FreeBSD x86_64 and every other platform are included.
- M14: recover existing macOS PDF associations after open and save
0.12.0> [!NOTE] > FreeBSD aarch64 is dropped from this release. We had to cut releases, and we cannot build this target within the 5-hour CI limit for any of the Craft apps, so we are dropping it for now. This is a known blocker, flagged for a future fix in storytold/craft-common-actions#39. FreeBSD x86_64 and every other platform are included.
> [!NOTE] > FreeBSD aarch64 is dropped from this release. We had to cut releases, and we cannot build this target within the 5-hour CI limit for any of the Craft apps, so we are dropping it for now. This is a known blocker, flagged for a future fix in storytold/craft-common-actions#39. FreeBSD x86_64 and every other platform are included.
- M7: lay out the Edit panel as Acrobat's
- fix(engine): PNG export writes opaque pages as RGB at deflate level 3 (3–5× faster, same size)
- M3: the mode bar has no Read tab, as in Acrobat
- fix(render): read each object stream's index once (vendored hayro-syntax patch 22)
- M4: Organize pages remembers its page size, as Acrobat does
- M3: the Tools panel has no tab strip while docked alone
- M7: lay out Format text as Acrobat's panel
- M6: renaming a field renames it in the calculations that read it
- Use chrono instead of hand-rolled UTC conversion
- M6: calculation order: read, check, fix and set the order fields calculate in
- security: enforce HTTPS on curl downloads (SonarCloud S6506)
- ci: pin GitHub Actions to full commit SHA (SonarCloud S7637)
- M6: Prepare a form ▸ Calculation order: a page to reorder, check and fix the order fields calculate in
- M6: Prepare a form ▸ Text field table: rows and columns of text fields as one edit
- M14: add Norwegian Bokmål interface and date language
- Integration batch: 218 PRs on main
- Fill & Sign marks stay upright on rotated pages
- M5: drag a line's ends (and a polygon's corners) to change its length and angle
- Preferences: list the languages alphabetically by their own name
- M14: complete Brazilian Portuguese catalog
- M6: hovering a form field shows its tooltip
- M7: keep a word on its line when its spacing differs by less than a thousandth of an em
- M7: open the paragraph editor without a fade-in
- M7: keep an applied paragraph's look until its page is drawn again
- M4: a new bookmark goes to where the reader is
- M7: keep a paragraph open with its typing when its edit fails
- M7: an added picture resized by a corner shows only at its new size
- Give the print preview's grayscale tag a bit of its own
- M14: the Preferences OK button stays in reach below the scrolling settings
- M14: Italian catalog: the 8-character digital ID password message
- M9: closing a half of a side-by-side comparison keeps the app running
- M7: a text editing session for one paragraph
- M14: JPEG and TIFF export refuse a raster of the wrong length instead of panicking
- Reject rounded page rasters beyond the pixel budget
- M7: opening a paragraph leaves the page as it is until it changes
- M5: a Replace text comment is named Replace text, not Strikethrough
- perf(render): read PDFCRAFT_TEXT_DEBUG once instead of per glyph
- perf(render): look CFF glyph names up in a map (vendored hayro-interpret patch 44)
- fix(engine): guard undo and redo refresh and roll back on failure
- M5: a stamp grows and shrinks with its handles before release
- Render: radial luminosity fades have regression coverage
- M12: XFA labels and buttons without a size grow to their content
- M9: read .p7b/.p7c certificate bundles for trust import
- fix: read the last array of a surplus-operand TJ, not the first
- M12: showing an XFA subform leaves its unnamed hidden objects hidden
- Forms: Highlight fields marks only the fields that can be filled
- M7: paint a new background over older ones
- fix(print): restore previous paper size after leaving Label mode
- M14: find Apple's Devanagari faces in the folders current macOS uses
- M14: Spanish catalog covers the bundled key union
- Page-tree walks in annot, forms and organize skip repeated children
- The image scan skips a path segment before any m instead of panicking
- Fix #3507: preserve content boundaries when merging image fragments
- Decode JavaScript hex and control escapes in AF script strings
- fix(forms): preserve comments across content streams
- Render: a doubled sign is one number, so a cm with it still has a matrix
- Control channel: wait after a failed accept instead of retrying at once
- fix(print): retain existing appearances without Subtype
- Fix named properties in forms without resources
- Pair /ActualText correctly past 256 levels of marked content
- fix(render): draw missing spacing glyphs in Japanese CID substitutes as spaces
- Keep filtered inline images whole when their data contains EI
- fix(xtask): wait for Chrome child processes to settle PDF after launcher exits
- Accept a delimiter after EI when ending an inline image
- M8: applying redactions drops structure-tree references to the comments and fields it removes
- M2: text extraction keeps doubled letters in text condensed to 20 Tz and below
- fix(a11y): resolve /MarkInfo /Marked when it is an indirect reference
- M3: let Escape close an open menu before it clears the selection
- Edit text: keep a line together across subsets of the same font
- M3: fix multiline comment hover bounds and paint order
- Parse a bare trailing "a" as AM in AcroForm date/time parsing
- fix(sign): embed the issuers of macOS Keychain identities
- Stop Std14::recognise mapping sans-serif font names to Times
- Return empty WordNum result when cents rounding carries to 1e12
- Keep zero annotation flags through XFDF export/import
- fix(render): hit-test selection against the glyph quad, not its bounding box
- M12: accept Identity CJK Unicode mappings in accessibility checks
- Redact: count shared outline items once so the walk ends
- Join /Contents pieces with a space in measure snap
- Refuse redaction marks with no readable area instead of skipping them
- M4: resolve indirect initial-view boolean preferences
- fix(comments): the eraser's size sets how wide it rubs
- feat(edit): Header & Footer can be drawn in Times or Courier
- Print: keep the picked printer for the next print
- fix(organize): imports find the objects they added when new numbers fill gaps
- fix(xfdf): a field name full of periods no longer overflows the stack on export
- fix(annot): a comment listed many times gets one display appearance
- Add thumbnail size controls to the Pages inspector
- fix(ui): the Read mode command leaves Edit as the Edit tab does
- fix(render): draw device colour in the resources' /DefaultGray, /DefaultRGB and /DefaultCMYK (vendored hayro-interpret patch 38)
- fix(ui): Fill & Sign font size resizes the selected text
- fix(save): preserve destination extended attributes on macOS
- M3: layer_set shows or hides a layer, and page_render draws with the document's view settings
- M7: the paragraph editor draws on its page only
- docs(roadmap): record #2662, the audit's one-word cover
- test: the image-drag pixel test waits for the page raster (flaky on windows-latest)
- feat(viewer): add optional gapless continuous page display
- fix(render): emit clip-only text (7 Tr) to devices for text extraction
- fix(render): apply the JP2 palette of a JPX image with no /ColorSpace
- Prevent overflow when rotating added images through automation
- fix(forms): an XFA form whose config forbids dynamic rendering is static
- Vendor and patch hayro-cmap for tolerant CMap parsing
- M8: phone pattern finds slashed and labelled unseparated numbers
- M3: extract text from glyph names outside the Adobe Glyph List
- Draw a note without an appearance as a fixed-size icon at the corner of its Rect
- Shading patterns use the stroke or fill alpha current at paint time
- fix(content): accept inline image EI without preceding whitespace
- Lay out vertical (Identity-V) text as columns in the edit layer
- Renderer: sample a mesh shading over its triangles alone, not the whole path
- Keep text rows in other layers, gs states or Tz out of a paragraph
- fix(organize): prune named destinations without recursive calls
- M6: Optimize AcroForm JavaScript snapshots and diffs
- M6: Treat AcroForm /MaxLen 0 as unlimited
- Rail: scroll the panel buttons above the page navigation in short windows
- Render: a five-point polyline is no longer painted as its bounding box
- M2: preserve word spaces around TOC leaders
- fix(a11y): join and splice page content streams with cross-stream rules
- fix(windows): present Direct3D 12 through a composition visual, so resizing doesn't stretch
- M12: an XFA script that fails partway keeps what it changed before the error
- Honor single-page redaction selections
- M5: centre selected inspector comments without changing zoom
- fix(render): use unfiltered inline image byte length before EI heuristic
- fix(engine): a reload keeps reading colours and hidden comments
- fix(edit): keep a superscript footnote marker in its paragraph's row
- fix(forms): draw fields the file leaves to the viewer, for display only
- M2: Type 0 fonts with /ToUnicode /Identity-H read their codes as Unicode
- i18n: add Central Kurdish (Sorani) as an interface language
- M12: XFA text honors its horizontal font scale
- M12: a space at the end of a line doesn't count when fitting XFA text
- M3: snapshot tests of every side panel
- M6: a push button's caption uses the font, size and color of its /DA
- M7: let a list marker open an item and a hanging indent continue it
- fix(xfa): run click scripts for every repeated print button
- feat(forms): nudge the selected field with the arrow keys in Prepare a form
- Print ▸ Properties…: the driver's options in the UI language
- fix(comments): Add a text box takes a drag that sizes the box
- i18n: add Lao (lo) translation support
- fix(automation): tools on a file the viewer reads fewer pages of answer instead of panicking
- fix(edit): keep a one-row centred title centred when it grows
- fix(print): disable Print on documents whose security forbids printing
- Layers panel: Reset to Initial Visibility
- M7: a paragraph number keeps naming the paragraph text_paragraphs listed
- M14: complete and review the Czech catalog
- M5: reduce Comments panel scans on large reviews (#2669 item 5)
- fix(cli): info, text, render and audit take the owner password of R2–R4 files
- M7: Header & footer: shrink the page content out of their way
- M6: detected form fields get no border or fill
- fix(print): offer the US #10 envelope as a paper size
- Redaction audit: an opaque filled Square annotation over text is a cover
- Treat CRLF as a single line break in fonts::wrap
- fix(ui): Korean (Hangul) file names and tab titles draw as boxes
- M3: the "Save changes?" prompt opens on Save and moves between buttons by keyboard
- M9: rewriting a certified form's XFA data is a form fill
- Forms: measure a field's own simple font, not Helvetica, when laying out its text
- fix(render): draw comma-below letters in non-embedded standard fonts …
- Fix/cli option value errors
- fix(ui): keep a closed right panel closed when a PDF asks to open on its outline
- M2: a post table version with swapped halves doesn't make a font unusable
- Keep seconds in FormCalc Time2Num/IsoTime2Num for ISO 8601 times
- fix(render): blend modes over an empty part of the page keep their colour
- fix(render): knockout transparency groups knock out
- fix(render): a stencil mask is drawn at the fill opacity once
- fix(render): a visibility expression decides what an OCMD shows
- fix(sign): explain 0x8009001D and 0xC0000225 when a store key's provider fails
- Render month and weekday names in XFA date patterns
- M10: Export to Word keeps the page background colour
- Zero-pad required integer digits in FormCalc Format()
- fix(cos): write whole reals past the 32-bit integer range as reals
- fix(ui): the password prompt takes typing on Linux again
- fix(edit): a paragraph's width handle rewraps it from its whole handle, not just the inner half
- fix(ui): the mode tabs keep the hand over a page scrolled under them
- M12: the page side of a measuring scale takes a unit, so 1:50 is 1 mm = 50 mm
- fix(forms): renaming a nested field checks the full name it would take
- fix(comments): the note editor takes the keyboard once, so V and H pick tools again
- fix(render): draw each ICC profile through itself when two have the same stream dictionary (vendored hayro-interpret patch 40)
- fix(ui): on-page text editors leave the mode tabs their pointer when scrolled under them
- fix(render): mesh triangles that share an edge leave no seam
- Ita Translate
- Hebrew file names: draw them with an installed Hebrew face when the build has none
- XFA: decode BMP and TIFF pictures
- Open: opening an already-open document focuses its tab
- fix(sign): render Unicode characters in visible signatures using bundled Inter font
- docs: keep one copy of the catalog paragraph in localization.md
- M10: keep dotted-leader contents entries together
- M11: remove PDF/A or PDF/X identification (optimize.remove-standards-id)
- fix(cos): check object-stream member numbers and offsets
- M9: read DocMDP permissions from the signed revision
- i18n: add Indonesian, Vietnamese, Hindi and Korean interfaces
- Edit images: rotate an image by any angle with a knob
- fix(ui): respect reading background while pages load
- M3: full screen shows one fitted page at a time, as Acrobat's Full Screen Mode
- cos: property tests for save fidelity (part of #1187)
- i18n: add Albanian (sq) interface language
- i18n: add Thai (th) interface language
- fix(ui): a second file dialog waits for the open one instead of being refused
- fix(docs): correct spelling of "Formatting" in comments
- Print: remember selected paper size across restarts (fixes #2156)
- Add Finnish interface and date language
- fix(cos): find objects a broken cross-reference table leaves out
- M14: add Catalan interface and date localization
- fix(forms): Tab and Space reach check boxes and radio buttons, and a click focuses them
- Preferences: field highlights on by default, toggle in Appearance
- Draw the widget border inside /Tx BMC so Acrobat keeps it on focus changes
- Keep Auto font size in the field properties Appearance tab
- fix(optimize): reject hostile image dimensions safely
- crypt: authenticate against encryption numbers qpdf wrote (plus one hand-derived vector)
- Issue #2365: a rebuilt file keeps the /Info and /ID of its cross-reference stream
- Issue #2366: a trailer whose /Prev is a reference still reaches the earlier sections
- M14: Polish says what a signature says, and the rest of the interface
- M5: year-first slash dates (yyyy/mm/dd, yyyy/m/d) for Fill & Sign and headers
- macOS: bring the window forward when a file is opened in the running app (fixes #1928)
- M7: show a shaped run in one text object instead of one per glyph
- M7: drop the fallback fonts a text edit leaves unused
- Ctrl+V pastes a picture from the system clipboard onto the page
- fix(sign): fill typed signature outlines with non-zero winding
- docs(claude): check for existing issues and PRs before starting a fix
- Signatures: signed attributes must carry the message digest and the data content type
- Signatures: the message bar shows a problem before "Certified by"
- M10: Two-sided starts at Printer default, so the printer's own duplex applies
- fix(combine): let the cards zoom to 500%
- M12: Compare panel filters text changes and visual differences (gap 21)
- fix(edit): draw the Cyrillic the Japanese faces lack with the bundled Inter face
- fix(xfa): enforce maxLength on rich-text fields
- fix(xfa): reflow growable multiline fields after filling
- Wake idle windows for pending recovery snapshots
- fix(ui): show the physical page position under a labelled page box
- M14: complete the French interface catalog (267 entries)
- Preferences: always use my default zoom and page layout
- README: the app icon above the title
- fix: add generic font-family fallbacks (SonarCloud css:S4649)
- Build each crate's integration tests as one binary
- fix(cos, sign): close encryption and signature-validation gaps from a security scan
- fix(engine, automation, js, platform): enforce copy, print and removal limits and check code compiled from strings
- fix(xfdf, create, optimize): keep imported comments off form fields, draw imported redaction marks, neutralise CSV formulas and bound two parsers
- fix(redact): remove hidden information completely or refuse, and bound its scan
- fix(a11y, fonts, export, optimize): bound the work that repeated page, font and export structures multiply
- fix(redact): redact what the page draws, check every input stream, and bound redaction's work
- @AdrianTM made their first contribution in
- @ohagmann made their first contribution in
- @nikolainyegaard made their first contribution in
- @johnpetersa19 made their first contribution in
- @eliets2 made their first contribution in
- @narain1 made their first contribution in
- @ffishman made their first contribution in
- @MichaelMuClaude made their first contribution in
- @hazeliscoding made their first contribution in
- @jpeskov made their first contribution in
- @rahul05ranjan made their first contribution in
- @Jayesh-Prajapati9 made their first contribution in
- @amanmprojects made their first contribution in
- @MatrixMagician made their first contribution in
- @Lombardi2003 made their first contribution in
- @petarlaf made their first contribution in
- @robertobulltech made their first contribution in
- @DjPeepjay made their first contribution in
- @Ozt-y made their first contribution in
- @djmushin made their first contribution in
- @majidninja made their first contribution in
- @Lcoding15 made their first contribution in
- @Nyanpasuwu made their first contribution in
- @Dubblbindong made their first contribution in
- @fanyzp made their first contribution in
- @bounkirdni-2025 made their first contribution in
- @qwerin made their first contribution in
- @boneyland made their first contribution in
- @brian-moon made their first contribution in
- @Harrison-Booth made their first contribution in
- @TiagoCK made their first contribution in
- @Bode512 made their first contribution in
- @Nai-ITA made their first contribution in
- @PINYOPATTANAWASANPORN made their first contribution in
- @Saimirbaci made their first contribution in
- @mixlnwuu made their first contribution in
- @arpan-star made their first contribution in
- @Janiz-zzz made their first contribution in
- @guillemvela made their first contribution in
- @marcintrojnacki made their first contribution in
- @Atalantis made their first contribution in
0.11.0Skip CodeRabbit reviews on Dependabot PRs
- Skip CodeRabbit reviews on Dependabot PRs
- fix(redact): evaluate OCMD visibility during sanitization
- ci: switch to shared nix workflow from craft-common-actions
- Release: PdfCraft v0.11.0
- Source
- GitHub releases
- Last checked
Similar apps
- PhotoCraft

PhotoCraftA free, open-source image editor laid out like Photoshop.Free - FilmCraft

FilmCraftA free, open-source video editor that works like Premiere Pro.Free - PDFgear

PDFgearFree PDF editor that also reads, merges and converts documents.Free - Longform Box

Longform BoxSimple writing and graphics for shareable, printable storiesPaid - Craft

CraftTop pickA polished native editor for good-looking notes and documents.Freemium - Acorn

AcornAn image editor for people who are not professional photographers.Paid - AFFiNE

AFFiNETop pickOpen-source workspace that combines docs, whiteboards, and databases.Freemium - Figma

FigmaCollaborative interface design tool with a desktop app for Mac.Freemium




