Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Note for PDF/A and PDF/UA: the exporter deliberately writes no timestamp, so the document has to carry its own date (`#set document(date: ...)`) and, for PDF/UA, a title and language.
- `compiler.CompilePdf(Stream)`, `compiler.CompilePdfAsync(Stream)`, `compiler.CompilePdf(string outputFile)` and `compiler.CompilePdfAsync(string outputFile)` now stream the document straight from native memory to the destination and return the compiler warnings, rather than returning a `PdfResult` that had to be materialised on the managed heap first. Use `compiler.CompilePdf()` when you want the bytes.
- `compiler.Compile(outputFile, format)` and `compiler.CompileSvg(...)` no longer copy the rendered output onto the managed heap before writing or decoding it.
- `sysInputs` parameters on `TypstCompiler` and the `SetSysInputs` argument are now `IDictionary<string, string>` instead of `Dictionary<string, string>`, so a `ReadOnlyDictionary<string, string>`, `ImmutableDictionary<string, string>` or any other implementation can be passed. Existing calls that pass a `Dictionary<string, string>` are unaffected.

### Added
- Added `compiler.CompileToDocument(...)`, returning a disposable `TypstDocument` that exposes the rendered output while it is still in the memory the native library allocated. `GetOutputSpan`, `OpenOutputStream`, `CopyOutputTo`, `WriteOutputToFile` and `RentOutput` read it without putting a multi-megabyte PDF on the large object heap; `GetOutputBytes` copies when a `byte[]` is what you need.
Expand Down
23 changes: 23 additions & 0 deletions src/typstsharp.tests/Tests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.ObjectModel;
using System.Text;
using UglyToad.PdfPig;
using UglyToad.PdfPig.Content;
Expand Down Expand Up @@ -343,6 +344,28 @@ public async Task ErrorWithNullByteIsHandledCorrectly()
await Assert.That(ex!.Message).Contains("foo\0bar");
}

[Test]
public async Task SysInputsParameterAcceptsReadOnlyDictionary()
{
var sysInputs = new ReadOnlyDictionary<string, string>(
new Dictionary<string, string> { ["greeting"] = "Hello Inputs" });

using var compiler = TypstCompiler.FromSource("#sys.inputs.greeting", sysInputs: sysInputs);
var plainText = GetPlainText(compiler.CompilePdf());
await Assert.That(plainText).Contains("Hello Inputs");
}

[Test]
public async Task SetSysInputsAcceptsReadOnlyDictionary()
{
using var compiler = TypstCompiler.FromSource("#sys.inputs.greeting");
compiler.SetSysInputs(new ReadOnlyDictionary<string, string>(
new Dictionary<string, string> { ["greeting"] = "Hello Later" }));

var plainText = GetPlainText(compiler.CompilePdf());
await Assert.That(plainText).Contains("Hello Later");
}

