mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-15 19:10:47 +02:00
Ground work for page editor
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { getDocument } from 'pdfjs-dist';
|
||||
import { PDFDocument, PDFPage } from '../types/pageEditor';
|
||||
|
||||
export function usePDFProcessor() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const generatePageThumbnail = useCallback(async (
|
||||
file: File,
|
||||
pageNumber: number,
|
||||
scale: number = 0.5
|
||||
): Promise<string> => {
|
||||
try {
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const pdf = await getDocument({ data: arrayBuffer }).promise;
|
||||
const page = await pdf.getPage(pageNumber);
|
||||
|
||||
const viewport = page.getViewport({ scale });
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
throw new Error('Could not get canvas context');
|
||||
}
|
||||
|
||||
await page.render({ canvasContext: context, viewport }).promise;
|
||||
const thumbnail = canvas.toDataURL();
|
||||
|
||||
// Clean up
|
||||
pdf.destroy();
|
||||
|
||||
return thumbnail;
|
||||
} catch (error) {
|
||||
console.error('Failed to generate thumbnail:', error);
|
||||
throw error;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const processPDFFile = useCallback(async (file: File): Promise<PDFDocument> => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const pdf = await getDocument({ data: arrayBuffer }).promise;
|
||||
const totalPages = pdf.numPages;
|
||||
|
||||
const pages: PDFPage[] = [];
|
||||
|
||||
// Generate thumbnails for all pages
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const thumbnail = await generatePageThumbnail(file, i);
|
||||
pages.push({
|
||||
id: `${file.name}-page-${i}`,
|
||||
pageNumber: i,
|
||||
thumbnail,
|
||||
rotation: 0,
|
||||
selected: false
|
||||
});
|
||||
}
|
||||
|
||||
// Clean up
|
||||
pdf.destroy();
|
||||
|
||||
const document: PDFDocument = {
|
||||
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
||||
name: file.name,
|
||||
file,
|
||||
pages,
|
||||
totalPages
|
||||
};
|
||||
|
||||
return document;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to process PDF';
|
||||
setError(errorMessage);
|
||||
throw error;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [generatePageThumbnail]);
|
||||
|
||||
return {
|
||||
processPDFFile,
|
||||
generatePageThumbnail,
|
||||
loading,
|
||||
error
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
export interface Command {
|
||||
execute(): void;
|
||||
undo(): void;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface CommandSequence {
|
||||
commands: Command[];
|
||||
execute(): void;
|
||||
undo(): void;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export function useUndoRedo() {
|
||||
const [undoStack, setUndoStack] = useState<(Command | CommandSequence)[]>([]);
|
||||
const [redoStack, setRedoStack] = useState<(Command | CommandSequence)[]>([]);
|
||||
|
||||
const executeCommand = useCallback((command: Command | CommandSequence) => {
|
||||
command.execute();
|
||||
setUndoStack(prev => [command, ...prev]);
|
||||
setRedoStack([]); // Clear redo stack when new command is executed
|
||||
}, []);
|
||||
|
||||
const undo = useCallback(() => {
|
||||
if (undoStack.length === 0) return false;
|
||||
|
||||
const command = undoStack[0];
|
||||
command.undo();
|
||||
|
||||
setUndoStack(prev => prev.slice(1));
|
||||
setRedoStack(prev => [command, ...prev]);
|
||||
|
||||
return true;
|
||||
}, [undoStack]);
|
||||
|
||||
const redo = useCallback(() => {
|
||||
if (redoStack.length === 0) return false;
|
||||
|
||||
const command = redoStack[0];
|
||||
command.execute();
|
||||
|
||||
setRedoStack(prev => prev.slice(1));
|
||||
setUndoStack(prev => [command, ...prev]);
|
||||
|
||||
return true;
|
||||
}, [redoStack]);
|
||||
|
||||
const clear = useCallback(() => {
|
||||
setUndoStack([]);
|
||||
setRedoStack([]);
|
||||
}, []);
|
||||
|
||||
const canUndo = undoStack.length > 0;
|
||||
const canRedo = redoStack.length > 0;
|
||||
|
||||
return {
|
||||
executeCommand,
|
||||
undo,
|
||||
redo,
|
||||
clear,
|
||||
canUndo,
|
||||
canRedo,
|
||||
undoStack,
|
||||
redoStack
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user