使用Javascript/React合并图像

5
我正在创建一个网站,每个用户都有一个“头像”。头像有不同的配饰,如帽子、面部表情等。我之前在php网站上做过这个,但我现在使用react来创建这个新网站。我从firestore中加载每个用户的头像和其物品链接。我不想使用绝对定位或css,我希望头像是一张图片。
我想要实现的示例: enter image description here 我找到了这个库:https://github.com/lukechilds/merge-images,它似乎正是我需要的,但我不能加载外部图片,否则会出现这个错误:

error img

任何解决此错误或提供替代方案的建议都将不胜感激。
我的代码:
render() {

mergeImages([
  'http://example.com/images/Avatar.png',
  'http://example.com/images/Hat.png',
])
.then((b64) => {
  document.querySelector('img.abc').src = b64;
})
.catch(error => console.log(error))
return (
  ...
      <img class="abc" src='' width={100} height={200} alt="avatar"/>
  ...
); }

图片是否来自于不同的域名?这很可能是发生的情况。 - azium
是的,它们将来自不同的域,很可能是 Firebase 云存储。但在这些测试中,我只是使用其他网站上的随机图像。这是其中一个主要困难。 - Perniferous
2个回答

4

merge-images 包有一些怪癖。其中之一是它期望单独的图像要么从您的本地服务器提供(例如:http://localhost:3000/images/head.pnghttp://localhost:3000/images/eyes.pnghttp://localhost:3000/images/mouth.png),或者将这些单独的图像导入到一个文件中。

工作示例: https://github.com/mattcarlotta/merge-images-example (此示例包括下面解释的前三个选项,第四个选项利用使用第三方CDN的最终结果)

要运行示例,请克隆存储库:

git clone https://github.com/mattcarlotta/merge-images-example

更改目录:

cd merge-images-example

然后安装依赖:
yarn install

然后运行开发服务器:
yarn dev

选项1: 最简单的实现方式是将它们导入到AvatarFromFiles组件中。然而,如所述,它不具有可重用性,并且不适用于动态选择头像。

选项2: 您可以像使用AvatarFromLocalServer组件一样从本地服务器提供它们,使用Webpack Dev Config。然后,您将从API检索存储的字符串并将其传递到状态中传递到组件中。再次强调,这仍然需要图像存在于images文件夹中,但更重要的是,它并不适合生产环境,因为images文件夹必须放在src文件夹之外才能提供服务。这也可能会导致安全问题。因此,我根本不建议使用此选项。

选项3: 与选项1相同,但像AvatarFromLazyFiles组件一样进行了惰性加载,因此更加灵活。您可以通过其name加载图像;但是,它仍然需要在运行时和生产编译期间存在所有图像。换句话说,您手头拥有的就是您所得到的。

选项4: 那么...理想的选择是构建一个图像微服务或使用CDN来处理所有的图像(上传、操纵/合并和提供图像)。客户端只能选择/上传新图像到这个微服务/CDN,而微服务/CDN处理其他所有事情。这可能需要更多的工作,但提供了最大的灵活性超级容易 实现, 并且具有最佳性能 - 因为它将所有工作从客户端转移到专用服务。

总之,除非你计划使用固定数量的图像,否则请使用选项3,否则使用选项4。

enter image description here


谢谢!这太棒了。不幸的是,对于我的当前结构来说,选项4并不是很可行,但我通过像你在示例中展示的惰性加载使其工作。 - Perniferous

1

问题

这是一个CORS问题。图片来自于不同的源,而不是你的服务器。

如果你查看库的源代码,你会发现它在幕后使用了<canvas>来合并图片,然后获取结果数据。Canvas无法处理从另一个域加载的图片。这背后有很好的原因。本质上,将一张图片加载到画布中是获取数据的一种方式,由于你可以从画布中检索出base64格式的数据,所以恶意者可以通过先将其加载到<canvas>中,然后再将其取出来来窃取信息。

你可以直接从<canvas>元素的规范中阅读相关内容。

解决方案

您需要将图像从相同的来源(基本上是相同的域)提供,或在提供图像的HTTP标头中包含Access-Control-Allow-Origin: ...。有在Firebase存储中实现此目的的方法,或者您可以使用其他服务器解决方案。

1
这确实是一个CORS问题。当我尝试你提到的所有线程中的一切时,Access-Control-Allow-Origin似乎无法正常工作。 - Perniferous
1
哦,你确认图片是否使用宽松的“Access-Control-Allow-Origin”进行服务了吗?你可以在浏览器的网络选项卡中检查。编辑:我刚注意到你上面评论说已经解决了。很高兴听到这个消息! - Kevin Chavez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接