diff --git a/src/app/WardrobePage/OutfitControls.js b/src/app/WardrobePage/OutfitControls.js
index 3ea60be..9310b44 100644
--- a/src/app/WardrobePage/OutfitControls.js
+++ b/src/app/WardrobePage/OutfitControls.js
@@ -21,9 +21,10 @@ import {
import { MdPause, MdPlayArrow } from "react-icons/md";
import { Link } from "react-router-dom";
+import { getBestImageUrlForLayer } from "../components/OutfitPreview";
import PosePicker from "./PosePicker";
import SpeciesColorPicker from "../components/SpeciesColorPicker";
-import { useLocalStorage } from "../util";
+import { loadImage, useLocalStorage } from "../util";
import useOutfitAppearance from "../components/useOutfitAppearance";
/**
@@ -409,15 +410,8 @@ function useDownloadableImage(visibleLayers) {
setDownloadImageUrl(null);
- const imagePromises = visibleLayers.map(
- (layer) =>
- new Promise((resolve, reject) => {
- const image = new window.Image();
- image.crossOrigin = "Anonymous"; // Requires S3 CORS config!
- image.addEventListener("load", () => resolve(image), false);
- image.addEventListener("error", (e) => reject(e), false);
- image.src = layer.imageUrl + "&xoxo";
- })
+ const imagePromises = visibleLayers.map((layer) =>
+ loadImage(getBestImageUrlForLayer(layer))
);
const images = await Promise.all(imagePromises);
diff --git a/src/app/components/OutfitMovieLayer.js b/src/app/components/OutfitMovieLayer.js
index aa807d3..5b80ccb 100644
--- a/src/app/components/OutfitMovieLayer.js
+++ b/src/app/components/OutfitMovieLayer.js
@@ -1,6 +1,6 @@
import React from "react";
-import { safeImageUrl } from "../util";
+import { loadImage, safeImageUrl } from "../util";
function OutfitMovieLayer({ libraryUrl, width, height, isPaused = false }) {
const [stage, setStage] = React.useState(null);
@@ -221,7 +221,7 @@ export async function loadMovieLibrary(librarySrc) {
const manifestImages = new Map(
library.properties.manifest.map(({ id, src }) => [
id,
- loadImage(safeImageUrl(librarySrcDir + "/" + src)),
+ loadImage({src: safeImageUrl(librarySrcDir + "/" + src)}),
])
);
await Promise.all(manifestImages.values());
@@ -242,19 +242,6 @@ export async function loadMovieLibrary(librarySrc) {
return library;
}
-export function loadImage(url) {
- const image = new Image();
- const promise = new Promise((resolve, reject) => {
- image.onload = () => resolve(image);
- image.onerror = (e) => reject(e);
- image.src = url;
- });
- promise.cancel = () => {
- image.src = "";
- };
- return promise;
-}
-
export function buildMovieClip(library, libraryUrl) {
let constructorName;
try {
diff --git a/src/app/components/OutfitPreview.js b/src/app/components/OutfitPreview.js
index 75dcfeb..14e6055 100644
--- a/src/app/components/OutfitPreview.js
+++ b/src/app/components/OutfitPreview.js
@@ -7,12 +7,11 @@ import { CSSTransition, TransitionGroup } from "react-transition-group";
import OutfitMovieLayer, {
buildMovieClip,
hasAnimations,
- loadImage,
loadMovieLibrary,
useEaselDependenciesLoader,
} from "./OutfitMovieLayer";
import HangerSpinner from "./HangerSpinner";
-import { safeImageUrl, useLocalStorage } from "../util";
+import { loadImage, safeImageUrl, useLocalStorage } from "../util";
import useOutfitAppearance from "./useOutfitAppearance";
/**
@@ -190,7 +189,13 @@ export function OutfitLayers({
/>
) : (
tags are always allowed through CORS), but
+ // this means we make the same request that the Download
+ // button makes, so it can use the cached version of this
+ // image instead of requesting it again with crossOrigin!
+ crossOrigin={getBestImageUrlForLayer(layer).crossOrigin}
alt=""
// We manage the fade-in and fade-out separately! The fade-in
// happens here, when the finishes preloading and
@@ -216,12 +221,6 @@ export function OutfitLayers({
`,
doTransitions && "do-animations"
)}
- // This sets up the cache to not need to reload images during
- // download!
- // TODO: Re-enable this once we get our change into Chakra
- // main. For now, this will make Downloads a bit slower, which
- // is fine!
- // crossOrigin="Anonymous"
/>
)}
@@ -280,11 +279,11 @@ export function FullScreenCenter({ children, ...otherProps }) {
);
}
-function getBestImageUrlForLayer(layer) {
+export function getBestImageUrlForLayer(layer) {
if (layer.svgUrl) {
- return safeImageUrl(layer.svgUrl);
+ return { src: safeImageUrl(layer.svgUrl) };
} else {
- return layer.imageUrl;
+ return { src: layer.imageUrl, crossOrigin: "anonymous" };
}
}
diff --git a/src/app/util.js b/src/app/util.js
index a150835..6d95951 100644
--- a/src/app/util.js
+++ b/src/app/util.js
@@ -225,3 +225,19 @@ export function useLocalStorage(key, initialValue) {
return [storedValue, setValue];
}
+
+export function loadImage({ src, crossOrigin = null }) {
+ const image = new Image();
+ const promise = new Promise((resolve, reject) => {
+ image.onload = () => resolve(image);
+ image.onerror = (e) => reject(e);
+ if (crossOrigin) {
+ image.crossOrigin = crossOrigin;
+ }
+ image.src = src;
+ });
+ promise.cancel = () => {
+ image.src = "";
+ };
+ return promise;
+}