mirror of
https://github.com/documenso/documenso.git
synced 2026-07-14 23:07:13 +10:00
fix: add client side pdf render
This commit is contained in:
@@ -9,7 +9,7 @@ import { useFormContext } from 'react-hook-form';
|
||||
|
||||
import { APP_DOCUMENT_UPLOAD_SIZE_LIMIT } from '@documenso/lib/constants/app';
|
||||
import { PDF_IMAGE_RENDER_SCALE } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { pdfToImages } from '@documenso/lib/server-only/ai/pdf-to-images';
|
||||
import { pdfToImagesClientSide } from '@documenso/lib/server-only/ai/pdf-to-images.client';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@@ -54,7 +54,7 @@ export const ConfigureDocumentUpload = ({ isSubmitting = false }: ConfigureDocum
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
const pdfImages = await pdfToImages(uint8Array, {
|
||||
const pdfImages = await pdfToImagesClientSide(uint8Array, {
|
||||
scale: PDF_IMAGE_RENDER_SCALE,
|
||||
});
|
||||
|
||||
@@ -64,11 +64,7 @@ export const ConfigureDocumentUpload = ({ isSubmitting = false }: ConfigureDocum
|
||||
type: file.type,
|
||||
size: file.size,
|
||||
data: uint8Array, // Store as UInt8Array
|
||||
images: pdfImages.map((image) => ({
|
||||
width: image.originalWidth,
|
||||
height: image.originalHeight,
|
||||
image: image.image,
|
||||
})),
|
||||
images: pdfImages,
|
||||
});
|
||||
|
||||
// Auto-populate title if it's empty
|
||||
|
||||
@@ -50,7 +50,7 @@ export const ZConfigureEmbedFormSchema = z.object({
|
||||
.object({
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
image: z.instanceof(Buffer),
|
||||
image: z.string(),
|
||||
})
|
||||
.array(),
|
||||
})
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import pMap from 'p-map';
|
||||
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/legacy/build/pdf.worker.min.mjs',
|
||||
import.meta.url,
|
||||
).toString();
|
||||
|
||||
export type PdfToImagesOptions = {
|
||||
scale?: number;
|
||||
};
|
||||
|
||||
export type PdfImageResult = {
|
||||
pageIndex: number;
|
||||
image: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export const pdfToImagesClientSide = async (
|
||||
pdfBytes: Uint8Array,
|
||||
options: PdfToImagesOptions = {},
|
||||
): Promise<PdfImageResult[]> => {
|
||||
const { scale = 2 } = options;
|
||||
|
||||
const task = pdfjsLib.getDocument({
|
||||
data: pdfBytes,
|
||||
});
|
||||
|
||||
const pdf = await task.promise;
|
||||
|
||||
const images = await pMap(
|
||||
Array.from({ length: pdf.numPages }),
|
||||
async (_, pageIndex) => {
|
||||
const pageNumber = pageIndex + 1;
|
||||
const page = await pdf.getPage(pageNumber);
|
||||
|
||||
const viewport = page.getViewport({ scale });
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = Math.floor(viewport.width);
|
||||
canvas.height = Math.floor(viewport.height);
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
throw new Error('Failed to get 2D canvas context');
|
||||
}
|
||||
|
||||
await page.render({
|
||||
canvasContext: context,
|
||||
viewport,
|
||||
canvas,
|
||||
}).promise;
|
||||
|
||||
const imageBase64 = canvas.toDataURL('image/jpeg');
|
||||
|
||||
page.cleanup();
|
||||
|
||||
return {
|
||||
pageIndex,
|
||||
image: imageBase64,
|
||||
width: canvas.width,
|
||||
height: canvas.height,
|
||||
};
|
||||
},
|
||||
{ concurrency: 50 },
|
||||
);
|
||||
|
||||
await pdf.destroy();
|
||||
await task.destroy();
|
||||
|
||||
return images;
|
||||
};
|
||||
@@ -19,7 +19,7 @@ import { useVirtualList } from '../virtual-list/use-virtual-list';
|
||||
import { PdfViewerErrorState, PdfViewerLoadingState } from './pdf-viewer-states';
|
||||
|
||||
export type OverrideImage = {
|
||||
image: Buffer;
|
||||
image: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
@@ -78,7 +78,7 @@ export const PDFViewer = ({
|
||||
const derivedPages = useMemo((): PageMeta[] => {
|
||||
if (overrideImages) {
|
||||
return overrideImages.map((image) => ({
|
||||
imageUrl: `data:image/jpeg;base64,${image.image.toString('base64')}`,
|
||||
imageUrl: image.image,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
documentDataId: '',
|
||||
|
||||
Reference in New Issue
Block a user