@f-o-t/pdf 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/objects.d.ts +42 -0
- package/dist/core/objects.d.ts.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index-4jtcmpfh.js +48 -0
- package/dist/index-4jtcmpfh.js.map +10 -0
- package/dist/index-jsfksnj3.js +503 -0
- package/dist/index-jsfksnj3.js.map +14 -0
- package/dist/index-kjz7by1m.js +572 -0
- package/dist/index-kjz7by1m.js.map +13 -0
- package/dist/index.d.ts +7 -808
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -5
- package/dist/index.js.map +9 -0
- package/dist/plugins/generation/document.d.ts +38 -0
- package/dist/plugins/generation/document.d.ts.map +1 -0
- package/dist/plugins/generation/fonts.d.ts +59 -0
- package/dist/plugins/generation/fonts.d.ts.map +1 -0
- package/dist/plugins/generation/index.d.ts +5 -0
- package/dist/plugins/generation/index.d.ts.map +1 -0
- package/dist/plugins/generation/index.js +26 -0
- package/dist/plugins/generation/index.js.map +9 -0
- package/dist/plugins/generation/page.d.ts +56 -0
- package/dist/plugins/generation/page.d.ts.map +1 -0
- package/dist/plugins/generation/writer.d.ts +14 -0
- package/dist/plugins/generation/writer.d.ts.map +1 -0
- package/dist/plugins/parsing/index.d.ts +4 -0
- package/dist/plugins/parsing/index.d.ts.map +1 -0
- package/dist/plugins/parsing/index.js +16 -0
- package/dist/plugins/parsing/index.js.map +9 -0
- package/dist/plugins/parsing/lexer.d.ts +76 -0
- package/dist/plugins/parsing/lexer.d.ts.map +1 -0
- package/dist/plugins/parsing/parser.d.ts +63 -0
- package/dist/plugins/parsing/parser.d.ts.map +1 -0
- package/dist/plugins/parsing/reader.d.ts +66 -0
- package/dist/plugins/parsing/reader.d.ts.map +1 -0
- package/dist/schemas.d.ts +233 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +27 -70
- package/dist/generation/index.d.ts +0 -268
- package/dist/generation/index.js +0 -26
- package/dist/parsing/index.d.ts +0 -234
- package/dist/parsing/index.js +0 -16
- package/dist/shared/chunk-10ftnz45.js +0 -572
- package/dist/shared/chunk-37mjkw9w.js +0 -492
- package/dist/shared/chunk-6dengthp.js +0 -48
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/schemas.ts", "../src/plugins/generation/fonts.ts", "../src/plugins/generation/page.ts", "../src/plugins/generation/writer.ts", "../src/plugins/generation/document.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { z } from \"zod\";\n\n/**\n * PDF Reference schema\n */\nexport const PDFRefSchema = z.object({\n objectNumber: z.number().int().positive(),\n generation: z.number().int().nonnegative(),\n});\n\n/**\n * PDF Name schema\n */\nexport const PDFNameSchema = z.object({\n type: z.literal(\"name\"),\n value: z.string(),\n});\n\n/**\n * Page size schema\n */\nexport const PageSizeSchema = z.union([\n z.enum([\"A4\", \"Letter\", \"Legal\", \"A3\", \"A5\", \"Tabloid\"]),\n z.object({\n width: z.number().positive(),\n height: z.number().positive(),\n }),\n]);\n\n/**\n * RGB color schema\n */\nexport const RGBColorSchema = z.object({\n type: z.literal(\"rgb\"),\n r: z.number().min(0).max(1),\n g: z.number().min(0).max(1),\n b: z.number().min(0).max(1),\n});\n\n/**\n * CMYK color schema\n */\nexport const CMYKColorSchema = z.object({\n type: z.literal(\"cmyk\"),\n c: z.number().min(0).max(1),\n m: z.number().min(0).max(1),\n y: z.number().min(0).max(1),\n k: z.number().min(0).max(1),\n});\n\n/**\n * Gray color schema\n */\nexport const GrayColorSchema = z.object({\n type: z.literal(\"gray\"),\n gray: z.number().min(0).max(1),\n});\n\n/**\n * PDF Color schema\n */\nexport const PDFColorSchema = z.union([\n RGBColorSchema,\n CMYKColorSchema,\n GrayColorSchema,\n]);\n\n/**\n * Text options schema\n */\nexport const TextOptionsSchema = z.object({\n x: z.number(),\n y: z.number(),\n size: z.number().positive().optional(),\n font: z.string().optional(),\n color: PDFColorSchema.optional(),\n align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n});\n\n/**\n * Rectangle options schema\n */\nexport const RectOptionsSchema = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n fill: PDFColorSchema.optional(),\n stroke: PDFColorSchema.optional(),\n lineWidth: z.number().positive().optional(),\n});\n\n/**\n * Line options schema\n */\nexport const LineOptionsSchema = z.object({\n x1: z.number(),\n y1: z.number(),\n x2: z.number(),\n y2: z.number(),\n color: PDFColorSchema.optional(),\n lineWidth: z.number().positive().optional(),\n});\n\n/**\n * PDF metadata schema\n */\nexport const PDFMetadataSchema = z.object({\n title: z.string().optional(),\n author: z.string().optional(),\n subject: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n creator: z.string().optional(),\n producer: z.string().optional(),\n creationDate: z.date().optional(),\n modificationDate: z.date().optional(),\n});\n\n/**\n * PDF Dictionary schema (recursive)\n */\nexport const PDFDictionarySchema: z.ZodType<Record<string, any>> = z.lazy(() =>\n z.record(z.string(), PDFValueSchema),\n);\n\n/**\n * PDF Array schema (recursive)\n */\nexport const PDFArraySchema: z.ZodType<any[]> = z.lazy(() =>\n z.array(PDFValueSchema),\n);\n\n/**\n * PDF Stream schema\n */\nexport const PDFStreamSchema = z.object({\n dictionary: PDFDictionarySchema,\n data: z.instanceof(Uint8Array),\n});\n\n/**\n * PDF Value schema (recursive union)\n */\nexport const PDFValueSchema: z.ZodType<any> = z.lazy(() =>\n z.union([\n z.boolean(),\n z.number(),\n z.string(),\n PDFNameSchema,\n PDFArraySchema,\n PDFDictionarySchema,\n PDFStreamSchema,\n z.null(),\n PDFRefSchema,\n ]),\n);\n\n/**\n * PDF Indirect Object schema\n */\nexport const PDFIndirectObjectSchema = z.object({\n ref: PDFRefSchema,\n value: PDFValueSchema,\n});\n\n/**\n * PDF Object Type schema\n */\nexport const PDFObjectTypeSchema = z.enum([\n \"boolean\",\n \"number\",\n \"string\",\n \"name\",\n \"array\",\n \"dictionary\",\n \"stream\",\n \"null\",\n \"indirect\",\n]);\n\n/**\n * PDF version schema\n */\nexport const PDFVersionSchema = z.enum([\"1.4\", \"1.5\", \"1.6\", \"1.7\"]);\n",
|
|
6
|
+
"/**\n * PDF Standard 14 Fonts\n * These fonts are guaranteed to be available in all PDF readers\n */\nexport const STANDARD_FONTS = {\n // Serif fonts\n \"Times-Roman\": \"Times-Roman\",\n \"Times-Bold\": \"Times-Bold\",\n \"Times-Italic\": \"Times-Italic\",\n \"Times-BoldItalic\": \"Times-BoldItalic\",\n\n // Sans-serif fonts\n Helvetica: \"Helvetica\",\n \"Helvetica-Bold\": \"Helvetica-Bold\",\n \"Helvetica-Oblique\": \"Helvetica-Oblique\",\n \"Helvetica-BoldOblique\": \"Helvetica-BoldOblique\",\n\n // Monospace fonts\n Courier: \"Courier\",\n \"Courier-Bold\": \"Courier-Bold\",\n \"Courier-Oblique\": \"Courier-Oblique\",\n \"Courier-BoldOblique\": \"Courier-BoldOblique\",\n\n // Symbol fonts\n Symbol: \"Symbol\",\n ZapfDingbats: \"ZapfDingbats\",\n} as const;\n\nexport type StandardFont = keyof typeof STANDARD_FONTS;\n\n/**\n * Font families for convenience\n */\nexport const FONT_FAMILIES = {\n times: {\n regular: \"Times-Roman\" as StandardFont,\n bold: \"Times-Bold\" as StandardFont,\n italic: \"Times-Italic\" as StandardFont,\n boldItalic: \"Times-BoldItalic\" as StandardFont,\n },\n helvetica: {\n regular: \"Helvetica\" as StandardFont,\n bold: \"Helvetica-Bold\" as StandardFont,\n oblique: \"Helvetica-Oblique\" as StandardFont,\n boldOblique: \"Helvetica-BoldOblique\" as StandardFont,\n },\n courier: {\n regular: \"Courier\" as StandardFont,\n bold: \"Courier-Bold\" as StandardFont,\n oblique: \"Courier-Oblique\" as StandardFont,\n boldOblique: \"Courier-BoldOblique\" as StandardFont,\n },\n symbol: {\n regular: \"Symbol\" as StandardFont,\n },\n zapfDingbats: {\n regular: \"ZapfDingbats\" as StandardFont,\n },\n};\n\n/**\n * Check if a font is a standard PDF font\n */\nexport function isStandardFont(font: string): font is StandardFont {\n return font in STANDARD_FONTS;\n}\n\n/**\n * Get font object reference name\n */\nexport function getFontRefName(font: StandardFont): string {\n return `F${Object.keys(STANDARD_FONTS).indexOf(font) + 1}`;\n}\n",
|
|
7
|
+
"import type { PDFRef, PDFDictionary, PageSize, TextOptions, RectOptions, LineOptions, PDFColor, PDFStream } from \"../../types.ts\";\nimport {\n createDictionary,\n createName,\n createArray,\n createRef,\n createStream,\n} from \"../../core/objects.ts\";\nimport { PageSizeSchema, TextOptionsSchema, RectOptionsSchema, LineOptionsSchema } from \"../../schemas.ts\";\nimport { STANDARD_FONTS, isStandardFont, getFontRefName, type StandardFont } from \"./fonts.ts\";\n\nexport type PDFPageOptions = {\n size?: PageSize;\n parent?: PDFRef;\n};\n\n// Standard page sizes in points (1/72 inch)\nconst PAGE_SIZES = {\n A4: { width: 595, height: 842 },\n Letter: { width: 612, height: 792 },\n Legal: { width: 612, height: 1008 },\n A3: { width: 842, height: 1191 },\n A5: { width: 420, height: 595 },\n Tabloid: { width: 792, height: 1224 },\n};\n\n/**\n * PDF Page class\n */\nexport class PDFPage {\n ref: PDFRef;\n size: PageSize;\n parent?: PDFRef;\n contentStream: string[] = [];\n private resources: PDFDictionary;\n\n constructor(ref: PDFRef, options: PDFPageOptions = {}) {\n this.ref = ref;\n this.size = PageSizeSchema.parse(options.size ?? \"A4\");\n this.parent = options.parent;\n this.resources = createDictionary({\n Font: createDictionary(),\n });\n }\n\n /**\n * Get page dimensions in points\n */\n getDimensions(): { width: number; height: number } {\n if (typeof this.size === \"string\") {\n return PAGE_SIZES[this.size];\n }\n return this.size;\n }\n\n /**\n * Set fill color\n */\n private setFillColor(color: PDFColor): void {\n if (color.type === \"rgb\") {\n this.contentStream.push(`${color.r} ${color.g} ${color.b} rg`);\n } else if (color.type === \"cmyk\") {\n this.contentStream.push(\n `${color.c} ${color.m} ${color.y} ${color.k} k`,\n );\n } else if (color.type === \"gray\") {\n this.contentStream.push(`${color.gray} g`);\n }\n }\n\n /**\n * Set stroke color\n */\n private setStrokeColor(color: PDFColor): void {\n if (color.type === \"rgb\") {\n this.contentStream.push(`${color.r} ${color.g} ${color.b} RG`);\n } else if (color.type === \"cmyk\") {\n this.contentStream.push(\n `${color.c} ${color.m} ${color.y} ${color.k} K`,\n );\n } else if (color.type === \"gray\") {\n this.contentStream.push(`${color.gray} G`);\n }\n }\n\n /**\n * Draw text on the page\n */\n drawText(text: string, options: TextOptions): void {\n const validOptions = TextOptionsSchema.parse(options);\n const { x, y, size = 12, font = \"Helvetica\", color, align = \"left\" } = validOptions;\n\n // Register font in resources\n const fontName = font || \"Helvetica\";\n if (!isStandardFont(fontName)) {\n throw new Error(\n `Font \"${fontName}\" is not a standard PDF font. Use one of: ${Object.keys(STANDARD_FONTS).join(\", \")}`,\n );\n }\n\n const fontRefName = getFontRefName(fontName);\n const fontDict = this.resources.Font as PDFDictionary;\n if (!fontDict[fontRefName]) {\n // Create font object\n const fontObj = createDictionary({\n Type: createName(\"Font\"),\n Subtype: createName(\"Type1\"),\n BaseFont: createName(fontName),\n });\n fontDict[fontRefName] = fontObj;\n }\n\n // Calculate text position based on alignment\n let xPos = x;\n if (align === \"center\") {\n // Approximate centering (proper calculation needs font metrics)\n xPos = x - text.length * size * 0.3;\n } else if (align === \"right\") {\n xPos = x - text.length * size * 0.6;\n }\n\n // Set color if provided\n if (color) {\n this.setFillColor(color);\n }\n\n // Draw text\n this.contentStream.push(\"BT\"); // Begin text\n this.contentStream.push(`/${fontRefName} ${size} Tf`); // Set font and size\n this.contentStream.push(`${xPos} ${y} Td`); // Position\n\n // Escape special characters in text\n const escapedText = text\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\(/g, \"\\\\(\")\n .replace(/\\)/g, \"\\\\)\");\n this.contentStream.push(`(${escapedText}) Tj`); // Show text\n this.contentStream.push(\"ET\"); // End text\n }\n\n /**\n * Draw a rectangle\n */\n drawRectangle(options: RectOptions): void {\n const validOptions = RectOptionsSchema.parse(options);\n const { x, y, width, height, fill, stroke, lineWidth = 1 } = validOptions;\n\n // Set graphics state\n if (lineWidth && stroke) {\n this.contentStream.push(`${lineWidth} w`);\n }\n\n if (fill) {\n this.setFillColor(fill);\n }\n\n if (stroke) {\n this.setStrokeColor(stroke);\n }\n\n // Draw rectangle\n this.contentStream.push(`${x} ${y} ${width} ${height} re`);\n\n // Fill, stroke, or both\n if (fill && stroke) {\n this.contentStream.push(\"B\"); // Fill and stroke\n } else if (fill) {\n this.contentStream.push(\"f\"); // Fill only\n } else if (stroke) {\n this.contentStream.push(\"S\"); // Stroke only\n } else {\n this.contentStream.push(\"S\"); // Default to stroke\n }\n }\n\n /**\n * Draw a line\n */\n drawLine(options: LineOptions): void {\n const validOptions = LineOptionsSchema.parse(options);\n const { x1, y1, x2, y2, color, lineWidth = 1 } = validOptions;\n\n // Set graphics state\n if (lineWidth) {\n this.contentStream.push(`${lineWidth} w`);\n }\n\n if (color) {\n this.setStrokeColor(color);\n }\n\n // Draw line\n this.contentStream.push(`${x1} ${y1} m`); // Move to start\n this.contentStream.push(`${x2} ${y2} l`); // Line to end\n this.contentStream.push(\"S\"); // Stroke\n }\n\n /**\n * Get content stream reference\n */\n getContentStreamRef(): PDFRef {\n // Content stream ref is page ref + 1\n return createRef(this.ref.objectNumber + 1, 0);\n }\n\n /**\n * Generate content stream as PDFStream\n */\n toContentStream(): PDFStream {\n const content = this.contentStream.join(\"\\n\");\n const data = new TextEncoder().encode(content);\n \n const dict = createDictionary({\n Length: data.length,\n });\n\n return createStream(data, dict);\n }\n\n /**\n * Convert page to PDF dictionary\n */\n toDictionary(): PDFDictionary {\n const dims = this.getDimensions();\n const dict = createDictionary({\n Type: createName(\"Page\"),\n MediaBox: createArray([0, 0, dims.width, dims.height]),\n Contents: this.getContentStreamRef(),\n Resources: this.resources,\n });\n\n if (this.parent) {\n dict.Parent = this.parent;\n }\n\n return dict;\n }\n}\n",
|
|
8
|
+
"import type { PDFValue, PDFDictionary, PDFRef, PDFStream, PDFArray, PDFName } from \"../../types.ts\";\n\n/**\n * Serialize a PDF value to string\n */\nexport function serializeValue(value: PDFValue): string {\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n if (typeof value === \"number\") {\n return value.toString();\n }\n if (typeof value === \"string\") {\n // Escape special characters\n const escaped = value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\(/g, \"\\\\(\").replace(/\\)/g, \"\\\\)\");\n return `(${escaped})`;\n }\n if (isName(value)) {\n return `/${value.value}`;\n }\n if (isRef(value)) {\n return `${value.objectNumber} ${value.generation} R`;\n }\n if (Array.isArray(value)) {\n return `[${value.map(serializeValue).join(\" \")}]`;\n }\n if (typeof value === \"object\" && !Array.isArray(value)) {\n // Dictionary\n const dict = value as Record<string, PDFValue>;\n const entries = Object.entries(dict)\n .map(([key, val]) => `/${key} ${serializeValue(val)}`)\n .join(\"\\n\");\n return `<<\\n${entries}\\n>>`;\n }\n return \"\";\n}\n\n/**\n * Serialize a PDF stream\n */\nexport function serializeStream(stream: PDFStream): Uint8Array {\n const dictStr = serializeValue(stream.dictionary);\n const header = new TextEncoder().encode(`${dictStr}\\nstream\\n`);\n const footer = new TextEncoder().encode(\"\\nendstream\");\n\n // Combine header, data, footer\n const result = new Uint8Array(header.length + stream.data.length + footer.length);\n result.set(header, 0);\n result.set(stream.data, header.length);\n result.set(footer, header.length + stream.data.length);\n\n return result;\n}\n\n/**\n * Serialize an indirect object\n */\nexport function serializeObject(objectNumber: number, generation: number, value: any): Uint8Array {\n const header = `${objectNumber} ${generation} obj\\n`;\n let body: Uint8Array;\n\n if (isStream(value)) {\n body = serializeStream(value);\n } else {\n body = new TextEncoder().encode(serializeValue(value));\n }\n\n const footer = new TextEncoder().encode(\"\\nendobj\\n\");\n\n const result = new Uint8Array(header.length + body.length + footer.length);\n result.set(new TextEncoder().encode(header), 0);\n result.set(body, header.length);\n result.set(footer, header.length + body.length);\n\n return result;\n}\n\n// Type guards\nfunction isName(value: any): value is PDFName {\n return typeof value === \"object\" && value !== null && value.type === \"name\";\n}\n\nfunction isRef(value: any): value is PDFRef {\n return typeof value === \"object\" && value !== null && \"objectNumber\" in value && \"generation\" in value;\n}\n\nfunction isStream(value: any): value is PDFStream {\n return typeof value === \"object\" && value !== null && \"data\" in value && value.data instanceof Uint8Array;\n}\n",
|
|
9
|
+
"import {\n createArray,\n createDictionary,\n createName,\n createRef,\n} from \"../../core/objects.ts\";\nimport { PDFMetadataSchema, PDFVersionSchema } from \"../../schemas.ts\";\nimport type { PDFMetadata, PDFRef, PDFVersion, PDFDictionary, PDFStream } from \"../../types.ts\";\nimport { PDFPage } from \"./page.ts\";\nimport { serializeValue, serializeObject } from \"./writer.ts\";\n\nexport type PDFDocumentOptions = {\n version?: PDFVersion;\n metadata?: PDFMetadata;\n};\n\nexport type { PDFPageOptions } from \"./page.ts\";\n\n/**\n * Main PDF Document class for generation\n *\n * @property version - PDF version (1.4, 1.5, 1.6, or 1.7)\n * @property metadata - Document metadata (title, author, etc.)\n * @property catalog - Reference to the document catalog\n * @property pages - Reference to the pages tree root\n */\nexport class PDFDocument {\n version: PDFVersion;\n metadata: PDFMetadata;\n private objects: Map<number, PDFDictionary | PDFStream> = new Map();\n private nextObjectNumber = 1;\n\n catalog: PDFRef;\n pages: PDFRef;\n private pagesArray: PDFPage[] = [];\n\n constructor(options: PDFDocumentOptions = {}) {\n this.version = PDFVersionSchema.parse(options.version ?? \"1.7\");\n this.metadata = PDFMetadataSchema.parse(options.metadata ?? {});\n\n // Create catalog\n this.catalog = this.allocateRef();\n\n // Create pages tree\n this.pages = this.allocateRef();\n\n // Initialize catalog dictionary\n const catalogDict = createDictionary({\n Type: createName(\"Catalog\"),\n Pages: this.pages,\n });\n this.objects.set(this.catalog.objectNumber, catalogDict);\n\n // Initialize pages dictionary\n const pagesDict = createDictionary({\n Type: createName(\"Pages\"),\n Kids: createArray([]),\n Count: 0,\n });\n this.objects.set(this.pages.objectNumber, pagesDict);\n\n // Store metadata if provided (will be serialized in future tasks)\n if (Object.keys(this.metadata).length > 0) {\n const infoRef = this.allocateRef();\n const metadataDict: Record<string, string | number> = {};\n if (this.metadata.title) metadataDict.Title = this.metadata.title;\n if (this.metadata.author) metadataDict.Author = this.metadata.author;\n if (this.metadata.subject) metadataDict.Subject = this.metadata.subject;\n if (this.metadata.creator) metadataDict.Creator = this.metadata.creator;\n if (this.metadata.producer) metadataDict.Producer = this.metadata.producer;\n const infoDict = createDictionary(metadataDict);\n this.objects.set(infoRef.objectNumber, infoDict);\n }\n }\n\n /**\n * Allocate a new object reference\n */\n private allocateRef(): PDFRef {\n return createRef(this.nextObjectNumber++, 0);\n }\n\n /**\n * Add a page to the document\n */\n addPage(options?: import(\"./page.ts\").PDFPageOptions): PDFPage {\n const pageRef = this.allocateRef();\n const contentStreamRef = this.allocateRef(); // Allocate content stream ref\n \n const page = new PDFPage(pageRef, { ...options, parent: this.pages });\n this.pagesArray.push(page);\n\n // Update pages dictionary\n const pagesDict = this.objects.get(\n this.pages.objectNumber,\n ) as PDFDictionary;\n const kids = pagesDict.Kids as PDFRef[];\n kids.push(pageRef);\n pagesDict.Count = (pagesDict.Count as number) + 1;\n\n // Store page dictionary\n this.objects.set(pageRef.objectNumber, page.toDictionary());\n\n // Store content stream\n this.objects.set(contentStreamRef.objectNumber, page.toContentStream());\n\n return page;\n }\n\n /**\n * Save PDF to bytes\n */\n save(): Uint8Array {\n // Refresh all objects (pages might have changed)\n for (const page of this.pagesArray) {\n this.objects.set(page.ref.objectNumber, page.toDictionary());\n const contentStreamRef = page.getContentStreamRef();\n this.objects.set(contentStreamRef.objectNumber, page.toContentStream());\n }\n\n const parts: Uint8Array[] = [];\n\n // 1. PDF Header with binary marker\n const header = new TextEncoder().encode(`%PDF-${this.version}\\n%\\xE2\\xE3\\xCF\\xD3\\n`);\n parts.push(header);\n\n // 2. Write objects and track byte offsets\n const offsets: number[] = [0]; // Object 0 is always at offset 0\n let currentOffset = header.length;\n\n // Sort object numbers to write in order\n const objectNumbers = Array.from(this.objects.keys()).sort((a, b) => a - b);\n\n for (const objNum of objectNumbers) {\n const obj = this.objects.get(objNum);\n const objBytes = serializeObject(objNum, 0, obj);\n parts.push(objBytes);\n offsets[objNum] = currentOffset;\n currentOffset += objBytes.length;\n }\n\n // 3. Cross-reference table\n const xrefStart = currentOffset;\n const xrefLines = [`xref\\n0 ${offsets.length}\\n`];\n\n // Object 0 entry (free)\n xrefLines.push(\"0000000000 65535 f \\n\");\n\n // In-use objects\n for (let i = 1; i < offsets.length; i++) {\n const offset = offsets[i] || 0;\n const offsetStr = offset.toString().padStart(10, \"0\");\n xrefLines.push(`${offsetStr} 00000 n \\n`);\n }\n\n const xref = new TextEncoder().encode(xrefLines.join(\"\"));\n parts.push(xref);\n\n // 4. Trailer\n const trailerDict = serializeValue(\n createDictionary({\n Size: offsets.length,\n Root: this.catalog,\n })\n );\n const trailer = new TextEncoder().encode(\n `trailer\\n${trailerDict}\\nstartxref\\n${xrefStart}\\n%%EOF\\n`\n );\n parts.push(trailer);\n\n // 5. Combine all parts\n const totalLength = parts.reduce((sum, part) => sum + part.length, 0);\n const result = new Uint8Array(totalLength);\n let position = 0;\n for (const part of parts) {\n result.set(part, position);\n position += part.length;\n }\n\n return result;\n }\n}\n"
|
|
10
|
+
],
|
|
11
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "CC23B1DD7B3E218A64756E2164756E21",
|
|
13
|
+
"names": []
|
|
14
|
+
}
|
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createArray,
|
|
4
|
+
createDictionary,
|
|
5
|
+
createName,
|
|
6
|
+
createRef,
|
|
7
|
+
createStream
|
|
8
|
+
} from "./index-4jtcmpfh.js";
|
|
9
|
+
|
|
10
|
+
// src/plugins/parsing/lexer.ts
|
|
11
|
+
var TokenType;
|
|
12
|
+
((TokenType2) => {
|
|
13
|
+
TokenType2["NUMBER"] = "NUMBER";
|
|
14
|
+
TokenType2["STRING"] = "STRING";
|
|
15
|
+
TokenType2["NAME"] = "NAME";
|
|
16
|
+
TokenType2["BOOLEAN"] = "BOOLEAN";
|
|
17
|
+
TokenType2["NULL"] = "NULL";
|
|
18
|
+
TokenType2["ARRAY_START"] = "ARRAY_START";
|
|
19
|
+
TokenType2["ARRAY_END"] = "ARRAY_END";
|
|
20
|
+
TokenType2["DICT_START"] = "DICT_START";
|
|
21
|
+
TokenType2["DICT_END"] = "DICT_END";
|
|
22
|
+
TokenType2["OBJ"] = "OBJ";
|
|
23
|
+
TokenType2["ENDOBJ"] = "ENDOBJ";
|
|
24
|
+
TokenType2["STREAM"] = "STREAM";
|
|
25
|
+
TokenType2["ENDSTREAM"] = "ENDSTREAM";
|
|
26
|
+
TokenType2["XREF"] = "XREF";
|
|
27
|
+
TokenType2["TRAILER"] = "TRAILER";
|
|
28
|
+
TokenType2["STARTXREF"] = "STARTXREF";
|
|
29
|
+
TokenType2["R"] = "R";
|
|
30
|
+
TokenType2["EOF"] = "EOF";
|
|
31
|
+
})(TokenType ||= {});
|
|
32
|
+
|
|
33
|
+
class PDFLexer {
|
|
34
|
+
data;
|
|
35
|
+
position = 0;
|
|
36
|
+
constructor(data) {
|
|
37
|
+
this.data = data;
|
|
38
|
+
}
|
|
39
|
+
nextToken() {
|
|
40
|
+
this.skipWhitespace();
|
|
41
|
+
if (this.position >= this.data.length) {
|
|
42
|
+
return { type: "EOF" /* EOF */, value: null, position: this.position };
|
|
43
|
+
}
|
|
44
|
+
const char = String.fromCharCode(this.data[this.position]);
|
|
45
|
+
if (char === "[") {
|
|
46
|
+
this.position++;
|
|
47
|
+
return { type: "ARRAY_START" /* ARRAY_START */, value: "[", position: this.position - 1 };
|
|
48
|
+
}
|
|
49
|
+
if (char === "]") {
|
|
50
|
+
this.position++;
|
|
51
|
+
return { type: "ARRAY_END" /* ARRAY_END */, value: "]", position: this.position - 1 };
|
|
52
|
+
}
|
|
53
|
+
if (char === "<" && this.peek() === "<") {
|
|
54
|
+
this.position += 2;
|
|
55
|
+
return { type: "DICT_START" /* DICT_START */, value: "<<", position: this.position - 2 };
|
|
56
|
+
}
|
|
57
|
+
if (char === ">" && this.peek() === ">") {
|
|
58
|
+
this.position += 2;
|
|
59
|
+
return { type: "DICT_END" /* DICT_END */, value: ">>", position: this.position - 2 };
|
|
60
|
+
}
|
|
61
|
+
if (char === "/") {
|
|
62
|
+
return this.readName();
|
|
63
|
+
}
|
|
64
|
+
if (char === "(") {
|
|
65
|
+
return this.readString();
|
|
66
|
+
}
|
|
67
|
+
if (char === "-" || char === "+" || char === "." || char >= "0" && char <= "9") {
|
|
68
|
+
return this.readNumber();
|
|
69
|
+
}
|
|
70
|
+
return this.readKeyword();
|
|
71
|
+
}
|
|
72
|
+
peek() {
|
|
73
|
+
if (this.position + 1 >= this.data.length)
|
|
74
|
+
return "";
|
|
75
|
+
return String.fromCharCode(this.data[this.position + 1]);
|
|
76
|
+
}
|
|
77
|
+
skipWhitespace() {
|
|
78
|
+
while (this.position < this.data.length) {
|
|
79
|
+
const char = this.data[this.position];
|
|
80
|
+
if (char === 32 || char === 9 || char === 10 || char === 13 || char === 0) {
|
|
81
|
+
this.position++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (char === 37) {
|
|
85
|
+
while (this.position < this.data.length && this.data[this.position] !== 10 && this.data[this.position] !== 13) {
|
|
86
|
+
this.position++;
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
readName() {
|
|
94
|
+
const start = this.position;
|
|
95
|
+
this.position++;
|
|
96
|
+
let value = "";
|
|
97
|
+
while (this.position < this.data.length) {
|
|
98
|
+
const char = String.fromCharCode(this.data[this.position]);
|
|
99
|
+
if (this.isDelimiter(char) || this.isWhitespace(this.data[this.position])) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
value += char;
|
|
103
|
+
this.position++;
|
|
104
|
+
}
|
|
105
|
+
return { type: "NAME" /* NAME */, value, position: start };
|
|
106
|
+
}
|
|
107
|
+
readString() {
|
|
108
|
+
const start = this.position;
|
|
109
|
+
this.position++;
|
|
110
|
+
let value = "";
|
|
111
|
+
let depth = 1;
|
|
112
|
+
while (this.position < this.data.length && depth > 0) {
|
|
113
|
+
const char = String.fromCharCode(this.data[this.position]);
|
|
114
|
+
if (char === "\\") {
|
|
115
|
+
this.position++;
|
|
116
|
+
if (this.position < this.data.length) {
|
|
117
|
+
const escaped = String.fromCharCode(this.data[this.position]);
|
|
118
|
+
value += escaped === "n" ? `
|
|
119
|
+
` : escaped === "r" ? "\r" : escaped === "t" ? "\t" : escaped;
|
|
120
|
+
}
|
|
121
|
+
} else if (char === "(") {
|
|
122
|
+
depth++;
|
|
123
|
+
value += char;
|
|
124
|
+
} else if (char === ")") {
|
|
125
|
+
depth--;
|
|
126
|
+
if (depth > 0)
|
|
127
|
+
value += char;
|
|
128
|
+
} else {
|
|
129
|
+
value += char;
|
|
130
|
+
}
|
|
131
|
+
this.position++;
|
|
132
|
+
}
|
|
133
|
+
return { type: "STRING" /* STRING */, value, position: start };
|
|
134
|
+
}
|
|
135
|
+
readNumber() {
|
|
136
|
+
const start = this.position;
|
|
137
|
+
let value = "";
|
|
138
|
+
while (this.position < this.data.length) {
|
|
139
|
+
const char = String.fromCharCode(this.data[this.position]);
|
|
140
|
+
if (char === "-" || char === "+" || char === "." || char >= "0" && char <= "9") {
|
|
141
|
+
value += char;
|
|
142
|
+
this.position++;
|
|
143
|
+
} else {
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { type: "NUMBER" /* NUMBER */, value: value.includes(".") ? parseFloat(value) : parseInt(value, 10), position: start };
|
|
148
|
+
}
|
|
149
|
+
readKeyword() {
|
|
150
|
+
const start = this.position;
|
|
151
|
+
let value = "";
|
|
152
|
+
while (this.position < this.data.length) {
|
|
153
|
+
const char = String.fromCharCode(this.data[this.position]);
|
|
154
|
+
if (this.isDelimiter(char) || this.isWhitespace(this.data[this.position])) {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
value += char;
|
|
158
|
+
this.position++;
|
|
159
|
+
}
|
|
160
|
+
const upper = value.toUpperCase();
|
|
161
|
+
if (upper === "OBJ")
|
|
162
|
+
return { type: "OBJ" /* OBJ */, value, position: start };
|
|
163
|
+
if (upper === "ENDOBJ")
|
|
164
|
+
return { type: "ENDOBJ" /* ENDOBJ */, value, position: start };
|
|
165
|
+
if (upper === "STREAM")
|
|
166
|
+
return { type: "STREAM" /* STREAM */, value, position: start };
|
|
167
|
+
if (upper === "ENDSTREAM")
|
|
168
|
+
return { type: "ENDSTREAM" /* ENDSTREAM */, value, position: start };
|
|
169
|
+
if (upper === "XREF")
|
|
170
|
+
return { type: "XREF" /* XREF */, value, position: start };
|
|
171
|
+
if (upper === "TRAILER")
|
|
172
|
+
return { type: "TRAILER" /* TRAILER */, value, position: start };
|
|
173
|
+
if (upper === "STARTXREF")
|
|
174
|
+
return { type: "STARTXREF" /* STARTXREF */, value, position: start };
|
|
175
|
+
if (upper === "R")
|
|
176
|
+
return { type: "R" /* R */, value, position: start };
|
|
177
|
+
if (upper === "TRUE")
|
|
178
|
+
return { type: "BOOLEAN" /* BOOLEAN */, value: true, position: start };
|
|
179
|
+
if (upper === "FALSE")
|
|
180
|
+
return { type: "BOOLEAN" /* BOOLEAN */, value: false, position: start };
|
|
181
|
+
if (upper === "NULL")
|
|
182
|
+
return { type: "NULL" /* NULL */, value: null, position: start };
|
|
183
|
+
return { type: "NAME" /* NAME */, value, position: start };
|
|
184
|
+
}
|
|
185
|
+
isDelimiter(char) {
|
|
186
|
+
return ["(", ")", "<", ">", "[", "]", "{", "}", "/", "%"].includes(char);
|
|
187
|
+
}
|
|
188
|
+
isWhitespace(byte) {
|
|
189
|
+
return byte === 32 || byte === 9 || byte === 10 || byte === 13 || byte === 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// src/plugins/parsing/parser.ts
|
|
193
|
+
class PDFParser {
|
|
194
|
+
lexer;
|
|
195
|
+
currentToken;
|
|
196
|
+
nextToken = null;
|
|
197
|
+
data;
|
|
198
|
+
constructor(data) {
|
|
199
|
+
this.data = data;
|
|
200
|
+
this.lexer = new PDFLexer(data);
|
|
201
|
+
this.currentToken = this.lexer.nextToken();
|
|
202
|
+
}
|
|
203
|
+
parseValue() {
|
|
204
|
+
switch (this.currentToken.type) {
|
|
205
|
+
case "NUMBER" /* NUMBER */:
|
|
206
|
+
return this.parseNumberOrRef();
|
|
207
|
+
case "STRING" /* STRING */:
|
|
208
|
+
return this.parseString();
|
|
209
|
+
case "NAME" /* NAME */:
|
|
210
|
+
return this.parseName();
|
|
211
|
+
case "BOOLEAN" /* BOOLEAN */:
|
|
212
|
+
return this.parseBoolean();
|
|
213
|
+
case "NULL" /* NULL */:
|
|
214
|
+
return this.parseNull();
|
|
215
|
+
case "ARRAY_START" /* ARRAY_START */:
|
|
216
|
+
return this.parseArray();
|
|
217
|
+
case "DICT_START" /* DICT_START */:
|
|
218
|
+
return this.parseDictionary();
|
|
219
|
+
default:
|
|
220
|
+
throw new Error(`Unexpected token: ${this.currentToken.type}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
parseNumberOrRef() {
|
|
224
|
+
const first = this.currentToken.value;
|
|
225
|
+
this.advance();
|
|
226
|
+
if (this.currentToken.type === "NUMBER" /* NUMBER */) {
|
|
227
|
+
const second = this.currentToken.value;
|
|
228
|
+
this.advance();
|
|
229
|
+
if (this.currentToken.type === "R" /* R */) {
|
|
230
|
+
this.advance();
|
|
231
|
+
return createRef(first, second);
|
|
232
|
+
}
|
|
233
|
+
const thirdToken = this.currentToken;
|
|
234
|
+
this.currentToken = { type: "NUMBER" /* NUMBER */, value: second, position: 0 };
|
|
235
|
+
this.nextToken = thirdToken;
|
|
236
|
+
return first;
|
|
237
|
+
}
|
|
238
|
+
return first;
|
|
239
|
+
}
|
|
240
|
+
parseString() {
|
|
241
|
+
const value = this.currentToken.value;
|
|
242
|
+
this.advance();
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
parseName() {
|
|
246
|
+
const value = this.currentToken.value;
|
|
247
|
+
this.advance();
|
|
248
|
+
return createName(value);
|
|
249
|
+
}
|
|
250
|
+
parseBoolean() {
|
|
251
|
+
const value = this.currentToken.value;
|
|
252
|
+
this.advance();
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
parseNull() {
|
|
256
|
+
this.advance();
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
parseArray() {
|
|
260
|
+
this.advance();
|
|
261
|
+
const values = [];
|
|
262
|
+
while (this.currentToken.type !== "ARRAY_END" /* ARRAY_END */) {
|
|
263
|
+
if (this.currentToken.type === "EOF" /* EOF */) {
|
|
264
|
+
throw new Error("Unexpected EOF in array");
|
|
265
|
+
}
|
|
266
|
+
values.push(this.parseValue());
|
|
267
|
+
}
|
|
268
|
+
this.advance();
|
|
269
|
+
return createArray(values);
|
|
270
|
+
}
|
|
271
|
+
parseDictionary() {
|
|
272
|
+
this.advance();
|
|
273
|
+
const entries = {};
|
|
274
|
+
while (this.currentToken.type !== "DICT_END" /* DICT_END */) {
|
|
275
|
+
if (this.currentToken.type === "EOF" /* EOF */) {
|
|
276
|
+
throw new Error("Unexpected EOF in dictionary");
|
|
277
|
+
}
|
|
278
|
+
if (this.currentToken.type !== "NAME" /* NAME */) {
|
|
279
|
+
throw new Error(`Expected name in dictionary, got ${this.currentToken.type}`);
|
|
280
|
+
}
|
|
281
|
+
const key = this.currentToken.value;
|
|
282
|
+
this.advance();
|
|
283
|
+
const value = this.parseValue();
|
|
284
|
+
entries[key] = value;
|
|
285
|
+
}
|
|
286
|
+
this.advance();
|
|
287
|
+
return createDictionary(entries);
|
|
288
|
+
}
|
|
289
|
+
parseIndirectObject() {
|
|
290
|
+
if (this.currentToken.type !== "NUMBER" /* NUMBER */) {
|
|
291
|
+
throw new Error("Expected object number");
|
|
292
|
+
}
|
|
293
|
+
const objectNumber = this.currentToken.value;
|
|
294
|
+
this.advance();
|
|
295
|
+
if (this.currentToken.type !== "NUMBER" /* NUMBER */) {
|
|
296
|
+
throw new Error("Expected generation number");
|
|
297
|
+
}
|
|
298
|
+
const generation = this.currentToken.value;
|
|
299
|
+
this.advance();
|
|
300
|
+
if (this.currentToken.type !== "OBJ" /* OBJ */) {
|
|
301
|
+
throw new Error("Expected 'obj' keyword");
|
|
302
|
+
}
|
|
303
|
+
this.advance();
|
|
304
|
+
let value = this.parseValue();
|
|
305
|
+
if (this.currentToken.type === "STREAM" /* STREAM */) {
|
|
306
|
+
value = this.parseStream(value);
|
|
307
|
+
}
|
|
308
|
+
if (this.currentToken.type !== "ENDOBJ" /* ENDOBJ */) {
|
|
309
|
+
throw new Error("Expected 'endobj' keyword");
|
|
310
|
+
}
|
|
311
|
+
this.advance();
|
|
312
|
+
return {
|
|
313
|
+
ref: createRef(objectNumber, generation),
|
|
314
|
+
value
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
parseStream(dictionary) {
|
|
318
|
+
const streamKeywordPos = this.currentToken.position;
|
|
319
|
+
this.advance();
|
|
320
|
+
let streamDataStart = streamKeywordPos + 6;
|
|
321
|
+
while (streamDataStart < this.data.length) {
|
|
322
|
+
const byte = this.data[streamDataStart];
|
|
323
|
+
if (byte === 13 || byte === 10) {
|
|
324
|
+
streamDataStart++;
|
|
325
|
+
if (byte === 13 && this.data[streamDataStart] === 10) {
|
|
326
|
+
streamDataStart++;
|
|
327
|
+
}
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
streamDataStart++;
|
|
331
|
+
}
|
|
332
|
+
const length = dictionary.Length;
|
|
333
|
+
if (typeof length !== "number") {
|
|
334
|
+
throw new Error("Stream dictionary missing Length");
|
|
335
|
+
}
|
|
336
|
+
const data = this.data.slice(streamDataStart, streamDataStart + length);
|
|
337
|
+
while (this.currentToken.type !== "ENDSTREAM" /* ENDSTREAM */ && this.currentToken.type !== "EOF" /* EOF */) {
|
|
338
|
+
this.advance();
|
|
339
|
+
}
|
|
340
|
+
if (this.currentToken.type !== "ENDSTREAM" /* ENDSTREAM */) {
|
|
341
|
+
throw new Error("Expected 'endstream' keyword");
|
|
342
|
+
}
|
|
343
|
+
this.advance();
|
|
344
|
+
return createStream(data, dictionary);
|
|
345
|
+
}
|
|
346
|
+
advance() {
|
|
347
|
+
if (this.nextToken !== null) {
|
|
348
|
+
this.currentToken = this.nextToken;
|
|
349
|
+
this.nextToken = null;
|
|
350
|
+
} else {
|
|
351
|
+
this.currentToken = this.lexer.nextToken();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
hasMore() {
|
|
355
|
+
return this.currentToken.type !== "EOF" /* EOF */;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// src/errors.ts
|
|
359
|
+
class PDFError extends Error {
|
|
360
|
+
constructor(message) {
|
|
361
|
+
super(message);
|
|
362
|
+
this.name = "PDFError";
|
|
363
|
+
if (Error.captureStackTrace) {
|
|
364
|
+
Error.captureStackTrace(this, this.constructor);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
class PDFParseError extends PDFError {
|
|
370
|
+
offset;
|
|
371
|
+
constructor(message, offset) {
|
|
372
|
+
super(message);
|
|
373
|
+
this.offset = offset;
|
|
374
|
+
this.name = "PDFParseError";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
class PDFGenerationError extends PDFError {
|
|
379
|
+
constructor(message) {
|
|
380
|
+
super(message);
|
|
381
|
+
this.name = "PDFGenerationError";
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
class InvalidPDFObjectError extends PDFError {
|
|
386
|
+
objectType;
|
|
387
|
+
constructor(objectType, reason) {
|
|
388
|
+
super(`Invalid ${objectType}: ${reason}`);
|
|
389
|
+
this.objectType = objectType;
|
|
390
|
+
this.name = "InvalidPDFObjectError";
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
class FontNotFoundError extends PDFError {
|
|
395
|
+
fontName;
|
|
396
|
+
constructor(fontName) {
|
|
397
|
+
super(`Font not found: ${fontName}`);
|
|
398
|
+
this.fontName = fontName;
|
|
399
|
+
this.name = "FontNotFoundError";
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
class InvalidImageError extends PDFError {
|
|
404
|
+
constructor(reason) {
|
|
405
|
+
super(`Invalid image: ${reason}`);
|
|
406
|
+
this.name = "InvalidImageError";
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
class PDFSignatureError extends PDFError {
|
|
411
|
+
constructor(reason) {
|
|
412
|
+
super(`PDF signature error: ${reason}`);
|
|
413
|
+
this.name = "PDFSignatureError";
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
class PDFEncryptionError extends PDFError {
|
|
418
|
+
constructor(reason) {
|
|
419
|
+
super(`PDF encryption error: ${reason}`);
|
|
420
|
+
this.name = "PDFEncryptionError";
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
class NotImplementedError extends PDFError {
|
|
425
|
+
constructor(feature) {
|
|
426
|
+
super(`Feature not yet implemented: ${feature}`);
|
|
427
|
+
this.name = "NotImplementedError";
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/plugins/parsing/reader.ts
|
|
432
|
+
class PDFReader {
|
|
433
|
+
data;
|
|
434
|
+
objects = new Map;
|
|
435
|
+
constructor(data) {
|
|
436
|
+
this.data = data;
|
|
437
|
+
}
|
|
438
|
+
parse() {
|
|
439
|
+
const xrefOffset = this.findStartXRef();
|
|
440
|
+
const xrefTable = this.parseXRefTable(xrefOffset);
|
|
441
|
+
const trailer = this.parseTrailer(xrefOffset);
|
|
442
|
+
const catalogRef = trailer.Root;
|
|
443
|
+
this.readObjects(xrefTable);
|
|
444
|
+
const version = this.parseVersion();
|
|
445
|
+
const pages = this.parsePages(catalogRef);
|
|
446
|
+
return {
|
|
447
|
+
version,
|
|
448
|
+
catalog: catalogRef,
|
|
449
|
+
pages,
|
|
450
|
+
objects: this.objects
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
findStartXRef() {
|
|
454
|
+
const decoder = new TextDecoder;
|
|
455
|
+
const content = decoder.decode(this.data);
|
|
456
|
+
const match = content.match(/startxref\s+(\d+)/);
|
|
457
|
+
if (!match) {
|
|
458
|
+
throw new PDFParseError("Could not find startxref");
|
|
459
|
+
}
|
|
460
|
+
return parseInt(match[1], 10);
|
|
461
|
+
}
|
|
462
|
+
parseXRefTable(offset) {
|
|
463
|
+
const decoder = new TextDecoder;
|
|
464
|
+
const content = decoder.decode(this.data.slice(offset));
|
|
465
|
+
const lines = content.split(`
|
|
466
|
+
`);
|
|
467
|
+
const xref = new Map;
|
|
468
|
+
let i = 0;
|
|
469
|
+
while (i < lines.length && !lines[i].trim().startsWith("xref"))
|
|
470
|
+
i++;
|
|
471
|
+
i++;
|
|
472
|
+
while (i < lines.length && !lines[i].trim().startsWith("trailer")) {
|
|
473
|
+
const subsection = lines[i].trim().split(/\s+/);
|
|
474
|
+
if (subsection.length === 2) {
|
|
475
|
+
const start = parseInt(subsection[0], 10);
|
|
476
|
+
const count = parseInt(subsection[1], 10);
|
|
477
|
+
i++;
|
|
478
|
+
for (let j = 0;j < count; j++) {
|
|
479
|
+
const entry = lines[i].trim().split(/\s+/);
|
|
480
|
+
if (entry.length >= 3 && entry[2] === "n") {
|
|
481
|
+
const offset2 = parseInt(entry[0], 10);
|
|
482
|
+
xref.set(start + j, offset2);
|
|
483
|
+
}
|
|
484
|
+
i++;
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
i++;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return xref;
|
|
491
|
+
}
|
|
492
|
+
parseTrailer(xrefOffset) {
|
|
493
|
+
const decoder = new TextDecoder;
|
|
494
|
+
const content = decoder.decode(this.data.slice(xrefOffset));
|
|
495
|
+
const trailerMatch = content.match(/trailer\s*<<[\s\S]*?>>/);
|
|
496
|
+
if (!trailerMatch) {
|
|
497
|
+
throw new PDFParseError("Could not find trailer");
|
|
498
|
+
}
|
|
499
|
+
const parser = new PDFParser(new TextEncoder().encode(trailerMatch[0].replace("trailer", "")));
|
|
500
|
+
return parser.parseValue();
|
|
501
|
+
}
|
|
502
|
+
readObjects(xrefTable) {
|
|
503
|
+
for (const [objectNum, offset] of xrefTable) {
|
|
504
|
+
try {
|
|
505
|
+
const objData = this.data.slice(offset);
|
|
506
|
+
const parser = new PDFParser(objData);
|
|
507
|
+
const obj = parser.parseIndirectObject();
|
|
508
|
+
this.objects.set(objectNum, obj.value);
|
|
509
|
+
} catch (error) {}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
parseVersion() {
|
|
513
|
+
const decoder = new TextDecoder;
|
|
514
|
+
const header = decoder.decode(this.data.slice(0, 20));
|
|
515
|
+
const match = header.match(/%PDF-(\d+\.\d+)/);
|
|
516
|
+
return match ? match[1] : "1.7";
|
|
517
|
+
}
|
|
518
|
+
parsePages(catalogRef) {
|
|
519
|
+
const catalog = this.objects.get(catalogRef.objectNumber);
|
|
520
|
+
if (!catalog) {
|
|
521
|
+
throw new PDFParseError("Catalog not found");
|
|
522
|
+
}
|
|
523
|
+
const pagesRef = catalog.Pages;
|
|
524
|
+
const pagesTree = this.objects.get(pagesRef.objectNumber);
|
|
525
|
+
if (!pagesTree) {
|
|
526
|
+
throw new PDFParseError("Pages tree not found");
|
|
527
|
+
}
|
|
528
|
+
const kids = pagesTree.Kids;
|
|
529
|
+
const pages = [];
|
|
530
|
+
for (const kidRef of kids) {
|
|
531
|
+
if (kidRef != null && typeof kidRef === "object" && "objectNumber" in kidRef) {
|
|
532
|
+
const page = this.parsePage(kidRef);
|
|
533
|
+
if (page)
|
|
534
|
+
pages.push(page);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return pages;
|
|
538
|
+
}
|
|
539
|
+
parsePage(ref) {
|
|
540
|
+
const pageDict = this.objects.get(ref.objectNumber);
|
|
541
|
+
if (!pageDict)
|
|
542
|
+
return null;
|
|
543
|
+
const mediaBox = pageDict.MediaBox;
|
|
544
|
+
const size = {
|
|
545
|
+
width: mediaBox[2],
|
|
546
|
+
height: mediaBox[3]
|
|
547
|
+
};
|
|
548
|
+
let content = "";
|
|
549
|
+
const contentsRef = pageDict.Contents;
|
|
550
|
+
if (contentsRef && typeof contentsRef === "object" && "objectNumber" in contentsRef) {
|
|
551
|
+
content = this.extractText(contentsRef);
|
|
552
|
+
}
|
|
553
|
+
return { ref, size, content };
|
|
554
|
+
}
|
|
555
|
+
extractText(ref) {
|
|
556
|
+
const stream = this.objects.get(ref.objectNumber);
|
|
557
|
+
if (!stream || !stream.data)
|
|
558
|
+
return "";
|
|
559
|
+
const decoder = new TextDecoder;
|
|
560
|
+
const content = decoder.decode(stream.data);
|
|
561
|
+
const texts = [];
|
|
562
|
+
const regex = /\(([^)]*)\)\s*Tj/g;
|
|
563
|
+
let match;
|
|
564
|
+
while ((match = regex.exec(content)) !== null) {
|
|
565
|
+
texts.push(match[1]);
|
|
566
|
+
}
|
|
567
|
+
return texts.join(" ");
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
export { PDFError, PDFParseError, PDFGenerationError, InvalidPDFObjectError, FontNotFoundError, InvalidImageError, PDFSignatureError, PDFEncryptionError, NotImplementedError, TokenType, PDFLexer, PDFParser, PDFReader };
|
|
571
|
+
|
|
572
|
+
//# debugId=084165B12C841F7C64756E2164756E21
|