+ imgRef.current.click()}>
+ {t('home.edit')}
+
@@ -83,6 +106,13 @@ const ViewImageCard = forwardRef((props: any, ref: any) => {
className="fileRef"
onChange={handleUploadFile}
/>
+
{
gifBlobRef.current = blob;
- const gifUrl = URL.createObjectURL(blob);
- gifRef.current.src = gifUrl;
});
gif.on('progress', (progress) => {
diff --git a/packages/web/src/i18n/locales/de-DE.json b/packages/web/src/i18n/locales/de-DE.json
index 1a927c4e..74659d09 100644
--- a/packages/web/src/i18n/locales/de-DE.json
+++ b/packages/web/src/i18n/locales/de-DE.json
@@ -14,7 +14,10 @@
"viewImage": "Bild anzeigen",
"playAudio": "Audio abspielen",
"watchVideo": "Video abspielen",
- "history": "Verlauf"
+ "history": "Verlauf",
+ "editImg": "edit image",
+ "gif": "gif",
+ "edit": "edit"
},
"editImage": {
"save": "speichern"
@@ -74,4 +77,4 @@
"close": "schließen",
"download": "Download"
}
-}
\ No newline at end of file
+}
diff --git a/packages/web/src/i18n/locales/en-US.json b/packages/web/src/i18n/locales/en-US.json
index fab02af9..7efce2aa 100644
--- a/packages/web/src/i18n/locales/en-US.json
+++ b/packages/web/src/i18n/locales/en-US.json
@@ -19,7 +19,9 @@
"playAudio": "play audio",
"watchVideo": "watch video",
"history": "history",
- "editImg": "edit image"
+ "editImg": "edit image",
+ "gif": "gif",
+ "edit": "edit"
},
"editImage": {
"save": "save"
@@ -82,4 +84,4 @@
"openServer": "open server",
"serverPath": "server path"
}
-}
\ No newline at end of file
+}
diff --git a/packages/web/src/i18n/locales/zh-CN.json b/packages/web/src/i18n/locales/zh-CN.json
index bbc1bf50..c78d8907 100644
--- a/packages/web/src/i18n/locales/zh-CN.json
+++ b/packages/web/src/i18n/locales/zh-CN.json
@@ -19,7 +19,9 @@
"playAudio": "查看音频",
"watchVideo": "查看视频",
"history": "历史",
- "editImg": "修改图片"
+ "editImg": "编辑图片",
+ "gif": "动图",
+ "edit": "编辑"
},
"editImage": {
"save": "保存"
@@ -82,4 +84,4 @@
"openServer": "打开服务",
"serverPath": "服务地址"
}
-}
\ No newline at end of file
+}
diff --git a/packages/web/src/pages/editGif/index.module.scss b/packages/web/src/pages/editGif/index.module.scss
index 068d1edb..9f0cfa50 100644
--- a/packages/web/src/pages/editGif/index.module.scss
+++ b/packages/web/src/pages/editGif/index.module.scss
@@ -45,7 +45,9 @@
position: relative;
img {
padding: 5px;
- height: calc(100% - 15px);
+ margin: 0 5px;
+ height: calc(100% - 16px);
+ border: 1px solid #ccc;
}
.info {
position: absolute;
@@ -61,7 +63,7 @@
-1px 1px 1px black;
}
}
- .current {
+ .current img {
background-color: rgb(203 232 246);
}
}
diff --git a/packages/web/src/pages/editGif/index.tsx b/packages/web/src/pages/editGif/index.tsx
index 061d4664..1954ad45 100644
--- a/packages/web/src/pages/editGif/index.tsx
+++ b/packages/web/src/pages/editGif/index.tsx
@@ -34,8 +34,55 @@ const EditGif = () => {
const searchParams = new URLSearchParams(paramsString);
let videoUrl = searchParams.get('videoUrl');
let filePath = searchParams.get('filePath');
+ let imgUrl = searchParams.get('imgUrl');
- videoUrl ? loadVideo(videoUrl) : loadVideoFrames(filePath);
+ videoUrl && loadVideo(videoUrl);
+ filePath && loadVideoFrames(filePath);
+ imgUrl && loadImg(imgUrl);
+ }
+
+ const fetchImageByteStream = async (imgUrl: string) => {
+ const response = await fetch(imgUrl);
+ return response.body!;
+ };
+
+ const createImageDecoder = async (imageByteStream: ReadableStream) => {
+ const imageDecoder = new (window as any).ImageDecoder({
+ data: imageByteStream,
+ type: 'image/gif',
+ });
+ await imageDecoder.tracks.ready;
+ await imageDecoder.completed;
+ return imageDecoder;
+ };
+
+ async function loadImg(imgUrl) {
+ const imageByteStream = await fetchImageByteStream(imgUrl);
+ const imageDecoder = await createImageDecoder(imageByteStream);
+ const { image: imageFrame } = await imageDecoder.decode({ frameIndex: 0 });
+ const frameCount = imageDecoder.tracks.selectedTrack!.frameCount;
+ const frameDuration = imageFrame.duration! / 1000;
+ let _videoFrames = [];
+
+ for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
+ const result = await imageDecoder.decode({ frameIndex });
+ await saveImg(result.image, frameIndex);
+ result.image.close();
+ }
+ setVideoFrames(_videoFrames);
+
+ async function saveImg(videoFrame, frameIndex) {
+ const canvas = new OffscreenCanvas(videoFrame.displayWidth, videoFrame.displayHeight);
+ const context = canvas.getContext('2d');
+ context.drawImage(videoFrame, 0, 0);
+ const blob = await canvas.convertToBlob({ type: 'image/jpeg' });
+ const url = URL.createObjectURL(blob);
+ _videoFrames.push({
+ url: url,
+ filePath: frameIndex,
+ index: frameIndex,
+ });
+ }
}
function loadVideo(videoUrl) {
diff --git a/packages/web/src/pages/home/index.tsx b/packages/web/src/pages/home/index.tsx
index e25783a0..db808ad8 100644
--- a/packages/web/src/pages/home/index.tsx
+++ b/packages/web/src/pages/home/index.tsx
@@ -8,7 +8,7 @@ import RecordAudioCard from '../../components/card/recordAudioCard';
import ViewImageCard from '../../components/card/viewImageCard';
import ViewVideoCard from '../../components/card/viewVideoCard';
import ViewAudioCard from '../../components/card/viewAudioCard';
-import EditImageCard from '../../components/card/editImageCard';
+import EditGifCard from '../../components/card/editGifCard';
import ininitApp from '../../pages/main';
import { useUserApi } from '../../api/user';
import styles from './index.module.scss';
@@ -107,7 +107,7 @@ const Home: React.FC = () => {
-
+