
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@imgly/pdf-importer
Advanced tools
The PDF Importer for the CE.SDK allows you to seamlessly integrate PDF files into the editor while retaining essential design attributes.
Here's an overview of the main features:
pdfjs-dist (Mozilla's pdf.js), in its legacy/CJS-safe build.RGBAColor, CMYKColor, and SpotColor variants. CMYK values are preserved end-to-end instead of collapsed to sRGB; Separation inks are registered on the document's spot-color registry (via engine.editor.setSpotColorCMYK) with their declared alternate CMYK values. DeviceN inks degrade to their alternate-space solid for now.The following PDF design elements will be preserved by the import:
/ColorSpace resource dictionary) are preserved as SpotColor fills and registered on the CE.SDK document-level spot registry.The importer runs a three-stage pipeline on each PDF page:
pdfjs-dist operator walker emits drawable blocks (images, vector paths, text outlines) in paint order. page.getTextContent() produces one editable text run per line.PDF points are converted to inches (1pt = 1/72 inch) for CE.SDK design units. Embedded images become buffer:// URIs; engine-provided fonts use bundle:// URIs.
You can install @imgly/pdf-importer via npm or yarn. Use the following commands to install the package:
npm install @imgly/pdf-importer
yarn add @imgly/pdf-importer
import CreativeEngine from "@cesdk/engine";
import { PDFParser, addGfontsAssetLibrary } from "@imgly/pdf-importer";
const blob = await fetch("https://example.com/document.pdf").then((res) =>
res.blob()
);
const engine = await CreativeEngine.init({
license: "YOUR_LICENSE",
});
// We use google fonts to replace well known fonts in the default font resolver.
await addGfontsAssetLibrary(engine);
const parser = await PDFParser.fromFile(engine, blob);
await parser.parse();
const image = await engine.block.export(
engine.block.findByType("//ly.img.ubq/page")[0],
"image/png"
);
const sceneExportUrl = window.URL.createObjectURL(image);
console.log("The imported PDF file looks like:", sceneExportUrl);
// You can now e.g export the scene as archive with engine.scene.saveToArchive()
By default, the PDF importer creates internal buffer:// URLs for embedded images. These are transient resources that work well when saving to an archive (engine.scene.saveToArchive()), which bundles all assets together.
However, if you want to save scenes as JSON strings (engine.scene.saveToString()) with stable, permanent URLs (e.g., for storing in a database or referencing CDN-hosted assets), you need to relocate the transient resources first.
saveToArchive): Include all assets in a single ZIP file. Transient buffer:// URLs work fine.saveToString): Only contain references to assets. Transient URLs won't work when reloading the scene later. You need permanent URLs (e.g., https://).After parsing the PDF file, use CE.SDK's native APIs to find and relocate all transient resources:
// 1. Parse the PDF file
const parser = await PDFParser.fromFile(engine, blob);
await parser.parse();
// 2. Find all transient resources (embedded images from the PDF)
const transientResources = engine.editor.findAllTransientResources();
// 3. Upload each resource and relocate to permanent URL
for (const resource of transientResources) {
const { URL: bufferUri, size } = resource;
// Extract binary data from the buffer
const data = engine.editor.getBufferData(bufferUri, 0, size);
// Upload to your backend/CDN (implement your own upload logic)
const permanentUrl = await uploadToBackend(data);
// Relocate the resource to the permanent URL
engine.editor.relocateResource(bufferUri, permanentUrl);
}
// 4. Now save to string - all URLs will be permanent
const sceneString = await engine.scene.saveToString();
When using addGfontsAssetLibrary() (the default font resolver), the resulting scene string will contain Google CDN URLs for fonts. If you need fonts hosted on your own infrastructure, configure a custom font resolver instead of using the default Google Fonts integration.
The importer ships with three font-handling presets that trade editability against visual fidelity. Pick one via PDFParser.fromFile(engine, blob, { fontStrategy }), or compose your own with createFontStrategy / createFontCascade.
| Preset | Behavior | When to use |
|---|---|---|
editableFirstStrategy (default) | perfect-match → PDF-embedded subset bytes → any-match substitution | General-purpose import. Prefers asset-library typefaces for editability, falls back to the PDF's embedded subset for fidelity, substitutes when neither is available. |
exactFidelityStrategy | perfect-match → PDF-embedded subset bytes | Print finalization. Never substitutes; falls through to vector outline when no matching typeface or embedded font is available. |
assetLibraryStrategy | perfect-match → any-match substitution | Brand-locked tools. Skips the embedded-subset stage so only asset-library typefaces are used; non-matching fonts go through substitution or vector outline. |
import { PDFParser, exactFidelityStrategy } from "@imgly/pdf-importer";
const parser = await PDFParser.fromFile(engine, blob, {
fontStrategy: exactFidelityStrategy,
});
await parser.parse();
Prerequisite — emoji handling. Two CE.SDK settings need attention when running the importer headlessly under
@cesdk/node:
ubq://forceSystemEmojis = false— by default the engine routes any codepoint that ICU classifies asRGI_Emoji(e.g.♥,★, the dingbats block) through the emoji font even when the active typeface has a glyph for it. Customer PDFs frequently embed real text fonts (ZapfDingbats, Webdings, …) that map these codepoints to actual glyphs; forcing the substitution discards the producer's intended glyph and pulls in a generic color emoji. Setting the flag tofalsemakes the engine respect the embedded/substituted font when it covers the codepoint.ubq://defaultEmojiFontFileUri = <CDN URL>—@cesdk/nodeships onlyassets/core/, notassets/emoji/NotoColorEmoji.ttf. Even withforceSystemEmojis=false, true color emoji (🧐, 🎉, …) that no embedded text font covers still need a working emoji font URI, orengine.block.export(page, "image/png")aborts withFILE_FETCH_FAILEDfor the engine's synthesised local-file URL. Point the engine at the IMG.LY-hosted preset, or self-host the file and supply your own URI /bundle://path.engine.editor.setSettingBool("ubq://forceSystemEmojis", false); engine.editor.setSettingString( "ubq://defaultEmojiFontFileUri", "https://cdn.img.ly/assets/v4/emoji/NotoColorEmoji.ttf", );See the CE.SDK Emojis guide for the full set of options. Browser consumers initialised with the default IMG.LY-CDN
baseURLalready get the emoji font for free, and most integrations also wantforceSystemEmojis=falsefor the same embedded-font-respect reason.
// index.mjs
import CreativeEngine from "@cesdk/node";
import { promises as fs } from "fs";
import { PDFParser, addGfontsAssetLibrary } from "@imgly/pdf-importer";
async function main() {
const engine = await CreativeEngine.init({
license: "YOUR_LICENSE",
});
// Respect embedded fonts for emoji-class codepoints (♥, ★, …) and
// give true color emoji a working font URI — see the prerequisite
// note above.
engine.editor.setSettingBool("ubq://forceSystemEmojis", false);
engine.editor.setSettingString(
"ubq://defaultEmojiFontFileUri",
"https://cdn.img.ly/assets/v4/emoji/NotoColorEmoji.ttf",
);
await addGfontsAssetLibrary(engine);
const pdfBuffer = await fs.readFile("./document.pdf");
const parser = await PDFParser.fromFile(engine, pdfBuffer.buffer);
await parser.parse();
const image = await engine.block.export(
engine.block.findByType("//ly.img.ubq/page")[0],
"image/png"
);
const imageBuffer = await image.arrayBuffer();
await fs.writeFile("./example.png", Buffer.from(imageBuffer));
engine.dispose();
}
main();
If you encounter any issues or have questions, please don't hesitate to contact us at support@img.ly.
The PDF importer has some limitations and unsupported features that you should be aware of:
Linked Images
Font Support
fontStrategy (see Font Strategies above): embedded subset bytes when present, then resolver substitution, then a vector-outline rendering. The default strategy substitutes; configure exactFidelityStrategy to disable substitution.Complex Vector Paths
Annotations and Forms
Transparency Groups
Image SMask Compositing
See CHANGELOG.md for release notes.
The software is free for use under the AGPL License.
FAQs
Import PDF files into the Creative Editor Ecosystem
The npm package @imgly/pdf-importer receives a total of 4,535 weekly downloads. As such, @imgly/pdf-importer popularity was classified as popular.
We found that @imgly/pdf-importer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 12 open source maintainers collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.