UNPKG

pdf-lib

Version:

Create and modify PDF files with JavaScript

149 lines (118 loc) 3.96 kB
import PDFDict from 'src/core/objects/PDFDict'; import PDFName from 'src/core/objects/PDFName'; import PDFStream from 'src/core/objects/PDFStream'; import PDFArray from 'src/core/objects/PDFArray'; import PDFRef from 'src/core/objects/PDFRef'; import PDFNumber from 'src/core/objects/PDFNumber'; class PDFAnnotation { readonly dict: PDFDict; static fromDict = (dict: PDFDict): PDFAnnotation => new PDFAnnotation(dict); protected constructor(dict: PDFDict) { this.dict = dict; } // This is technically required by the PDF spec Rect(): PDFArray | undefined { return this.dict.lookup(PDFName.of('Rect'), PDFArray); } AP(): PDFDict | undefined { return this.dict.lookupMaybe(PDFName.of('AP'), PDFDict); } F(): PDFNumber | undefined { const numberOrRef = this.dict.lookup(PDFName.of('F')); return this.dict.context.lookupMaybe(numberOrRef, PDFNumber); } getRectangle(): { x: number; y: number; width: number; height: number } { const Rect = this.Rect(); return Rect?.asRectangle() ?? { x: 0, y: 0, width: 0, height: 0 }; } setRectangle(rect: { x: number; y: number; width: number; height: number }) { const { x, y, width, height } = rect; const Rect = this.dict.context.obj([x, y, x + width, y + height]); this.dict.set(PDFName.of('Rect'), Rect); } getAppearanceState(): PDFName | undefined { const AS = this.dict.lookup(PDFName.of('AS')); if (AS instanceof PDFName) return AS; return undefined; } setAppearanceState(state: PDFName) { this.dict.set(PDFName.of('AS'), state); } setAppearances(appearances: PDFDict) { this.dict.set(PDFName.of('AP'), appearances); } ensureAP(): PDFDict { let AP = this.AP(); if (!AP) { AP = this.dict.context.obj({}); this.dict.set(PDFName.of('AP'), AP); } return AP; } getNormalAppearance(): PDFRef | PDFDict { const AP = this.ensureAP(); const N = AP.get(PDFName.of('N')); if (N instanceof PDFRef || N instanceof PDFDict) return N; throw new Error(`Unexpected N type: ${N?.constructor.name}`); } /** @param appearance A PDFDict or PDFStream (direct or ref) */ setNormalAppearance(appearance: PDFRef | PDFDict) { const AP = this.ensureAP(); AP.set(PDFName.of('N'), appearance); } /** @param appearance A PDFDict or PDFStream (direct or ref) */ setRolloverAppearance(appearance: PDFRef | PDFDict) { const AP = this.ensureAP(); AP.set(PDFName.of('R'), appearance); } /** @param appearance A PDFDict or PDFStream (direct or ref) */ setDownAppearance(appearance: PDFRef | PDFDict) { const AP = this.ensureAP(); AP.set(PDFName.of('D'), appearance); } removeRolloverAppearance() { const AP = this.AP(); AP?.delete(PDFName.of('R')); } removeDownAppearance() { const AP = this.AP(); AP?.delete(PDFName.of('D')); } getAppearances(): | { normal: PDFStream | PDFDict; rollover?: PDFStream | PDFDict; down?: PDFStream | PDFDict; } | undefined { const AP = this.AP(); if (!AP) return undefined; const N = AP.lookup(PDFName.of('N'), PDFDict, PDFStream); const R = AP.lookupMaybe(PDFName.of('R'), PDFDict, PDFStream); const D = AP.lookupMaybe(PDFName.of('D'), PDFDict, PDFStream); return { normal: N, rollover: R, down: D }; } getFlags(): number { return this.F()?.asNumber() ?? 0; } setFlags(flags: number) { this.dict.set(PDFName.of('F'), PDFNumber.of(flags)); } hasFlag(flag: number): boolean { const flags = this.getFlags(); return (flags & flag) !== 0; } setFlag(flag: number) { const flags = this.getFlags(); this.setFlags(flags | flag); } clearFlag(flag: number) { const flags = this.getFlags(); this.setFlags(flags & ~flag); } setFlagTo(flag: number, enable: boolean) { if (enable) this.setFlag(flag); else this.clearFlag(flag); } } export default PDFAnnotation;