diff --git a/package-lock.json b/package-lock.json index dfdf8db4f..09a3fd0bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "exif-js": "^2.3.0", "file-saver": "^2.0.5", "history": "^5.3.0", + "html2canvas": "^1.4.1", "i18next": "^23.6.0", "i18next-browser-languagedetector": "^7.1.0", "i18next-chained-backend": "^4.5.0", @@ -5054,6 +5055,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "devOptional": true }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -6019,6 +6028,14 @@ "node": ">= 8" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", @@ -9135,6 +9152,18 @@ } } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -14372,6 +14401,14 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -14900,6 +14937,14 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", diff --git a/package.json b/package.json index f45aaa0c8..4de16110a 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "exif-js": "^2.3.0", "file-saver": "^2.0.5", "history": "^5.3.0", + "html2canvas": "^1.4.1", "i18next": "^23.6.0", "i18next-browser-languagedetector": "^7.1.0", "i18next-chained-backend": "^4.5.0", diff --git a/src/components/NavItems/tools/SyntheticImageDetection/index.jsx b/src/components/NavItems/tools/SyntheticImageDetection/index.jsx index 9a8f1a25d..04a869e11 100644 --- a/src/components/NavItems/tools/SyntheticImageDetection/index.jsx +++ b/src/components/NavItems/tools/SyntheticImageDetection/index.jsx @@ -14,6 +14,7 @@ import { CardHeader, Grid, LinearProgress, + Stack, } from "@mui/material"; import useMyStyles from "../../../Shared/MaterialUiStyles/useMyStyles"; @@ -211,7 +212,7 @@ const SyntheticImageDetection = () => { }; return ( -
+ { } /> - - {keywordWarning("warning_beta_synthetic_image_detection")} - - - + + + {keywordWarning("warning_beta_synthetic_image_detection")} + + { handleClose={handleClose} /> )} -
+ ); }; diff --git a/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx b/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx index cc7aa063a..d770a61f7 100644 --- a/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx +++ b/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx @@ -4,23 +4,29 @@ import { AccordionDetails, AccordionSummary, Alert, + Backdrop, Box, Card, CardHeader, Chip, Divider, + Fade, Grid, IconButton, + Link, + Modal, Stack, Typography, } from "@mui/material"; -import { Close, ExpandMore } from "@mui/icons-material"; +import { Close, Download, ExpandMore, Square } from "@mui/icons-material"; import { i18nLoadNamespace } from "components/Shared/Languages/i18nLoadNamespace"; import { useSelector } from "react-redux"; import { useTrackEvent } from "Hooks/useAnalytics"; import { getclientId } from "components/Shared/GoogleAnalytics/MatomoAnalytics"; import CustomAlertScore from "../../../Shared/CustomAlertScore"; import GaugeChart from "react-gauge-chart"; +import Tooltip from "@mui/material/Tooltip"; +import html2canvas from "html2canvas"; const SyntheticImageDetectionResults = (props) => { const keyword = i18nLoadNamespace( @@ -83,6 +89,10 @@ const SyntheticImageDetectionResults = (props) => { const [resultsHaveErrors, setResultsHaveErrors] = useState(false); + const [openGaugeColorsModal, setOpenGaugeColorsModal] = React.useState(false); + + const gaugeChartRef = useRef(null); + useEffect(() => { setResultsHaveErrors(false); @@ -246,6 +256,45 @@ const SyntheticImageDetectionResults = (props) => { ); }; + const handleOpenGaugeColorsModal = () => { + setOpenGaugeColorsModal(true); + }; + + const handleCloseGaugeColorsModal = () => setOpenGaugeColorsModal(false); + + const gaugeColorsModalStyle = { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + minWidth: "400px", + width: "30vw", + backgroundColor: "background.paper", + outline: "unset", + borderRadius: "10px", + boxShadow: 24, + p: 4, + maxHeight: "60vh", + overflow: "auto", + }; + + const downloadGaugeChartAsPng = async () => { + const canvas = await html2canvas(gaugeChartRef.current).catch((e) => + console.log(e), + ); + console.log(canvas); + console.log(gaugeChartRef.current); + const img = canvas.toDataURL("image/jpeg", 1.0); + const link = document.createElement("a"); + link.style.display = "none"; + link.download = "gaugeChart"; + link.href = img; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + link.remove(); + }; + return ( { spacing={4} width="100%" sx={{ boxSizing: "border-box" }} + position="relative" > - + - - {keyword("synthetic_image_detection_gauge_no_detection")} - - - {keyword("synthetic_image_detection_gauge_detection")} - + {maxScore > DETECTION_THRESHOLDS.THRESHOLD_2 && ( + + {keyword( + "synthetic_image_detection_generic_detection_text", + )} + + )} + + + + + + {keyword( + "synthetic_image_detection_gauge_no_detection", + )} + + + {keyword("synthetic_image_detection_gauge_detection")} + + + + + + + + + + + + + {keyword("synthetic_image_detection_scale_explanation_link")} + + + + + + + {keyword( + "synthetic_image_detection_scale_modal_explanation_title", + )} + + + + + + + + + + {keyword( + "synthetic_image_detection_scale_modal_explanation_rating_1", + )} + + + + + + {keyword( + "synthetic_image_detection_scale_modal_explanation_rating_2", + )} + + + + + + + {keyword( + "synthetic_image_detection_scale_modal_explanation_rating_3", + )} + + + + + + {keyword( + "synthetic_image_detection_scale_modal_explanation_rating_4", + )} + + + + + + - - {keyword( - "synthetic_image_detection_additional_explanation_text", - )} - {resultsHaveErrors && ( {keyword("synthetic_image_detection_algorithms_errors")} @@ -395,7 +581,7 @@ const SyntheticImageDetectionResults = (props) => { } diff --git a/src/components/Shared/CustomAlertScore/index.jsx b/src/components/Shared/CustomAlertScore/index.jsx index 552aadacf..412d9f294 100644 --- a/src/components/Shared/CustomAlertScore/index.jsx +++ b/src/components/Shared/CustomAlertScore/index.jsx @@ -2,6 +2,7 @@ import React from "react"; import { Alert } from "@mui/material"; import CopyButton from "../CopyButton"; import { i18nLoadNamespace } from "../Languages/i18nLoadNamespace"; +import Typography from "@mui/material/Typography"; const CustomAlertScore = ({ score, detectionType, toolName, thresholds }) => { const keyword = i18nLoadNamespace(`components/NavItems/tools/${toolName}`); @@ -103,7 +104,7 @@ const CustomAlertScore = ({ score, detectionType, toolName, thresholds }) => { /> } > - {alertSettings.displayText} + {alertSettings.displayText} ); };