Skip to content

Commit

Permalink
fix: 录屏截图 bug
Browse files Browse the repository at this point in the history
  • Loading branch information
027xiguapi committed Apr 11, 2024
1 parent 7bed6a2 commit 21c0d26
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 46 deletions.
3 changes: 2 additions & 1 deletion packages/desktop/electron/main/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const DIST = path.join(DIST_ELECTRON, '../dist');
export const PUBLIC = url ? path.join(DIST_ELECTRON, '../public') : process.env.DIST;

export const ICON = path.join(PUBLIC, './imgs/icons/png/32x32.png');
export const ICONx2 = path.join(PUBLIC, './imgs/icons/png/64x64.png');

export const DOCS_PATH = path.join(homedir(), 'Documents');

Expand Down Expand Up @@ -125,7 +126,7 @@ export const WIN_CONFIG = {
fullscreenable: false, // 窗口是否可以进入全屏状态
alwaysOnTop: true, // 窗口是否永远在别的窗口的上面
skipTaskbar: true,
// resizable: false,
resizable: false,
},
recorderVideo: {
html: path.join(process.env.DIST, 'recorderVideo.html'),
Expand Down
2 changes: 2 additions & 0 deletions packages/desktop/electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { protocolHandle, registerSchemesAsPrivileged } from './protocol';
import { initTray } from './tray';
import { update } from './update';
import { initApp } from './app';
import { initNotification } from './notification';

initConfig();
initApp();
Expand Down Expand Up @@ -58,6 +59,7 @@ app.whenReady().then(() => {
protocolHandle();
createWindow();
initTray(config.language);
initNotification();
update();
});

Expand Down
15 changes: 11 additions & 4 deletions packages/desktop/electron/main/notification.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Notification } from 'electron';
import { ICON } from './constant';
import { ICONx2 } from './constant';

export function showNotification(_options) {
const options = { icon: ICON, ..._options };
new Notification(options).show();
let notification = null;

export function showNotification(options) {
notification.title = options.title;
notification.body = options.body;
notification.show();
}

export function initNotification() {
notification = new Notification({ icon: ICONx2 });
}
4 changes: 3 additions & 1 deletion packages/desktop/electron/win/recorderScreenWin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ function createRecorderScreenWin(search?: any): BrowserWindow {
fullscreenable: WIN_CONFIG.recorderScreen.fullscreenable, // 窗口是否可以进入全屏状态
alwaysOnTop: WIN_CONFIG.recorderScreen.alwaysOnTop, // 窗口是否永远在别的窗口的上面
// skipTaskbar: WIN_CONFIG.recorderScreen.skipTaskbar,
// resizable: WIN_CONFIG.recorderScreen.resizable,
resizable: WIN_CONFIG.recorderScreen.resizable,
webPreferences: {
preload,
},
});

// recorderScreenWin.webContents.openDevTools();

