Instructions for AI agents working with this package.
Render documents to HTML, PNG, JPG, or PDF -- 170+ file formats supported.
pip install groupdocs-viewer-netPython: 3.5 - 3.14 | Platforms: Windows, Linux, macOS
| 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 |
If your environment has MCP configured, you can connect your AI tool to the GroupDocs documentation server for on-demand API lookups:
{
"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.
from groupdocs.viewer import License, FileType, Viewer, ViewerSettings
from groupdocs.viewer.exceptions import (
GroupDocsViewerException, IncorrectPasswordException,
PasswordRequiredException, InvalidFontFormatException, InvalidImageFormatException,
)
from groupdocs.viewer.caching import CacheKeys, FileCache, ICache
from groupdocs.viewer.drawing import (
Argb32Color, Rgb24Color, CssLevel1, CssLevel2, CssLevel3, CssLevel4,
Image2DFormat, KnownColors,
)
from groupdocs.viewer.fonts import (
FolderFontSource, FontFormat, FontSettings, FontStyles, IFontInfo, IFontSource,
PdfFontInfo, PresentationFontInfo, SpreadsheetFontInfo, WordProcessingFontInfo,
WordProcessingSubstitutedFontInfo, SearchOption,
)
from groupdocs.viewer.interfaces import (
CreatePageStream, CreateResourceStream, CreateResourceUrl, CreateFileStream,
ReleasePageStream, ReleaseResourceStream, ReleaseFileStream,
IPageStreamFactory, IResourceStreamFactory, IFileStreamFactory,
)
from groupdocs.viewer.logging import ConsoleLogger, FileLogger, ILogger
from groupdocs.viewer.options import (
# View-options flavours — the four output formats
HtmlViewOptions, PngViewOptions, JpgViewOptions, PdfViewOptions,
ViewInfoOptions, ViewOptions, BaseViewOptions,
# Loading + format-specific rendering tweaks
LoadOptions, ArchiveOptions, CadOptions, EmailOptions, MailStorageOptions,
OutlookOptions, PdfOptimizationOptions, PdfOptions, PresentationOptions,
ProjectManagementOptions, SearchHighlightOptions, SpreadsheetOptions,
TextOptions, VisioRenderingOptions, WebDocumentOptions, WordProcessingOptions,
# Rendering primitives
Watermark, Rotation, Position, ImageQuality, PageSize, Permissions, Security,
Resolution, Size, Tile, TimeUnit, TextOverflowMode, Field, FileName,
)
from groupdocs.viewer.results import (
ViewInfo, FileInfo, Attachment, Page, Resource, TextElement, Character, Word, Line,
ArchiveViewInfo, CadViewInfo, MailMessageViewInfo, MboxViewInfo, OutlookViewInfo,
LotusNotesViewInfo, PdfViewInfo, ProjectManagementViewInfo, Layer, Layout,
)from groupdocs.viewer import Viewer
from groupdocs.viewer.options import HtmlViewOptions
with Viewer("document.docx") as viewer:
options = HtmlViewOptions.for_embedded_resources("page_{0}.html")
viewer.view(options)from groupdocs.viewer import Viewer
from groupdocs.viewer.options import PngViewOptions
with Viewer("document.pdf") as viewer:
viewer.view(PngViewOptions("page_{0}.png"))from groupdocs.viewer import Viewer
from groupdocs.viewer.options import PdfViewOptions
with Viewer("spreadsheet.xlsx") as viewer:
viewer.view(PdfViewOptions("output.pdf"))# Render only pages 1 and 3
with Viewer("document.docx") as viewer:
viewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"),
page_numbers=[1, 3])
# Reorder: render page 2 first, then page 1
with Viewer("document.docx") as viewer:
viewer.view(PdfViewOptions("out.pdf"), page_numbers=[2, 1])from groupdocs.viewer import Viewer
from groupdocs.viewer.options import HtmlViewOptions, LoadOptions
load_options = LoadOptions()
load_options.password = "12345"
with Viewer("protected.docx", load_options) as viewer:
viewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"))from groupdocs.viewer import Viewer
from groupdocs.viewer.options import ViewInfoOptions
with Viewer("document.pdf") as viewer:
info = viewer.get_view_info(ViewInfoOptions.for_html_view())
print(f"Pages: {len(info.pages)}")
for page in info.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:
from groupdocs.viewer import Viewer, ViewerSettings
from groupdocs.viewer.logging import ConsoleLogger
settings = ViewerSettings(logger=ConsoleLogger())
with Viewer("input.docx", settings=settings) as viewer: # no None placeholder
viewer.view(HtmlViewOptions.for_embedded_resources("page_{0}.html"))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.
# Write each page to an in-memory buffer
import io
from groupdocs.viewer import Viewer
from groupdocs.viewer.options import PngViewOptions
page_buffers = {}
def create_page_stream(page_number):
buf = io.BytesIO()
page_buffers[page_number] = buf
return buf
with Viewer("input.docx") as viewer:
viewer.view(PngViewOptions(create_page_stream))
# page_buffers now holds {1: <BytesIO>, 2: <BytesIO>, ...}# Write HTML pages + resources with custom naming
import os
from groupdocs.viewer import Viewer
from groupdocs.viewer.options import HtmlViewOptions
def create_page(page_number):
os.makedirs("out", exist_ok=True)
return open(f"out/page_{page_number}.html", "wb")
def create_resource(page_number, resource_name):
return open(f"out/res_{page_number}_{resource_name}", "wb")
def resource_url(page_number, resource_name):
return f"res_{page_number}_{resource_name}"
with Viewer("input.docx") as viewer:
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.
from groupdocs.viewer import Viewer
with Viewer("with_attachments.msg") as viewer:
for attachment in viewer.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 bytesNote: .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.
FontSettings.set_font_sources(...) is the .NET
params IFontSource[] method and accepts any of these call shapes:
from groupdocs.viewer.fonts import FontSettings, FolderFontSource, SearchOption
src1 = FolderFontSource("C:/fonts/primary", SearchOption.ALL_FOLDERS)
src2 = FolderFontSource("C:/fonts/backup", SearchOption.TOP_FOLDER_ONLY)
FontSettings.set_font_sources(src1, src2) # varargs
FontSettings.set_font_sources([src1, src2]) # single list
FontSettings.set_font_sources([src1], [src2]) # multiple lists (flattened)
FontSettings.set_font_sources([src1, src2], src3) # mixed — also flattened
FontSettings.reset_font_sources() # clearAll 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).
from groupdocs.viewer import License
# From file
License().set_license("path/to/license.lic")
# From stream
with open("license.lic", "rb") as f:
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
| 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 |
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 |
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 |
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.
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 |
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 |
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 |
Viewer exposes 190+ file formats on a single flat FileType class — access via FileType.DOCX, FileType.PDF, etc. (case-insensitive). Members grouped by family:
| 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 |
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) |
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.
-
Properties: use
snake_case-- auto-mapped to .NETPascalCase -
Context managers:
with Viewer(...) as x:ensures resources are released -
Streams: pass
open("file", "rb")orio.BytesIO(data)where .NET expects Stream -
Stream write-back:
BytesIOobjects are updated after .NET writes to them -
Enums: case-insensitive, lazy-loaded (e.g.,
FileType.DOCX) -
Collections: every property whose declared return type is
List[T]comes back wrapped as a_NetListProxy— a thin layer that gives you the full Python MutableSequence surface over the underlying.NET List<T>:Python op .NET call coll.append(v)Add(v)coll.extend(it)/coll += itAddRange(it)coll.insert(i, v)Insert(i, v)coll.remove(v)Remove(v)coll.clear()Clear()coll.index(v)IndexOf(v)coll[i],coll[-1],coll[a:b]get_Item(i)+ slice materializecoll[i] = vset_Item(i, v)del coll[i],del coll[a:b]RemoveAt(i)(slices walk)coll.pop()/coll.pop(i)get_Item(i)+RemoveAt(i)v in collContains(v)(falls back to linear scan)coll.count(v)linear scan coll.reverse()Reverse()len(coll)Countpropertyfor v in collGetEnumerator# view_options.cad_options.tiles is a List<Tile>. tiles = view_options.cad_options.tiles tiles.append(Tile(0, 0, 500, 500)) tiles.extend([Tile(100, 100, 200, 200)]) first = tiles[0] last = tiles[-1] popped = tiles.pop() del tiles[0] tiles += [Tile(1, 1, 10, 10), Tile(2, 2, 20, 20)] tiles.reverse() tiles.clear()
Slice assignment (
coll[a:b] = [...]) is not yet supported — use explicitdel+insertfor now. -
Callbacks: Python functions work for handler interfaces including the three stream factories (
CreatePageStream,CreateResourceStream,CreateFileStream). See Render to custom streams above — the bridge auto-wraps Python callables that return file-like objects as .NETStreamfactories. -
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 |
|---|---|
| Windows | None |
| Linux | apt install libgdiplus libfontconfig1 ttf-mscorefonts-installer |
| macOS | brew install mono-libgdiplus |
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.