您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
对当前页面正在播放的视频的当前帧进行截图,并启用浏览器下载功能保存到本地。支持设置圆角大小。
当前为
// ==UserScript== // @name 当前页面当前帧视频截图 // @namespace http://tampermonkey.net/ // @version 2024-01-05 // @description 对当前页面正在播放的视频的当前帧进行截图,并启用浏览器下载功能保存到本地。支持设置圆角大小。 // @author 小张 // @match https://www.bilibili.com/video/* // @match https://www.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @grant GM_download // @grant GM_setClipboard // @grant GM_addStyle // @license MIT // ==/UserScript== (function() { 'use strict'; let isVideoPlaying = true; // Variable to track video playback state // 引入jQuery const script = document.createElement('script'); script.src = 'https://code.jquery.com/jquery-3.6.4.min.js'; document.head.appendChild(script); script.onload = () => { // 创建一个按钮 function createScreenshotButton() { const screenshotButton = $('<button>', { text: '截屏', style: 'position: fixed; top: 10px; left: 10px; z-index: 999999999; padding: 10px; background-color: #3498db; color: #fff; border: none; border-radius: 5px; cursor: pointer;', click: function() { toggleVideoPlayback(false); // Pause the video showSettings(); } }); $('body').append(screenshotButton); } // 显示设置界面 function showSettings() { // 移除已存在的设置界面 $('#screenshotSettings').remove(); const settingsContainer = $('<div>', { id: 'screenshotSettings', style: 'position: fixed; display: flex; flex-wrap: wrap; gap: 10px 13px; width:550px; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fff; padding: 20px; border: 2px solid #3498db; z-index: 999999999;border-radius: 6px; box-shadow: 0px 0px 0px 600px #0006;' }); const radiusSlider = $('<input>', { type: 'range', min: 0, max: 250, value: 0, style: 'width: calc(90% - 10px);' }); const radiusInput = $('<input>', { type: 'number', min: 0, max: 250, value: 0, style: 'width: 7%;' }); const previewContainer = $('<div>', { style: 'position: relative;display: flex; flex-wrap: wrap; gap: 10px; align-content: space-between;' }); const previewImage = $('<img>', { style: 'width: calc(100% - 16px); height: auto; border: 1px solid #3498db; image-rendering: pixelated; padding: 8px;background-image: repeating-linear-gradient(45deg, rgba(0, 0, 0, 0.1) 0px, rgba(0, 0, 0, 0.1) 10px, transparent 10px, transparent 20px);box-shadow: inset 0px 0px 20px 2px #27272759;' // 添加 image-rendering 样式 }); const copyButton = $('<button>', { text: '复制', style: 'width: calc(50% - 5px); padding: 10px; background-color: #3498db; color: #fff; border: none; cursor: pointer; float: left;', click: function() { copyImageToClipboard(previewImage[0]); } }); const downloadButton = $('<button>', { text: '下载', style: 'width: calc(50% - 5px); padding: 10px; background-color: #3498db; color: #fff; border: none; cursor: pointer; float: left;', // 修改样式 click: function() { takeScreenshot(parseInt(radiusInput.val())); settingsContainer.remove(); } }); const closeButton = $('<button>', { html: '❌', style: 'position: absolute; top: 10px; right: 10px; padding: 5px; color: #e74c3c; border: none; cursor: pointer; background: none;', // 修改样式 click: function() { toggleVideoPlayback(true); // Resume the video settingsContainer.remove(); } }); // 截取视频当前帧的截图 function takeScreenshot(radius) { const video = $('video')[0]; if (video) { const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const context = canvas.getContext('2d'); context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); const dataURL = processScreenshot(imageData, radius); previewImage.attr('src', dataURL); saveScreenshot(dataURL, getScreenshotFileName()); } } // 复制图片到剪贴板 function copyImageToClipboard(img) { const canvas = document.createElement('canvas'); canvas.width = img.naturalWidth; // 使用 naturalWidth 保持原始分辨率 canvas.height = img.naturalHeight; // 使用 naturalHeight 保持原始分辨率 const context = canvas.getContext('2d'); context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight); canvas.toBlob((blob) => { const item = new ClipboardItem({ "image/png": blob }); navigator.clipboard.write([item]).then( function() { // 修改按钮文字和颜色表示复制成功 copyButton.text('复制成功'); copyButton.css({ 'background-color': '#4CAF50' }); // 2秒后恢复初始状态 setTimeout(function() { copyButton.text('复制'); copyButton.css({ 'background-color': '#3498db' }); }, 2000); }, function(error) { console.error('复制失败:', error); // 修改按钮文字和颜色表示复制失败 copyButton.text('复制失败'); copyButton.css({ 'background-color': '#e74c3c' }); // 2秒后恢复初始状态 setTimeout(function() { copyButton.text('复制'); copyButton.css({ 'background-color': '#3498db' }); }, 2000); } ); }, 'image/png'); } // 获取截图文件名 function getScreenshotFileName() { let pageTitle = $('title').text(); pageTitle = pageTitle.replace('_哔哩哔哩_bilibili', ''); // 去除特定字符串 pageTitle = pageTitle.replace('- YouTube', ''); // 去除特定字符串 const currentTime = formatTime(getCurrentTime()); return `${pageTitle}_${currentTime}.png`; } // 获取当前视频帧时间 function getCurrentTime() { const video = $('video')[0]; return video.currentTime; } // 将时间格式化为mm分ss秒 function formatTime(time) { const minutes = Math.floor(time / 60); const seconds = Math.floor(time % 60); return `${String(minutes).padStart(2, '0')}m${String(seconds).padStart(2, '0')}s`; } // 保存截图到本地 function saveScreenshot(dataURL, fileName) { GM_download({ url: dataURL, name: fileName, saveAs: true, onerror: function(error) { console.error('截图保存失败:', error); } }); } // 添加圆角等处理 function processScreenshot(imageData, radius) { const { width, height, data } = imageData; const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const context = canvas.getContext('2d'); context.putImageData(imageData, 0, 0); context.globalCompositeOperation = 'destination-over'; context.fillStyle = '#fff'; context.fillRect(0, 0, width, height); context.globalCompositeOperation = 'source-over'; context.drawImage(canvas, 0, 0, width, height); context.globalCompositeOperation = 'destination-in'; context.beginPath(); context.moveTo(radius, 0); context.lineTo(width - radius, 0); context.quadraticCurveTo(width, 0, width, radius); context.lineTo(width, height - radius); context.quadraticCurveTo(width, height, width - radius, height); context.lineTo(radius, height); context.quadraticCurveTo(0, height, 0, height - radius); context.lineTo(0, radius); context.quadraticCurveTo(0, 0, radius, 0); context.closePath(); context.fill(); return canvas.toDataURL('image/png'); } // 更新预览图 function updatePreview(radius) { const video = $('video')[0]; if (video) { const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const context = canvas.getContext('2d'); context.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); const dataURL = processScreenshot(imageData, radius); previewImage.attr('src', dataURL); } } // 绑定滑块和输入框的事件 radiusSlider.on('input', function() { radiusInput.val($(this).val()); updatePreview(parseInt($(this).val())); }); radiusInput.on('input', function() { radiusSlider.val($(this).val()); updatePreview(parseInt($(this).val())); }); // 初始化 updatePreview(parseInt(radiusSlider.val())); // 添加到设置界面 previewContainer.append(previewImage, copyButton, downloadButton); // 放置复制按钮和下载按钮 settingsContainer.append( closeButton, $('<label>', { text: '圆角大小', style: 'font-size: 16px; font-weight: bold;width: 100%;' }), radiusSlider, radiusInput, previewContainer, // 使用包含图片和按钮的容器 ); $('body').append(settingsContainer); } // 切换视频播放状态 function toggleVideoPlayback(play) { const video = $('video')[0]; if (video) { if (play && !isVideoPlaying) { video.play(); isVideoPlaying = true; } else if (!play && isVideoPlaying) { video.pause(); isVideoPlaying = false; } } } // 初始化 createScreenshotButton(); }; })();