Skip to content

Add escape argument to PSDraw text method - #9996

Merged
radarhere merged 6 commits into
python-pillow:mainfrom
lllleolin-max:fix/psdraw-text-escaping
Sep 16, 2026
Merged

radarhere merged 6 commits into
python-pillow:mainfrom
lllleolin-max:fix/psdraw-text-escaping

Conversation

@lllleolin-max

@lllleolin-max lllleolin-max commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

This PR adds opt-in backslash escaping to PSDraw.text() while preserving its existing behavior by default, following radarhere's compatibility feedback.

ps.text((10, 20), text)  # Existing behavior: leave backslashes unchanged
ps.text((10, 20), text, escape=True)  # Also escape input backslashes

escape is a keyword-only boolean defaulting to False. Parentheses continue to be escaped in both modes. With True, backslashes are doubled before parentheses are escaped, which supports text such as Windows paths and trailing backslashes without changing existing callers.

The scope remains deliberately narrow: Latin-1 encoding and existing error behavior are unchanged. PostScript normalizes unescaped CR and CRLF line endings to LF; backslash line continuations retain their existing behavior in the default mode. This is not a new layout or arbitrary-character rendering API.

Changes:

  • Add the opt-in parameter and document its default and scope.
  • Test default, explicit False, and True output using literal expected bytes, including paths, parentheses, intentional escapes, continuation sequences, controls, empty text, and Latin-1 text.
  • Test encoding failures and the keyword-only boundary.
  • Replace the unconditional-fix release note with an API addition and add a reference example.

Local validation of the revised implementation:

  • Tests/test_psdraw.py: 57 passed; Tests/test_pdfparser.py: 8 passed; selftest: 59 passed.
  • A separate audit compared 107,179 inputs against the actual pre-PR source: default and explicit False remained byte-for-byte compatible. Opt-in output matched the original proposed escaping behavior. Supplemental PdfParser checks are only a literal-string parsing cross-check, not a complete PostScript oracle or rendering test.
  • Black, Ruff, mypy, Bandit, Sphinx-lint, file hygiene, and a focused warning-free Sphinx build of the changed reference and release-note pages passed.

Validation used Windows/Python 3.12.11, the checkout's selected Python modules, and Pillow 12.3.0's prebuilt native extensions and remaining dependencies. Native extensions were not rebuilt. Ghostscript is unavailable, so no interpreter/rendering check was run. The full test suite, all pre-commit hooks, and complete documentation site were not run; upstream CI remains authoritative for those environments.

Prepared with AI assistance.

@radarhere radarhere added the 🤖-assisted AI-assisted label Sep 13, 2026
@radarhere

Copy link
Copy Markdown
Member

Hmm.

  1. This would completely block the use of PostScript escape sequences. Are there any escape sequences that are potentially useful?
  2. Is this potentially a breaking change? Before this PR, users might have figured out that four slashes \\\\ would render as \, but with PR, four slashes would suddenly start rendering as \\. Pillow values backwards-compatibility.

I wonder if it might be better to leave the current behaviour as it is, and instead add a new escape keyword argument. So ps.text((10, 20), text would continue to function as-is, but ps.text((10, 20), text, escape=True) would render the text as you expect.

What do you think?

@lllleolin-max

Copy link
Copy Markdown
Contributor Author

Thanks for pointing this out. I agree that changing the default could break callers that already rely on PostScript escapes. Your suggestion makes sense: I am updating the PR to preserve the existing behavior by default and make literal-text escaping opt-in with escape=True, with tests for both paths.

@lllleolin-max lllleolin-max changed the title Escape backslashes when drawing PostScript text Add opt-in backslash escaping to PSDraw.text Sep 14, 2026
@lllleolin-max

Copy link
Copy Markdown
Contributor Author

Updated in c2173c4. The default leaves backslashes unchanged, and escape=True enables backslash escaping; parentheses retain their existing handling in both modes. I added compatibility tests for both paths and clarified the documentation. The 65 focused tests and 59 selftests pass locally; Ghostscript rendering was not available to verify. Thanks again for catching the compatibility issue.

@radarhere

Copy link
Copy Markdown
Member

I've created lllleolin-max#3 with some suggestions.

@radarhere radarhere changed the title Add opt-in backslash escaping to PSDraw.text Add escape argument to PSDraw text method Sep 16, 2026
@radarhere
radarhere merged commit 8b669b5 into python-pillow:main Sep 16, 2026
97 of 103 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🤖-assisted AI-assisted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants