mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Camera Fix
This commit is contained in:
@@ -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<CameraWidgetEditorViewProps> = props =>
|
||||
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
|
||||
const [ effectsThumbnails, setEffectsThumbnails ] = useState<CameraPictureThumbnail[]>([]);
|
||||
const [ isZoomed, setIsZoomed ] = useState(false);
|
||||
const [ currentPictureUrl, setCurrentPictureUrl ] = useState<string>('');
|
||||
const [ currentPictureUrl, setCurrentPictureUrl ] = useState<string>(picture?.imageUrl ?? '');
|
||||
const [ stableTexture, setStableTexture ] = useState<Texture>(null);
|
||||
const debounceTimerRef = useRef<ReturnType<typeof setTimeout>>(null);
|
||||
const requestIdRef = useRef<number>(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<CameraWidgetEditorViewProps> = 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<CameraWidgetEditorViewProps> = 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<CameraWidgetEditorViewProps> = props =>
|
||||
return () => {
|
||||
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
||||
};
|
||||
}, [ picture, selectedEffects ]);
|
||||
}, [ stableTexture, selectedEffects ]);
|
||||
|
||||
return (
|
||||
<NitroCardView className="w-[620px] h-[500px]">
|
||||
<NitroCardView className="w-[600px] h-[500px]">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('camera.editor.button.text') } onCloseClick={ event => processAction('close') } />
|
||||
<NitroCardTabsView>
|
||||
{ TABS.map(tab => (
|
||||
@@ -177,16 +192,14 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||
</Column>
|
||||
<Column justifyContent="between" overflow="hidden" size={ 7 }>
|
||||
<Column center>
|
||||
<LayoutImage
|
||||
style={{
|
||||
width: '320px',
|
||||
height: '320px',
|
||||
backgroundImage: `url(${currentPictureUrl})`,
|
||||
backgroundPosition: isZoomed ? 'center' : 'top left',
|
||||
backgroundSize: isZoomed ? 'contain' : 'auto', // Zoom only affects display
|
||||
backgroundRepeat: 'no-repeat'
|
||||
}}
|
||||
/>
|
||||
<div className="w-[325px] h-[325px] overflow-hidden">
|
||||
{ currentPictureUrl && <img
|
||||
alt=""
|
||||
src={ currentPictureUrl }
|
||||
className="w-[325px] h-[325px] [image-rendering:pixelated]"
|
||||
style={ isZoomed ? { transform: 'scale(2)', transformOrigin: 'center' } : undefined }
|
||||
/> }
|
||||
</div>
|
||||
{ selectedEffectName && (
|
||||
<Column center fullWidth gap={ 1 }>
|
||||
<Text>{ LocalizeText('camera.effect.name.' + selectedEffectName) }</Text>
|
||||
|
||||
Reference in New Issue
Block a user