Show HN: ManasPDF – GPU-accelerated PDF renderer built from scratch in C++

2026-02-1522:5742github.com

Contribute to Informal061/ManasPDF development by creating an account on GitHub.

NameName

ManasPDF Logo

Version Status License

A high-performance, GPU-accelerated PDF rendering engine written in C++ with a .NET wrapper and WPF viewer control.

Developed by The Big Studio

Website & Screenshots | Download Setup (Windows x64)

Alpha Release - This project is in active development. APIs may change between versions. Not recommended for production use yet. Feedback and bug reports are welcome!

ManasPDF is a from-scratch PDF rendering engine built on Direct2D for GPU-accelerated rendering with an automatic CPU software renderer fallback. The core engine is a native C++ DLL (ManasPDFCore.dll) that handles all PDF parsing, content stream interpretation, font rasterization, and pixel output. A .NET wrapper and WPF control are provided for easy integration into C# applications.

  • Direct2D GPU renderer - Hardware-accelerated path rasterization, gradient shading, image compositing
  • CPU software renderer - Pure C++ scanline rasterizer with configurable SSAA (1x/2x/4x)
  • Automatic fallback - GPU failure (device lost, remote desktop) falls back to CPU seamlessly
  • Render quality modes - Fast (no SSAA), Standard (SSAA=1), Quality (SSAA=2)
  • BGRA32 output - Raw pixel buffer, ready for display or further processing
  • Cross-reference table and stream parsing
  • Object streams, indirect references, stream filters
  • Page tree traversal with inherited attributes
  • 90+ PDF operators implemented (paths, text, color, shading, clipping, XObjects)
  • FreeType font rasterization (TrueType, CFF/PostScript, Type1)
  • Type0/CID fonts with CID-to-GID mapping
  • Custom encodings and ToUnicode CMap support
  • Glyph-level text extraction with pixel coordinates
Codec Filter Library
JPEG DCTDecode libjpeg-turbo
JPEG2000 JPXDecode OpenJPEG (x64)
Flate/Deflate FlateDecode zlib
LZW LZWDecode Built-in
CCITT Fax CCITTFaxDecode Built-in (Group 3/4)
ASCII85 ASCII85Decode Built-in
RunLength RunLengthDecode Built-in
PNG Predictor - Built-in (Up/Sub/Avg/Paeth)

Filter chains (multiple filters in sequence) are fully supported.

DeviceRGB, DeviceCMYK, DeviceGray, CalRGB, CalGray, ICCBased, Indexed, Separation, DeviceN, Lab

  • Paths: moveto, lineto, cubic bezier, rectangle, close
  • Fill rules: even-odd, non-zero winding
  • Stroke: line width, cap styles, join styles, miter limit, dash patterns
  • Gradients: axial (linear) and radial with LUT-based evaluation + dithering
  • Tiling patterns with arbitrary transforms
  • Nested clipping paths (Form XObject clip layer stacking)
  • Password encryption (/Standard handler)
    • RC4 40-128 bit (Revision 2-3)
    • AES-128 / AES-256 (Revision 5)
  • Certificate encryption (/Adobe.PubSec)
    • PKCS#7 EnvelopedData parsing
    • RSA key transport with recipient enumeration
    • Full ASN.1 DER parser for certificate matching
  • Page render cache - Per-document, per-zoom LRU cache (500MB limit)
  • Glyph cache - Rasterized glyphs by font hash + glyph ID + pixel size (128MB / 20K glyphs)
  • Font cache - FT_Face objects cached by font program hash (100 fonts max)
  • Text batching - BT/ET glyph atlas composition reduces draw calls (GPU)
  • Active document filter - Multi-tab optimization, skip rendering for inactive documents
  • Zero-copy interop - Cache results copied directly to output buffer
                    +---------------------------+
                    |      Your Application     |
                    +---------------------------+
                               |
                    +----------+----------+
                    |                     |
           +-------v-------+    +--------v--------+
           |   ManasPDF    |    |  ManasPDF.Wpf   |
           | (.NET Wrapper)|    | (WPF Control)   |
           |   NuGet pkg   |    |   NuGet pkg     |
           +-------+-------+    +-----------------+
                   |
            P/Invoke (C interop)
                   |
         +---------v-----------+
         |   ManasPDFCore.dll  |
         |   (C++ Engine)      |
         +-----+-------+------+
               |       |
      +--------v--+ +--v---------+
      |  Direct2D | |  Software  |
      |    GPU    | |    CPU     |
      |  Renderer | |  Renderer  |
      +-----------+ +------------+
               |       |
    +----------+-------+-----------+
    |  FreeType  |  zlib    |      |
    |  libjpeg   | OpenJPEG |      |
    +------------------------------+
