add conflict resolution mode for SWF screenshots
The "Dyeworks Pink: Peaceful Tree Garland" was a tricky case, with animated falling leaves… we decided that having transparency in the main pet area, and some incorrect transparent holes in the trees, was a better conflict resolution for this one Probably would be good to manually upload a Totally Good version, but like, this flag is probably good to have
This commit is contained in:
parent
71e1112b63
commit
0f97693500
1 changed files with 96 additions and 22 deletions
|
@ -10,6 +10,7 @@ import {
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
|
Select,
|
||||||
useToast,
|
useToast,
|
||||||
} from "@chakra-ui/core";
|
} from "@chakra-ui/core";
|
||||||
import { ExternalLinkIcon } from "@chakra-ui/icons";
|
import { ExternalLinkIcon } from "@chakra-ui/icons";
|
||||||
|
@ -33,6 +34,8 @@ function ItemLayerSupportUploadModal({ item, itemLayer, isOpen, onClose }) {
|
||||||
const [isUploading, setIsUploading] = React.useState(false);
|
const [isUploading, setIsUploading] = React.useState(false);
|
||||||
const [uploadError, setUploadError] = React.useState(null);
|
const [uploadError, setUploadError] = React.useState(null);
|
||||||
|
|
||||||
|
const [conflictMode, setConflictMode] = React.useState("onBlack");
|
||||||
|
|
||||||
const supportSecret = useSupportSecret();
|
const supportSecret = useSupportSecret();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
@ -47,14 +50,16 @@ function ItemLayerSupportUploadModal({ item, itemLayer, isOpen, onClose }) {
|
||||||
setNumWarnings(null);
|
setNumWarnings(null);
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
|
|
||||||
mergeIntoImageWithAlpha(imageOnBlackUrl, imageOnWhiteUrl).then(
|
mergeIntoImageWithAlpha(
|
||||||
([url, blob, numWarnings]) => {
|
imageOnBlackUrl,
|
||||||
|
imageOnWhiteUrl,
|
||||||
|
conflictMode
|
||||||
|
).then(([url, blob, numWarnings]) => {
|
||||||
setImageWithAlphaUrl(url);
|
setImageWithAlphaUrl(url);
|
||||||
setImageWithAlphaBlob(blob);
|
setImageWithAlphaBlob(blob);
|
||||||
setNumWarnings(numWarnings);
|
setNumWarnings(numWarnings);
|
||||||
}
|
});
|
||||||
);
|
}, [imageOnBlackUrl, imageOnWhiteUrl, conflictMode]);
|
||||||
}, [imageOnBlackUrl, imageOnWhiteUrl]);
|
|
||||||
|
|
||||||
const onUpload = React.useCallback(
|
const onUpload = React.useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -167,6 +172,8 @@ function ItemLayerSupportUploadModal({ item, itemLayer, isOpen, onClose }) {
|
||||||
<ItemLayerSupportReviewStep
|
<ItemLayerSupportReviewStep
|
||||||
imageWithAlphaUrl={imageWithAlphaUrl}
|
imageWithAlphaUrl={imageWithAlphaUrl}
|
||||||
numWarnings={numWarnings}
|
numWarnings={numWarnings}
|
||||||
|
conflictMode={conflictMode}
|
||||||
|
onChangeConflictMode={setConflictMode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
@ -250,7 +257,12 @@ function ItemLayerSupportScreenshotStep({ itemLayer, step, onUpload }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemLayerSupportReviewStep({ imageWithAlphaUrl, numWarnings }) {
|
function ItemLayerSupportReviewStep({
|
||||||
|
imageWithAlphaUrl,
|
||||||
|
numWarnings,
|
||||||
|
conflictMode,
|
||||||
|
onChangeConflictMode,
|
||||||
|
}) {
|
||||||
if (imageWithAlphaUrl == null) {
|
if (imageWithAlphaUrl == null) {
|
||||||
return <Box>Generating image…</Box>;
|
return <Box>Generating image…</Box>;
|
||||||
}
|
}
|
||||||
|
@ -283,6 +295,31 @@ function ItemLayerSupportReviewStep({ imageWithAlphaUrl, numWarnings }) {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{numWarnings > 0 && (
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
flexDirection="row"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
width="600px"
|
||||||
|
marginTop="2"
|
||||||
|
>
|
||||||
|
<Box flex="0 1 auto" marginRight="2">
|
||||||
|
When pixels conflict, we use…
|
||||||
|
</Box>
|
||||||
|
<Select
|
||||||
|
flex="0 0 200px"
|
||||||
|
value={conflictMode}
|
||||||
|
onChange={(e) => onChangeConflictMode(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="onBlack">the version on black</option>
|
||||||
|
<option value="onWhite">the version on white</option>
|
||||||
|
<option value="transparent">transparent pixels</option>
|
||||||
|
</Select>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -386,7 +423,11 @@ function ItemLayerSupportFlashPlayer({ swfUrl, backgroundColor }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mergeIntoImageWithAlpha(imageOnBlackUrl, imageOnWhiteUrl) {
|
async function mergeIntoImageWithAlpha(
|
||||||
|
imageOnBlackUrl,
|
||||||
|
imageOnWhiteUrl,
|
||||||
|
conflictMode
|
||||||
|
) {
|
||||||
const [imageOnBlack, imageOnWhite] = await Promise.all([
|
const [imageOnBlack, imageOnWhite] = await Promise.all([
|
||||||
readImageDataFromUrl(imageOnBlackUrl),
|
readImageDataFromUrl(imageOnBlackUrl),
|
||||||
readImageDataFromUrl(imageOnWhiteUrl),
|
readImageDataFromUrl(imageOnWhiteUrl),
|
||||||
|
@ -394,7 +435,8 @@ async function mergeIntoImageWithAlpha(imageOnBlackUrl, imageOnWhiteUrl) {
|
||||||
|
|
||||||
const [imageWithAlphaData, numWarnings] = mergeDataIntoImageWithAlpha(
|
const [imageWithAlphaData, numWarnings] = mergeDataIntoImageWithAlpha(
|
||||||
imageOnBlack,
|
imageOnBlack,
|
||||||
imageOnWhite
|
imageOnWhite,
|
||||||
|
conflictMode
|
||||||
);
|
);
|
||||||
const [
|
const [
|
||||||
imageWithAlphaUrl,
|
imageWithAlphaUrl,
|
||||||
|
@ -404,7 +446,7 @@ async function mergeIntoImageWithAlpha(imageOnBlackUrl, imageOnWhiteUrl) {
|
||||||
return [imageWithAlphaUrl, imageWithAlphaBlob, numWarnings];
|
return [imageWithAlphaUrl, imageWithAlphaBlob, numWarnings];
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeDataIntoImageWithAlpha(imageOnBlack, imageOnWhite) {
|
function mergeDataIntoImageWithAlpha(imageOnBlack, imageOnWhite, conflictMode) {
|
||||||
const imageWithAlpha = new ImageData(600, 600);
|
const imageWithAlpha = new ImageData(600, 600);
|
||||||
let numWarnings = 0;
|
let numWarnings = 0;
|
||||||
|
|
||||||
|
@ -428,13 +470,29 @@ function mergeDataIntoImageWithAlpha(imageOnBlack, imageOnWhite) {
|
||||||
` vs ` +
|
` vs ` +
|
||||||
`#${rOnBlack.toString(16)}${bOnBlack.toString(16)}` +
|
`#${rOnBlack.toString(16)}${bOnBlack.toString(16)}` +
|
||||||
`${gOnWhite.toString(16)}. ` +
|
`${gOnWhite.toString(16)}. ` +
|
||||||
`Falling back to the pixel on black, with alpha = 100%. `
|
`Using conflict mode ${conflictMode} to fall back.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conflictMode === "onBlack") {
|
||||||
imageWithAlpha.data[pixelIndex] = rOnBlack;
|
imageWithAlpha.data[pixelIndex] = rOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 1] = gOnBlack;
|
imageWithAlpha.data[pixelIndex + 1] = gOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 2] = bOnBlack;
|
imageWithAlpha.data[pixelIndex + 2] = bOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 3] = 255;
|
imageWithAlpha.data[pixelIndex + 3] = 255;
|
||||||
|
} else if (conflictMode === "onWhite") {
|
||||||
|
imageWithAlpha.data[pixelIndex] = rOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 1] = gOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 2] = bOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 3] = 255;
|
||||||
|
} else if (conflictMode === "transparent") {
|
||||||
|
imageWithAlpha.data[pixelIndex] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 1] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 2] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 3] = 0;
|
||||||
|
} else {
|
||||||
|
throw new Error(`unexpected conflict mode ${conflictMode}`);
|
||||||
|
}
|
||||||
|
|
||||||
numWarnings++;
|
numWarnings++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -460,13 +518,29 @@ function mergeDataIntoImageWithAlpha(imageOnBlack, imageOnWhite) {
|
||||||
` vs ` +
|
` vs ` +
|
||||||
`#${rOnBlack.toString(16)}${bOnBlack.toString(16)}` +
|
`#${rOnBlack.toString(16)}${bOnBlack.toString(16)}` +
|
||||||
`${gOnWhite.toString(16)}. ` +
|
`${gOnWhite.toString(16)}. ` +
|
||||||
`Falling back to the pixel on black, with alpha = 100%. `
|
`Using conflict mode ${conflictMode} to fall back.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conflictMode === "onBlack") {
|
||||||
imageWithAlpha.data[pixelIndex] = rOnBlack;
|
imageWithAlpha.data[pixelIndex] = rOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 1] = gOnBlack;
|
imageWithAlpha.data[pixelIndex + 1] = gOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 2] = bOnBlack;
|
imageWithAlpha.data[pixelIndex + 2] = bOnBlack;
|
||||||
imageWithAlpha.data[pixelIndex + 3] = 255;
|
imageWithAlpha.data[pixelIndex + 3] = 255;
|
||||||
|
} else if (conflictMode === "onWhite") {
|
||||||
|
imageWithAlpha.data[pixelIndex] = rOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 1] = gOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 2] = bOnWhite;
|
||||||
|
imageWithAlpha.data[pixelIndex + 3] = 255;
|
||||||
|
} else if (conflictMode === "transparent") {
|
||||||
|
imageWithAlpha.data[pixelIndex] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 1] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 2] = 0;
|
||||||
|
imageWithAlpha.data[pixelIndex + 3] = 0;
|
||||||
|
} else {
|
||||||
|
throw new Error(`unexpected conflict mode ${conflictMode}`);
|
||||||
|
}
|
||||||
|
|
||||||
numWarnings++;
|
numWarnings++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue