diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index b6cb80b2..22da9d3a 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/web +## 1.4.11 + +fix: 动图导出 bug、视频解析动图 bug + ## 1.4.10 feat: 网站统计 diff --git a/packages/web/public/video-decode-display/renderer_2d.js b/packages/web/public/video-decode-display/renderer_2d.js index 43663ea1..64cedf36 100644 --- a/packages/web/public/video-decode-display/renderer_2d.js +++ b/packages/web/public/video-decode-display/renderer_2d.js @@ -1,24 +1,38 @@ class Canvas2DRenderer { #canvas = null; #ctx = null; + #timeStart = 0; + #timeEnd = 0; + #num = 0; + #index = 0; - constructor(canvas) { + constructor(canvas, option) { this.#canvas = canvas; this.#ctx = canvas.getContext('2d'); + this.#timeStart = option.timeStart; + this.#timeEnd = option.timeEnd; + this.#num = option.num; } draw(frame) { - this.#canvas.width = frame.displayWidth; - this.#canvas.height = frame.displayHeight; - this.#ctx.drawImage(frame, 0, 0, frame.displayWidth, frame.displayHeight); + if ( + (this.#index < this.#num || !this.#num) && + ((this.#timeStart == 0 && this.#timeEnd == 0) || + (this.#timeStart <= frame.timestamp && this.#timeEnd > frame.timestamp)) + ) { + this.#index++; + this.#canvas.width = frame.displayWidth; + this.#canvas.height = frame.displayHeight; + this.#ctx.drawImage(frame, 0, 0, frame.displayWidth, frame.displayHeight); + this.#canvas.convertToBlob({ type: 'image/png' }).then((blob) => { + let videoFrame = { + fileName: `pear-rec_${+new Date()}.png`, + fileData: blob, + frameDuration: (frame.duration / 1000).toFixed(0), + }; + self.postMessage({ videoFrame, index: this.#index }); + }); + } frame.close(); - this.#canvas.convertToBlob({ type: 'image/png' }).then((blob) => { - let videoFrame = { - fileName: `pear-rec_${+new Date()}.png`, - fileData: blob, - frameDuration: (frame.duration / 1000).toFixed(0), - }; - self.postMessage({ videoFrame }); - }); } } diff --git a/packages/web/public/video-decode-display/worker.js b/packages/web/public/video-decode-display/worker.js index 9bc9322e..1493ab1e 100644 --- a/packages/web/public/video-decode-display/worker.js +++ b/packages/web/public/video-decode-display/worker.js @@ -48,11 +48,11 @@ async function renderAnimationFrame() { } // Startup. -function start({ dataUri, rendererName, canvas, duration }) { +function start({ dataUri, rendererName, canvas, option }) { // Pick a renderer to use. switch (rendererName) { case '2d': - renderer = new Canvas2DRenderer(canvas); + renderer = new Canvas2DRenderer(canvas, option); break; case 'webgl': renderer = new WebGLRenderer(rendererName, canvas); diff --git a/packages/web/src/components/editGif/tool/File.tsx b/packages/web/src/components/editGif/tool/File.tsx index df2614d7..37b1192f 100644 --- a/packages/web/src/components/editGif/tool/File.tsx +++ b/packages/web/src/components/editGif/tool/File.tsx @@ -1,6 +1,5 @@ import { Close, FileGif, Save, VideoFile } from '@icon-park/react'; import { Modal, Progress } from 'antd'; -import async from 'async'; import { saveAs } from 'file-saver'; import GIF from 'gif.js'; import { useContext, useRef, useState } from 'react'; @@ -38,33 +37,26 @@ const File = () => { async function loadImage(videoFrame, callback) { const img = new Image(); - const data = await fetch(videoFrame.url); - const blob = await data.blob(); - const videoFrameUrl = URL.createObjectURL(blob); - img.src = videoFrameUrl; - + img.crossOrigin = ''; img.onload = function () { - return callback(null, img); + return callback(img); }; img.onerror = function (error) { - return callback(new Error('Could load ' + error)); + return console.log('Could load ' + error); }; - - return img; + img.src = URL.createObjectURL(videoFrame.fileData); } - async.map(gifState.videoFrames, loadImage, function (error, images) { - if (error != null) { - throw error; - } - for (let j = 0; j < images.length; j++) { - let image = images[j]; + gifState.videoFrames.map((videoFrame, index) => { + loadImage(videoFrame, function (image) { gif.addFrame(image, { - delay: gifState.videoFrames[j].duration, + delay: videoFrame.duration, copy: true, }); - } - return gif.render(); + if (index == gifState.videoFrames.length - 1) { + gif.render(); + } + }); }); } @@ -75,7 +67,7 @@ const File = () => { async function handleDownloadFile(blob) { try { const record = { - fileName: `pear-rec_${+new Date()}.webm`, + fileName: `pear-rec_${+new Date()}.gif`, fileData: blob, fileType: 'eg', userId: user.id, diff --git a/packages/web/src/pages/editGif/index.tsx b/packages/web/src/pages/editGif/index.tsx index 60da40cf..6478e23b 100644 --- a/packages/web/src/pages/editGif/index.tsx +++ b/packages/web/src/pages/editGif/index.tsx @@ -146,8 +146,10 @@ const EditGif = () => { _videoUrl = `pearrec://${gifState.videoUrl}`; } const duration = 100; + const num = 500; const rendererName = '2d'; const canvas = (document.querySelector('#canvas') as any).transferControlToOffscreen?.(); + let option = { timeStart: 0 * 1e6, timeEnd: 0 * 1e6, duration, num }; const worker = new Worker( window.isElectron ? './video-decode-display/worker.js' : '/video-decode-display/worker.js', { @@ -160,17 +162,17 @@ const EditGif = () => { let videoFrame = message.data['videoFrame']; await uploadFileCache(videoFrame.fileData, videoFrame.frameDuration); gifDispatch({ type: 'setLoadAdd', num: 1 }); - } - if (message.data['render']) { - setTimeout(() => { - gifDispatch({ type: 'setLoad', load: 100 }); - setVideoFrames(); - }, 500); + if (message.data['index'] == num) { + setTimeout(() => { + gifDispatch({ type: 'setLoad', load: 100 }); + setVideoFrames(); + }, 500); + } } } worker.addEventListener('message', setStatus); - worker.postMessage({ dataUri: _videoUrl, rendererName, canvas, duration }, [canvas]); + worker.postMessage({ dataUri: _videoUrl, rendererName, canvas, option }, [canvas]); } return (