You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中将PDF缩放至Canvas的宽高尺寸?

解决PDF预览无法占满Canvas的问题

问题分析

你的代码存在三个核心问题导致PDF无法占满Canvas:

  • useEffect 依赖数组为空,容器尺寸或PDF文件变化时不会重新渲染预览
  • 渲染PDF时未对内容做居中对齐,留白集中在一侧,视觉上显得未占满
  • Canvas的显示样式未与实际画布尺寸绑定,可能出现尺寸不匹配的情况

修复方案

1. 更新ImagePreview组件代码

以下提供两种适配模式,按需选择:

模式一:保持比例居中显示(无裁剪,完整展示PDF)

这种模式下PDF会完整显示,空白均匀分布在Canvas两侧:

function ImagePreview({ pdf, containerWidth, containerHeight }) {
    const canvasRef = useRef(null);

    useEffect(() => {
        async function init() {
            try {
                const canvas = canvasRef.current;
                if (!canvas) return;
                const ctx = canvas.getContext("2d");
                const uid = await getUserId();
                const publicUrl = await supabase.storage.from("pdf-documents").getPublicUrl(uid + "/" + pdf.name).data.publicUrl;

                // 重置画布内容
                ctx.clearRect(0, 0, canvas.width, canvas.height);

                const pdfDoc = await pdfjsLib.getDocument(publicUrl).promise;
                const page = await pdfDoc.getPage(1);
                
                const viewport = page.getViewport({ scale: 1 });
                const canvasWidth = containerWidth;
                const canvasHeight = containerHeight;
                
                // 计算缩放比例(保持PDF比例,适配画布最小边)
                const scaleX = canvasWidth / viewport.width;
                const scaleY = canvasHeight / viewport.height;
                const scale = Math.min(scaleX, scaleY);
                const newViewport = page.getViewport({ scale });

                // 设置画布实际像素尺寸
                canvas.width = canvasWidth;
                canvas.height = canvasHeight;

                // 计算居中偏移量,让PDF在画布中居中
                const offsetX = (canvasWidth - newViewport.width) / 2;
                const offsetY = (canvasHeight - newViewport.height) / 2;

                // 平移画布上下文,实现居中渲染
                ctx.translate(offsetX, offsetY);
                await page.render({
                    canvasContext: ctx,
                    viewport: newViewport,
                }).promise;
                // 恢复上下文初始状态
                ctx.translate(-offsetX, -offsetY);
            } catch (error) {
                console.log(error);
            }
        }

        init();
    }, [pdf, containerWidth, containerHeight]); // 添加依赖,参数变化时自动重新渲染

    return (
        <div>
            {/* 绑定Canvas显示样式与实际尺寸,消除默认间距 */}
            <canvas 
                ref={canvasRef} 
                style={{ 
                    width: `${containerWidth}px`, 
                    height: `${containerHeight}px`,
                    display: "block"
                }} 
            />
        </div>
    );
}

模式二:铺满Canvas显示(裁剪超出部分,完全占满画布)

这种模式下PDF会填满整个Canvas,超出画布的部分会被裁剪:
仅需修改缩放比例和偏移量计算部分,其余代码与模式一一致:

// ...其他代码不变
// 计算缩放比例(保持PDF比例,覆盖画布最大边)
const scaleX = canvasWidth / viewport.width;
const scaleY = canvasHeight / viewport.height;
const scale = Math.max(scaleX, scaleY);
const newViewport = page.getViewport({ scale });

// 计算居中裁剪的偏移量
const offsetX = (canvasWidth - newViewport.width) / 2;
const offsetY = (canvasHeight - newViewport.height) / 2;
// ...其他代码不变

2. 优化父容器样式

为父div添加overflow: hidden(适配模式二的裁剪需求),并确保容器尺寸与传入的参数一致:

{documents.map((doc) => {
    return (
        <div 
            key={doc.id} 
            className="border-solid border-2 border-sky-500 overflow-hidden"
            style={{ width: `${110}px`, height: `${130}px` }}
        >
            <ImagePreview pdf={doc} containerHeight={130} containerWidth={110}/>
        </div>
    );
})}

内容的提问来源于stack exchange,提问作者neil_ruaro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 06:37:49