如何将 Firebase Storage 中被 cors 阻止的图像 URL 作为 PDF 文件的一部分包含进来

问题描述 投票:0回答:1

我有一个组件,可以呈现 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>
vuejs3 pdf-generation firebase-storage jspdf html2canvas
1个回答
0
投票

您遇到的 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>
© www.soinside.com 2019 - 2024. All rights reserved.