if (url) {
recorderScreenWin.loadURL(WEB_URL + `recorderScreen.html?type=${search?.type || ''}`);
} else {
Expand Down
21 changes: 21 additions & 0 deletions packages/web/src/components/recorderScreen/Camera.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useState, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { CameraOne } from '@icon-park/react';

const Camera = (props) => {
const { t } = useTranslation();

function handleCamera() {
if (window.electronAPI) {
window.electronAPI?.sendPvOpenWin();
}
}

return (
<div className={`toolbarIcon camera`} title={t('recorderScreen.camera')} onClick={handleCamera}>
<CameraOne className="icon" size={28} />
</div>
);
};

export default Camera;
10 changes: 6 additions & 4 deletions packages/web/src/components/recorderScreen/FullScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ const FullScreen = (props) => {
const { t } = useTranslation();

function handleFullRecordScreen() {
window.electronAPI?.sendRsCloseWin();
window.electronAPI
? window.electronAPI.sendRfsOpenWin()
: window.open('/recorderFullScreen.html');
if (!props.isRecording) {
window.electronAPI?.sendRsCloseWin();
window.electronAPI
? window.electronAPI.sendRfsOpenWin()
: window.open('/recorderFullScreen.html');
}
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const MuteRecorder = (props) => {
const [isMute, setIsMute] = useState(false); // 标记是否静音

function handleToggleMute() {
isMute ? unmuteRecording() : muteRecording();
if (!props.isRecording) {
isMute ? unmuteRecording() : muteRecording();
}
}

// 静音录制
Expand Down
41 changes: 34 additions & 7 deletions packages/web/src/components/recorderScreen/ScreenRecorder.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CameraOutlined, ExclamationCircleFilled, DesktopOutlined } from '@ant-design/icons';
import { ExclamationCircleFilled } from '@ant-design/icons';
import Timer from '@pear-rec/timer';
import useTimer from '@pear-rec/timer/src/useTimer';
import { mp4StreamToOPFSFile } from '@webav/av-cliper';
Expand All @@ -16,6 +16,7 @@ import MicMuteRecorder from './MicMuteRecorder';
import SoundMuteRecorder from './SoundMuteRecorder';
import FullScreen from './FullScreen';
import ShotScreen from './ShotScreen';
import Camera from './Camera';
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile, toBlobURL } from '@ffmpeg/util';

Expand Down Expand Up @@ -188,15 +189,40 @@ const ScreenRecorder = (props) => {
mediaRecorder.current = new AVRecorder(recodeMS, { width: size.width, height: size.height });
}

function handleShotScreen() {
const { width, height } = props.size;
async function handleShotScreen() {
const { width, height } = window.isElectron
? await window.electronAPI?.invokeRsGetBoundsClip()
: props.size;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
context.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height);
const url = canvas.toDataURL('image/png');
saveAs(url, `pear-rec_${+new Date()}.png`);
canvas.toBlob((blob) => {
saveImg(blob);
}, 'image/png');
}

async function saveImg(blob) {
try {
const fileName = `pear-rec_${+new Date()}.png`;
const record = {
fileName: fileName,
fileData: blob,
fileType: 'ss',
userId: user.id,
createdAt: new Date(),
createdBy: user.id,
updatedAt: new Date(),
updatedBy: user.id,
};
const recordId = await db.records.add(record);
if (recordId) {
window.electronAPI?.sendNotification({ title: '截图成功', body: '可以在历史中查看' });
}
} catch (err) {
console.log('截图保存失败', err);
}
}

// 开始录制
Expand Down Expand Up @@ -316,7 +342,7 @@ const ScreenRecorder = (props) => {
<div className="screenRecorder">
<video ref={videoRef} className="hide" playsInline autoPlay />
<div>
<div className={`toolbarIcon recordBtn ${isRecording ? 'blink' : ''}`}>
<div className={`recordBtn ${isRecording ? 'blink' : ''}`}>
<BsRecordCircle />
</div>
<div>录制</div>
Expand All @@ -330,8 +356,9 @@ const ScreenRecorder = (props) => {
className="timer"
/>
<div className="tool">
<Camera />
<FullScreen isRecording={isRecording} />
<ShotScreen onShotScreen={handleShotScreen} />
<ShotScreen isRecording={isRecording} onShotScreen={handleShotScreen} />
<MicMuteRecorder isRecording={isRecording} />
<SoundMuteRecorder isRecording={isRecording} />
</div>
Expand Down
5 changes: 2 additions & 3 deletions packages/web/src/components/recorderScreen/ShotScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ const ShotScreen = (props) => {
const { t } = useTranslation();

function handleShotScreen() {
props.onShotScreen();
console.log('截图');
props.isRecording && props.onShotScreen();
}

return (
<div
className="toolbarIcon shotScreenBtn"
className={`${props.isRecording ? '' : 'disabled'} toolbarIcon shotScreenBtn`}
title={t('recorderScreen.shotScreen')}
onClick={handleShotScreen}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const SoundMuteRecorder = (props) => {
const [isMute, setIsMute] = useState(false); // 标记是否静音

function handleToggleMute() {
isMute ? unmuteRecording() : muteRecording();
if (!props.isRecording) {
isMute ? unmuteRecording() : muteRecording();
}
}

// 静音录制
Expand Down
3 changes: 2 additions & 1 deletion packages/web/src/pages/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ table {

.disabled {
opacity: 0.5;
cursor: not-allowed;
// pointer-events: none !important;
cursor: not-allowed !important;
}

#root {
Expand Down
14 changes: 0 additions & 14 deletions packages/web/src/pages/recorderFullScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,6 @@ const RecorderScreen = () => {
<div className={styles.recorderFullScreen}>
<div className={'recordTool ' + `${isRecording ? 'recording' : ''}`}>
<BsRecordCircle className={'recordIcon ' + `${isRecording && !isPause ? 'blink' : ''}`} />
{/* <Button
type="text"
icon={<SettingOutlined />}
className="toolbarIcon settingBtn"
title={t('nav.setting')}
onClick={handleOpenSettingWin}
></Button> */}
<Button
type="text"
icon={<CameraOne theme="outline" size="22" fill="#333" strokeWidth={3} />}
Expand All @@ -288,13 +281,6 @@ const RecorderScreen = () => {
title={t('nav.close')}
onClick={handleCloseWin}
></Button>
{/* <Button
type="text"
icon={<CameraOutlined />}
className="toolbarIcon shotScreenBtn"
title={t('recorderScreen.shotScreen')}
onClick={handleShotScreen}
></Button> */}
<Timer
seconds={timer.seconds}
minutes={timer.minutes}
Expand Down
29 changes: 20 additions & 9 deletions packages/web/src/pages/recorderScreen/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@
z-index: 100;
outline: 2px solid #ccc;
display: flex;
// cursor: pointer;
width: 100%;
height: 100%;
// background-color: #ccc;
align-items: center;
justify-content: space-around;
.info {
Expand All @@ -44,10 +42,27 @@
}
.toolbarIcon {
font-size: 26px;
height: 35px;
display: flex;
width: 30px;
align-items: center;
justify-content: center;
cursor: pointer;
.icon {
display: flex;
align-items: center;
}
}
.toolbarIcon:hover {
background-color: #ccc;
}
.recordBtn {
font-size: 32px;
height: 35px;
display: flex;
width: 30px;
align-items: center;
justify-content: center;
}
.settingBtn {
line-height: 15px;
Expand All @@ -61,8 +76,10 @@
.playBtn {
color: #1677ff;
font-size: 40px;
width: 45px;
}
.stopBtn {
width: 45px;
color: red;
}
.pauseBtn {
Expand All @@ -75,14 +92,8 @@
background: transparent;
}
.playRecorder {
width: 55px;
width: 45px;
text-align: center;
// line-height: 40px;
// display: flex;
.toolbarTitle {
// height: 30px;
// line-height: 35px;
}
}
}
.iframeRef {
Expand Down

0 comments on commit 21c0d26

Please sign in to comment.