Files
bentopdf/src/js/utils/ghostscript-dynamic-loader.ts
alam00000 9d0b68e18c Refactor and enhance type safety across various modules
- Updated function parameters and return types in `page-preview.ts`, `pdf-decrypt.ts`, and `pymupdf-loader.ts` for improved type safety.
- Introduced type definitions for `CpdfInstance`, `PyMuPDFInstance`, and other related types to ensure better type checking.
- Enhanced error handling in `sanitize.ts` by creating a utility function for error messages.
- Removed unnecessary type assertions and improved type inference in `editor.ts`, `serialization.ts`, and `tools.test.ts`.
- Added type definitions for markdown-it plugins to improve compatibility and type safety.
- Enforced stricter TypeScript settings by enabling `noImplicitAny` in `tsconfig.json`.
- Cleaned up test files by refining type assertions and ensuring consistency in type usage.
2026-03-31 17:59:49 +05:30

100 lines
2.8 KiB
TypeScript

import { WasmProvider } from './wasm-provider.js';
import type {
GlobalScopeWithGhostscript,
GhostscriptDynamicInstance,
} from '@/types';
let cachedGS: GhostscriptInterface | null = null;
let loadPromise: Promise<GhostscriptInterface> | null = null;
export interface GhostscriptInterface {
convertToPDFA(pdfBuffer: ArrayBuffer, profile: string): Promise<ArrayBuffer>;
fontToOutline(pdfBuffer: ArrayBuffer): Promise<ArrayBuffer>;
}
export async function loadGhostscript(): Promise<GhostscriptInterface> {
if (cachedGS) {
return cachedGS;
}
if (loadPromise) {
return loadPromise;
}
loadPromise = (async () => {
const baseUrl = WasmProvider.getUrl('ghostscript');
if (!baseUrl) {
throw new Error(
'Ghostscript is not configured. Please configure it in Advanced Settings.'
);
}
const normalizedUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
try {
const wrapperUrl = `${normalizedUrl}gs.js`;
await loadScript(wrapperUrl);
const globalScope = (
typeof globalThis !== 'undefined' ? globalThis : window
) as typeof globalThis & GlobalScopeWithGhostscript;
if (typeof globalScope.loadGS === 'function') {
const instance = await globalScope.loadGS({
baseUrl: normalizedUrl,
});
cachedGS = instance as unknown as GhostscriptInterface;
} else if (typeof globalScope.GhostscriptWASM === 'function') {
const instance: GhostscriptDynamicInstance =
new globalScope.GhostscriptWASM(normalizedUrl);
await instance.init?.();
cachedGS = instance as unknown as GhostscriptInterface;
} else {
throw new Error(
'Ghostscript wrapper did not expose expected interface. Expected loadGS() or GhostscriptWASM class.'
);
}
return cachedGS;
} catch (error: unknown) {
loadPromise = null;
const msg = error instanceof Error ? error.message : String(error);
throw new Error(
`Failed to load Ghostscript from ${normalizedUrl}: ${msg}`,
{ cause: error }
);
}
})();
return loadPromise;
}
function loadScript(url: string): Promise<void> {
return new Promise((resolve, reject) => {
if (document.querySelector(`script[src="${url}"]`)) {
resolve();
return;
}
const script = document.createElement('script');
script.src = url;
script.type = 'text/javascript';
script.async = true;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
document.head.appendChild(script);
});
}
export function isGhostscriptAvailable(): boolean {
return WasmProvider.isConfigured('ghostscript');
}
export function clearGhostscriptCache(): void {
cachedGS = null;
loadPromise = null;
}