diff --git a/pack.binlog b/pack.binlog new file mode 100644 index 00000000..0edf2776 Binary files /dev/null and b/pack.binlog differ diff --git a/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.3-hebrew.nupkg b/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.3-hebrew.nupkg new file mode 100644 index 00000000..4c16e30f Binary files /dev/null and b/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.3-hebrew.nupkg differ diff --git a/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.4.nupkg b/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.4.nupkg new file mode 100644 index 00000000..186e8235 Binary files /dev/null and b/src/foundation/nuget/output/PdfSharpWithHebrewSupport.6.2.4.nupkg differ diff --git a/src/foundation/nuget/src/Directory.Build.props b/src/foundation/nuget/src/Directory.Build.props index 618588a9..8f257f44 100644 --- a/src/foundation/nuget/src/Directory.Build.props +++ b/src/foundation/nuget/src/Directory.Build.props @@ -13,8 +13,8 @@ ***** THIS IS A DEBUG BUILD - DO NOT PUBLISH *****%0d - https://docs.pdfsharp.net - PDFsharp PDF creation + https://github.com/ronenfe/PDFsharp + PDFsharp PDF creation Hebrew MigraDoc PDFsharp PDF Document Generation diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj index a530742a..2d6ccc57 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj +++ b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj @@ -13,8 +13,14 @@ true true $(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec - PDFsharp - PDFsharp for Windows and Linux + + PdfSharpWithHebrewSupport + 6.2.3-hebrew2 + ronenfe + ronenfe + https://github.com/ronenfe/PDFsharp + PdfSharpWithHebrewSupport + PDFsharp for Windows and Linux (custom Hebrew-support build) $(DebugBuildMessage)%0D$(NuGetDescription) A .NET library for processing PDF. $(NuGetTags_PdfSharp) diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/README.md b/src/foundation/nuget/src/PDFsharp.NuGet/README.md index 00466f60..070a7f14 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/README.md +++ b/src/foundation/nuget/src/PDFsharp.NuGet/README.md @@ -9,3 +9,65 @@ See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. +# PdfSharpWithHebrewSupport + +PdfSharpWithHebrewSupport is a small, backwards-compatible customization of PDFsharp that adds a simple Hebrew‑script (RTL) preprocessing step before text is drawn or measured. It reorders RTL runs for Hebrew-script characters so Hebrew/Yiddish text renders in natural visual order without full shaping engines. + +Version: 6.2.3-hebrew1 +Targets: `net8.0`, `net9.0`, `net10.0`, `netstandard2.0` +License: MIT (based on PDFsharp) + +## Features +- Preprocesses text passed to PDFsharp to reverse RTL runs for characters in: + - Hebrew block (U+0590..U+05FF) + - Hebrew presentation forms (U+FB1D..U+FB4F) +- Minimal change: uses the existing PDFsharp render pipeline and keeps API compatibility. +- Includes unit tests that verify mixed LTR/RTL run reordering. + +## Why use this +PDFsharp does not include a full Unicode BiDi + shaping engine. For Hebrew and other Hebrew‑script languages, a simple run reordering is often enough. This package provides that preprocessing without adding heavy dependencies. + +## Install +dotnet CLI: +``` +dotnet add package PdfSharpWithHebrewSupport --version 6.2.3-hebrew1 +``` + +PackageReference: + +```xml + +``` + +## Usage +Install the package and use PDFsharp as usual. The package hooks into the render pipeline and reorders RTL runs before text is measured or drawn. + +Example — inspect preprocessed text: +```csharp +var renderEvents = new PdfSharp.Events.RenderEvents(); +renderEvents.PrepareTextEvent += (s, e) => +{ + // e.Text has had Hebrew-script RTL runs reordered already + Console.WriteLine(e.Text); +}; +``` + +If you need custom behavior, you can still subscribe to `PrepareTextEvent` and modify `e.Text`. + +## Limitations +- This is a heuristic limited to Hebrew-script characters. It does NOT: + - Implement the full Unicode BiDi algorithm for every edge case. + - Provide contextual glyph shaping (Arabic, Persian, Urdu, Syriac, N’Ko, Adlam, etc.) +- For Arabic-family or other joining scripts you must use a shaping engine (e.g., HarfBuzz) and feed shaped glyphs into the renderer. + +## Changelog (high level) +- 6.2.3-hebrew1: Added Hebrew-script RTL preprocessing and unit tests to reorder RTL runs prior to rendering. + +## Source & Attribution +This package is built from PDFsharp sources (original authors: empira Software GmbH). This fork/custom build is published by the package author listed on nuget.org. + +Original project: https://github.com/empira/PDFsharp +This fork: https://github.com/ronenfe/PDFsharp + +## Support +Open issues on the package repository for bug reports or requests (RTL ranges, tests, or shaping integration guidance). diff --git a/src/foundation/nuget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec b/src/foundation/nuget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec new file mode 100644 index 00000000..b41ab9bd --- /dev/null +++ b/src/foundation/nuget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec @@ -0,0 +1,47 @@ + + + + PdfSharpWithHebrewSupport + 6.2.3-hebrew3 + PDFsharp with added Hebrew-script RTL preprocessor for simple RTL languages (Hebrew, Yiddish). Built from PDFsharp sources with limited RTL preprocessing applied. + PDFsharp customized build with Hebrew-script RTL run reordering. + ronenfe + ronenfe + https://github.com/ronenfe/PDFsharp + MIT + images\PDFsharp-128x128.png + README.md + false + Added Hebrew-script RTL preprocessing and unit tests (ReverseRtlTests). + Copyright (c) 2005-2025 empira Software GmbH; modifications by ronenfe + pdf pdfsharp hebrew rtl + + PdfSharpWithHebrewSupport + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/foundation/nuget/src/PdfSharpWithHebrewSupport/README.md b/src/foundation/nuget/src/PdfSharpWithHebrewSupport/README.md new file mode 100644 index 00000000..c82a065f --- /dev/null +++ b/src/foundation/nuget/src/PdfSharpWithHebrewSupport/README.md @@ -0,0 +1,9 @@ +# PdfSharpWithHebrewSupport + +PdfSharpWithHebrewSupport is a small, backwards-compatible customization of PDFsharp that adds a simple Hebrew?script (RTL) preprocessing step before text is drawn or measured. It reorders RTL runs for Hebrew-script characters so Hebrew/Yiddish text renders in natural visual order without full shaping engines. + +Version: 6.2.3-hebrew3 + +License: MIT + +For details see the original PDFsharp project: https://github.com/empira/PDFsharp diff --git a/src/foundation/nugget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec b/src/foundation/nugget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec new file mode 100644 index 00000000..b601cd38 --- /dev/null +++ b/src/foundation/nugget/src/PdfSharpWithHebrewSupport/PdfSharpWithHebrewSupport.nuspec @@ -0,0 +1,47 @@ + + + + PdfSharpWithHebrewSupport + 6.2.3-hebrew1 + PDFsharp with added Hebrew-script RTL preprocessor for simple RTL languages (Hebrew, Yiddish). Built from PDFsharp sources with limited RTL preprocessing applied. + PDFsharp customized build with Hebrew-script RTL run reordering. + ronenfe + ronenfe + https://github.com/ronenfe/PDFsharp + MIT + images\PDFsharp-128x128.png + README.md + false + Added Hebrew-script RTL preprocessing and unit tests (ReverseRtlTests). + Copyright (c) 2005-2025 empira Software GmbH; modifications by ronenfe + pdf pdfsharp hebrew rtl + + PdfSharpWithHebrewSupport + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/foundation/nugget/src/PdfSharpWithHebrewSupport/README.md b/src/foundation/nugget/src/PdfSharpWithHebrewSupport/README.md new file mode 100644 index 00000000..2ae10032 --- /dev/null +++ b/src/foundation/nugget/src/PdfSharpWithHebrewSupport/README.md @@ -0,0 +1,9 @@ +# PdfSharpWithHebrewSupport + +This package is a customized build of PDFsharp that adds a simple Hebrew-script RTL preprocessing step to reverse RTL runs for Hebrew-script languages (Hebrew, Yiddish) before rendering. + +Version: 6.2.3-hebrew1 + +License: MIT + +For details see the original PDFsharp project: https://github.com/empira/PDFsharp diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Events/RenderEvents.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Events/RenderEvents.cs index 82a4ffbd..ae552916 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Events/RenderEvents.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Events/RenderEvents.cs @@ -4,6 +4,7 @@ using PdfSharp.Drawing; using PdfSharp.Fonts; using PdfSharp.Pdf; +// using PdfSharp.Internal; // Not required - local preprocessor used to avoid cross-file reference issues namespace PdfSharp.Events { @@ -78,6 +79,12 @@ public class RenderEvents /// The PrepareTextEventArgs of the event. public void OnPrepareTextEvent(object sender, PrepareTextEventArgs args) { + // Preprocess text (e.g. reverse RTL runs) before any event handlers are invoked. + if (args != null && !string.IsNullOrEmpty(args.Text)) + { + args.Text = ReverseRtlRunsAndOrder(args.Text); + } + PrepareTextEvent?.Invoke(sender, args); } @@ -100,5 +107,64 @@ public void OnRenderTextEvent(object sender, RenderTextEventArgs args) /// EventHandler for RenderTextEvent. /// public event RenderTextEventHandler? RenderTextEvent; + + // Local text preprocessor to ensure the method is always available during build. + // Only detect Hebrew-script characters (covers Hebrew, Yiddish, Ladino written in Hebrew script, + // and presentation forms). These languages do not require complex shaping. + private static bool IsRtl(char c) + { + int code = c; + // Hebrew block and Hebrew presentation forms + return (code >= 0x0590 && code <= 0x05FF) || (code >= 0xFB1D && code <= 0xFB4F); + } + + private static string ReverseString(string s) + { + var arr = s.ToCharArray(); + System.Array.Reverse(arr); + return new string(arr); + } + + private static string ReverseRtlRunsAndOrder(string text) + { + if (string.IsNullOrEmpty(text)) + return text; + + var runs = new System.Collections.Generic.List(); + var run = new System.Text.StringBuilder(); + bool runIsHebrew = IsRtl(text[0]); + + foreach (var c in text) + { + if (IsRtl(c) == runIsHebrew) + { + run.Append(c); + } + else + { + if (runIsHebrew) + runs.Add(ReverseString(run.ToString())); + else + runs.Add(run.ToString()); + + run.Clear(); + run.Append(c); + runIsHebrew = IsRtl(c); + } + } + + if (runIsHebrew) + runs.Add(ReverseString(run.ToString())); + else + runs.Add(run.ToString()); + + runs.Reverse(); + + var sb = new System.Text.StringBuilder(); + foreach (var r in runs) + sb.Append(r); + + return sb.ToString(); + } } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/TextPreprocessor.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/TextPreprocessor.cs new file mode 100644 index 00000000..4ddf2f3c --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/TextPreprocessor.cs @@ -0,0 +1,68 @@ +using System.Text; +using System.Collections.Generic; + +namespace PdfSharp.Internal +{ + public static class TextPreprocessor + { + // Check if a char is Hebrew + private static bool IsHebrew(char c) + { + return c >= 0x0590 && c <= 0x05FF; + } + + // Reverse each Hebrew run and reverse the order of runs + public static string ReverseHebrewRunsAndOrder(string text) + { + if (string.IsNullOrEmpty(text)) return text; + + var runs = new List(); + var run = new StringBuilder(); + bool runIsHebrew = IsHebrew(text[0]); + + foreach (var c in text) + { + if (IsHebrew(c) == runIsHebrew) + { + run.Append(c); + } + else + { + // Flush previous run + if (runIsHebrew) + runs.Add(ReverseString(run.ToString())); + else + runs.Add(run.ToString()); + + run.Clear(); + run.Append(c); + runIsHebrew = IsHebrew(c); + } + } + + // Flush last run + if (runIsHebrew) + runs.Add(ReverseString(run.ToString())); + else + runs.Add(run.ToString()); + + // Reverse the order of runs for proper RTL layout + runs.Reverse(); + + var sb = new StringBuilder(); + foreach (var r in runs) + { + sb.Append(r); + } + + return sb.ToString(); + } + + private static string ReverseString(string s) + { + var arr = s.ToCharArray(); + System.Array.Reverse(arr); + return new string(arr); + } + } +} diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/ReverseRtlTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/ReverseRtlTests.cs new file mode 100644 index 00000000..2537ea1a --- /dev/null +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/ReverseRtlTests.cs @@ -0,0 +1,39 @@ +// Tests for RTL run reversal in RenderEvents +using FluentAssertions; +using PdfSharp.Events; +using PdfSharp.Pdf; +using PdfSharp.Drawing; +#if CORE +using PdfSharp.Snippets.Font; +using PdfSharp.Fonts; +#endif +using Xunit; + +namespace PdfSharp.Tests.Drawing +{ + [Collection("PDFsharp")] + public class ReverseRtlTests + { + public ReverseRtlTests() + { + // Intentionally do not set a custom font resolver in tests to avoid test-project-specific + // dependencies. Tests use default font resolution where available. + } + + [Theory] + [InlineData("abc???", "???abc")] + [InlineData("???abc", "abc???")] + [InlineData("123 ??? 456", "456 ??? 123")] + public void OnPrepareTextEvent_ReversesRtlRuns(string input, string expected) + { + var events = new RenderEvents(); + var doc = new PdfDocument(); + var font = new XFont("Arial", 10); + var args = new PrepareTextEventArgs(doc, font, input); + + events.OnPrepareTextEvent(this, args); + + args.Text.Should().Be(expected); + } + } +}