Pdf_RenderPageToRgba(doc, pageIndex, zoom)
  |
  +-> Check PageRenderCache (LRU, zero-copy)
  |     |-> Cache hit: copy to output buffer, return
  |     |-> Cache miss: continue
  |
  +-> Acquire render mutex
  +-> PdfPainterGPU::initialize(width, height)
  +-> PdfDocument::renderPageToPainter()
  |     |-> PdfContentParser::parse(contentStream)
  |           |-> Graphics state operators (q, Q, cm, w, J, ...)
  |           |-> Path operators (m, l, c, re, h, ...)
  |           |-> Paint operators (f, S, B, n, ...)
  |           |-> Text operators (BT, ET, Tf, Tm, Tj, TJ, ...)
  |           |-> Color operators (CS, SC, RG, K, G, ...)
  |           |-> XObject operators (Do -> Form/Image)
  |           |-> Clipping operators (W, W*)
  |
  +-> PdfPainterGPU::getBuffer() -> BGRA32 pixels
  +-> Store in PageRenderCache
  +-> Return to caller
  • ID2D1RenderTarget + IWICBitmap per render instance
  • Static D2D/WIC/DirectWrite factories shared across all instances
  • Glyph atlas batching: glyphs collected during BT/ET blocks, rendered as a single atlas texture (threshold: 1000 glyphs, 4MB atlas)
  • Brush caching: D2D solid color brushes cached by BGRA value
  • Clip layer stack: nested Form XObjects use D2D clip layers
  • Max bitmap: 16384x16384 (1GB RGBA)
  • Scanline polygon rasterization
  • Configurable supersampling (SSAA 1x/2x/4x)
  • Direct pixel blending for grayscale glyphs
  • Gradient evaluation with 4096-sample LUT + dithering
  • No GPU/DirectX dependency

The native library exports a flat C API for cross-language interop:

// Document
PDF_API void* Pdf_OpenDocument(const wchar_t* path);
PDF_API void Pdf_CloseDocument(void* doc);
PDF_API int Pdf_GetPageCount(void* doc);
PDF_API int Pdf_GetPageSize(void* doc, int pageIndex, double* w, double* h);
PDF_API int Pdf_GetPageRotate(void* doc, int pageIndex); // Rendering (BGRA32 output)
PDF_API int Pdf_RenderPageToRgba(void* doc, int pageIndex, double zoom, void* buffer, int bufferSize, int* outWidth, int* outHeight);
PDF_API int Pdf_RenderPageToRgba_CPU(void* doc, ...); // CPU-only
PDF_API int Pdf_RenderPageToRgba_Fast(void* doc, ...); // No SSAA
PDF_API int Pdf_RenderPageToRgba_Quality(void* doc, ...); // SSAA=2 // Text extraction
PDF_API int Pdf_ExtractPageText(void* doc, int pageIndex);
PDF_API int Pdf_GetTextGlyphCount(void* doc, int pageIndex);
PDF_API int Pdf_GetExtractedGlyphs(void* doc, int pageIndex, PdfTextGlyphExport* out, int maxCount);
PDF_API int Pdf_GetExtractedTextUtf8(void* doc, int pageIndex, char* outBuffer, int maxLen); // Links
PDF_API int Pdf_GetPageLinkCount(void* doc, int pageIndex);
PDF_API int Pdf_GetPageLinks(void* doc, int pageIndex, ...); // Encryption
PDF_API int Pdf_GetEncryptionStatus(void* doc); // 0=none, 1=ready, -1=locked
PDF_API int Pdf_GetEncryptionType(void* doc); // 0=none, 1=password, 2=cert
PDF_API int Pdf_TryPassword(void* doc, const char* password);
PDF_API int Pdf_SupplyCertSeed(void* doc, const uint8_t* seed, int seedLen);
PDF_API int Pdf_GetCertRecipientCount(void* doc);
PDF_API int Pdf_GetCertRecipientEncryptedKey(void* doc, int idx, ...); // Cache management
PDF_API void Pdf_ClearDocumentCache(void* doc);
PDF_API void Pdf_ClearAllCache();
PDF_API void Pdf_SetActiveDocument(void* doc);
struct PdfTextGlyphExport { uint32_t unicode; // Unicode code point float x, y; // Position in bitmap pixels (at zoom=1, 96 DPI) float width; // Glyph advance width float height; // Glyph height float fontSize; // Effective font size in pixels
};

