使用jsPDF和html2canvas无法打印带CSS滤镜的图片
问题根源
html2canvas 对 CSS filter: grayscale() 的支持存在局限性,Tailwind 的 grayscale 类本质就是这个CSS属性,当你用html2canvas捕获DOM时,它可能无法正确解析并应用这个滤镜效果,导致生成的canvas还是彩色,最终PDF里的图片自然也保持彩色。
解决方法
下面提供几种可行的修复方案,按推荐程度排序:
方案1:生成Canvas后手动灰度化
在html2canvas生成canvas之后,通过Canvas API直接修改像素数据,将图片转为灰度。这种方法不需要修改原DOM结构,直接处理最终的canvas即可。
修改你的handlePrint函数:
const handlePrint = async () => { const grid = document.getElementById('image-grid'); const canvas = await html2canvas(grid); // 手动处理灰度化 const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; for (let i = 0; i < data.length; i += 4) { // 计算标准灰度值:Y = 0.299*R + 0.587*G + 0.114*B const gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114; data[i] = gray; // 红色通道 data[i + 1] = gray; // 绿色通道 data[i + 2] = gray; // 蓝色通道 // alpha通道保持不变 } ctx.putImageData(imageData, 0, 0); const imgData = canvas.toDataURL('image/png'); // 后续PDF生成代码保持不变 const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgWidth = pdfWidth; const imgHeight = (canvas.height * imgWidth) / canvas.width; const spaceForText = imgHeight; const adjustedImgHeight = imgHeight - spaceForText; const x = 0; const y = (pdfHeight - adjustedImgHeight) / 2; pdf.addImage(imgData, 'PNG', 20, 20, 555, 555); const text = "Your Text Here"; const textHeight = 12; const textY = (pdfHeight + adjustedImgHeight) / 2 + 20; const textWidth = pdf.getTextWidth(text); const centerX = (pdfWidth - textWidth) / 2; pdf.setFont("Helvetica", "normal"); pdf.setFontSize(25); pdf.text(text, centerX - 10, 650); pdf.autoPrint(); window.open(pdf.output('bloburl')); };
方案2:提前将图片转为灰度图再渲染
在组件加载图片时,先通过Canvas将图片转为灰度格式,替换原图片的src,这样html2canvas捕获的DOM本身就是灰度图,自然能生成正确的PDF。
修改你的ImagePreviewModal组件:
const ImagePreviewModal = ({ selectedImages }) => { const [items, setItems] = useState([]); useEffect(() => { const convertToGrayscale = async (imageSrc) => { return new Promise((resolve) => { const img = new Image(); img.crossOrigin = 'anonymous'; // 处理跨域图片,同域图片可移除该行 img.src = imageSrc; img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); // 绘制原图并应用灰度滤镜 ctx.filter = 'grayscale(100%)'; ctx.drawImage(img, 0, 0); resolve(canvas.toDataURL('image/png')); }; }); }; const processImages = async () => { const processed = await Promise.all( selectedImages.map(async (img) => ({ ...img, imageSrc: await convertToGrayscale(img.imageSrc) })) ); setItems(processed); }; processImages(); }, [selectedImages]); return ( <div id="image-grid"> {items.map((image, index) => ( <div className="w-full h-auto "> <div className='grid grid-cols-2 gap-3 my-1 px-7 py-4 rounded-md '> <img src={image.imageSrc} alt={`Selected ${index + 1}`} className="w-full h-auto rounded-sm border border-white" /> <img src={image.imageSrc} alt={`Selected ${index + 2}`} className="w-full h-auto rounded-sm border border-white" /> </div> </div> ))} </div> ); };
方案3:配置html2canvas支持CSS滤镜
部分较新版本的html2canvas支持通过配置项启用滤镜解析,你可以尝试在调用html2canvas时添加如下配置:
const canvas = await html2canvas(grid, { useCORS: true, allowTaint: true, logging: true // 可选,用于调试是否成功捕获滤镜 });
不过这个方案兼容性不稳定,不同浏览器和html2canvas版本可能表现不一致,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者Anshu Patel
相关产品推荐
相关产品推荐

