我有一个组件,可以呈现 html 的发票部分,其中包含一个图像,其中 src 是来自 Firebase Storage 的 url。我正在使用 jspdf 和 html2canvas 创建 pdf 文件。但由于 cors 问题,该图像不被允许。
尝试找到一种方法来显示pdf文件中的图像。我在 html2canvas 文档中看到您需要使用代理,不确定如何在我的应用程序中执行此操作或者是否有必要。最后只是想要一个下载的pdf。
编辑
这是一个工作演示
请注意,演示中显示的 200 x 200 图像不在 pdf 中
请注意,可以更改的图像 src url 并不意味着要进行硬编码。
这是我的 HTML
<template>
<div ref="invoiceContent">
<div>
<AppAvatarImage :src="invoice.avatar" />
</div>
</div>
..... other stuff that renders fine
</template>
这是我保存pdf文件的方法。
<script setup>
import { ref } from 'vue';
import { jsPDF } from 'jspdf';
import html2canvas from 'html2canvas';
const invoiceContent = ref(null);
const props = defineProps({
invoice: {
type: Object,
required: true,
},
});
const savePdf = () => {
const doc = new jsPDF({
orientation: 'p',
unit: 'px',
format: 'legal',
hotfixes: ['px_scaling'],
});
html2canvas(invoiceContent.value, {
width: doc.internal.pageSize.getWidth(),
height: doc.internal.pageSize.getHeight(),
}).then((canvas) => {
const img = canvas.toDataURL('image/jpeg', 0.5);
if (screen.width < 700) {
doc.addImage(img, 'JPEG', 50, 50, screen.width * 3, doc.internal.pageSize.getHeight());
} else {
doc.addImage(img, 'JPEG', 150, 50, doc.internal.pageSize.getWidth(), doc.internal.pageSize.getHeight());
}
doc.save('Invoice.pdf');
});
};
</script>
这是我从 Firebase Storage 获取图像 url 的方法。
async uploadAvatar({ file }) {
if (!file) return null;
let filename = file.name;
try {
const storeAuth = useStoreAuth();
let name = `${Date.now()}-${filename}`;
let path = `uploads/${storeAuth.user.id}/profileImgs/${name}`;
const storageRef = ref(storage, path);
await uploadBytes(storageRef, file);
const avatarURL = await getDownloadURL(storageRef);
let data = {
id: storeAuth.user.id,
avatar: avatarURL,
};
await this.updateUserAvatar(data);
return avatarURL;
} catch (error) {
console.log('File Upload Error');
console.error(error);
}
}
我的AppAvatarImage组件。
<template>
<img :src="src || profileImg" />
</template>
<script setup>
import profileImg from '@/assets/images/all-img/user.svg';
const props = defineProps({
src: {
type: String,
},
});
</script>
您遇到的 CORS(跨源资源共享)问题是因为您尝试从 Firebase 存储加载到 PDF 中的图像的来源与应用程序的域不同。您可以使用代理服务器来获取图像并将其提供给您的应用程序。
创建一个 Node.js 服务器作为从 Firebase 存储获取图像的代理。您可以使用像express这样的库来实现此目的
npm install express
创建一个新的 Node.js 文件
const express = require('express');
const fetch = require('node-fetch');
const app = express();
const port = 3000;
app.get('/proxy-image', async (req, res) => {
try {
const imageUrl = req.query.url;
const response = await fetch(imageUrl);
if (response.ok) {
const imageBuffer = await response.buffer();
res.setHeader('Content-Type', response.headers.get('content-type'));
res.send(imageBuffer);
} else {
res.status(response.status).send('Failed to fetch image');
}
} catch (error) {
console.error('Proxy error:', error);
res.status(500).send('Proxy error');
}
});
app.listen(port, () => {
console.log(`Image proxy server is running on port ${port}`);
});
通过运行启动代理服务器
node imageProxy.js
更新您的 Vue 组件以使用代理服务器获取图像。修改 AppAvatarImage 组件以使用 /proxy-image 路由来获取图像。 AppAvatarImage 组件的更新版本
<template>
<img :src="imageSrc || profileImg" />
</template>
<script setup>
import profileImg from '@/assets/images/all-img/user.svg';
import { ref, onMounted } from 'vue';
const props = defineProps({
src: {
type: String,
},
});
const imageSrc = ref(props.src);
onMounted(() => {
if (props.src && !props.src.startsWith('data:')) {
// If the source is not a data URI, fetch it through the proxy
imageSrc.value = `/proxy-image?url=${encodeURIComponent(props.src)}`;
}
});
</script>