141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import { PDFDocument, degrees } from 'pdf-lib';
|
|
import type { PdfFile, SplitResult, Range } from './pdfTypes';
|
|
|
|
function createId() {
|
|
return Math.random().toString(36).slice(2);
|
|
}
|
|
|
|
export async function loadPdfFromFile(file: File): Promise<PdfFile> {
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const doc = await PDFDocument.load(arrayBuffer);
|
|
|
|
return {
|
|
id: createId(),
|
|
name: file.name,
|
|
doc,
|
|
pageCount: doc.getPageCount(),
|
|
arrayBuffer,
|
|
};
|
|
}
|
|
|
|
export async function splitIntoSinglePages(
|
|
pdf: PdfFile
|
|
): Promise<SplitResult[]> {
|
|
const { doc, name } = pdf;
|
|
|
|
const title = doc.getTitle();
|
|
const author = doc.getAuthor();
|
|
const subject = doc.getSubject();
|
|
const keywords = doc.getKeywords();
|
|
const producer = doc.getProducer();
|
|
const creator = doc.getCreator();
|
|
const creationDate = doc.getCreationDate();
|
|
const modificationDate = doc.getModificationDate();
|
|
|
|
const results: SplitResult[] = [];
|
|
|
|
for (let i = 0; i < doc.getPageCount(); i++) {
|
|
const newDoc = await PDFDocument.create();
|
|
const [copiedPage] = await newDoc.copyPages(doc, [i]);
|
|
newDoc.addPage(copiedPage);
|
|
|
|
if (title) newDoc.setTitle(title);
|
|
if (author) newDoc.setAuthor(author);
|
|
if (subject) newDoc.setSubject(subject);
|
|
if (keywords) newDoc.setKeywords(keywords);
|
|
if (producer) newDoc.setProducer(producer);
|
|
if (creator) newDoc.setCreator(creator);
|
|
if (creationDate) newDoc.setCreationDate(creationDate);
|
|
if (modificationDate) newDoc.setModificationDate(modificationDate);
|
|
|
|
const bytes = await newDoc.save();
|
|
const blob = new Blob([bytes], { type: 'application/pdf' });
|
|
|
|
const base = name.replace(/\.pdf$/i, '');
|
|
const filename = `${base}_page_${String(i + 1).padStart(3, '0')}.pdf`;
|
|
|
|
results.push({
|
|
pageIndex: i,
|
|
blob,
|
|
filename,
|
|
});
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
export async function extractRange(
|
|
pdf: PdfFile,
|
|
range: Range
|
|
): Promise<Blob> {
|
|
const { doc } = pdf;
|
|
const pageCount = doc.getPageCount();
|
|
|
|
const fromIndex = Math.max(0, range.from - 1);
|
|
const toIndex = Math.min(pageCount - 1, range.to - 1);
|
|
|
|
if (fromIndex > toIndex) {
|
|
throw new Error('Invalid range: from > to');
|
|
}
|
|
|
|
const newDoc = await PDFDocument.create();
|
|
const indices: number[] = [];
|
|
for (let i = fromIndex; i <= toIndex; i++) indices.push(i);
|
|
|
|
const copiedPages = await newDoc.copyPages(doc, indices);
|
|
copiedPages.forEach((p) => newDoc.addPage(p));
|
|
|
|
const bytes = await newDoc.save();
|
|
return new Blob([bytes], { type: 'application/pdf' });
|
|
}
|
|
|
|
export async function mergePdfs(pdfs: PdfFile[]): Promise<Blob> {
|
|
const newDoc = await PDFDocument.create();
|
|
|
|
for (const pdf of pdfs) {
|
|
const pageCount = pdf.doc.getPageCount();
|
|
const indices = Array.from({ length: pageCount }, (_, i) => i);
|
|
const copiedPages = await newDoc.copyPages(pdf.doc, indices);
|
|
copiedPages.forEach((p) => newDoc.addPage(p));
|
|
}
|
|
|
|
const bytes = await newDoc.save();
|
|
return new Blob([bytes], { type: 'application/pdf' });
|
|
}
|
|
|
|
export async function exportReordered(
|
|
pdf: PdfFile,
|
|
order: number[],
|
|
rotations?: Record<number, number>
|
|
): Promise<Blob> {
|
|
const { doc } = pdf;
|
|
const pageCount = doc.getPageCount();
|
|
|
|
if (order.length === 0) {
|
|
throw new Error('Order must contain at least one page');
|
|
}
|
|
|
|
if (order.some((i) => i < 0 || i >= pageCount)) {
|
|
throw new Error('Order contains invalid page indices');
|
|
}
|
|
|
|
const newDoc = await PDFDocument.create();
|
|
const indices = [...order];
|
|
|
|
const copiedPages = await newDoc.copyPages(doc, indices);
|
|
|
|
copiedPages.forEach((page, idx) => {
|
|
const originalIndex = indices[idx];
|
|
const angle = rotations?.[originalIndex];
|
|
|
|
if (typeof angle === 'number' && angle % 360 !== 0) {
|
|
page.setRotation(degrees(angle));
|
|
}
|
|
|
|
newDoc.addPage(page);
|
|
});
|
|
|
|
const bytes = await newDoc.save();
|
|
return new Blob([bytes], { type: 'application/pdf' });
|
|
}
|