Commit Graph
436 Commits
Author SHA1 Message Date
Vikram Bhaskaran 3de58750cd Add PDF/X-4 validation command (#200) 2026-10-10 01:51:17 -04:00
moppeeerandmoppeeer c984624956 Make menu entries selectable across the full row (#249)
Co-authored-by: moppeeer <[email protected]>
2026-10-10 01:51:12 -04:00
SawizzleandClaude Opus 5.5 a42fa20677 docs: register the MCP server from an installed release (#269)
* docs: register the MCP server from an installed release

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* docs: drop the third-party link; the Windows path is the default install folder

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 01:51:07 -04:00
aiongg 4d16a8ce3d IDML: layers import and export in stacking order; font names with a format suffix (#247)
* IDML: layers import and export in stacking order

* Fonts: a family named with a format suffix such as (OTF) resolves to the installed family
2026-10-10 01:51:03 -04:00
DWAA1660andCodex fb68b7cc2d M5: rebind embedded image links when opening relocated packages (#235) (#244)
Reuse packaged-link candidates for embedded IDML images and native files.
Resolve missing original paths beside the opened document, retaining the
embedded image bytes and any original link that still exists. Bound path
lookup allocations and cover actual package relocation through commands.

Make existing data-merge test path assertions portable to Windows.

Co-authored-by: Codex <[email protected]>
2026-10-10 01:50:58 -04:00
skylar taylor-barrick 452134c13b FID2: preserve decoration color resets, geometry and paint order (#230) 2026-10-10 01:50:52 -04:00
skylar taylor-barrick cfac46a8d9 FID1: prevent mixed gradient color spaces from aborting PDF export (#229) 2026-10-10 01:50:47 -04:00
Vikram Bhaskaran 67d4539df7 Distribute selected table rows evenly and keep the edit undoable. (#224)
The rows share one fixed height that preserves their composed total. Merged rows and rows that are not laid out are refused, and the table stays unchanged.
2026-10-10 01:50:43 -04:00
Gert Pellin - GPE 3d2bda4d6b Desktop: write log records to standard error and a rotating log file (#122)
* Desktop: write log records to standard error and a rotating log file

The desktop app installed no logger, so every log::warn!/log::error! in
the workspace was discarded: the crash guard's panic report, a failed
crash-recovery save, font folders that can't be read. A launch from a
desktop menu has no terminal either, so there was nothing to attach to a
bug report.

apps/designcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/designcraft.log (beside
  ui.json and prefs.json); each launch rotates the previous log to
  designcraft.1.log and .2.log, so the log of a run that crashed
  survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
  (bounded) and written once the file is attached
- default levels: info for designcraft*, warn for everything else;
  RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
  error as the only sink

The logger is installed first in main (before the engine's panic hook)
and the file is opened after argument parsing (--version leaves no
file). The settings directory moves out of prefs_path into config_dir.
A --control or DESIGNCRAFT_CONTROL_PORT value that is not a port is now
logged instead of silently leaving the control channel off. Documented
in README.md (Quick start > Logs).

* Desktop: no eprintln! on the log and panic paths

eprintln! panics when standard error is a broken pipe (a GUI launch on
Windows), and a panic inside the panic hook aborts. The "no log file"
message goes through log::warn! (standard error only by then); the panic
hook's fallback writes to standard error with write_fmt and ignores the
error. Same fix as storytold/vectorcraft#465.
2026-10-10 01:50:38 -04:00
5369687497 fix(cli): --help prints usage to stdout and exits 0 (#254)
Asking for help is not an error, but `designcraft-cli --help` shared the
catch-all arm with unknown commands, so it wrote the usage block to
stderr and exited 1 — unusable in a pipeline and wrong by convention
(`--version` already exits 0).

Split the arm: `--help`, `-h` and `help` now print the same usage block
to stdout and succeed, while an unknown command keeps it on stderr and
still fails. The usage text and links line are hoisted into a shared
`USAGE` const and `usage_footer()` so the two paths can't drift.

Fixes #243

🤖 Generated with Codebuff

Co-authored-by: Codebuff <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 01:50:34 -04:00
bbe234aaa6 PDF: a damaged PNG, GIF or WebP is skipped, not fatal (#147)
A placed PNG, GIF or WebP that is cut off (an interrupted download) or
has a bad checksum made the whole PDF export fail with
"PDF writer error: Image(Image(ImageRepr {..}), None, "unexpected end of
file")", which names no file. A damaged TIFF or BMP in the same place is
skipped with the warning "image `name` could not be decoded and was
skipped", and the rest of the document is exported.

The exporter decides whether an image can be embedded by asking krilla
to open it. krilla opens PNG, GIF and WebP lazily: it reads the header,
accepts the file, and decodes the pixels only when the PDF is written,
where an error ends the export. TIFF and BMP are decoded by us first, so
they took the skip path.

lossless() now decodes the image first for every format. A file that
does not decode returns None and takes the existing skip-with-warning
path. This costs one extra decode per PNG, GIF or WebP asset: the sample
magazine (two PNGs, 820 KB) exports in 0.19 s instead of 0.17 s in a
debug build.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-10 01:50:29 -04:00
5a7ca767db UI: the Control panel shows its second row (#142)
In every workspace that shows the Control panel (Advanced, Typography,
Printing and Proofing, Book), the second row of fields was cut off at the
panel's lower edge: Y and H in object mode, leading, tracking and the
indents in text mode.

The panel lays its groups out in a row that centres each child
vertically. The two-row grids were placed as if they were one row tall
and then grew downward, so they started 13.5 pt below the panel's top
instead of at it and ended 5.5 pt past the 59 pt panel.

The row is now top-aligned, which is where the font menus, the
separators and the reference-point proxy already sat.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-10 01:50:23 -04:00
aiongg 4fbf8938bf UI: the shortcut recorder waits for the key; Interactive for PDF and Digital Publishing open their panels (#264)
* Keyboard Shortcuts: the recorder waits for the key pressed with the modifiers

* Workspaces: Interactive for PDF and Digital Publishing open their own panels
2026-10-10 01:14:54 -04:00
aiongg 6a331e6712 UI: Quick Apply opens without running an entry; rows are left-aligned (#239)
* UI: the Quick Apply shortcut doesn't also run its first entry

Cmd+Return opened Quick Apply, and in the same frame the list saw the
same press as Enter and ran its first entry (New Document). A key press
that fires a command shortcut is now consumed, so nothing else handles
it that frame. This also stops Cmd+Return from inserting a paragraph
break while typing.

* UI: Quick Apply rows are left-aligned

Rows without a shortcut or style kind were drawn with their label
centred, because add_sized lays a button out centred and only the rows
with a shortcut have an element that fills the remaining width. Each
row is now laid out left to right in a fixed 460×22 area.

* UI: Quick Apply runs its first entry only on a fresh Return

Pressing Cmd+Return again while Quick Apply is open, or holding it until
it repeats, reached the palette as Enter and ran the first entry. The
palette now counts only a Return press that isn't a repeat and has no
Cmd.
2026-10-10 01:14:48 -04:00
aiongg 54a4a8d4ae Fonts: the Document Fonts folder is found whatever its case (#287)
Packages name the folder `Document fonts`; on a case-sensitive file system, opening a document beside it loaded none of its fonts. The exact name still wins when both exist.
2026-10-10 01:14:43 -04:00
kubuntugamerandCodebuff a9326be318 fix(engine): object.opacity accepts its documented lowercase blend modes (#275)
`object.opacity` documents `blend?: normal|multiply|…`, but parsed the
value with `serde_json::from_value`, which only accepts the enum's
PascalCase variant names. Every documented lowercase form was silently
dropped: the command returned `{"changed": 1}` while the stored blend
stayed as it was, so a client following the parameter description could
save and export the previous appearance without any error (#260).

Parse with the codebase's own `BlendMode::parse`, which is already
case-, space-, underscore- and hyphen-insensitive and covered by tests,
so `multiply`, `MULTIPLY`, `Color Burn`, `soft_light` and the serialized
`Multiply` all resolve to the same mode. An unrecognized value is now an
error rather than a silent no-op, matching how sibling commands treat a
bad parameter — restoring `normal` after `Multiply` really does go back
to Normal.

Three tests in `blend_mode_tests`: the documented forms apply, the
PascalCase names the Properties panel submits still apply, and an
unknown value is rejected without changing the item.

Fixes #260

🤖 Generated with Codebuff

Co-authored-by: Codebuff <[email protected]>
2026-10-10 01:14:38 -04:00
thaynejandClaude Opus 5.5 ecadfcee3e Autoflow: add only the pages breaks ask for (#266)
A frame that a column, frame or page break ends early held only a few
characters, and autoflow took that as the rate frames fill at: placing
text that starts with a page break added a page per few characters
(33 pages for 98 characters, 271 for a one-page Word section). The
estimate now comes from full frames only; with none yet, one page is
added and the story measured again. Regression test covers a leading
break and a break between every paragraph. Fixes #262.


Claude-Session: https://claude.ai/code/session_01GLcnoDFjqsh5x3MzVbfZeb

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 01:14:32 -04:00
thaynejandClaude Opus 5.5 4aea57fea7 Word import: keep tracked moved text (w:moveTo) (#257)
Text inside a tracked move destination was dropped on .docx import, so
moved passages vanished from both places. Treat moveTo like ins (both
kept as accepted); moveFrom stays skipped like del. Regression test
covers ins, del, moveFrom and moveTo together. Fixes #256.

Also adds my contributor credit entry.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 01:14:27 -04:00
skylar taylor-barrick 06322045a5 Security: escape HTML and EPUB metadata (#152) 2026-10-10 01:14:22 -04:00
jahalaandClaude Opus 5.5 4349919a4a Import: RTF and Tagged Text keep characters past U+FFFF (#149)
Placing an RTF or Tagged Text file dropped every character outside the
Basic Multilingual Plane: emoji, mathematical letters and the rarer CJK
ideographs such as 𠮷 (U+20BB7, used in Japanese names). The text
around them came in, so the loss was silent. It also broke our own round
trip: Export Text writes these characters correctly and Place lost them.

Both formats carry such a character as a UTF-16 surrogate pair, two
units in a row: \u-10179?\u-8704? in RTF, <0xD83D><0xDE00> in Tagged
Text. Both readers passed each unit to char::from_u32 on its own. Half a
pair is not a character, so each half was dropped.

A small shared Utf16Units joins the units: a first half waits for the
second, and the pair becomes one character. Half a pair with no partner
is still left out, as before.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 01:14:17 -04:00
aiongg 9b8aaadae0 UI: ruler units by right-click, Language in Properties (#145)
* UI: right-clicking a ruler picks that ruler's units, and the vertical ruler measures in the vertical units (#133)

* UI: the Properties panel's Character section sets the text's language, from the same list as the Character panel (#130)
2026-10-10 01:14:10 -04:00
jahalaandClaude Opus 5.5 c614e0ab9e Docs, About: the Illustrator-class sibling is VectorCraft (#59) (#139)
DrawCraft was renamed VectorCraft, and its repository is now
storytold/vectorcraft. Three places still used the old name:

- AGENTS.md and CLAUDE.md told contributors and agents that the sibling
  checkout lives at ../drawcraft. A clone made from the README link lands
  in ../vectorcraft, so that path does not exist.
- The About window's sibling list used the app-page slug "drawcraft".
  getartcraft.com/apps/drawcraft still redirects to /apps/vectorcraft,
  so the link worked, but the README (which the list says it matches)
  uses /apps/vectorcraft.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 01:14:05 -04:00
jahalaandClaude Opus 5.5 d323b4e702 Web: AltGr and other named keys no longer type their names (#134) (#138)
In the browser, pressing AltGr while editing text on the canvas inserted
the word "AltGraph" into the story.

eframe's web backend (0.36.2, web/input.rs text_from_keyboard_event)
turns a keydown into a text event unless the key is on a fixed list of
names. Browsers report many more named keys than that list holds:
AltGraph, Dead, Unidentified, the media keys. Each one arrived as text.
Panel text fields are not affected, because a focused egui text field
takes its text from the browser's input events instead of keydown.

The web shell now drops a text event that is a key name (ASCII letters
and digits, starting with a capital, longer than one character) unless
an egui text field has the keyboard. One key press never types such a
word; a text field's input events can, so they are left alone.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 01:13:59 -04:00
jahalaandClaude Opus 5.5 ce3deb651a Commands: huge row and column counts can't exhaust memory (#137)
Three commands took a count from their parameters and used it unchecked.
Parameters come from MCP, the control channel and scripts, so the count
is hostile input (never-crash: cap input-sized allocations, checked
arithmetic).

- layout.createGuides made one or two guides per row and column with no
  upper limit: 30 million rows took 1.2 GB, and 2^32 - 1 would exhaust
  memory, which aborts the process past the command guard. A count over
  2^32 wrapped to a small one. Both counts are now capped at 100.
- edit.stepAndRepeat multiplied rows by columns as usize. In debug builds
  the overflow panicked; in release builds 2^32 x 2^32 wraps to 0, passes
  the 1000-copy limit and starts a grid of 2^64 copies. The product is
  now checked, and a grid that large falls back to `count` copies like
  any other grid over 1000.
- file.new stored any column count in the page (4 billion, or a wrapped
  value past 2^32). Page::column_rects builds one rect per column each
  time the columns are laid out. The count is now clamped to 1..=216,
  the range layout.marginsAndColumns already uses.

Each case has a regression test that failed before the fix.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 01:13:54 -04:00
aiongg fe16e00e37 PDF/A keeps placed images; right-to-left tables and columns (#128)
* PDF: PDF/A exports keep placed PNG, JPEG, GIF and WebP images by writing them without interpolation (#71)

* Tables: new tables take their paragraph's direction, and the Table panel sets a table's direction (#100)

* Text: stories made in a right-to-left-bound document fill their columns from the right (#100)
2026-10-10 01:13:48 -04:00
aiongg 3033c8cc64 CLI: export options after the last export are an error; MCP and README docs match the code (#127)
* CLI: run rejects an export option with no export after it (#67)

--page, --scale and --pdf-options apply to the exports that follow them; one
given after the last --export or --all-pages did nothing and said nothing.
The usage text and docs/agents.md say so.

* MCP: document that text offsets and story lengths are UTF-8 bytes (#68)

* MCP: docs name the UI-only commands precisely; app.links works headless (#62)

* README: PDF and EPUB export ship (#60)
2026-10-10 01:13:42 -04:00
skylar taylor-barrick 691d0de183 #72: preserve typed generic dialog values (#120) 2026-10-10 01:13:35 -04:00
skylar taylor-barrick fc2739a8cd #61: honor MCP typing, story and page contracts (#118) 2026-10-10 01:13:29 -04:00
skylar taylor-barrick 4c6aa4cd4b browser-correctness: fix print, startup flags, and document MIME (#117) 2026-10-10 01:13:23 -04:00
Haseom Shin 788e0eac66 Images: set SVG text in the shared fonts when the bundled ones lack it (#116) 2026-10-10 01:13:17 -04:00
aiongg d730d8fa27 UI: toolbars that don't fit the window switch to two columns or scroll (#57) (#112)
* UI: toolbars that don't fit the window switch to two columns or scroll (#57)

In a short window the Tools panel lays its tools out in two columns,
without changing the single/double-column preference, which comes back
when the window grows again. While the window forces two columns the
column toggle is disabled. Whatever two columns can't fit scrolls
vertically.

The Control panel and the application bar scroll sideways when their
controls are wider than the window. The Control panel keeps its height.
In the application bar the workspace controls follow the menus instead of
overlapping them. A plain mouse wheel scrolls these one-direction bars,
and a thin floating scroll bar shows only when something overflows, so
nothing changes while everything fits.

Tool buttons, icon buttons and the Fill proxy carry accessibility
labels, which the new window-size tests use to find them.

* UI: captions in a sideways-scrolled bar stay on one line

The last group of a scrolled Control bar row got only the width left
over, so a caption like Columns wrapped one letter per line.
2026-10-10 01:09:52 -04:00
aiongg 4564ec6707 UI: text fields take Select All, Copy, Cut, Paste, Undo and Redo from the Mac menu (#30) (#111)
The macOS menu bar takes Cmd+A, Cmd+C, Cmd+X, Cmd+V, Cmd+Z and Cmd+Shift+Z
before the window sees them, so in a panel, dialog or search field they ran
the document's commands: Select All selected every frame, Paste pasted into
the layout, Undo undid the last document change.

While a text field has keyboard focus, these Edit items now act on the field,
whether chosen by shortcut or from the menu: Select All, Undo and Redo reach
it as their keys, Copy and Cut as clipboard events, and Paste asks the
window for the system clipboard. The items stay enabled for the field even
when the document has nothing to copy or undo. With no field focused, and
for every other item, the menu works as before.
2026-10-10 01:09:47 -04:00
aiongg 9fbd6d2402 Show an alert when a file can't be opened or placed (#80)
* Opening an InDesign document says to export IDML (#21)

.indd and .indt files (recognised by their published 16-byte signature)
failed to open or place with a confusing format error. They now explain
that the format is closed and how to export IDML from InDesign instead.

File › Open offers .indd and .indt files (desktop and web), and dropping
one on the window opens it like a .designcraft or .idml file. A file that
can't be opened or placed from File › Open, Place, a drop, the command
line or the control channel's app.open shows an alert with the reason, as
well as the status line.

* File open: an .indd file is an unreadable file like any other

Remove the INDD signature check and message, and .indd/.indt from the
Open filters and drop routing. The alert tests use a generic unreadable
file.

* Control channel: a failed app.open answers with the error and opens no alert

An alert waits for a click that a control client can't give. app.open
reports the error in its response, as engine.execute does; File › Open,
drops and the command line still show the alert.
2026-10-10 01:09:41 -04:00
Haseom Shin 07b95eb7b3 Compose: don't panic when a hyphenated paragraph starts with a no-break letter (#115) 2026-10-10 01:09:36 -04:00
jahalaandClaude Opus 5.5 aeabc82ca6 Images: PSD decode passes clippy on Rust 1.98 (#136)
Rust 1.98 adds the clippy lint chunks_exact_to_as_chunks. It flags two
loops in the PSD decoder, so `cargo xtask ci` stops at the clippy step on
unmodified main for anyone on current stable.

Both loops now use as_chunks / as_chunks_mut (stable since 1.88, below the
workspace rust-version 1.90). The chunks are arrays, so the try_from that
could never fail goes away too. Decoded pixels are unchanged; the existing
PSD tests cover both paths.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 01:09:30 -04:00
Brandon ThomasandClaude Opus 5.5 4e0e3949f1 Bump version to 0.5.0 (from 0.4.0) for release; refresh contributors
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v0.5.0
2026-10-09 21:02:05 -04:00
Brandon Thomas 66c7ce7e96 Merge pull request #131 from XusBadia/dmg-background
macOS DMG: branded window background and icon layout
2026-10-09 09:20:37 -04:00
Xus BadiaandClaude Opus 5.5 ec42e542e9 macOS DMG: branded window background and icon layout
The DMG opened as a plain Finder window. It now shows the app icon's figure on
the DesignCraft colour, with DesignCraft.app and the Applications link side by side.
Same approach as PhotoCraft's and VectorCraft's (storytold/photocraft#1201,
storytold/vectorcraft#493).

- packaging/macos/dmg/: background.svg (source; text outlined, no paper grain,
  the figure an <image> of assets/app-icon), background.tiff (1x + 2x HiDPI,
  16-colour palette, Deflate, sRGB; ~90 KB)
  and dmg-layout.DS_Store (Finder view settings: window, icon size 128,
  positions, background).
- generate.py writes the TIFF and the layout on any OS, byte-for-byte
  reproducible, with nothing from the machine that ran it (no paths, users,
  disk names or volume UUIDs).
- package.sh copies them into the staging folder; the image is still built with
  hdiutil makehybrid. Nothing extra runs in the signing job.
- The volume name drops the version: the layout finds the background through
  an alias that includes the volume name. The DMG file name keeps the version.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 07:43:40 +02:00
Brandon ThomasandClaude Opus 5.5 14e677b242 Bump version to 0.4.0 (from 0.3.0) for release
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v0.4.0
2026-10-08 10:02:08 -04:00
d26b91335c README Downloads: where to get it first, then builds with Windows before macOS (#135)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-08 09:50:30 -04:00
865640b70a Release: FreeBSD x86_64, Flatpak x86_64/aarch64, AppImage zsync updates; README Downloads (#132)
- freebsd job: builds packaging/freebsd/package.sh in a FreeBSD 14.3 VM (same image and
  packages as freebsd.yml) into designcraft-<ver>-freebsd-x86_64.tar.gz.
- flatpak jobs (x86_64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm): repackage the Linux
  tarball with packaging/linux/flatpak-bundle.sh and a new bundle manifest; runtime and
  finish-args shared with the from-source manifest (checked by packaging-lint).
- AppImages embed gh-releases-zsync update information and ship a .zsync beside them.
- version, linux, web, flatpak and freebsd no longer use the release environment (they read
  no secrets), so a workflow_dispatch on a branch dry-runs them; the signing jobs and the
  draft release stay environment-gated.
- nfpm package description described an image editor; now describes DesignCraft.
- README: Downloads section listing every build.

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-08 09:38:16 -04:00
Brandon ThomasandClaude Opus 5.5 5382fd4fb7 Bump version to 0.3.0 (from 0.2.1) for release
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 08:13:12 -04:00
Brandon Thomas f4a4c9709b Merge pull request #76 from CameronGilroy/pr/data-merge
Data merge: linked source, placeholders, preview, and tiled merge
2026-10-07 22:53:41 -04:00
Brandon Thomas b05fe0aed4 Merge pull request #78 from ShaoWenbinSaleh/multi-language-fix
Complete Arabic translations, refine Chinese terminology, and cache RTL label layouts
2026-10-07 22:46:52 -04:00
Brandon ThomasandClaude Opus 5.5 8d2d180062 Merge origin/main into multi-language-fix
Resolve i18n conflicts: keep this branch's revised zh/ar wording plus
main's new rows (font-name, missing-glyph, Korean line-break labels).
Brazilian Portuguese (#103) now uses the same cached HashMap lookup as
Arabic; the cached-lookup test covers pt-br too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:32:13 -04:00
Brandon ThomasandClaude Opus 5.5 48dfbcfd19 Merge origin/main into data-merge
Resolve conflicts keeping both sides: doc gains both `cjk` and
`datamerge` modules; file.open resolves data-merge sources and loads the
document's fonts; DocState keeps preview_stash/preview_record and fonts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:28:15 -04:00
Brandon Thomas 8e2a5b1fc3 Merge pull request #55 from EthanSuquet/fix/cmyk-tiff-pdf-export
PDF: placed CMYK TIFFs keep their inks
2026-10-07 22:13:56 -04:00
Brandon Thomas 2c8ea6d167 Merge remote-tracking branch 'origin/main' into r55
# Conflicts:
#	Cargo.toml
2026-10-07 22:13:23 -04:00
Brandon Thomas e97d98977f Merge pull request #103 from RicSchonfelder/i18n-pt-br
i18n: add Brazilian Portuguese (pt-br) UI translation
2026-10-07 22:13:15 -04:00
Brandon Thomas 9f2f61bfbf Merge pull request #82 from aiongg/fix/psd-channels
Images: PSD composites decode by colour mode
2026-10-07 22:13:10 -04:00