style: image display ratio

main
jialin 1 year ago
parent cb13f66b3d
commit 804cbb8c56

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 KiB

@ -3,9 +3,11 @@
justify-content: center;
align-items: center;
text-align: center;
width: 100%;
canvas {
display: block;
width: 100%;
image-rendering: crisp-edges;
}
}

@ -1,3 +1,4 @@
import useResizeObserver from '@/components/logs-viewer/use-size';
import React, { useEffect } from 'react';
import './index.less';
@ -5,24 +6,31 @@ interface AudioAnimationProps {
width: number;
height: number;
scaleFactor?: number;
maxBarCount?: number;
analyserData: {
data: Uint8Array;
analyser: any;
};
}
const AudioAnimation: React.FC<AudioAnimationProps> = ({
width,
height,
scaleFactor = 1.2,
analyserData
}) => {
const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
const {
scaleFactor = 1.2,
maxBarCount = 128,
analyserData,
width,
height
} = props;
const canvasRef = React.useRef<HTMLCanvasElement>(null);
const animationId = React.useRef<number>(0);
const isScaled = React.useRef<boolean>(false);
const oscillationOffset = React.useRef(0);
const direction = React.useRef(1);
const maxBarCount = 128;
// const [width, setWidth] = useState(props.width);
// const [height, setHeight] = useState(props.height);
const containerRef = React.useRef<any>(null);
const size = useResizeObserver(containerRef);
const calculateJitter = (
i: number,
@ -120,7 +128,29 @@ const AudioAnimation: React.FC<AudioAnimationProps> = ({
draw(performance.now());
};
// const handleResizeThrottle = React.useCallback(
// throttle(() => {
// console.log('size:', size);
// if (size.width && size.width !== width) {
// setWidth(size.width);
// }
// if (size.height && size.height !== height) {
// setHeight(size.height);
// }
// }, 100),
// [size, width, height]
// );
// useEffect(() => {
// handleResizeThrottle();
// window.addEventListener('resize', handleResizeThrottle);
// return () => {
// handleResizeThrottle.cancel();
// };
// }, [size, width, height]);
useEffect(() => {
if (!canvasRef.current) return;
const clearCanvas = () => {
if (canvasRef.current) {
const ctx = canvasRef.current.getContext('2d');
@ -145,6 +175,7 @@ const AudioAnimation: React.FC<AudioAnimationProps> = ({
return (
<div
ref={containerRef}
className="canvas-wrap"
style={{
width: '100%',

@ -75,6 +75,10 @@ const AutoImage: React.FC<
handleOnLoad();
}, [handleOnLoad]);
useEffect(() => {
setWidth(w || 0);
}, [w]);
return (
<AntImage
{...rest}

@ -51,7 +51,6 @@
}
.single-image {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
@ -59,6 +58,11 @@
overflow: hidden;
border-radius: var(--border-radius-base);
&.loading {
width: 100%;
height: 100%;
}
&.auto-bg-color {
position: relative;

@ -2,6 +2,7 @@ import { CloseCircleOutlined } from '@ant-design/icons';
import { Progress } from 'antd';
import classNames from 'classnames';
import * as Vibrant from 'node-vibrant';
import ResizeObserver from 'rc-resize-observer';
import React from 'react';
import AutoImage from './index';
import './single-image.less';
@ -39,10 +40,14 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
const [color, setColor] = React.useState({});
const imgWrapper = React.useRef<HTMLSpanElement>(null);
const [imgSize, setImgSize] = React.useState({
width: width,
height: height
});
const thumImgWrapStyle = React.useMemo(() => {
return loading ? { width: width, height: height } : {};
}, [loading, width, height]);
return loading ? { width: '100%', height: '100%' } : {};
}, [loading, imgSize]);
const handleOnLoad = React.useCallback(async () => {
if (!autoBgColor) {
@ -73,76 +78,114 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
});
}, []);
const handleResize = React.useCallback(
(size: { width: number; height: number }) => {
if (!autoSize) return;
const { width: containerWidth, height: containerHeight } = size;
const { width: originalWidth, height: originalHeight } = props;
if (!originalWidth || !originalHeight) return;
const imageAspectRatio = originalWidth / originalHeight;
const containerAspectRatio = containerWidth / containerHeight;
let newWidth, newHeight;
if (containerAspectRatio > imageAspectRatio) {
newHeight = containerHeight;
newWidth = containerHeight * imageAspectRatio;
} else {
newWidth = containerWidth;
newHeight = containerWidth / imageAspectRatio;
}
setImgSize({
width: newWidth,
height: newHeight
});
},
[autoSize, props]
);
return (
<div
key={uid}
className={classNames('single-image', { 'auto-bg-color': autoBgColor })}
>
{autoBgColor && (
<div
className="mask"
<ResizeObserver onResize={handleResize}>
<div
key={uid}
className={classNames('single-image', {
'auto-bg-color': autoBgColor,
'auto-size': autoSize,
loading: loading
})}
>
{autoBgColor && (
<div
className="mask"
style={{
background: `url(${dataUrl}) center center / cover no-repeat`
}}
></div>
)}
<span
className="thumb-img"
style={{
background: `url(${dataUrl}) center center / cover no-repeat`
...thumImgWrapStyle
}}
></div>
)}
<span
className="thumb-img"
style={{
...thumImgWrapStyle
}}
ref={imgWrapper}
>
<>
{loading ? (
<span
className="progress-wrap"
style={{
width: '100%',
height: '100%',
display: 'flex',
border: '1px solid var(--ant-color-split)',
borderRadius: 'var(--border-radius-base)',
justifyContent: 'center',
alignItems: 'center',
padding: '10px',
overflow: 'hidden'
}}
>
<Progress
percent={progress}
type="dashboard"
steps={{ count: 50, gap: 2 }}
format={() => <span className="font-size-20">{progress}%</span>}
trailColor="var(--ant-color-fill-secondary)"
/>
</span>
) : (
<span
className="img"
style={{
maxHeight: `min(${maxHeight}, 100%)`,
maxWidth: `min(${maxWidth}, 100%)`
}}
>
<AutoImage
autoSize={autoSize}
src={dataUrl}
width={width || 100}
height={height || 100}
onLoad={handleOnLoad}
/>
ref={imgWrapper}
>
<>
{loading ? (
<span
className="progress-wrap"
style={{
width: '100%',
height: '100%',
display: 'flex',
border: '1px solid var(--ant-color-split)',
borderRadius: 'var(--border-radius-base)',
justifyContent: 'center',
alignItems: 'center',
padding: '10px',
overflow: 'hidden'
}}
>
<Progress
percent={progress}
type="dashboard"
steps={{ count: 50, gap: 2 }}
format={() => (
<span className="font-size-20">{progress}%</span>
)}
trailColor="var(--ant-color-fill-secondary)"
/>
</span>
) : (
<span
className="img"
style={{
maxHeight: `min(${maxHeight}, 100%)`,
maxWidth: `min(${maxWidth}, 100%)`
}}
>
<AutoImage
autoSize={autoSize}
src={dataUrl}
width={imgSize.width || 100}
height={imgSize.height || 100}
onLoad={handleOnLoad}
/>
</span>
)}
</>
{editable && (
<span className="del" onClick={() => handleOnDelete(uid)}>
<CloseCircleOutlined />
</span>
)}
</>
{editable && (
<span className="del" onClick={() => handleOnDelete(uid)}>
<CloseCircleOutlined />
</span>
)}
</span>
</div>
</span>
</div>
</ResizeObserver>
);
};

@ -1,13 +1,27 @@
import useResizeObserver from '@react-hook/resize-observer';
import React from 'react';
import { useEffect, useState } from 'react';
export default function useSize(target: any) {
const [size, setSize] = React.useState();
const useResizeObserver = (ref: React.RefObject<HTMLElement>) => {
const [size, setSize] = useState({ width: 0, height: 0 });
React.useLayoutEffect(() => {
setSize(target.current?.getBoundingClientRect());
}, [target]);
useEffect(() => {
const element = ref.current;
if (!element) return;
const observer = new ResizeObserver((entries) => {
if (entries[0]) {
const { width, height } = entries[0].contentRect;
setSize({ width, height });
}
});
observer.observe(element);
return () => {
observer.disconnect();
};
}, [ref]);
useResizeObserver(target, (entry: any) => setSize(entry?.contentRect));
return size;
}
};
export default useResizeObserver;

@ -14,10 +14,11 @@ interface AudioPlayerProps {
ref?: any;
height?: number;
width?: number;
onReady?: () => void;
onReady?: (duration: number) => void;
onClick?: (value: number) => void;
onFinish?: () => void;
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
onAudioprocess?: (current: number) => void;
}
const AudioPlayer: React.FC<
@ -29,7 +30,6 @@ const AudioPlayer: React.FC<
const audioContext = useRef<any>(null);
const analyser = useRef<any>(null);
const dataArray = useRef<any>(null);
const audioStream = useRef<any>(null);
const mediaElement = useRef<any>(null);
const initAudioContext = useCallback(() => {
@ -50,8 +50,8 @@ const AudioPlayer: React.FC<
}, []);
const listenEvents = () => {
wavesurfer.current?.on('ready', () => {
props.onReady?.();
wavesurfer.current?.on('ready', (duration: number) => {
props.onReady?.(duration);
});
wavesurfer.current?.on('click', (value) => {
@ -60,9 +60,13 @@ const AudioPlayer: React.FC<
wavesurfer.current?.on('finish', () => {
props.onFinish?.();
});
wavesurfer.current?.on('audioprocess', (current: number) => {
console.log('audioprocess==========:', current);
props.onAudioprocess?.(current);
});
wavesurfer.current?.on('play', () => {
// analyser.current?.getByteFrequencyData(dataArray.current);
// props.onAnalyse?.(dataArray.current, analyser);
analyser.current?.getByteFrequencyData(dataArray.current);
props.onAnalyse?.(dataArray.current, analyser);
});
};

@ -1,5 +1,4 @@
import IconFont from '@/components/icon-font';
import { formatTime } from '@/utils/index';
import useResizeObserver from '@/components/logs-viewer/use-size';
import {
DownloadOutlined,
PauseCircleOutlined,
@ -8,7 +7,8 @@ import {
import { useIntl } from '@umijs/max';
import { Button, Tooltip } from 'antd';
import dayjs from 'dayjs';
import React, { useRef, useState } from 'react';
import _ from 'lodash';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import AudioPlayer from './audio-player';
import './styles/index.less';
@ -36,16 +36,19 @@ interface SpeechContentProps {
}
const SpeechItem: React.FC<SpeechContentProps> = (props) => {
const intl = useIntl();
const [collapsed, setCollapsed] = useState(false);
const [isPlay, setIsPlay] = useState(props.autoplay);
const [duration, setDuration] = useState(0);
const [animationSize, setAnimationSize] = useState({ width: 900, height: 0 });
const [currentTime, setCurrentTime] = useState(0);
const [audioChunks, setAudioChunks] = useState<any>({
data: [],
data: new Uint8Array(128),
analyser: null
});
const wrapper = useRef<any>(null);
const ref = useRef<any>(null);
const size = useResizeObserver(wrapper);
const handlePlay = () => {
if (isPlay) {
ref.current?.pause();
@ -56,24 +59,44 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
setIsPlay(true);
};
const handleOnAnalyse = (data: any, analyser: any) => {
const handleOnAnalyse = useCallback((data: any, analyser: any) => {
setAudioChunks((pre: any) => {
return {
data: data,
analyser: analyser
};
});
};
}, []);
const handleReay = () => {
const duration = ref.current?.duration?.();
setDuration(duration < 1 ? 1 : duration);
};
const handleOnFinish = useCallback(() => {
setIsPlay(false);
}, []);
const handleOnAudioprocess = useCallback((current: number) => {
setCurrentTime(() => current);
console.log('current:', current, duration);
}, []);
const handleReay = useCallback((duration: number) => {
setIsPlay(props.autoplay);
setDuration(duration);
}, []);
const handleOnClick = (value: number) => {
const handleOnClick = useCallback((value: number) => {
console.log('current:', value);
};
}, []);
const handleAnimationResize = useCallback((size: any) => {
console.log('size:=======', size);
setAnimationSize({
width: size.width,
height: size.height
});
}, []);
useEffect(() => {
console.log('width:', size);
}, [size]);
const onDownload = () => {
const url = props.audioUrl || '';
const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${props.format}`;
@ -89,33 +112,37 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
return (
<div>
<div className="speech-item">
{/* {isPlay && (
<AudioAnimation
height={82}
width={500}
analyserData={audioChunks}
></AudioAnimation>
)} */}
<div className="voice">
<IconFont type="icon-user_voice" className="font-size-16" />
</div>
<div className="wrapper">
<div
className="wrapper"
style={{ height: 82, width: '100%' }}
ref={wrapper}
>
<AudioPlayer
{...props}
audioUrl={props.audioUrl}
onReady={handleReay}
onClick={handleOnClick}
onFinish={() => setIsPlay(false)}
onFinish={handleOnFinish}
onAnalyse={handleOnAnalyse}
onAudioprocess={handleOnAudioprocess}
ref={ref}
></AudioPlayer>
{/* {isPlay && (
<AudioAnimation
maxBarCount={180}
height={82}
width={800}
analyserData={audioChunks}
></AudioAnimation>
)} */}
</div>
</div>
{/* <Slider value={currentTime} max={duration} step={0.01}></Slider> */}
<div className="speech-actions">
<span className="tags">
<span className="item">{props.format}</span>
</span>
<span className="duration">{formatTime(duration)}</span>
<span className="duration">{_.round(duration, 2)}</span>
<div className="actions">
<Tooltip
title={

@ -2,6 +2,7 @@
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
.voice {
width: 80px;
@ -55,7 +56,7 @@
justify-content: space-between;
align-items: center;
margin-top: 10px;
padding-left: 80px;
// padding-left: 80px;
.actions {
display: flex;

@ -263,8 +263,8 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const progress = _.round(item.progress, 0);
newImageList[item.index] = {
dataUrl: imgItem.dataUrl,
height: '100%',
width: '100%',
height: imgSize[1],
width: imgSize[0],
maxHeight: `${imgSize[1]}px`,
maxWidth: `${imgSize[0]}px`,
uid: imgItem.uid,

@ -212,7 +212,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
const res = await queryModelVoices({
model: value
});
console.log('res:', res);
if (res?.error) {
setVoiceError({
error: true,
@ -235,6 +234,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
const newList = sortVoiceList(locale, list);
setVoiceList(newList);
setVoiceError(null);
setParams((pre: any) => {
return {
...pre,

@ -1,7 +1,5 @@
import AutoImage from '@/components/auto-image';
import SingleImage from '@/components/auto-image/single-image';
import { CloseCircleOutlined } from '@ant-design/icons';
import { Col, Progress, Row } from 'antd';
import { Col, Row } from 'antd';
import _ from 'lodash';
import React, { useCallback } from 'react';
import '../style/thumb-img.less';
@ -38,57 +36,6 @@ const ThumbImg: React.FC<{
return null;
}
const renderImageItem = (item: any) => {
const thumImgWrapStyle = item.loading
? { width: item.width, height: item.height }
: {};
return (
<span key={item.uid} className="thumb-img" style={thumImgWrapStyle}>
<>
{item.loading ? (
<span
className="progress-wrap"
style={{
width: '100%',
height: '100%',
display: 'flex',
border: '1px solid var(--ant-color-split)',
borderRadius: 'var(--border-radius-base)',
justifyContent: 'center',
alignItems: 'center',
padding: '10px',
overflow: 'hidden'
}}
>
<Progress percent={item.progress} type="circle" />
</span>
) : (
<span
className="img"
style={{
maxHeight: `min(${item.maxHeight}, 100%)`,
maxWidth: `min(${item.maxWidth}, 100%)`
}}
>
<AutoImage
autoSize={autoSize}
src={item.dataUrl}
width={item.width || 100}
height={item.height || 100}
/>
</span>
)}
</>
{editable && (
<span className="del" onClick={() => handleOnDelete(item.uid)}>
<CloseCircleOutlined />
</span>
)}
</span>
);
};
return (
<>
{
@ -147,6 +94,7 @@ const ThumbImg: React.FC<{
>
<SingleImage
{...item}
loading={item.loading}
autoSize={autoSize}
editable={editable}
autoBgColor={autoBgColor}

@ -311,7 +311,7 @@ export const ImageAdvancedParamsConfig: ParamsSchema[] = [
},
{
type: 'Input',
name: 'negative_prompt',
name: 'negative_prompt', //ng_deepnegative_v1_75t,(badhandv4:1.2),EasyNegative,(worst quality:2),
label: {
text: 'playground.image.params.negativePrompt',
isLocalized: true

@ -1,39 +1,44 @@
// import Img01 from '@/assets/images/img_01.png';
import Img02 from '@/assets/images/img_02.png';
export default [
{
dataUrl:
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
height: 'auto',
width: 'auto',
// dataUrl:
// 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
dataUrl: Img02,
height: 1024,
width: 512,
uid: 0,
span: 12,
loading: true,
span: 24,
loading: false,
progress: 30
},
{
dataUrl:
'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
height: 'auto',
width: 'auto',
uid: 1,
span: 12,
progress: 15
},
{
dataUrl:
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
height: 'auto',
width: 'auto',
uid: 3,
span: 12,
progress: 10
},
{
dataUrl:
'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
height: 'auto',
width: 'auto',
uid: 4,
span: 12,
progress: 15
}
// {
// // dataUrl:
// // 'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
// dataUrl: Img02,
// height: 1024,
// width: 512,
// uid: 1,
// span: 12,
// progress: 15
// }
// {
// dataUrl:
// 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
// height: 'auto',
// width: 'auto',
// uid: 3,
// span: 12,
// progress: 10
// },
// {
// dataUrl:
// 'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
// height: 'auto',
// width: 'auto',
// uid: 4,
// span: 12,
// progress: 15
// }
];

@ -23,8 +23,8 @@
.del {
position: absolute;
top: -4px;
right: -2px;
top: 2px;
right: 2px;
font-size: var(--font-size-middle);
cursor: pointer;
background-color: var(--color-white-1);

@ -137,6 +137,6 @@ export const isHTMLDocumentString = (str: string) => {
// generate a random number between 0 and 64 bit
export const generateRandomNumber = () => {
// 0x100000000
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
// 16: 0x100032:0x100000000
return Math.floor(Math.random() * 0x100000000);
};

Loading…
Cancel
Save