GroupDocs.Viewer for Python via .NET is designed to work seamlessly with AI agents, LLMs, and automated code generation tools. The library ships machine-readable documentation in multiple formats — including an AGENTS.md file inside the pip package itself — so that AI assistants can discover and use the API without manual guidance.
MCP server
GroupDocs provides an MCP (Model Context Protocol) server that enables LLMs to query the documentation on demand instead of loading it all at once. This saves tokens and lets your AI assistant fetch only the information it needs for the current task.
To connect your AI tool to the MCP server, add the GroupDocs endpoint to your MCP configuration:
// Claude Code: ~/.claude/settings.json (or project .mcp.json)
// Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
{"mcpServers":{"groupdocs-docs":{"url":"https://docs.groupdocs.com/mcp"}}}
// .vscode/mcp.json in your project root
{"servers":{"groupdocs-docs":{"url":"https://docs.groupdocs.com/mcp"}}}
// .cursor/mcp.json in your project root
{"mcpServers":{"groupdocs-docs":{"url":"https://docs.groupdocs.com/mcp"}}}
The groupdocs-viewer-net pip package includes an AGENTS.md file at groupdocs/viewer/AGENTS.md. AI coding assistants that scan installed packages (such as Claude Code, Cursor, GitHub Copilot) can automatically discover the API surface, usage patterns, and troubleshooting tips.
After installing the package, you can find it at:
pip show -f groupdocs-viewer-net | grep AGENTS
Machine-readable documentation
Every documentation page is available as a plain Markdown file that AI tools can fetch and process directly:
Point your AI assistant to the full documentation file for comprehensive context:
Fetch https://docs.groupdocs.com/viewer/python-net/llms-full.txt and use it
as a reference for GroupDocs.Viewer for Python via .NET API.
Or reference individual pages for focused tasks:
Read https://docs.groupdocs.com/viewer/python-net/getting-started/quick-start-guide.md
and help me render a DOCX to HTML in Python.
Why GroupDocs.Viewer is a good building block for AI document pipelines
LLMs and RAG systems can rarely consume DOCX, XLSX, PPTX, EML, CAD drawings, or scanned PDFs directly. GroupDocs.Viewer renders the long tail of office, image, CAD, email, and archive formats into the few formats your model can actually read:
Render to per-page PNG / JPG for vision models — one image per page, size-controlled, ready to feed straight to a multimodal LLM.
Render to PDF for OCR and page-level routing — with watermarks, password protection, or optimization applied during rendering.
Render to HTML when you want to keep semantic structure (headings, tables, lists) for downstream parsers or embedding generators.
Render to HTML with external resources for indexing systems that want the markup and assets separated.
A typical preprocessing step looks like:
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimport(HtmlViewOptions,PdfViewOptions,PngViewOptions,ViewInfoOptions,)# Step 1: Inspect — let the agent decide what to do based on metadatawithViewer("inbox/incoming.docx")asv:info=v.get_view_info(ViewInfoOptions.for_html_view())print(f"format={info.file_type} pages={info.pages_count}")# Step 2: Render to a model-friendly formatwithViewer("inbox/incoming.docx")asv:# HTML for structure-preserving parsingv.view(HtmlViewOptions.for_embedded_resources("staging/incoming_{0}.html"))# PDF for OCR / page routingv.view(PdfViewOptions("staging/incoming.pdf"))# Per-page PNG for vision modelsv.view(PngViewOptions("staging/incoming_page_{0}.png"))
For end-to-end examples — including rendering archives, attachments, password-protected documents, and format-specific options — see the Developer Guide and Rendering Basics. Every code block on those pages has a runnable counterpart in the examples repository.
Pair with GroupDocs.Conversion for hard-to-render inputs
If you are handling exotic or legacy formats (older DOC/XLS/PPT, password-protected archives, custom email containers), chain GroupDocs.Viewer with GroupDocs.Conversion for Python via .NET:
Use GroupDocs.Conversion to normalise the source — for example, convert a legacy .doc or a PST archive entry to .docx or .pdf.
Use GroupDocs.Viewer to render the normalised file to HTML, PDF, PNG, or JPG that your model can consume.
This combination covers the long tail of input formats while keeping the model-facing stage simple and predictable.
AGENTS.md reference
The content below is the same AGENTS.md file that ships inside the groupdocs-viewer-net package. Copy it into your project as AGENTS.md or point your AI assistant to this page.
# GroupDocs.Viewer for Python via .NET -- AGENTS.md
> Instructions for AI agents working with this package.
Render documents to HTML, PNG, JPG, or PDF -- 170+ file formats supported.
## Install
```bash
pip install groupdocs-viewer-net
```**Python**: 3.5 - 3.14 | **Platforms**: Windows, Linux, macOS
## Resources
| Resource | URL |
|---|---|
| Documentation | https://docs.groupdocs.com/viewer/python-net/ |
| LLM-optimized docs | https://docs.groupdocs.com/viewer/python-net/llms-full.txt |
| API reference | https://reference.groupdocs.com/viewer/python-net/ |
| Code examples | https://docs.groupdocs.com/viewer/python-net/developer-guide/ |
| Release notes | https://releases.groupdocs.com/viewer/python-net/release-notes/ |
| PyPI | https://pypi.org/project/groupdocs-viewer-net/ |
| Free support forum | https://forum.groupdocs.com/c/viewer/ |
| Temporary license | https://purchase.groupdocs.com/temporary-license |
## MCP Server
If your environment has MCP configured, you can connect your AI tool to the GroupDocs documentation server for on-demand API lookups:
```json
{"mcpServers":{"groupdocs-docs":{"url":"https://docs.groupdocs.com/mcp"}}}```Works with Claude Code (`~/.claude/settings.json`), Cursor (`.cursor/mcp.json`), VS Code Copilot (`.vscode/mcp.json`), and any MCP-compatible client. If MCP is unavailable, fall back to the LLM-optimized docs URL above and this file -- both are shipped inside the wheel.
## Imports
```python
fromgroupdocs.viewerimportLicense,FileType,Viewer,ViewerSettingsfromgroupdocs.viewer.exceptionsimport(GroupDocsViewerException,IncorrectPasswordException,PasswordRequiredException,InvalidFontFormatException,InvalidImageFormatException,)fromgroupdocs.viewer.cachingimportCacheKeys,FileCache,ICachefromgroupdocs.viewer.drawingimport(Argb32Color,Rgb24Color,CssLevel1,CssLevel2,CssLevel3,CssLevel4,Image2DFormat,KnownColors,)fromgroupdocs.viewer.fontsimport(FolderFontSource,FontFormat,FontSettings,FontStyles,IFontInfo,IFontSource,PdfFontInfo,PresentationFontInfo,SpreadsheetFontInfo,WordProcessingFontInfo,WordProcessingSubstitutedFontInfo,SearchOption,)fromgroupdocs.viewer.interfacesimport(CreatePageStream,CreateResourceStream,CreateResourceUrl,CreateFileStream,ReleasePageStream,ReleaseResourceStream,ReleaseFileStream,IPageStreamFactory,IResourceStreamFactory,IFileStreamFactory,)fromgroupdocs.viewer.loggingimportConsoleLogger,FileLogger,ILoggerfromgroupdocs.viewer.optionsimport(# View-options flavours — the four output formatsHtmlViewOptions,PngViewOptions,JpgViewOptions,PdfViewOptions,ViewInfoOptions,ViewOptions,BaseViewOptions,# Loading + format-specific rendering tweaksLoadOptions,ArchiveOptions,CadOptions,EmailOptions,MailStorageOptions,OutlookOptions,PdfOptimizationOptions,PdfOptions,PresentationOptions,ProjectManagementOptions,SearchHighlightOptions,SpreadsheetOptions,TextOptions,VisioRenderingOptions,WebDocumentOptions,WordProcessingOptions,# Rendering primitivesWatermark,Rotation,Position,ImageQuality,PageSize,Permissions,Security,Resolution,Size,Tile,TimeUnit,TextOverflowMode,Field,FileName,)fromgroupdocs.viewer.resultsimport(ViewInfo,FileInfo,Attachment,Page,Resource,TextElement,Character,Word,Line,ArchiveViewInfo,CadViewInfo,MailMessageViewInfo,MboxViewInfo,OutlookViewInfo,LotusNotesViewInfo,PdfViewInfo,ProjectManagementViewInfo,Layer,Layout,)```## Quick Start
```python
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportHtmlViewOptionswithViewer("document.docx")asviewer:options=HtmlViewOptions.for_embedded_resources("page_{0}.html")viewer.view(options)```## Render to PNG
```python
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportPngViewOptionswithViewer("document.pdf")asviewer:viewer.view(PngViewOptions("page_{0}.png"))```## Render to PDF
```python
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportPdfViewOptionswithViewer("spreadsheet.xlsx")asviewer:viewer.view(PdfViewOptions("output.pdf"))```## Render selected pages / reorder pages
```python
# Render only pages 1 and 3withViewer("document.docx")asviewer:viewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"),page_numbers=[1,3])# Reorder: render page 2 first, then page 1withViewer("document.docx")asviewer:viewer.view(PdfViewOptions("out.pdf"),page_numbers=[2,1])```## Load password-protected documents
```python
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportHtmlViewOptions,LoadOptionsload_options=LoadOptions()load_options.password="12345"withViewer("protected.docx",load_options)asviewer:viewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"))```## Get View Info
```python
fromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportViewInfoOptionswithViewer("document.pdf")asviewer:info=viewer.get_view_info(ViewInfoOptions.for_html_view())print(f"Pages: {len(info.pages)}")forpageininfo.pages:print(f" Page {page.number}: {page.width}x{page.height}")```**Viewer constructor.**`Viewer(source, load_options=None, settings=None, leave_open=None)` accepts all four positional **or** as kwargs. Prefer kwargs when you only need `settings`:
```python
fromgroupdocs.viewerimportViewer,ViewerSettingsfromgroupdocs.viewer.loggingimportConsoleLoggersettings=ViewerSettings(logger=ConsoleLogger())withViewer("input.docx",settings=settings)asviewer:# no None placeholderviewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"))```## Render to custom streams
Unlike most GroupDocs products, Viewer **does** support Python callables that return streams. Pass a function to the `HtmlViewOptions` / `PngViewOptions` / `JpgViewOptions` / `PdfViewOptions` constructors that accept `CreatePageStream` / `CreateResourceStream` / `CreateFileStream` factories — the bridge auto-wraps your Python callable as a .NET stream factory.
```python
# Write each page to an in-memory bufferimportiofromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportPngViewOptionspage_buffers={}defcreate_page_stream(page_number):buf=io.BytesIO()page_buffers[page_number]=bufreturnbufwithViewer("input.docx")asviewer:viewer.view(PngViewOptions(create_page_stream))# page_buffers now holds {1: <BytesIO>, 2: <BytesIO>, ...}``````python
# Write HTML pages + resources with custom namingimportosfromgroupdocs.viewerimportViewerfromgroupdocs.viewer.optionsimportHtmlViewOptionsdefcreate_page(page_number):os.makedirs("out",exist_ok=True)returnopen(f"out/page_{page_number}.html","wb")defcreate_resource(page_number,resource_name):returnopen(f"out/res_{page_number}_{resource_name}","wb")defresource_url(page_number,resource_name):returnf"res_{page_number}_{resource_name}"withViewer("input.docx")asviewer:viewer.view(HtmlViewOptions.for_external_resources(create_page,create_resource,resource_url))```The three factory interfaces (`IPageStreamFactory`, `IResourceStreamFactory`, `IFileStreamFactory`) all accept Python callables — no bridge imports needed. The callable returns any file-like object (`open(...)` or `io.BytesIO()`); the bridge reads from it after `view()` returns.
## Save attachments
```python
fromgroupdocs.viewerimportViewerwithViewer("with_attachments.msg")asviewer:forattachmentinviewer.get_attachments():# Pass a filesystem path — the wrapper opens the file, writes,# and closes it. Parent directories are created as needed.viewer.save_attachment(attachment,f"./out/{attachment.file_name}")# Equivalent stream form (explicit control over the sink):# import io# buf = io.BytesIO()# viewer.save_attachment(attachment, buf)# buf.getvalue() # attachment bytes```**Note**: .NET 26.4's native `SaveAttachment` only exposes the
`(Attachment, Stream)` overload. The path-accepting form is a Python-
side convenience layered on top — it wraps the open/close for you.
## Font sources
`FontSettings.set_font_sources(...)` is the .NET
`params IFontSource[]` method and accepts any of these call shapes:
```python
fromgroupdocs.viewer.fontsimportFontSettings,FolderFontSource,SearchOptionsrc1=FolderFontSource("C:/fonts/primary",SearchOption.ALL_FOLDERS)src2=FolderFontSource("C:/fonts/backup",SearchOption.TOP_FOLDER_ONLY)FontSettings.set_font_sources(src1,src2)# varargsFontSettings.set_font_sources([src1,src2])# single listFontSettings.set_font_sources([src1],[src2])# multiple lists (flattened)FontSettings.set_font_sources([src1,src2],src3)# mixed — also flattenedFontSettings.reset_font_sources()# clear```All four shapes normalize to the same flat list before crossing the
bridge. Strings are never flattened (a string path is passed through
as-is, not exploded into characters).
## Licensing
```python
fromgroupdocs.viewerimportLicense# From fileLicense().set_license("path/to/license.lic")# From streamwithopen("license.lic","rb")asf:License().set_license(f)```Or auto-apply: `export GROUPDOCS_LIC_PATH="path/to/license.lic"`**Evaluation vs licensed.** Without a license the library still runs, but PDF output carries an evaluation watermark stamp and non-PDF targets show an equivalent evaluation mark; there is also a page/document count cap. Set `GROUPDOCS_LIC_PATH` (or call `License().set_license(...)`) and re-run to clear both. A 30-day full license is free: https://purchase.groupdocs.com/temporary-license
## API Reference
### Viewer
| Method | Returns | Description |
|---|---|---|
| `__init__(source, load_options=None, settings=None, leave_open=None)` | | `source` is a path, bytes, or stream |
| `view(options, cancellation_token=None, page_numbers=None)` | `None` | Render with `HtmlViewOptions` / `PngViewOptions` / `JpgViewOptions` / `PdfViewOptions` |
| `get_view_info(options)` | `ViewInfo` | Page count, size, layout info (use `ViewInfoOptions.for_html_view()` etc.) |
| `get_file_info()` | `FileInfo` | Format, name, encrypted flag without viewing |
| `get_attachments(cancellation_token=None)` | `list[Attachment]` | Embedded attachments (emails, PDFs) |
| `save_attachment(attachment, destination)` | `None` | Extract one attachment. `destination` can be a filesystem path (`str` / `os.PathLike`) or a writable stream (`BytesIO` / `open(..., "wb")`). Paths: the wrapper opens the file, writes through, and closes it — parent dirs are auto-created. Streams: passed straight to the bridge; caller owns the lifetime. |
| `get_all_fonts()` | `list` | Fonts embedded in the document |
| `search(options)` | `None` | Search with `SearchHighlightOptions` |
### HtmlViewOptions
Accepts the factory methods `for_embedded_resources(...)` and `for_external_resources(...)`. Each factory takes either a format string (e.g. `"page_{0}.html"`) or callables for `CreatePageStream` / `CreateResourceStream` / `CreateResourceUrl`.
| Property | Type | Writable |
|---|---|---|
| `render_responsive` | `bool` | yes |
| `minify` | `bool` | yes |
| `render_to_single_page` | `bool` | yes |
| `for_printing` | `bool` | yes |
| `exclude_fonts` | `bool` | yes |
| `fonts_to_exclude` | `list[str]` | yes |
| `remove_java_script` | `bool` | yes |
| `image_width` / `image_height` | `int` | yes |
| `image_max_width` / `image_max_height` | `int` | yes |
| `watermark` | `Watermark` | yes (inherited from `ViewOptions`) |
| `render_comments` | `bool` | yes (inherited from `BaseViewOptions`) |
| `render_hidden_pages` | `bool` | yes (inherited from `BaseViewOptions`) |
| `render_notes` | `bool` | yes (inherited from `BaseViewOptions`) |
| `default_font_name` | `str` | yes (inherited from `BaseViewOptions`) |
| `*_options` (`archive_options`, `cad_options`, `email_options`, `outlook_options`, `pdf_options`, `presentation_options`, `project_management_options`, `spreadsheet_options`, `text_options`, `visio_rendering_options`, `web_document_options`, `word_processing_options`, `mail_storage_options`) | format-specific tweaks | yes |
### PngViewOptions / JpgViewOptions
Constructor takes `file_path_format` (e.g. `"page_{0}.png"`) OR a `CreatePageStream` callable.
| Property | Type | Writable |
|---|---|---|
| `width` / `height` | `int` | yes |
| `max_width` / `max_height` | `int` | yes |
| `quality` (JPG only) | `int` 1-100 | yes |
| `extract_text` | `bool` | yes |
| `watermark`, `render_comments`, `render_hidden_pages`, `render_notes`, `default_font_name`, and all `*_options` | | yes |
### PdfViewOptions
Constructor takes `output_file_path` (single PDF output) OR a `CreateFileStream` callable.
| Property | Type | Writable |
|---|---|---|
| `security` | `Security` | yes |
| `pdf_optimization_options` | `PdfOptimizationOptions` | yes |
| `image_width` / `image_height` | `int` | yes |
| `image_max_width` / `image_max_height` | `int` | yes |
| `watermark`, `render_comments`, `render_hidden_pages`, `render_notes`, `default_font_name`, and all `*_options` | | yes |
Also has `rotate_page(page_number, rotation)` — rotates a specific page in the output PDF. `rotation` is one of `Rotation.ON_90_DEGREE`, `ON_180_DEGREE`, `ON_270_DEGREE`.
### ViewInfoOptions
Factory methods: `for_html_view()`, `for_png_view()`, `for_jpg_view()`, `for_pdf_view()`.
| Property | Type | Writable |
|---|---|---|
| `width` / `height` | `int` | yes |
| `max_width` / `max_height` | `int` | yes |
| `extract_text` | `bool` | yes |
| Same `render_comments`, `render_hidden_pages`, `render_notes`, `default_font_name`, and `*_options` as `BaseViewOptions` | | yes |
### LoadOptions
Pass to `Viewer(source, load_options)` to control how the source document is parsed.
| Property | Type | Writable |
|---|---|---|
| `file_type` | `FileType` | yes |
| `password` | `str` | yes |
| `encoding` | `str` | yes |
| `detect_encoding` | `bool` | yes |
| `try_repair` | `bool` | yes |
| `resource_loading_timeout` | `timedelta` | yes |
| `skip_external_resources` | `bool` | yes |
| `whitelisted_resources` | `list[str]` | yes |
### Watermark
Construct with `Watermark(text)` then tweak appearance.
| Property | Type | Writable |
|---|---|---|
| `text` | `str` | yes |
| `color` | color (Argb32Color / KnownColors) | yes |
| `position` | `Position` | yes |
| `size` | `int` | yes |
| `font_name` | `str` | yes |
## FileType enum
Viewer exposes 190+ file formats on a single flat `FileType` class — access via `FileType.DOCX`, `FileType.PDF`, etc. (case-insensitive). Members grouped by family:
<!-- begin:filetypes -->| Family | Members |
| :- | :- |
| Archives / Compression | `ZIP, TAR, XZ, TXZ, TARXZ, TGZ, TARGZ, BZ2, RAR, GZ, GZIP, SevenZip, CPIO, Zstandard, Tzst, TarZst, Iso, Lha, Cab` |
| CAD | `DXF, DWG, DWT, STL, IFC, DWF, FBX, DWFX, DGN, PLT, CF2, OBJ, HPG, IGS` |
| Diagrams (Visio) | `VSD, VSDX, VSS, VSSX, VSDM, VST, VSTX, VSTM, VSSM, VSX, VTX` |
| Word-processing | `DOC, DOCM, DOCX, DOT, DOTM, DOTX, RTF, ODT, OTT, TXT, FlatOpc` |
| Spreadsheets | `XLS, XLSX, XLSM, XLSB, ODS, OTS, XLT, XLTX, XLTM, CSV, TSV, DIF, SXC, FlatOpc, Numbers` |
| Presentations | `PPT, PPS, PPTX, PPSX, ODP, OTP, POTX, POT, POTM, PPTM, PPSM, FlatOpc` |
| PDF / Page Description | `PDF, PS, EPS, XPS, OXPS, TEX, PCL` |
| eBook | `EPUB, MOBI, AZW3, CHM` |
| Email | `MSG, EML, EMLX, VCF, MBOX, PST, OST, OLM, ICS` |
| Images | `JPG, JPEG, JFIF, PNG, BMP, DIB, TIFF, TIF, GIF, ICO, WebP, EMZ, WMZ, EMF, WMF, SVG, SVGZ, DCM, DICOM, CDR, CMX, DjVu, DNG, Jp2, J2C, J2K, JPX, JPF, JPM, JPC, JLS, TGA, HEIC, AVIF, PSD, PSB, AI, APNG` |
| Project Management | `MPP, MPT, MPX, XER` |
| Web / Markup | `HTML, HTM, MHT, MHTML, XML, JSON, CSS` |
| 3D | `Usd, Usdz, Obj, Ply, Gltf, Glb, ThreeDS, ThreeMF` |
| Fonts | `TTF, EOT, OTF, CFF, WOFF, WOFF2, Type1` |
| Source code / Text | `MD, LOG, AS, AS3, ASM, BAT, C, CC, CMAKE, CPP, CS, CXX, DIFF, ...` (190+ total — use `FileType.get_supported_file_types()` to enumerate at runtime) |
<!-- end:filetypes -->Use `FileType.from_extension("docx")` when you don't know which family owns a format — it returns the correct `FileType` instance. `FileType.from_stream(stream)` sniffs file headers. `FileType.get_supported_file_types()` returns the full list.
## Key Patterns
- **Properties**: use `snake_case` -- auto-mapped to .NET `PascalCase`- **Context managers**: `with Viewer(...) as x:` ensures resources are released
- **Streams**: pass `open("file", "rb")` or `io.BytesIO(data)` where .NET expects Stream
- **Stream write-back**: `BytesIO` objects are updated after .NET writes to them
- **Enums**: case-insensitive, lazy-loaded (e.g., `FileType.DOCX`)
- **Collections**: `for item in result` and `len(result)` work on .NET collections
- **Callbacks**: Python functions work for handler interfaces including the three stream factories (`CreatePageStream`, `CreateResourceStream`, `CreateFileStream`). See [Render to custom streams](#render-to-custom-streams) above — the bridge auto-wraps Python callables that return file-like objects as .NET `Stream` factories.
- **Factory methods**: `HtmlViewOptions.for_embedded_resources("path/page_{0}.html")` and `.for_external_resources(page_fmt, resource_fmt, url_fmt)` accept either string path templates OR callback factories. The dispatcher Python-side type-checks before calling into .NET, so positional strings route to the string overload without a bridge round-trip.
## Platform Requirements
| Platform | Requirements |
|---|---|
| Windows | None |
| Linux | `apt install libgdiplus libfontconfig1 ttf-mscorefonts-installer` |
| macOS | `brew install mono-libgdiplus` |
## Troubleshooting
**`IncorrectPasswordException` / `PasswordRequiredException`** -- the document is encrypted. Pass `LoadOptions(password="...")` to `Viewer(...)`.
**`Cannot convert String to CreatePageStream`** (fixed in 26.4.0+) -- older wheels had a static-factory dispatcher that leaked .NET cast errors. Upgrade with `pip install --upgrade groupdocs-viewer-net`.
**`System.Drawing.Common is not supported`** -- install libgdiplus: `sudo apt install libgdiplus` (Linux) / `brew install mono-libgdiplus` (macOS)
**`Gdip` type initializer exception** -- outdated libgdiplus: `brew reinstall mono-libgdiplus` (macOS)
**Garbled text / missing fonts** -- install fonts: `sudo apt install ttf-mscorefonts-installer fontconfig && sudo fc-cache -f`**`DllNotFoundException: libSkiaSharp`** -- stale system copy conflicts with bundled version. Rename it: `sudo mv /usr/local/lib/libSkiaSharp.dylib /usr/local/lib/libSkiaSharp.dylib.bak`**`DOTNET_SYSTEM_GLOBALIZATION_INVARIANT` errors** -- do NOT set this. Install ICU: `sudo apt install libicu-dev`**`TypeLoadException`** -- reinstall: `pip install --force-reinstall groupdocs-viewer-net`**Still stuck?** Post your question at https://forum.groupdocs.com/c/viewer/ -- the development team responds directly.