chore: update image sources and version bump to 1.2.0

- Changed image sources for GDPR, CCPA, and HIPAA compliance logos to local paths.
- Updated package version to 1.2.0 in package-lock.json.
- Enhanced README and SIMPLE_MODE documentation with Docker usage instructions.
- Improved table-of-contents worker and related TypeScript definitions for better clarity and functionality.
- Refactored CSS styles for consistency and improved UI elements.
This commit is contained in:
abdullahalam123
2025-11-08 13:17:29 +05:30
parent 661c030ae1
commit bc181c8c96
16 changed files with 652 additions and 320 deletions

View File

@@ -129,4 +129,3 @@ body {
pointer-events: none;
z-index: 5;
}

View File

@@ -246,10 +246,10 @@ function showInputModal(title, fields = [], defaultValues = {}) {
// Store modal references
savedModalOverlay = overlay;
savedModal = modal;
// Hide modal completely
overlay.style.display = 'none';
startDestinationPicking((page, pdfX, pdfY) => {
const destPageInput = modal.querySelector('#modal-dest-page');
const destXInput = modal.querySelector('#modal-dest-x');
@@ -258,10 +258,10 @@ function showInputModal(title, fields = [], defaultValues = {}) {
if (destPageInput) destPageInput.value = page;
if (destXInput) destXInput.value = Math.round(pdfX);
if (destYInput) destYInput.value = Math.round(pdfY);
// Restore modal
overlay.style.display = '';
// Update preview to show the destination after a short delay to ensure modal is visible
setTimeout(() => {
updateDestinationPreview();
@@ -269,7 +269,7 @@ function showInputModal(title, fields = [], defaultValues = {}) {
});
});
}
// Add validation for page input
const destPageInput = modal.querySelector('#modal-dest-page');
if (destPageInput) {
@@ -285,7 +285,7 @@ function showInputModal(title, fields = [], defaultValues = {}) {
}
updateDestinationPreview();
});
destPageInput.addEventListener('blur', (e) => {
const value = parseInt(e.target.value);
const maxPages = parseInt(e.target.max) || 1;
@@ -299,32 +299,34 @@ function showInputModal(title, fields = [], defaultValues = {}) {
updateDestinationPreview();
});
}
// Function to update destination preview
function updateDestinationPreview() {
if (!pdfJsDoc) return;
const destPageInput = modal.querySelector('#modal-dest-page');
const destXInput = modal.querySelector('#modal-dest-x');
const destYInput = modal.querySelector('#modal-dest-y');
const destZoomSelect = modal.querySelector('#modal-dest-zoom');
const pageNum = destPageInput ? parseInt(destPageInput.value) : currentPage;
const pageNum = destPageInput
? parseInt(destPageInput.value)
: currentPage;
const x = destXInput ? parseFloat(destXInput.value) : null;
const y = destYInput ? parseFloat(destYInput.value) : null;
const zoom = destZoomSelect ? destZoomSelect.value : null;
if (pageNum >= 1 && pageNum <= pdfJsDoc.numPages) {
// Render the page with zoom if specified
renderPageWithDestination(pageNum, x, y, zoom);
}
}
// Add listeners for X, Y, and zoom changes
const destXInput = modal.querySelector('#modal-dest-x');
const destYInput = modal.querySelector('#modal-dest-y');
const destZoomSelect = modal.querySelector('#modal-dest-zoom');
if (destXInput) {
destXInput.addEventListener('input', updateDestinationPreview);
}
@@ -434,7 +436,7 @@ function cancelDestinationPicking() {
destinationMarker.remove();
destinationMarker = null;
}
// Remove coordinate display
const coordDisplay = document.getElementById('destination-coord-display');
if (coordDisplay) {
@@ -497,20 +499,22 @@ document.addEventListener('DOMContentLoaded', () => {
const page = await pdfJsDoc.getPage(currentPage);
viewport = page.getViewport({ scale: currentZoom });
}
// Convert canvas pixel coordinates to PDF coordinates
// The canvas CSS size matches viewport dimensions, so coordinates map directly
// PDF uses bottom-left origin, canvas uses top-left
const scaleX = viewport.width / rect.width;
const scaleY = viewport.height / rect.height;
const pdfX = canvasX * scaleX;
const pdfY = viewport.height - (canvasY * scaleY);
const pdfY = viewport.height - canvasY * scaleY;
// Remove old marker and coordinate display
if (destinationMarker) {
destinationMarker.remove();
}
const oldCoordDisplay = document.getElementById('destination-coord-display');
const oldCoordDisplay = document.getElementById(
'destination-coord-display'
);
if (oldCoordDisplay) {
oldCoordDisplay.remove();
}
@@ -528,16 +532,21 @@ document.addEventListener('DOMContentLoaded', () => {
const canvasRect = canvas.getBoundingClientRect();
const wrapperRect = canvasWrapper.getBoundingClientRect();
destinationMarker.style.position = 'absolute';
destinationMarker.style.left = (canvasX + canvasRect.left - wrapperRect.left) + 'px';
destinationMarker.style.top = (canvasY + canvasRect.top - wrapperRect.top) + 'px';
destinationMarker.style.left =
canvasX + canvasRect.left - wrapperRect.left + 'px';
destinationMarker.style.top =
canvasY + canvasRect.top - wrapperRect.top + 'px';
canvasWrapper.appendChild(destinationMarker);
// Create persistent coordinate display
const coordDisplay = document.createElement('div');
coordDisplay.id = 'destination-coord-display';
coordDisplay.className = 'absolute bg-blue-500 text-white px-2 py-1 rounded text-xs font-mono z-50 pointer-events-none';
coordDisplay.style.left = (canvasX + canvasRect.left - wrapperRect.left + 20) + 'px';
coordDisplay.style.top = (canvasY + canvasRect.top - wrapperRect.top - 30) + 'px';
coordDisplay.className =
'absolute bg-blue-500 text-white px-2 py-1 rounded text-xs font-mono z-50 pointer-events-none';
coordDisplay.style.left =
canvasX + canvasRect.left - wrapperRect.left + 20 + 'px';
coordDisplay.style.top =
canvasY + canvasRect.top - wrapperRect.top - 30 + 'px';
coordDisplay.textContent = `X: ${Math.round(pdfX)}, Y: ${Math.round(pdfY)}`;
canvasWrapper.appendChild(coordDisplay);
@@ -639,6 +648,12 @@ const jsonInput = document.getElementById('json-input');
const autoExtractCheckbox = document.getElementById('auto-extract-checkbox');
const appEl = document.getElementById('app');
const uploaderEl = document.getElementById('uploader');
const fileDisplayArea = document.getElementById(
'file-display-area'
) as HTMLElement;
const backToToolsBtn = document.getElementById(
'back-to-tools'
) as HTMLButtonElement;
const canvas = document.getElementById('pdf-canvas');
const ctx = canvas.getContext('2d');
const pageIndicator = document.getElementById('page-indicator');
@@ -974,6 +989,37 @@ collapseAllBtn.addEventListener('click', () => {
renderBookmarkTree();
});
// Format bytes helper
function formatBytes(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}
// Render file display
function renderFileDisplay(file: File) {
if (!fileDisplayArea) return;
fileDisplayArea.innerHTML = '';
fileDisplayArea.classList.remove('hidden');
const fileDiv = document.createElement('div');
fileDiv.className =
'flex items-center justify-between bg-gray-700 p-3 rounded-lg text-sm';
const nameSpan = document.createElement('span');
nameSpan.className = 'truncate font-medium text-gray-200';
nameSpan.textContent = file.name;
const sizeSpan = document.createElement('span');
sizeSpan.className = 'flex-shrink-0 ml-4 text-gray-400';
sizeSpan.textContent = formatBytes(file.size);
fileDiv.append(nameSpan, sizeSpan);
fileDisplayArea.appendChild(fileDiv);
}
fileInput.addEventListener('change', loadPDF);
async function loadPDF(e) {
@@ -982,6 +1028,7 @@ async function loadPDF(e) {
originalFileName = file.name.replace('.pdf', '');
filenameDisplay.textContent = originalFileName;
renderFileDisplay(file);
const arrayBuffer = await file.arrayBuffer();
currentPage = 1;
@@ -1057,47 +1104,47 @@ async function renderPage(num, zoom = null, destX = null, destY = null) {
if (!pdfJsDoc) return;
const page = await pdfJsDoc.getPage(num);
let zoomScale = currentZoom;
if (zoom !== null && zoom !== '' && zoom !== '0') {
zoomScale = parseFloat(zoom) / 100;
}
const dpr = window.devicePixelRatio || 1;
let viewport = page.getViewport({ scale: zoomScale });
currentViewport = viewport;
canvas.height = viewport.height * dpr;
canvas.width = viewport.width * dpr;
// Set CSS size to maintain aspect ratio (this is what the browser displays)
canvas.style.width = viewport.width + 'px';
canvas.style.height = viewport.height + 'px';
// Scale the canvas context to match device pixel ratio
ctx.scale(dpr, dpr);
await page.render({ canvasContext: ctx, viewport: viewport }).promise;
// Draw destination marker if coordinates are provided
if (destX !== null && destY !== null) {
const canvasX = destX;
const canvasY = viewport.height - destY; // Flip Y axis (PDF bottom-left, canvas top-left)
// Draw marker on canvas with animation effect
ctx.save();
ctx.strokeStyle = '#3b82f6';
ctx.fillStyle = '#3b82f6';
ctx.lineWidth = 3;
ctx.shadowBlur = 10;
ctx.shadowColor = 'rgba(59, 130, 246, 0.5)';
ctx.beginPath();
ctx.arc(canvasX, canvasY, 12, 0, 2 * Math.PI);
ctx.fill();
ctx.shadowBlur = 0;
// Draw crosshair
ctx.beginPath();
ctx.moveTo(canvasX - 15, canvasY);
@@ -1105,26 +1152,26 @@ async function renderPage(num, zoom = null, destX = null, destY = null) {
ctx.moveTo(canvasX, canvasY - 15);
ctx.lineTo(canvasX, canvasY + 15);
ctx.stroke();
// Draw inner circle
ctx.beginPath();
ctx.arc(canvasX, canvasY, 6, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
// Draw coordinate text background
const text = `X: ${Math.round(destX)}, Y: ${Math.round(destY)}`;
ctx.font = 'bold 12px monospace';
const textMetrics = ctx.measureText(text);
const textWidth = textMetrics.width;
const textHeight = 18;
ctx.fillStyle = 'rgba(59, 130, 246, 0.95)';
ctx.fillRect(canvasX + 18, canvasY - 25, textWidth + 10, textHeight);
ctx.fillStyle = 'white';
ctx.fillText(text, canvasX + 23, canvasY - 10);
ctx.restore();
}
@@ -1424,8 +1471,13 @@ function createNodeElement(node, level = 0) {
// Check if bookmark has a custom destination
if (node.destX !== null || node.destY !== null || node.zoom !== null) {
// Render page with destination highlighted and zoom applied
await renderPageWithDestination(node.page, node.destX, node.destY, node.zoom);
await renderPageWithDestination(
node.page,
node.destX,
node.destY,
node.zoom
);
// Highlight the destination briefly (2 seconds)
setTimeout(() => {
// Re-render without highlight but keep the zoom if it was set
@@ -1769,7 +1821,6 @@ extractExistingBtn.addEventListener('click', async () => {
}
});
async function extractExistingBookmarks(doc) {
try {
const outlines = doc.catalog.lookup(PDFName.of('Outlines'));
@@ -1792,7 +1843,9 @@ async function extractExistingBookmarks(doc) {
try {
function addNamePair(nameObj, destObj) {
try {
const key = nameObj.decodeText ? nameObj.decodeText() : String(nameObj);
const key = nameObj.decodeText
? nameObj.decodeText()
: String(nameObj);
namedDests.set(key, resolveRef(destObj));
} catch (_) {
// ignore malformed entry
@@ -1804,7 +1857,9 @@ async function extractExistingBookmarks(doc) {
node = resolveRef(node);
if (!node) return;
const namesArray = node.lookup ? node.lookup(PDFName.of('Names')) : null;
const namesArray = node.lookup
? node.lookup(PDFName.of('Names'))
: null;
if (namesArray && namesArray.array) {
for (let i = 0; i < namesArray.array.length; i += 2) {
const n = namesArray.array[i];
@@ -1848,7 +1903,8 @@ async function extractExistingBookmarks(doc) {
if (pageRef.numberValue !== undefined) {
const numericIndex = pageRef.numberValue | 0;
if (numericIndex >= 0 && numericIndex < pages.length) return numericIndex;
if (numericIndex >= 0 && numericIndex < pages.length)
return numericIndex;
}
if (pageRef.objectNumber !== undefined) {
@@ -1860,7 +1916,9 @@ async function extractExistingBookmarks(doc) {
if (pageRef.toString) {
const target = pageRef.toString();
const idxByString = pages.findIndex((p) => p.ref.toString() === target);
const idxByString = pages.findIndex(
(p) => p.ref.toString() === target
);
if (idxByString !== -1) return idxByString;
}
@@ -1884,7 +1942,7 @@ async function extractExistingBookmarks(doc) {
// Try Dest entry first
let dest = item.lookup(PDFName.of('Dest'));
// If no Dest, try Action/D
if (!dest) {
const action = resolveRef(item.lookup(PDFName.of('A')));
@@ -1902,7 +1960,10 @@ async function extractExistingBookmarks(doc) {
} else if (dest.lookup) {
// Some named destinations resolve to a dictionary with 'D' entry
const maybeDict = resolveRef(dest);
const dictD = maybeDict && maybeDict.lookup ? maybeDict.lookup(PDFName.of('D')) : null;
const dictD =
maybeDict && maybeDict.lookup
? maybeDict.lookup(PDFName.of('D'))
: null;
if (dictD) dest = resolveRef(dictD);
}
} catch (_) {
@@ -1975,7 +2036,7 @@ async function extractExistingBookmarks(doc) {
style,
destX,
destY,
zoom
zoom,
};
// Process children (make sure to resolve refs)
@@ -1986,7 +2047,6 @@ async function extractExistingBookmarks(doc) {
child = resolveRef(child.lookup(PDFName.of('Next')));
}
if (pageIndex === 0 && bookmark.children.length > 0) {
const firstChild = bookmark.children[0];
if (firstChild) {
@@ -2015,6 +2075,13 @@ async function extractExistingBookmarks(doc) {
}
}
// Back to tools button
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header';
});
}
downloadBtn.addEventListener('click', async () => {
const pages = pdfLibDoc.getPages();
const outlinesDict = pdfLibDoc.context.obj({});

View File

@@ -2,17 +2,29 @@ const worker = new Worker('/workers/table-of-contents.worker.js');
let pdfFile: File | null = null;
// Get DOM elements
const dropZone = document.getElementById('drop-zone') as HTMLElement;
const fileInput = document.getElementById('file-input') as HTMLInputElement;
const generateBtn = document.getElementById('generate-btn') as HTMLButtonElement;
const generateBtn = document.getElementById(
'generate-btn'
) as HTMLButtonElement;
const tocTitleInput = document.getElementById('toc-title') as HTMLInputElement;
const fontSizeSelect = document.getElementById('font-size') as HTMLSelectElement;
const fontFamilySelect = document.getElementById('font-family') as HTMLSelectElement;
const addBookmarkCheckbox = document.getElementById('add-bookmark') as HTMLInputElement;
const fontSizeSelect = document.getElementById(
'font-size'
) as HTMLSelectElement;
const fontFamilySelect = document.getElementById(
'font-family'
) as HTMLSelectElement;
const addBookmarkCheckbox = document.getElementById(
'add-bookmark'
) as HTMLInputElement;
const statusMessage = document.getElementById('status-message') as HTMLElement;
const fileDisplayArea = document.getElementById(
'file-display-area'
) as HTMLElement;
const backToToolsBtn = document.getElementById(
'back-to-tools'
) as HTMLButtonElement;
// Type definitions for the worker messages
interface GenerateTOCMessage {
command: 'generate-toc';
pdfData: ArrayBuffer;
@@ -35,14 +47,17 @@ interface TOCErrorResponse {
type TOCWorkerResponse = TOCSuccessResponse | TOCErrorResponse;
// Show status message
function showStatus(message: string, type: 'success' | 'error' | 'info' = 'info') {
function showStatus(
message: string,
type: 'success' | 'error' | 'info' = 'info'
) {
statusMessage.textContent = message;
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${
type === 'success'
? 'bg-green-900 text-green-200'
: type === 'error'
? 'bg-red-900 text-red-200'
: 'bg-blue-900 text-blue-200'
? 'bg-red-900 text-red-200'
: 'bg-blue-900 text-blue-200'
}`;
statusMessage.classList.remove('hidden');
}
@@ -52,6 +67,36 @@ function hideStatus() {
statusMessage.classList.add('hidden');
}
// Format bytes helper
function formatBytes(bytes: number): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}
// Render file display
function renderFileDisplay(file: File) {
fileDisplayArea.innerHTML = '';
fileDisplayArea.classList.remove('hidden');
const fileDiv = document.createElement('div');
fileDiv.className =
'flex items-center justify-between bg-gray-700 p-3 rounded-lg text-sm';
const nameSpan = document.createElement('span');
nameSpan.className = 'truncate font-medium text-gray-200';
nameSpan.textContent = file.name;
const sizeSpan = document.createElement('span');
sizeSpan.className = 'flex-shrink-0 ml-4 text-gray-400';
sizeSpan.textContent = formatBytes(file.size);
fileDiv.append(nameSpan, sizeSpan);
fileDisplayArea.appendChild(fileDiv);
}
// Handle file selection
function handleFileSelect(file: File) {
if (file.type !== 'application/pdf') {
@@ -61,6 +106,7 @@ function handleFileSelect(file: File) {
pdfFile = file;
generateBtn.disabled = false;
renderFileDisplay(file);
showStatus(`File selected: ${file.name}`, 'success');
}
@@ -103,7 +149,7 @@ async function generateTableOfContents() {
const arrayBuffer = await pdfFile.arrayBuffer();
showStatus('Offloading table of contents generation to background Worker...', 'info');
showStatus('Generating table of contents...', 'info');
const title = tocTitleInput.value || 'Table of Contents';
const fontSize = parseInt(fontSizeSelect.value, 10);
@@ -142,20 +188,24 @@ worker.onmessage = (e: MessageEvent<TOCWorkerResponse>) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = pdfFile?.name.replace('.pdf', '_with_toc.pdf') || 'output_with_toc.pdf';
a.download =
pdfFile?.name.replace('.pdf', '_with_toc.pdf') || 'output_with_toc.pdf';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showStatus('Table of contents generated successfully! Download started.', 'success');
showStatus(
'Table of contents generated successfully! Download started.',
'success'
);
setTimeout(() => {
hideStatus();
pdfFile = null;
fileInput.value = '';
generateBtn.disabled = true;
}, 3000);
hideStatus();
pdfFile = null;
fileInput.value = '';
fileDisplayArea.innerHTML = '';
fileDisplayArea.classList.add('hidden');
generateBtn.disabled = true;
} else if (e.data.status === 'error') {
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
console.error('Worker Error:', errorMessage);
@@ -169,4 +219,11 @@ worker.onerror = (error) => {
generateBtn.disabled = false;
};
generateBtn.addEventListener('click', generateTableOfContents);
// Back to tools button
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header';
});
}
generateBtn.addEventListener('click', generateTableOfContents);

View File

@@ -103,8 +103,15 @@
class="min-h-screen flex items-center justify-center p-4 bg-gray-900"
>
<div
class="bg-gray-900 rounded-xl shadow-xl p-8 max-w-md w-full text-gray-200"
class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-md w-full text-gray-200 border border-gray-700"
>
<button
id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold"
>
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<p class="text-gray-400 mb-6">
Upload a PDF to begin editing bookmarks
</p>
@@ -112,7 +119,7 @@
<!-- Drop Zone for Main PDF Upload -->
<div
id="drop-zone"
class="relative flex flex-col items-center justify-center w-full h-48 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
class="relative flex flex-col items-center justify-center w-full h-48 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-700 hover:bg-gray-600 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i
@@ -136,6 +143,9 @@
/>
</div>
<!-- File Display Area -->
<div id="file-display-area" class="mt-4 hidden"></div>
<!-- Auto Extract Checkbox -->
<div class="mt-4">
<label class="flex items-center gap-2 text-sm text-gray-300">
@@ -163,10 +173,7 @@
class="relative flex flex-col items-center justify-center w-full h-32 mt-2 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-4 pb-4">
<i
data-lucide="sheet"
class="w-8 h-8 mb-2 text-gray-400"
></i>
<i data-lucide="sheet" class="w-8 h-8 mb-2 text-gray-400"></i>
<p class="text-xs text-gray-400">
<span class="font-semibold">Click to upload CSV</span> or drag
here
@@ -207,7 +214,9 @@
</div>
<div id="app" class="hidden bg-gray-900 min-h-screen">
<header class="bg-gray-800 border-b border-gray-700 shadow-sm sticky top-0 z-50">
<header
class="bg-gray-800 border-b border-gray-700 shadow-sm sticky top-0 z-50"
>
<div class="max-w-7xl mx-auto px-4 py-3">
<div class="flex items-center justify-between flex-wrap gap-2">
<h1 class="text-xl font-bold text-white" id="filename-display">

View File

@@ -1,241 +1,369 @@
<!doctype html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate Table of Contents - BentoPDF</title>
<link rel="icon" type="image/png" href="../../images/favicon.svg" />
<link href="../../src/css/styles.css" rel="stylesheet" />
</head>
</head>
<body class="antialiased bg-gray-900">
<body class="antialiased bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 z-30">
<div class="container mx-auto px-4">
<div class="flex justify-between items-center h-16">
<div class="flex-shrink-0 flex items-center cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
</span>
</div>
<div class="container mx-auto px-4">
<div class="flex justify-between items-center h-16">
<div
class="flex-shrink-0 flex items-center cursor-pointer"
id="home-logo"
>
<img
src="../../public/images/favicon.svg"
alt="Bento PDF Logo"
class="h-8 w-8"
/>
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
</span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="../../index.html" class="nav-link">Home</a>
<a href="../../about.html" class="nav-link">About</a>
<a href="../../contact.html" class="nav-link">Contact</a>
<a href="../../index.html#tools-header" class="nav-link">All Tools</a>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="../../index.html" class="nav-link">Home</a>
<a href="../../about.html" class="nav-link">About</a>
<a href="../../contact.html" class="nav-link">Contact</a>
<a href="../../index.html#tools-header" class="nav-link"
>All Tools</a
>
</div>
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<!-- Hamburger Icon -->
<svg id="menu-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16" />
</svg>
<!-- Close Icon -->
<svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button
id="mobile-menu-button"
type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span class="sr-only">Open main menu</span>
<!-- Hamburger Icon -->
<svg
id="menu-icon"
class="block h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
<!-- Close Icon -->
<svg
id="close-icon"
class="hidden h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
</div>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="../../index.html" class="mobile-nav-link">Home</a>
<a href="../../about.html" class="mobile-nav-link">About</a>
<a href="../../contact.html" class="mobile-nav-link">Contact</a>
<a href="../../index.html#tools-header" class="mobile-nav-link">All Tools</a>
</div>
<!-- Mobile Menu Dropdown -->
<div
id="mobile-menu"
class="hidden md:hidden bg-gray-800 border-t border-gray-700"
>
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="../../index.html" class="mobile-nav-link">Home</a>
<a href="../../about.html" class="mobile-nav-link">About</a>
<a href="../../contact.html" class="mobile-nav-link">Contact</a>
<a href="../../index.html#tools-header" class="mobile-nav-link"
>All Tools</a
>
</div>
</div>
</nav>
<div id="uploader" class="min-h-screen flex items-center justify-center p-4 bg-gray-900">
<div class="bg-gray-900 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200">
<h1 class="text-2xl font-bold text-white mb-2">
Generate Table of Contents
</h1>
<p class="text-gray-400 mb-6">
Upload a PDF with bookmarks to generate a table of contents page
<div
id="uploader"
class="min-h-screen flex items-center justify-center p-4 bg-gray-900"
>
<div
class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200 border border-gray-700"
>
<button
id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold"
>
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<h1 class="text-2xl font-bold text-white mb-2">
Generate Table of Contents
</h1>
<p class="text-gray-400 mb-6">
Upload a PDF with bookmarks to generate a table of contents page
</p>
<!-- Drop Zone for Main PDF Upload -->
<div
id="drop-zone"
class="relative flex flex-col items-center justify-center w-full h-48 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-700 hover:bg-gray-600 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i
data-lucide="upload-cloud"
class="w-10 h-10 mb-3 text-gray-400"
></i>
<p class="mb-2 text-sm text-gray-300">
<span class="font-semibold">Click to select a file</span> or drag
and drop
</p>
<!-- Drop Zone for Main PDF Upload -->
<div id="drop-zone"
class="relative flex flex-col items-center justify-center w-full h-48 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i data-lucide="upload-cloud" class="w-10 h-10 mb-3 text-gray-400"></i>
<p class="mb-2 text-sm text-gray-300">
<span class="font-semibold">Click to select a file</span> or drag
and drop
</p>
<p class="text-xs text-gray-500">A single PDF file</p>
<p class="text-xs text-gray-500">
Your files never leave your device.
</p>
</div>
<input type="file" id="file-input" accept=".pdf"
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
</div>
<!-- Options Section -->
<div class="mt-6 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
TOC Title
</label>
<input type="text" id="toc-title" value="Table of Contents"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Table of Contents" />
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
Font Size
</label>
<select id="font-size"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="10">10pt</option>
<option value="11">11pt</option>
<option value="12" selected>12pt</option>
<option value="14">14pt</option>
<option value="16">16pt</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
Font Family
</label>
<select id="font-family"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="0">Times Roman</option>
<option value="1">Times Bold</option>
<option value="2">Times Italic</option>
<option value="3">Times Bold Italic</option>
<option value="4" selected>Helvetica</option>
<option value="5">Helvetica Bold</option>
<option value="6">Helvetica Oblique</option>
<option value="7">Helvetica Bold Oblique</option>
<option value="8">Courier</option>
<option value="9">Courier Bold</option>
<option value="10">Courier Oblique</option>
<option value="11">Courier Bold Oblique</option>
</select>
</div>
<div class="flex items-center gap-2">
<input type="checkbox" id="add-bookmark" checked class="w-4 h-4 accent-blue-500" />
<label for="add-bookmark" class="text-sm text-gray-300">
Add bookmark for TOC page
</label>
</div>
</div>
<!-- Generate Button -->
<button id="generate-btn" disabled
class="mt-6 w-full px-4 py-3 bg-gradient-to-b from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 disabled:from-gray-600 disabled:to-gray-700 disabled:cursor-not-allowed text-white rounded-lg font-medium flex items-center justify-center gap-2 focus:ring-2 focus:ring-blue-400 transition duration-200">
<i data-lucide="file-text" class="w-5 h-5"></i>
<span>Generate Table of Contents</span>
</button>
<!-- Status Message -->
<div id="status-message" class="mt-4 hidden p-3 rounded-lg text-sm"></div>
<p class="text-xs text-gray-500">A single PDF file</p>
<p class="text-xs text-gray-500">
Your files never leave your device.
</p>
</div>
<input
type="file"
id="file-input"
accept=".pdf"
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/>
</div>
<!-- File Display Area -->
<div id="file-display-area" class="mt-4 hidden"></div>
<!-- Options Section -->
<div class="mt-6 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
TOC Title
</label>
<input
type="text"
id="toc-title"
value="Table of Contents"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Table of Contents"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
Font Size
</label>
<select
id="font-size"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="10">10pt</option>
<option value="11">11pt</option>
<option value="12" selected>12pt</option>
<option value="14">14pt</option>
<option value="16">16pt</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-2">
Font Family
</label>
<select
id="font-family"
class="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="0">Times Roman</option>
<option value="1">Times Bold</option>
<option value="2">Times Italic</option>
<option value="3">Times Bold Italic</option>
<option value="4" selected>Helvetica</option>
<option value="5">Helvetica Bold</option>
<option value="6">Helvetica Oblique</option>
<option value="7">Helvetica Bold Oblique</option>
<option value="8">Courier</option>
<option value="9">Courier Bold</option>
<option value="10">Courier Oblique</option>
<option value="11">Courier Bold Oblique</option>
</select>
</div>
<div class="flex items-center gap-2">
<input
type="checkbox"
id="add-bookmark"
checked
class="w-4 h-4 accent-blue-500"
/>
<label for="add-bookmark" class="text-sm text-gray-300">
Add bookmark for TOC page
</label>
</div>
</div>
<!-- Generate Button -->
<button id="generate-btn" disabled class="btn-gradient w-full mt-6">
<span id="generate-btn-text">Generate Table of Contents</span>
</button>
<!-- Status Message -->
<div
id="status-message"
class="mt-4 hidden p-3 rounded-lg text-sm"
></div>
</div>
</div>
<footer class="mt-16 border-t-2 border-gray-700 py-8 bg-[#111827]">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8 text-center md:text-left">
<div class="mb-8 md:mb-0">
<div class="flex items-center justify-center md:justify-start mb-4">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-10 w-10 mr-3" />
<span class="text-xl font-bold text-white">BentoPDF</span>
</div>
<p class="text-gray-400 text-sm">
&copy; 2025 BentoPDF. All rights reserved.
</p>
</div>
<div>
<h3 class="font-bold text-white mb-4">Company</h3>
<ul class="space-y-2 text-gray-400">
<li>
<a href="../../about.html" class="hover:text-indigo-400">About Us</a>
</li>
<li>
<a href="../../faq.html" class="hover:text-indigo-400">FAQ</a>
</li>
<li>
<a href="../../contact.html" class="hover:text-indigo-400">Contact Us</a>
</li>
</ul>
</div>
<div>
<h3 class="font-bold text-white mb-4">Legal</h3>
<ul class="space-y-2 text-gray-400">
<li>
<a href="../../terms.html" class="hover:text-indigo-400">Terms and Conditions</a>
</li>
<li>
<a href="../../privacy.html" class="hover:text-indigo-400">Privacy Policy</a>
</li>
</ul>
</div>
<div>
<h3 class="font-bold text-white mb-4">Follow Us</h3>
<div class="flex justify-center md:justify-start space-x-4">
<a href="https://github.com/alam00000/bentopdf" target="_blank" rel="noopener noreferrer"
class="text-gray-400 hover:text-indigo-400" title="GitHub">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path fill-rule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clip-rule="evenodd" />
</svg>
</a>
<a href="https://discord.gg/q42xWQmJ" target="_blank" rel="noopener noreferrer"
class="text-gray-400 hover:text-indigo-400" title="Discord">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path
d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z" />
</svg>
</a>
<a href="https://www.instagram.com/thebentopdf/" class="text-gray-400 hover:text-indigo-400"
title="Instagram">
<i data-lucide="instagram"></i>
</a>
<a href="https://www.linkedin.com/company/bentopdf/" class="text-gray-400 hover:text-indigo-400"
title="LinkedIn">
<i data-lucide="linkedin"></i>
</a>
<a href="https://x.com/BentoPDF" class="text-gray-400 hover:text-indigo-400"
title="X (Twitter)">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
</a>
</div>
</div>
<div class="container mx-auto px-4">
<div
class="grid grid-cols-1 md:grid-cols-4 gap-8 text-center md:text-left"
>
<div class="mb-8 md:mb-0">
<div class="flex items-center justify-center md:justify-start mb-4">
<img
src="../../public/images/favicon.svg"
alt="Bento PDF Logo"
class="h-10 w-10 mr-3"
/>
<span class="text-xl font-bold text-white">BentoPDF</span>
</div>
<p class="text-gray-400 text-sm">
&copy; 2025 BentoPDF. All rights reserved.
</p>
</div>
<div>
<h3 class="font-bold text-white mb-4">Company</h3>
<ul class="space-y-2 text-gray-400">
<li>
<a href="../../about.html" class="hover:text-indigo-400"
>About Us</a
>
</li>
<li>
<a href="../../faq.html" class="hover:text-indigo-400">FAQ</a>
</li>
<li>
<a href="../../contact.html" class="hover:text-indigo-400"
>Contact Us</a
>
</li>
</ul>
</div>
<div>
<h3 class="font-bold text-white mb-4">Legal</h3>
<ul class="space-y-2 text-gray-400">
<li>
<a href="../../terms.html" class="hover:text-indigo-400"
>Terms and Conditions</a
>
</li>
<li>
<a href="../../privacy.html" class="hover:text-indigo-400"
>Privacy Policy</a
>
</li>
</ul>
</div>
<div>
<h3 class="font-bold text-white mb-4">Follow Us</h3>
<div class="flex justify-center md:justify-start space-x-4">
<a
href="https://github.com/alam00000/bentopdf"
target="_blank"
rel="noopener noreferrer"
class="text-gray-400 hover:text-indigo-400"
title="GitHub"
>
<svg
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
clip-rule="evenodd"
/>
</svg>
</a>
<a
href="https://discord.gg/q42xWQmJ"
target="_blank"
rel="noopener noreferrer"
class="text-gray-400 hover:text-indigo-400"
title="Discord"
>
<svg
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"
/>
</svg>
</a>
<a
href="https://www.instagram.com/thebentopdf/"
class="text-gray-400 hover:text-indigo-400"
title="Instagram"
>
<i data-lucide="instagram"></i>
</a>
<a
href="https://www.linkedin.com/company/bentopdf/"
class="text-gray-400 hover:text-indigo-400"
title="LinkedIn"
>
<i data-lucide="linkedin"></i>
</a>
<a
href="https://x.com/BentoPDF"
class="text-gray-400 hover:text-indigo-400"
title="X (Twitter)"
>
<svg
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
/>
</svg>
</a>
</div>
</div>
</div>
</div>
</footer>
<script type="module" src="../js/utils/lucide-init.ts"></script>
<script type="module" src="../js/logic/table-of-contents.ts"></script>
<script type="module" src="../js/mobileMenu.ts"></script>
</body>
</html>
</body>
</html>

View File

@@ -19,8 +19,37 @@ declare global {
// --- Type Aliases from Constants ---
type CpdfPermission = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
type CpdfEncryptionMethod = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
type CpdfPaperSize = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
type CpdfPositionAnchor = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
type CpdfPaperSize =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15;
type CpdfPositionAnchor =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12;
type CpdfFont = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;
type CpdfJustification = 0 | 1 | 2;
type CpdfLayout = 0 | 1 | 2 | 3 | 4 | 5;
@@ -36,25 +65,25 @@ declare const coherentpdf: {
* @returns The version number.
*/
version(): string;
/**
* Sets the global operation mode to 'fast'. The default is 'slow' mode, which works
* even on old-fashioned files.
*/
setFast(): void;
/**
* Sets the global operation mode to 'slow'. The default is 'slow' mode, which works
* even on old-fashioned files.
*/
setSlow(): void;
/**
* Delete a PDF so the memory representing it may be recovered. Must be called for every loaded PDF.
* @param pdf PDF document to delete.
*/
deletePdf(pdf: CoherentPdf): void;
/**
* A debug function which prints some information about resource usage.
* Can be used to detect if PDFs or ranges are being deallocated properly.
@@ -69,7 +98,7 @@ declare const coherentpdf: {
* @returns The loaded PDF document instance.
*/
fromFile(filename: string, userpw: string): CoherentPdf;
/**
* Loads a PDF from a file, doing only minimal parsing (lazily).
* @param filename File name.
@@ -77,7 +106,7 @@ declare const coherentpdf: {
* @returns The loaded PDF document instance.
*/
fromFileLazy(filename: string, userpw: string): CoherentPdf;
/**
* Loads a file from memory given any user password.
* @param data PDF document as an array of bytes.
@@ -85,7 +114,7 @@ declare const coherentpdf: {
* @returns The loaded PDF document instance.
*/
fromMemory(data: Uint8Array, userpw: string): CoherentPdf;
/**
* Loads a file from memory, but lazily (minimal parsing).
* @param data PDF document as an array of bytes.
@@ -93,7 +122,7 @@ declare const coherentpdf: {
* @returns The loaded PDF document instance.
*/
fromMemoryLazy(data: Uint8Array, userpw: string): CoherentPdf;
/**
* Writes the PDF document to memory as a byte array.
* @param pdf The PDF document.
@@ -102,7 +131,7 @@ declare const coherentpdf: {
* @returns The PDF document as a byte array.
*/
toMemory(pdf: CoherentPdf, linearize: boolean, make_id: boolean): Uint8Array;
/**
* Returns the total number of pages in the PDF document.
* @param pdf The PDF document.
@@ -116,20 +145,20 @@ declare const coherentpdf: {
* @param pdf The PDF document.
*/
startGetBookmarkInfo(pdf: CoherentPdf): void;
/**
* Gets the total number of bookmarks available after calling `startGetBookmarkInfo`.
* @returns The number of bookmarks.
*/
numberBookmarks(): number;
/**
* Gets the nesting level (0-based) for the bookmark at index `n`.
* @param n The bookmark index (0-based).
* @returns The bookmark level.
*/
getBookmarkLevel(n: number): number;
/**
* Gets the target page number (1-based) for the bookmark at index `n`.
* @param pdf The PDF document.
@@ -137,21 +166,21 @@ declare const coherentpdf: {
* @returns The target page number.
*/
getBookmarkPage(pdf: CoherentPdf, n: number): number;
/**
* Returns the text title of the bookmark at index `n`.
* @param n The bookmark index (0-based).
* @returns The bookmark text.
*/
getBookmarkText(n: number): string;
/**
* Returns the open/closed status for the bookmark at index `n`.
* @param n The bookmark index (0-based).
* @returns True if the bookmark is open.
*/
getBookmarkOpenStatus(n: number): boolean;
/**
* Ends the bookmark retrieval process and cleans up resources.
*/
@@ -165,7 +194,13 @@ declare const coherentpdf: {
* @param title The title for the TOC page.
* @param bookmark If true, the TOC page itself gets a bookmark.
*/
tableOfContents(pdf: CoherentPdf, font: CpdfFont, fontsize: number, title: string, bookmark: boolean): void;
tableOfContents(
pdf: CoherentPdf,
font: CpdfFont,
fontsize: number,
title: string,
bookmark: boolean
): void;
/** Times Roman font constant (0) */
readonly timesRoman: CpdfFont;
@@ -194,4 +229,3 @@ declare const coherentpdf: {
};
export { coherentpdf };