NuGet packages provide a managed wrapper and a ready-to-use WPF viewer control.

Package Description Target
ManasPDF .NET wrapper over the native engine net8.0
ManasPDF.Wpf Drop-in WPF PdfViewer control with toolbar net8.0-windows
dotnet add package ManasPDF.Wpf --prerelease

ManasPDF.Wpf automatically includes the ManasPDF core package. Use --prerelease for alpha versions.

using ManasPDF; using var doc = PdfDocument.Open("sample.pdf");
var page = doc.GetPage(0); // GPU-accelerated render -> BGRA32 pixels
byte[]? pixels = page.Render(1.5, out int width, out int height); // Text extraction
string text = page.ExtractText();
PdfTextGlyph[] glyphs = page.ExtractGlyphs(); // Hyperlinks
PdfLink[] links = page.GetLinks();
<Window xmlns:manaspdf="clr-namespace:ManasPDF.Wpf;assembly=ManasPDF.Wpf"> <manaspdf:PdfViewer x:Name="Viewer" Source="C:\docs\sample.pdf" />
</Window>

Built-in features: zoom, page navigation, text search & highlight, text selection & copy, rotation, print preview with printer selection, save as, hyperlink click, keyboard shortcuts (Ctrl+F/P/S/C).

Full .NET API documentation: DOTNET-API.md

  • Visual Studio 2022 with C++ Desktop workload
  • .NET 8.0 SDK
  • CMake 3.20+
cd src/PDFCore
cmake -B build -A x64
cmake --build build --config Release
# Output: ManasPDFCore.dll
dotnet build src/ManasPDF -c Release
dotnet build src/ManasPDF.Wpf -c Release

Place native DLLs into the runtimes folder, then pack:

src/ManasPDF/runtimes/win-x64/native/
  ManasPDFCore.dll
  freetype.dll
  jpeg62.dll
  openjp2.dll
dotnet pack src/ManasPDF -c Release
dotnet pack src/ManasPDF.Wpf -c Release
ManasPDF/
  src/
    PDFCore/                    # C++ native engine (ManasPDFCore.dll)
      PdfEngine.h               #   DLL export declarations
      PdfDocument.cpp/h          #   PDF parsing, encryption, font loading
      PdfContentParser.cpp/h     #   Content stream operator interpreter
      PdfPainterGPU.cpp/h        #   Direct2D GPU renderer
      PdfPainter.cpp/h           #   CPU software renderer
      PdfTextExtractor.cpp/h     #   Text extraction
      GlyphCache.cpp/h           #   Glyph bitmap cache
      PdfGradient.cpp/h          #   Gradient rendering
      PdfFilters.cpp/h           #   Stream decompression (7 codecs)
      IPdfPainter.h              #   Abstract renderer interface
      PdfGraphicsState.h         #   Graphics state model
      PdfPath.h                  #   Path representation
      PdfObject.h                #   PDF object model
      PdfParser.cpp/h            #   Object parser
      PdfLexer.cpp/h             #   Tokenizer
      CMakeLists.txt             #   Build configuration
    ManasPDF/                   # .NET wrapper (NuGet: ManasPDF)
      PdfDocument.cs             #   High-level API
      PdfPage.cs                 #   Page operations
      PdfTextGlyph.cs            #   Glyph struct (24-byte interop)
      PdfLinkExport.cs           #   Link classes
      PdfException.cs            #   Exception type
      Internal/NativeApi.cs      #   P/Invoke bindings
    ManasPDF.Wpf/               # WPF control (NuGet: ManasPDF.Wpf)
      PdfViewer.xaml              #   UserControl layout
      PdfViewer.xaml.cs           #   Control logic
  DOTNET-API.md                  # .NET API reference
  LICENSE                        # Apache 2.0
  THIRD-PARTY-NOTICES.txt        # Third-party licenses
  README.md