[Test]
public async Task SourceAfterNullByteIsNotTruncated()
{
Expand Down
2 changes: 1 addition & 1 deletion src/typstsharp/JsonSerialisation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
namespace typstsharp;

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, string>))]
[JsonSerializable(typeof(IDictionary<string, string>))]
internal partial class SourceGenerationContext : JsonSerializerContext { }
26 changes: 13 additions & 13 deletions src/typstsharp/TypstCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class TypstCompiler : IDisposable
/// that directory, which keeps compilation off the network.
/// </param>
/// <exception cref="Exception">Thrown when the Typst compiler fails to initialize.</exception>
public TypstCompiler(string inputPath, Fonts? fonts = null, Dictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
public TypstCompiler(string inputPath, Fonts? fonts = null, IDictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
: this(inputPath, null, fonts, sysInputs, root, packagePath, includeSystemPackages)
{
}
Expand All @@ -53,7 +53,7 @@ public TypstCompiler(string inputPath, Fonts? fonts = null, Dictionary<string, s
/// that directory, which keeps compilation off the network.
/// </param>
/// <returns>A new <see cref="TypstCompiler"/> instance.</returns>
public static TypstCompiler FromSource(string source, Fonts? fonts = null, Dictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
public static TypstCompiler FromSource(string source, Fonts? fonts = null, IDictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
{
return new TypstCompiler(null, source, fonts, sysInputs, root, packagePath, includeSystemPackages);
}
Expand All @@ -72,7 +72,7 @@ public static TypstCompiler FromSource(string source, Fonts? fonts = null, Dicti
/// that directory, which keeps compilation off the network.
/// </param>
/// <returns>A new <see cref="TypstCompiler"/> instance.</returns>
public static TypstCompiler FromFile(string path, Fonts? fonts = null, Dictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
public static TypstCompiler FromFile(string path, Fonts? fonts = null, IDictionary<string, string>? sysInputs = null, string? root = null, string? packagePath = null, bool includeSystemPackages = true)
{
return new TypstCompiler(path, null, fonts, sysInputs, root, packagePath, includeSystemPackages);
}
Expand All @@ -91,7 +91,7 @@ public static TypstCompiler FromFile(string path, Fonts? fonts = null, Dictionar
public static PdfResult CompilePdf(
string source,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true,
Expand All @@ -115,7 +115,7 @@ public static PdfResult CompilePdf(
public static PdfResult CompilePdfFromFile(
string path,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true,
Expand All @@ -140,7 +140,7 @@ public static SvgResult CompileSvg(
string source,
float ppi = 144.0f,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true)
Expand All @@ -164,7 +164,7 @@ public static SvgResult CompileSvgFromFile(
string path,
float ppi = 144.0f,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true)
Expand All @@ -188,7 +188,7 @@ public static PngResult CompilePng(
string source,
float ppi = 144.0f,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true)
Expand All @@ -212,7 +212,7 @@ public static PngResult CompilePngFromFile(
string path,
float ppi = 144.0f,
Fonts? fonts = null,
Dictionary<string, string>? sysInputs = null,
IDictionary<string, string>? sysInputs = null,
string? root = null,
string? packagePath = null,
bool includeSystemPackages = true)
Expand All @@ -223,7 +223,7 @@ public static PngResult CompilePngFromFile(



private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? fonts, Dictionary<string, string>? sysInputs, string? root, string? packagePath = null, bool includeSystemPackages = true)
private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? fonts, IDictionary<string, string>? sysInputs, string? root, string? packagePath = null, bool includeSystemPackages = true)
{
fonts ??= new Fonts();
var fontPaths = fonts.FontPaths ?? [];
Expand Down Expand Up @@ -267,7 +267,7 @@ private unsafe TypstCompiler(string? inputPath, string? inputSource, Fonts? font

var packagePathPtr = packagePath != null ? Marshal.StringToCoTaskMemUTF8(packagePath) : IntPtr.Zero;

var sysInputsJson = sysInputs == null ? "{}" : JsonSerializer.Serialize<Dictionary<string, string>>(sysInputs, sourceGenOptions);
var sysInputsJson = sysInputs == null ? "{}" : JsonSerializer.Serialize<IDictionary<string, string>>(sysInputs, sourceGenOptions);
var sysInputsPtr = Marshal.StringToCoTaskMemUTF8(sysInputsJson);

try
Expand Down Expand Up @@ -548,11 +548,11 @@ public void Compile(string outputFile, string format, float ppi = 144.0f, IEnume
/// </summary>
/// <param name="inputs">A dictionary of key-value pairs. Values are serialized to JSON and passed to the compiler.</param>
/// <exception cref="Exception">Thrown if the inputs fail to be set in the native compiler.</exception>
public unsafe void SetSysInputs(Dictionary<string, string> inputs)
public unsafe void SetSysInputs(IDictionary<string, string> inputs)
{
if (_disposed) throw new ObjectDisposedException(nameof(TypstCompiler));

var sysInputsJson = JsonSerializer.Serialize<Dictionary<string, string>>(inputs, sourceGenOptions);
var sysInputsJson = JsonSerializer.Serialize<IDictionary<string, string>>(inputs, sourceGenOptions);
var sysInputsPtr = Marshal.StringToCoTaskMemUTF8(sysInputsJson);
try
{
Expand Down
Loading