Majorsilence.Pdf#281
Merged
Merged
Conversation
Introduce a native PDF 1.4 writer and a raw PDF renderer. - Add PdfDocumentWriter: builds PDF files (fonts, embedded TrueType, images, annotations, metadata) and writes cross-reference/trailer; uses SharpZipLib for Flate compression. - Add TrueTypeFont: minimal TrueType/OpenType parser to extract metrics, glyph widths and cmap for embedding CIDFont Type2 and ToUnicode CMap. - Add RenderPdf_Raw: new renderer that emits PDF content streams (text, shapes, images, annotations) using PdfDocumentWriter and resolves/embeds fonts via TrueTypeFont; includes platform font-folder heuristics and image handling (JPEG and raw RGB). - Register new output type RenderPdf_Raw in ProcessReport enum. - Add tests scaffold ReportTests/RenderPdf_RawTests.cs. This enables an internal PDF output option without relying on a third-party PDF library and supports full font embedding for TrueType/OpenType fonts, basic image formats, and annotations.
Create a new Majorsilence.Pdf library and move PDF writer implementation into it. Adds Majorsilence.Pdf.csproj (netstandard2.0, SharpZipLib, packable) and registers the project in the solution and RdlEngine project references. Rename namespaces to Majorsilence.Pdf and relocate PdfDocumentWriter and TrueTypeFont files. Make types and members public, add nullable annotations, tighten APIs (SetMetadata, AddPage, GetOrAdd* methods, Write, Fmt, EncodeText, etc.), and clean up encoding/stream helpers and object serialization formatting. Also update references/usings in RenderPdf_Raw to use the new project. The change extracts a zero-dependency PDF generator into a reusable package and prepares it for NuGet packaging.
There was a problem hiding this comment.
Pull request overview
This PR adds a new PDF rendering path (RenderPdf_Raw) that generates PDF output without iTextSharp by introducing a new Majorsilence.Pdf library and wiring it into the RDL engine’s render switch, along with a basic NUnit test to exercise the new output type.
Changes:
- Add
OutputPresentationType.RenderPdf_Rawand route it throughReport.RunRender. - Implement a new raw PDF renderer (
RenderPdf_Raw) backed by a newMajorsilence.Pdfwriter and TTF parser. - Add a new NUnit test that renders several sample reports using the new raw PDF output.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| ReportTests/RenderPdf_RawTests.cs | Adds an integration-style test that renders reports to the new raw PDF output. |
| RdlEngine/Runtime/Report.cs | Wires the new RenderPdf_Raw output type into the rendering dispatch. |
| RdlEngine/Render/RenderPdf_Raw.cs | Implements the new PDF renderer that writes PDF content/resources directly. |
| RdlEngine/Render/ProcessReport.cs | Extends OutputPresentationType with RenderPdf_Raw. |
| RdlEngine/Majorsilence.Reporting.RdlEngine.csproj | Adds a project reference to the new Majorsilence.Pdf library. |
| MajorsilenceReporting.sln | Adds the Majorsilence.Pdf project to the solution. |
| Majorsilence.Pdf/TrueTypeFont.cs | Introduces a minimal TrueType/OpenType parser for metrics and cmap mappings. |
| Majorsilence.Pdf/PdfDocumentWriter.cs | Introduces a PDF 1.4 writer supporting fonts, images, annotations, and metadata. |
| Majorsilence.Pdf/Majorsilence.Pdf.csproj | Adds the new PDF library project (netstandard2.0) with SharpZipLib dependency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| using var sg = new OneFileStreamGen(outFile, true); | ||
| await rap.RunRender(sg, OutputPresentationType.RenderPdf_Raw); | ||
|
|
||
| Assert.That(File.Exists(outFile), "PDF output file was not created"); |
Introduce a new Majorsilence.Pdf library with core PDF functionality: PdfDocument, PdfCanvas, PdfColor, TextStyle/ShapeStyle/StrokeStyle/LineStyle, PageSizes, TrueTypeFont improvements, font registry and internal helpers (FontCache, PdfSerializer). Add a comprehensive test suite (Majorsilence.Pdf.Tests) exercising font registry, rendering and fallback behavior, and include an Examples/MajorsilencePdfExample console app demonstrating features and bundled fonts. Update solution files and adjust related projects (modified TrueTypeFont and RdlEngine render integration); remove PdfDocumentWriter (deleted). Tests use PdfPig for PDF validation and assume bundled/system fonts where applicable.
Build and attach a FontRegistry to the PDF document and overhaul font resolution. Introduces BuildFontRegistry, TryAddFamily and MapFaceToRegistryFamily to register bundled and system fonts (OS-specific handling) and select metric-compatible substitutions and fallbacks. ResolveFont now prefers the registry for embedding/variants and falls back to standard Type-1 families; NormalizeFace mappings updated (e.g. Times New Roman) and Symbol/ZapfDingbats handled as Type-1. Also small API/formatting cleanups: avoid copying JPEG image buffers, inline style construction for drawing calls, early returns and minor whitespace/structure refactors for readability.
Rename the OutputPresentationType enum member RenderPdf_Raw to RenderPdf_Majorsilence and update all usages accordingly. Adjusted the switch case in Report.RunRender to match the new enum value and updated the RenderPdf_RawTests to call RunRender with OutputPresentationType.RenderPdf_Majorsilence. No behavior changes intended; this is a symbolic rename across ProcessReport.cs, Report.cs, and the test.
Add horizontal alignment handling in PdfCanvas.DrawText so right- and center-aligned text is positioned correctly by measuring text width and adjusting x. Increase spacing before the "Total Due" line in the example (y offset from 4 to 14) to improve layout. Also include minor fixes and formatting cleanups across PdfCanvas (decoration line calculation, ellipse Bezier formatting, dash default formatting, and several whitespace/formatting refactors) to improve readability and maintain consistent code style.
Switch PDF compression to System.IO.Compression and multi-target .NET 6 and netstandard2.0. PdfSerializer now uses ZLibStream on NET6 (which handles zlib header + Adler-32) and falls back to writing the zlib envelope (0x78 0x9C), using DeflateStream and a manual Adler32 implementation for netstandard2.0. Removed SharpZipLib usings and package reference, and updated the project to target netstandard2.0;net6.0.
Track glyph IDs used on a page and produce subsetted TrueType fonts to reduce output size. FontResource now holds a UsedGlyphs set; PdfCanvas passes that set when encoding glyph IDs so EncodeGlyphIds records used glyphs. PdfSerializer.BuildTtfFontObjs filters the ToUnicode CMap and /W width array to only include used glyphs, and writes a subsetted FontFile2 stream (falling back to the full font if no subsetting is possible). TrueTypeFont.Subset implements glyph subsetting: it parses loca/glyf/head, includes .notdef and composite components, builds new loca/glyf/head tables (long format), reassembles the font tables and fixes checksum. Helper routines for writing binary tables and checksums were added.
Add a new Unicode/UTF-8 example to the sample program (UnicodeExample) and register it in the example runner. The example demonstrates Latin Extended, Greek, Cyrillic, emoji and CJK rendering and shows fallback behavior when glyphs are missing. Also add comprehensive NUnit tests (Majorsilence.Pdf.Tests/UnicodeRenderingTests.cs) covering accented Latin, Greek, Cyrillic, mixed-script fallback segmentation, emoji (surrogates), optional system CJK/emoji fonts, subsetting behavior, measurement of non-Latin text, and ensuring RTL/Arabic input does not crash. Includes a small formatting/whitespace tweak in the sample program.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces a comprehensive test suite for the
Majorsilence.Pdflibrary and adds example and test project scaffolding. The main focus is on ensuring correctness and robustness of core PDF features such as color handling, page sizing, and font registry management, as well as providing the necessary infrastructure for running and organizing these tests.Test coverage improvements:
PdfColorTeststo verify construction, parsing, equality, and string representation ofPdfColor, including hex parsing and named color values.PageSizeTeststo check correctness ofPdfPageSizeandPageSizes(dimensions, orientation, and series relationships).FontRegistryTeststo thoroughly testFontRegistryandFontSource, including registration, resolution, fallback mechanisms, directory scanning, and integration with PDF rendering and measurement.Project and solution scaffolding:
Majorsilence.Pdf.Tests.csprojwith references to required packages and the main project, targeting .NET 8.0 and 10.0, and enabled nullable reference types.MajorsilencePdfExample.csprojand corresponding solution fileMajorsilencePdfExample.slnxfor demonstration purposes. [1] [2]