Library File Purpose License
FreeType freetype.dll Font rasterization FTL/GPLv2
libjpeg-turbo jpeg62.dll JPEG decoding IJG/BSD
OpenJPEG openjp2.dll JPEG2000 decoding (x64) BSD-2
zlib statically linked Deflate compression zlib

Planned: HarfBuzz integration for complex text shaping (Arabic, Devanagari, etc.) is planned for a future release.

See THIRD-PARTY-NOTICES.txt for full license texts.

Bug Fixes

  • Fixed Turkish character rendering (ğ, ş, ı, İ, Ş, Ğ) in subset TrueType fonts with /Differences encoding

Bug Fixes

  • Fixed garbled text rendering for subset TrueType fonts with custom ToUnicode CMap
    • WinAnsi glyph names no longer override ToUnicode mappings for fonts without explicit /Encoding
    • Added symbolic cmap (0xF000+code) fallback per PDF spec for TrueType fonts with (3,0) cmap
    • Subset symbolic fonts (no glyph names, Mac-only cmap): direct code→GID mapping now takes priority over Unicode→GID lookup to prevent incorrect glyph substitution
  • Fixed rendering of complex gradient overlays using nested tiling patterns and rotated images with SMask
    • PdfStream objects in pattern resolution now handled correctly (fallback from PdfDictionary cast)
    • Tiling pattern tile size limit increased from 2048 to 4096 with dynamic scale calculation for large BBox patterns
    • Fixed double premultiplied alpha in tiling pattern bitmap brush creation
    • Proper brush transform composition: bitmap Y-flip → pattern matrix → default CTM → device scale
    • Unresolvable pattern fills now skip gracefully instead of falling back to solid black
    • Rotated images with rect clip now use bitmap brush transform instead of AABB stretch (rotation was lost)
    • Fixed pre-scaling dimension calculation for rotated images (per-axis extent instead of AABB)
  • Fixed UI overflow on multi-monitor setups with different DPI scales (e.g., 1080p main + 1440p secondary)
    • Added WM_DPICHANGED handler: updates DPI scale and applies suggested window rect when dragging between monitors
    • Clears render cache and re-renders visible pages at new DPI automatically

Memory Optimization

  • Eliminated redundant buffer copies during page rendering (peak memory reduced by ~50%)
    • Added getBufferDirect() to GPU painter: writes directly from WIC bitmap to output buffer
    • Added getDownsampledBufferDirect() to CPU painter: downsamples directly into output buffer
    • Added storeFromRaw() to page render cache: stores from raw pointer without extra vector copy
  • Proactive cache trimming: page cache is cleared before large renders when total exceeds 400MB
  • Large single entries (>125MB) are no longer cached to prevent cache thrashing

Crash Prevention

  • Added std::bad_alloc protection during GPU and CPU rendering: clears page + glyph caches on OOM
  • Added std::bad_alloc protection in cache store: gracefully skips caching if allocation fails
  • Added OutOfMemoryException protection for WriteableBitmap creation on C# side

Zoom Improvements

  • Instant zoom scaling for all pages — all pages resize immediately on zoom, not just visible ones
  • Mouse-centered zoom — Ctrl+Scroll zoom anchors to mouse position instead of jumping to another page
  • Viewport-anchored toolbar zoom — +/- buttons keep the current page in view

PDF Rendering Fixes

  • CropBox origin offset — correct initial CTM for PDFs with non-zero CropBox/MediaBox origin
  • Text quality improvement — snap glyph cache scale to 1.0 when within 5% for sharper text rendering
  • Form XObject /BBox clipping — apply BBox boundary as clip rect when rendering Form XObjects
  • D2D clip layer cleanup — pop unpaired PushLayer calls at end of content stream parsing, preventing GPU EndDraw failure and CPU fallback, fixes page clipping for PDFs using shared Form XObjects

Apache License 2.0 - see LICENSE for details.

ManasPDF is a product of The Big Studio | Report an Issue

You can’t perform that action at this time.


Read the original article

Comments

  • By informal061 2026-02-1714:11

    Currently it’s Windows-only since it uses Direct2D, but multi-platform support is planned. In the beginning a good portion was vibe-coded, though later I started to take the project more seriously and made the development more structured.

  • By eXpl0it3r 2026-02-166:11

    Since this uses Direct2D, is this Windows-only?

    How much of the code was vibe-coded?

  • By informal061 2026-02-1522:58

    [dead]

HackerNews