pdfRenderService.ts 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import * as pdfjs from 'pdfjs-dist';
  2. // Set worker path - using a CDN for the worker to avoid complex vite configuration for now
  3. // or we can try to use the bundled worker if vite handles it
  4. pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
  5. export const pdfRenderService = {
  6. async renderPageToCanvas(
  7. pdfData: Blob | ArrayBuffer,
  8. pageNumber: number,
  9. canvas: HTMLCanvasElement,
  10. targetWidth: number,
  11. targetHeight: number
  12. ): Promise<void> {
  13. const data = pdfData instanceof Blob ? await pdfData.arrayBuffer() : pdfData;
  14. const loadingTask = pdfjs.getDocument({ data });
  15. const pdf = await loadingTask.promise;
  16. if (pageNumber < 1 || pageNumber > pdf.numPages) {
  17. throw new Error(`Invalid page number: ${pageNumber}.`);
  18. }
  19. const page = await pdf.getPage(pageNumber);
  20. // Calculate scale to fit container while maintaining aspect ratio
  21. const unscaledViewport = page.getViewport({ scale: 1 });
  22. // Calculate the scale needed to fit the PDF page within the target dimensions
  23. const fitScale = Math.min(targetWidth / unscaledViewport.width, targetHeight / unscaledViewport.height);
  24. // Calculate a higher scale for rendering quality (anti-aliasing and clarity)
  25. const devicePixelRatio = window.devicePixelRatio || 1;
  26. const renderScale = fitScale * Math.max(2, devicePixelRatio);
  27. const viewport = page.getViewport({ scale: renderScale });
  28. // Set canvas to the high-resolution dimensions to maintain quality
  29. canvas.width = viewport.width;
  30. canvas.height = viewport.height;
  31. const context = canvas.getContext('2d');
  32. if (!context) return;
  33. // Save the context state before any transformations
  34. context.save();
  35. // Fill background
  36. context.fillStyle = '#f8fafc';
  37. context.fillRect(0, 0, canvas.width, canvas.height);
  38. // Calculate the position to center the PDF page in the canvas
  39. const offsetX = (canvas.width - viewport.width) / 2;
  40. const offsetY = (canvas.height - viewport.height) / 2;
  41. await page.render({
  42. canvasContext: context,
  43. viewport: viewport,
  44. transform: [1, 0, 0, 1, offsetX, offsetY]
  45. }).promise;
  46. // Restore the context state after rendering
  47. context.restore();
  48. }
  49. };