PDF Assets
Embed PDF pages as inline images or append full PDF documents to a REFRACT PDF output. Two modes (EMBED and APPEND) cover different use cases from extracting a single chart to attaching a complete technical manual. PDF assets work in standalone structured content blocks and inside supplementary annex image grids.
REFRACT PDF can include external PDF files in two ways:
| Mode | What it does | Output |
|---|---|---|
| EMBED | Extracts selected pages, rasterizes to JPEG, embeds as inline images | Pixel images (not searchable text) |
| APPEND | Merges a full PDF as native pages at the end of the document | Original PDF pages (text stays searchable) |
Both modes accept relative asset paths (resolved from your SharePoint or Blob assets library) or full HTTPS URLs.
Standalone image/image_grid/pdf_appendix now render (fixed)
A standalone image, image_grid, or pdf_appendix block placed directly in a structured_content YAML's top-level sections: array (outside any supplementary_Annex) used to fall through to an unhandled-block-type fallback and print literal [Unsupported block type: ...] text instead of drawing anything. This is fixed: renderContentBlock in structuredContentRenderer.ts now has case 'image' and case 'image_grid' branches, both delegating to _renderImageGrid - the same function supplementary_Annex image grids already used, now exported from supplementaryAnnexRenderer.ts and imported by structuredContentRenderer.ts. A standalone image/image_grid draws real pixels, or the same "[Image unavailable]" fallback an annex image already uses on a failed fetch - never a generic placeholder.
pdf_appendix pages append through the pre-existing pdfLibMerge.ts mechanism (collectPdfAppendices/mergePdfPages in renderOrchestrator.ts), which this fix did not change - that mechanism never went through renderContentBlock to begin with, since appended pages are merged onto the output PDF buffer after the main pdfmake render, not drawn in-flow. What changed is the in-flow marker: renderContentBlock's pdf_appendix case now only throws when PDF asset pre-processing did not run for the whole document at all (detected by a missing _prepared marker on the block) - it no longer leaves a [Unsupported block type: pdf_appendix] line in the document body in that case. A single failing pdf_appendix block (bad path, fetch error) is still silently dropped from the document during pre-processing, with no in-flow diagnostic and only a console.warn for an invalid-PDF-file case (nothing at all for a plain fetch failure) - see Failure Handling below for the per-block diagnostics added in a follow-up hardening change.
Designer/playground preview is a separate limitation
The fix above is a server-side change: resolveStructuredContentNodes (which eventually calls renderContentBlock) is invoked directly from the real render handler in apps/dispatcher-function/src/render.ts, and by processor-function too, per resolveStructuredContent.ts's own pipeline comment - a production PDF exercises this same fixed code, not just a live preview. Separately, and unrelated to this fix: the Designer/playground live preview (apps/website/app/playground/playground-client.js, which calls buildDocDefinitionFromSchema directly in the browser) never runs resolveStructuredContentNodes at all, because that step needs server-side asset-fetch credentials the browser doesn't have - so in the Designer, an entire structured_content node, of any block types, still shows only the placeholder text described under Designer Preview.
EMBED Mode
Extracts one or more pages from a PDF file, renders them to JPEG images, and embeds them inline wherever the block appears in your sections.
YAML Block
sections:
# ── Single page embed
- type: image
src: "Documents/certificate-of-compliance.pdf"
mode: "embed"
# ── Multi-page embed with all options
- type: image
src: "Documents/inspection-report.pdf"
mode: "embed"
pageRange: "1-3"
extractDpi: 300
extractQuality: 90
width: 487
columns: 3
show_captions: trueProperties
| Property | Type | Default | Required | Description |
|---|---|---|---|---|
type | "image" or "figure" | - | Yes | Standard image block type. |
src | string | - | Yes | Path to the PDF. Relative asset path (for example, "Media/report.pdf") or HTTPS URL. |
library | string | "assets" | No | Asset library name for a relative src, for the mode: "embed" PDF-extraction path - see Failure Handling below for the fetch/classification mechanism. |
mode | "embed" | - | Yes | Must be "embed" to activate PDF extraction. Without it, the .pdf file is ignored. |
pageRange | string | "1" | No | Which pages to extract. See page range syntax below. |
extractDpi | number | 150 | No | Render resolution. 72 = screen, 150 = balanced, 300 = print quality. |
extractQuality | number | 80 | No | JPEG compression quality (1 - 100). Lower equals smaller file, more artifacts. |
width | number | 540 | No | Target column width in points. |
columns | number | 2 | No | When multiple pages are extracted, arrange them in a grid with this many columns. |
show_captions | boolean | false | No | Show "Page N" captions below each image in multi-page grid. |
Page Range Syntax
| Value | Extracts |
|---|---|
"1" | Page 1 only |
"5" | Page 5 only |
"1-5" | Pages 1, 2, 3, 4, 5 |
"1,3,7" | Pages 1, 3, and 7 |
"1-3,5,8-10" | Pages 1, 2, 3, 5, 8, 9, 10 |
"all" does not extract every page. The extraction call site does not pass the PDF's total page count through to the page-range parser, so "all" always falls back to page 1 only, the same as omitting pageRange. Use an explicit range (for example "1-20") if you need more than the first page and know the page count in advance.
How It Works
The extraction pipeline:
PDF file
→ parse and extract page
→ render to PNG pixel buffer
→ compress PNG to JPEG at extractQuality
→ embed as base64 data URI in the PDF- Single page result: replaces the original
imageblock with a JPEG data URI. - Multiple pages: replaces the block with an
image_gridcontaining one image per page.
DPI and File Size
The rendered pixel width is: (width ÷ 72) × extractDpi
extractDpi | Pixel width (at 540 pt) |
|---|---|
| 72 | 540 px |
| 150 | 1,125 px |
| 300 | 2,250 px |
Standalone Images (not from a PDF)
A plain image or image_grid block, authored directly in a structured_content YAML's sections: array with an ordinary photo/graphic src (not a PDF), also renders - the same fix as EMBED mode above. It reuses the same _renderImageGrid function an annex image grid uses, so sizing, captions, alt text, PDF/UA figure tagging, and the "[Image unavailable]" fallback all behave identically to an annex-nested image.
sections:
# ── Single standalone image
- type: image
src: "Media/Images/site-photo.jpg"
caption: "Site overview"
# ── Standalone image grid
- type: image_grid
images:
- src: "Media/Images/before.jpg"
caption: "Before"
- src: "Media/Images/after.jpg"
caption: "After"
columns: 2| Property | Type | Default | Description |
|---|---|---|---|
image.src | string | - | Required. Library-relative asset path, HTTPS URL, or data: URI. |
image.library | string | "assets" | Asset library name for a relative src - see Failure Handling below for the fetch/classification mechanism. |
image.caption | string | - | Optional caption below the image. |
image.altText | string | - | Optional alt text for accessibility. |
image.width | number | 487 | Target column width in pdfmake points, used for downsampling (DEFAULT_STANDALONE_IMAGE_WIDTH_PT in pdfPreprocessor.ts). |
image_grid.images | array | - | Required. Each entry accepts src, caption, altText, library (same shape as a single image block, library per cell so one grid can mix libraries). |
image_grid.columns | number | 2 | Images per row. |
image_grid.show_captions | boolean | true | Show captions below each image. Only an explicit false turns captions off (block.show_captions !== false in structuredContentRenderer.ts) - this default is true here, unlike the mode: "embed" multi-page grid above, whose synthesized image_grid still defaults show_captions to false. |
APPEND Mode
Merges a complete PDF document as native pages appended after the main document. Text, vectors, and fonts are preserved. Nothing is rasterized.
YAML Block
sections:
# ── Minimal append
- type: pdf_appendix
src: "Attachments/warranty-terms.pdf"
# ── Full options
- type: pdf_appendix
src: "Documentation/safety-manual.pdf"
library: assets
title: "Appendix B: Safety Procedures"
pageNumbers: trueProperties
| Property | Type | Default | Required | Description |
|---|---|---|---|---|
type | "pdf_appendix" | - | Yes | Block type identifier. |
src | string | - | Yes | PDF path: relative asset path or HTTPS URL. |
library | "assets" | "assets" | No | Asset library name - see Failure Handling below for the fetch/classification mechanism. |
title | string | - | No | When set, a title page is generated and inserted before the appended pages. |
pageNumbers | boolean | false | No | When true, page numbers continue from the main document onto appended pages. |
How It Works
The merge pipeline:
PDF file
→ download or read from assets
→ validate PDF structure
→ store buffer and metadata
→ after main PDF is generated: merge pages into outputFailure Handling
This is a follow-up fix to the standalone-rendering fix above: the library field was defined but silently ignored, and a failed fetch gave no detail beyond a server-side console.warn nobody rendering a document would see.
library now works
library now actually selects the asset library for a standalone image block's src, for each cell in an image_grid.images[] array (so one grid can mix images from different libraries), for the mode: "embed" PDF-extraction path, and for pdf_appendix.src - all default to "assets" when omitted, matching the existing documented default. Cited from origin/main:
// pdfPreprocessor.ts, _resolveStandaloneImageSrc (standalone image/image_grid cell):
const library = typeof target.library === 'string' && target.library.trim() !== '' ? target.library : undefined;
const ref: AnnexImageRef = {
url: src,
caption: typeof target.caption === 'string' ? target.caption : undefined,
library,
};// pdfAssetHelper.ts, resolvePdfForAppend (pdf_appendix):
// block.library (a required field on PdfAppendixBlock, documented since [before]) called
// with library omitted, silently defaulting to 'assets' regardless.
const library = typeof block.library === 'string' && block.library.trim() !== '' ? block.library : 'assets';Fetch failures carry real diagnostic detail
A failed fetch now records which library, which path, and the underlying cause, classified as either author (a wrong path, a wrong library name, a blocked URL - deterministic, content-fixable) or environmental (permissions, a transient backend error, a network timeout, no asset reader configured at all):
// annexImageHelper.ts
export type FetchFailureCategory = 'author' | 'environmental';
export function _classifyAssetFailure(library: string, filePath: string, err: unknown): ClassifiedFetchFailure {
...
if (LIBRARY_NOT_CONFIGURED_RE.test(rawMessage)) {
return {
category: 'author',
message: `Asset library '${library}' is not configured in this environment. Check the 'library' value on this image (path: '${filePath}').`,
};
}
if (statusCode === 404) {
return {
category: 'author',
message: `Asset not found: '${filePath}' in library '${library}' (HTTP 404). Check the path and library name.`,
};
}
if (statusCode === 401 || statusCode === 403) {
return {
category: 'environmental',
message: `Access denied fetching '${filePath}' from library '${library}' (HTTP ${statusCode}). This may be a permissions issue in the storage backend, or an incorrect path/library treated as unauthorized.`,
};
}
...
}Failure handling differs by caller
| Caller | Author-fault failure (bad path, bad library, blocked URL) | Environmental failure (permissions, network, transient) |
|---|---|---|
Standalone image / image_grid (hand-authored) | Fails the whole render - renderContentBlock's 'image'/'image_grid' case throws | Degrades to the existing "[Image unavailable]" placeholder, now showing the real cause |
pdf_appendix (hand-authored) | Fails the whole render - renderContentBlock's 'pdf_appendix' case throws | Degrades to an inline "[Attachment unavailable]" diagnostic note in place of the missing appended pages, instead of silently dropping the block |
supplementary_Annex image grid (payload-driven) | Always degrades - shows the reason inline, same as environmental | Always degrades - shows the reason inline |
The annex path never throws, regardless of category, because it is payload-driven and can run many rows in one document - failing the whole render over one bad row in a hundred would be worse than showing that one row's diagnostic. A hand-authored block is different: it is written once, by a person, in small numbers, so a content mistake (not an infrastructure problem) is treated as a real authoring error worth stopping the render for.
The annex's own images payload array (see PDF in Supplementary Annex Image Grids below) also gains per-image library: each entry can now be { "src": "...", "altText": "...", "library": "..." } instead of only a bare string, letting one row mix images from different asset libraries - extractImageRefs in supplementaryAnnexRenderer.ts reads the new field.
Cited from origin/main:
// structuredContentRenderer.ts, case 'image':
case 'image': {
if (block.src && !block.data && block._authorFaultError) {
throw new Error(`[StructuredContent] image block failed to resolve: ${block._authorFaultError}`);
}
return renderImageBlock(block, theme);
}// structuredContentRenderer.ts, case 'pdf_appendix' (environmental branch):
if (appendix.failureReason) {
return [{
stack: [
{ text: '[Attachment unavailable]', ... },
{ text: appendix.failureReason, ... },
],
} as unknown as Content];
}// supplementaryAnnexRenderer.ts doc comment on AnnexImageRef.failureCategory:
// A caller that wants an author-fault failure to fail the whole render reads this back --
// see processAnnexImage's own doc comment for the full mechanism and why the annex path
// (this file) does not do that.Which Mode Handles Fonts Better?
The two modes handle fonts very differently. Choose based on your document's fonts and your use case.
| Scenario | APPEND | EMBED |
|---|---|---|
| PDF has embedded fonts | ✅ Perfect - fonts render exactly as original | ✅ Works - fonts rasterized to pixels at original quality |
| PDF uses system fonts | ✅ Works - if system fonts available | ⚠️ Falls back to default font on mismatch |
| PDF has corrupted fonts | ❌ Might render as boxes | ⚠️ Falls back to default, completes |
| Font substitution needed | ❌ Cannot substitute (raw page copy) | ✅ Handles automatically during extraction |
| Best use case | Technical docs, manuals, legal documents | Photo galleries, extracts, thumbnails |
TL;DR
APPEND mode: The PDF's fonts come with it - REFRACT PDF's font library is never consulted. The appended pages render exactly as they were in the source PDF. If fonts are corrupted or missing, the page might have rendering issues.
EMBED mode: Pages are rasterized to JPEG, so fonts become pixels. If a font is missing during extraction, the renderer falls back to a system default - the extraction still succeeds, but might look different from the original.
Choose your mode:
- Legal document with specific fonts? Use APPEND (preserves exact formatting)
- Photo gallery with PDFs as thumbnails? Use EMBED (looks like pixels anyway, font fallback is fine)
PDF in Supplementary Annex Image Grids
PDF files can also appear as image references inside a supplementary_annex block's data. When the annex image grid encounters a .pdf URL, it automatically extracts the first page and renders it as a JPEG thumbnail using the same pipeline as EMBED mode.
This allows your payload data to mix regular images and PDF files in the same images array:
{
"Lines": [
{
"No.": "A101",
"Description": "Foundation Inspection",
"notes": ["Concrete poured on 2025-11-15"],
"images": [
"Media/Images/foundation-photo.jpg",
"Documents/Reports/soil-test-report.pdf",
"https://storage.example.com/photos/rebar-layout.png"
]
}
]
}The .pdf file in the images array is detected by file extension. The first page is extracted, rendered to JPEG at the grid's target_dpi and image_quality, and displayed as a thumbnail alongside regular images.
Image Grid YAML with PDF Support
- type: image_grid
source: "{{item.images}}"
columns: 2
target_dpi: 150 # controls PDF render resolution too
image_quality: 80 # controls PDF JPEG quality too
show_captions: true
caption: "Documentation - Item {{item.id}}"No additional configuration is needed. PDF detection is automatic based on the .pdf file extension.
Complete Copy-Paste Examples
Example 1: Supplementary Annex with Image Grid (includes PDF support)
Template Node (.rpkg)
Add this node to your template's layoutSchema children:
{
"id": "supplementary-annex",
"type": "structured_content",
"props": {
"assetPath": "Documents/SupplementaryAnnex/supplementary-annex-layout.yaml",
"library": "assets"
},
"pagination": { "breakBefore": "always" }
}Layout YAML
Upload to: Assets/Documents/SupplementaryAnnex/supplementary-annex-layout.yaml
# ── Supplementary Annex Layout
#
# Per-line-item supporting documentation section.
# Renders a themed header, notes, and photo grid for every qualifying item.
#
# Supports JPEG, PNG, GIF, WebP, SVG images AND .pdf files in the images array.
# PDF files are auto-detected and the first page is extracted as a JPEG thumbnail.
documentType: supplementary-annex
version: "1.0.0"
title: Supporting Documentation
sections:
- type: supplementary_Annex
# ── Data source
# Top-level key in the payload containing the array of line items.
data_source: "{{Lines}}"
# ── Field bindings
notes_field: notes
images_field: images
id_field: "No."
name_field: Description
# ── Layout options
showDivider: false
includeInToc: true
sectionNumbering: true
# ── Per-item layout
item_template:
# Themed header bar
- type: sub_header
text: "Item {{item.id}} - {{item.name}}"
subtitle: "Document {{Header.No.}} | Date {{Header.Order Date|date}}"
style: variant_blue_bar
# One paragraph per note
- type: repeat_notes
source: "{{item.notes}}"
style: paragraph_block
# Photo grid (2 columns, 150 DPI)
# PDF files in the images array are auto-detected and rendered as thumbnails.
- type: image_grid
source: "{{item.images}}"
columns: 2
target_dpi: 150
image_quality: 80
show_captions: true
caption: "Documentation photo - Item {{item.id}}"Payload
{
"features": {
"supplementaryAnnex": true
},
"Header": {
"No.": "SO-2025-001",
"Order Date": "2025-11-15T00:00:00"
},
"Lines": [
{
"No.": "A101",
"Description": "Foundation Repair - Push Piers",
"notes": [
"Installed 8 push piers to 22 ft depth.",
"Load test passed at 35,000 lbs per pier."
],
"images": [
"Media/Images/push-pier-install.jpg",
"Documents/Reports/soil-test-report.pdf",
"Media/Images/load-test-gauge.png"
]
},
{
"No.": "B205",
"Description": "Crawlspace Encapsulation",
"notes": [
"20-mil vapor barrier installed across full crawlspace."
],
"images": [
"Media/Images/crawlspace-before.jpg",
"Media/Images/crawlspace-after.jpg"
]
}
]
}Example 2: Standalone PDF Embed
Template Node (.rpkg)
{
"id": "certificate-section",
"type": "structured_content",
"props": {
"assetPath": "Documents/certificate-layout.yaml",
"library": "assets"
}
}Layout YAML
Upload to: Assets/Documents/certificate-layout.yaml
documentType: certificate-embed
version: "1.0.0"
title: Certificates
sections:
- type: heading
level: 2
text: "Certificate of Compliance"
- type: paragraph
text: "The following certificate was issued upon completion of the project."
# Embed first page of the PDF as an inline image
- type: image
src: "Documents/Certificates/compliance-cert.pdf"
mode: "embed"
pageRange: "1"
extractDpi: 200
extractQuality: 85Example 3: Multi-Page PDF Embed (Grid)
documentType: inspection-gallery
version: "1.0.0"
title: Inspection Report Pages
sections:
- type: heading
level: 2
text: "Inspection Report"
# Extract pages 1 - 4 and display as a 2×2 grid
- type: image
src: "Documents/Reports/full-inspection-report.pdf"
mode: "embed"
pageRange: "1-4"
extractDpi: 150
extractQuality: 80
columns: 2
show_captions: trueExample 4: PDF Appendix
Template Node (.rpkg)
{
"id": "appendix-safety",
"type": "structured_content",
"props": {
"assetPath": "Documents/appendix-layout.yaml",
"library": "assets"
},
"pagination": { "breakBefore": "always" }
}Layout YAML
Upload to: Assets/Documents/appendix-layout.yaml
documentType: appendix-collection
version: "1.0.0"
title: Appendices
sections:
# Append the safety manual as native PDF pages
- type: pdf_appendix
src: "Documentation/safety-manual.pdf"
library: assets
title: "Appendix A: Safety Procedures"
pageNumbers: true
# Append warranty terms (no title page, no page numbers)
- type: pdf_appendix
src: "Attachments/warranty-terms.pdf"Example 5: Mixed Document (Embed + Annex + Append)
A single YAML file can combine all block types:
documentType: complete-project-report
version: "1.0.0"
title: Project Completion Report
sections:
# ── Standard content
- type: heading
level: 1
text: "Project Summary"
- type: paragraph
text: "This report documents the completion of project {{Header.No.}}."
# ── Inline PDF embed
- type: heading
level: 2
text: "Engineer's Certificate"
- type: image
src: "Documents/engineer-certificate.pdf"
mode: "embed"
pageRange: "1"
extractDpi: 200
extractQuality: 85
# ── Supplementary annex
- type: supplementary_Annex
data_source: "{{Lines}}"
notes_field: notes
images_field: images
id_field: "No."
name_field: Description
showDivider: false
includeInToc: true
sectionNumbering: true
item_template:
- type: sub_header
text: "Item {{item.id}} - {{item.name}}"
style: variant_blue_bar
- type: repeat_notes
source: "{{item.notes}}"
style: paragraph_block
- type: image_grid
source: "{{item.images}}"
columns: 2
target_dpi: 150
image_quality: 80
show_captions: true
# ── Full PDF appendix
- type: pdf_appendix
src: "Documentation/safety-manual.pdf"
title: "Appendix: Safety Manual"
pageNumbers: truesupplementary_Annex Block Reference
Complete property reference for the supplementary_Annex block type.
Data Binding
| Property | Type | Required | Description |
|---|---|---|---|
data_source | string | Yes | Variable reference to the data array, for example, "{{Lines}}". Must resolve to an array. |
notes_field | string or string[] | No | Field name(s) containing notes. When omitted, auto-detected by heuristic. |
images_field | string or string[] | No | Field name(s) containing image URLs. When omitted, auto-detected by heuristic. |
id_field | string | No | Field name for the item identifier (for example, "No."). Used in headers and table of contents. |
name_field | string | No | Field name for the item description (for example, "Description"). Used in headers. |
children_fields | string[] | No | Field names containing nested child arrays for hierarchical data flattening. |
Layout Options
| Property | Type | Default | Description |
|---|---|---|---|
showDivider | boolean | false | Render a thin horizontal rule between consecutive items. |
includeInToc | boolean | false | Add annex items to the document's table of contents. |
sectionNumbering | boolean | false | Show sequential section numbers for items in the table of contents. |
item_template
An ordered array of layout blocks rendered for each qualifying item.
sub_header
| Property | Type | Default | Description |
|---|---|---|---|
type | "sub_header" | - | Block type. |
text | string | - | Header text. Supports {{item.id}}, {{item.name}}, and payload variables. |
subtitle | string | - | Optional second line. Supports variables and format pipes (` |
style | string | - | Visual style. variant_blue_bar is currently the only implemented value. |
repeat_notes
| Property | Type | Default | Description |
|---|---|---|---|
type | "repeat_notes" | - | Block type. |
source | string | - | Variable reference to notes array, for example, "{{item.notes}}". |
style | string | - | Paragraph style. Options: paragraph_block, compact, etc. |
image_grid
| Property | Type | Default | Description |
|---|---|---|---|
type | "image_grid" | - | Block type. |
source | string | - | Variable reference to images array, for example, "{{item.images}}". |
columns | number | 2 | Images per row. |
target_dpi | number | 150 | Downsample DPI. Higher equals sharper, larger files. Also controls PDF page render resolution. |
image_quality | number | 80 | JPEG quality (1 - 100). Also controls PDF page JPEG quality. |
show_captions | boolean | true | Show captions below each image. |
caption | string | - | Caption template. Supports {{item.id}}, {{item.name}}, etc. |
Image Path Formats
All image and PDF asset paths can use any of these formats:
| Format | Example | When to use |
|---|---|---|
| Relative asset path | "Media/Images/photo.jpg" | Files uploaded to the assets library. Simplest and most portable. |
| HTTPS URL | "https://storage.example.com/photo.jpg" | Pre-authenticated download URLs (SAS tokens, Graph API @microsoft.graph.downloadUrl). |
| Data URI | "data:image/jpeg;base64,/9j/4AA..." | Pre-encoded images from the payload (rare, not supported for PDFs). |
For SharePoint assets, use the path relative to the assets library root. Use the same format you use to reference YAML files in assetPath.
Feature Flag
The supplementary_Annex block is gated behind a feature flag. When disabled, the entire annex section is silently omitted.
Enable via payload (recommended)
{
"features": {
"supplementaryAnnex": true
}
}Enable via template settings (default for all renders)
{
"templateSettings": {
"supplementaryAnnex": {
"enabled": true
}
}
}Priority: Payload features.supplementaryAnnex overrides templateSettings.supplementaryAnnex.enabled.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| PDF embed shows placeholder | Required dependencies not installed | These are auto-installed as dependencies. Check node_modules is complete. |
| PDF embed is blank or returns null | mode: "embed" missing from the block | Add mode: "embed" to the block. Without it, the .pdf src is ignored. |
| PDF in annex grid shows placeholder | File extension is not .pdf | Ensure the URL ends with .pdf (query strings like ?sv=... are fine). |
| Appendix pages not appearing | pdf_appendix fetch/validation failed for that block | Check the delivered PDF for an inline "[Attachment unavailable]" note - it names the cause. A bad path or library name fails the render outright instead; see Failure Handling. |
| Large output file size | High DPI or quality on many pages | Reduce extractDpi to 150 and extractQuality to 75 - 80. |
| Annex section missing entirely | Feature flag not set | Add "features": { "supplementaryAnnex": true } to the payload. |
Image Support Guide
Comprehensive guide to image rendering options in REFRACT PDF, including standalone images, image grids, and inline images in tables and cards. Supports both SharePoint asset paths and Base64 data URIs.
Icon Reference
Complete reference of valid icon names available for use in REFRACT PDF documents. Includes status, information, content, and system icons.