diff --git a/src/components/camera/views/editor/CameraWidgetEditorView.tsx b/src/components/camera/views/editor/CameraWidgetEditorView.tsx index 7777164..2197961 100644 --- a/src/components/camera/views/editor/CameraWidgetEditorView.tsx +++ b/src/components/camera/views/editor/CameraWidgetEditorView.tsx @@ -1,8 +1,9 @@ -import { GetRoomCameraWidgetManager, IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect, NitroLogger, RoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer'; +import { GetRoomCameraWidgetManager, IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect, NitroLogger, RoomCameraWidgetSelectedEffect, TextureUtils } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Texture } from 'pixi.js'; import { FaSave, FaSearchMinus, FaSearchPlus, FaTrash } from 'react-icons/fa'; import { CameraEditorTabs, CameraPicture, CameraPictureThumbnail, LocalizeText } from '../../../../api'; -import { Button, Column, Flex, Grid, LayoutImage, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, Slider, Text } from '../../../../common'; +import { Button, Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, Slider, Text } from '../../../../common'; import { CameraWidgetEffectListView } from './effect-list'; export interface CameraWidgetEditorViewProps { @@ -23,10 +24,18 @@ export const CameraWidgetEditorView: FC = props => const [ selectedEffects, setSelectedEffects ] = useState([]); const [ effectsThumbnails, setEffectsThumbnails ] = useState([]); const [ isZoomed, setIsZoomed ] = useState(false); - const [ currentPictureUrl, setCurrentPictureUrl ] = useState(''); + const [ currentPictureUrl, setCurrentPictureUrl ] = useState(picture?.imageUrl ?? ''); + const [ stableTexture, setStableTexture ] = useState(null); const debounceTimerRef = useRef>(null); const requestIdRef = useRef(0); + useEffect(() => + { + const img = new Image(); + img.onload = () => setStableTexture(Texture.from(img)); + img.src = picture.imageUrl; + }, [ picture ]); + const getColorMatrixEffects = useMemo(() => { return availableEffects.filter(effect => effect.colorMatrix); }, [ availableEffects ]); @@ -108,12 +117,14 @@ export const CameraWidgetEditorView: FC = props => setSelectedEffects([]); return; case 'download': { - (async () => { - const image = new Image(); - image.src = currentPictureUrl; - const newWindow = window.open(''); - newWindow.document.write(image.outerHTML); - })(); + if(!currentPictureUrl || !currentPictureUrl.startsWith('data:image/')) return; + + const link = document.createElement('a'); + link.href = currentPictureUrl; + link.download = 'camera_photo.png'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); return; } case 'zoom': @@ -123,25 +134,29 @@ export const CameraWidgetEditorView: FC = props => }, [ availableEffects, selectedEffectName, currentPictureUrl, getSelectedEffectIndex, onCancel, onCheckout, onClose ]); useEffect(() => { + if(!stableTexture) return; + const processThumbnails = async () => { const renderedEffects = await Promise.all( availableEffects.map(effect => - GetRoomCameraWidgetManager().applyEffects(picture.texture, [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false) + GetRoomCameraWidgetManager().applyEffects(stableTexture, [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false) ) ); setEffectsThumbnails(renderedEffects.map((image, index) => new CameraPictureThumbnail(availableEffects[index].name, image.src))); }; processThumbnails(); - }, [ picture, availableEffects ]); + }, [ stableTexture, availableEffects ]); useEffect(() => { + if(!stableTexture) return; + if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current); debounceTimerRef.current = setTimeout(() => { const id = ++requestIdRef.current; GetRoomCameraWidgetManager() - .applyEffects(picture.texture, selectedEffects, false) + .applyEffects(stableTexture, selectedEffects, false) .then(imageElement => { if (id !== requestIdRef.current) return; setCurrentPictureUrl(imageElement.src); @@ -152,10 +167,10 @@ export const CameraWidgetEditorView: FC = props => return () => { if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current); }; - }, [ picture, selectedEffects ]); + }, [ stableTexture, selectedEffects ]); return ( - + processAction('close') } /> { TABS.map(tab => ( @@ -177,16 +192,14 @@ export const CameraWidgetEditorView: FC = props => - +
+ { currentPictureUrl && } +
{ selectedEffectName && ( { LocalizeText('camera.effect.name.' + selectedEffectName) }