// ==UserScript== // @name 一键文本转图片 // @namespace mailto:iscyclebai@outlook.com // @version 1.5 // @description 按下 Alt+I 时将选中文字转为图片并复制到剪贴板 // @author Cycle Bai // @license LGPL // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 配置选项 const config = { fontSize: 16, fontFamily: 'Arial, "Microsoft YaHei", sans-serif', padding: 20, maxWidth: 800, lineHeight: 1.5, backgroundColor: '#ffffff', textColor: '#333333', borderRadius: 8, shadowColor: 'rgba(0, 0, 0, 0.1)', }; // 获取选中的文本 function getSelectedText() { const activeElement = document.activeElement; const selection = window.getSelection().toString().trim(); if (selection) return selection; if (activeElement.tagName === 'TEXTAREA' || activeElement.tagName === 'INPUT') { return activeElement.value.substring( activeElement.selectionStart, activeElement.selectionEnd ).trim(); } return ''; } // 优化的文本换行处理 function wrapText(context, text, maxWidth) { const characters = Array.from(text); let lines = []; let currentLine = ''; for (let char of characters) { const testLine = currentLine + char; const metrics = context.measureText(testLine); if (metrics.width > maxWidth - (config.padding * 2)) { lines.push(currentLine); currentLine = char; } else { currentLine = testLine; } } if (currentLine) { lines.push(currentLine); } return lines; } // 创建并配置画布 function setupCanvas(lines) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); // 设置字体 context.font = `${config.fontSize}px ${config.fontFamily}`; // 计算画布尺寸 const lineHeight = config.fontSize * config.lineHeight; const width = config.maxWidth; const height = lines.length * lineHeight + (config.padding * 2); // 设置画布尺寸(考虑设备像素比以提高清晰度) const scale = window.devicePixelRatio || 1; canvas.width = width * scale; canvas.height = height * scale; canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; // 缩放上下文以匹配设备像素比 context.scale(scale, scale); return { canvas, context, lineHeight }; } // 绘制图片 function drawImage(canvas, context, lines, lineHeight) { // 绘制背景 context.fillStyle = config.backgroundColor; context.fillRect(0, 0, canvas.width, canvas.height); // 添加圆角 context.beginPath(); context.roundRect(0, 0, canvas.width, canvas.height, config.borderRadius); context.clip(); // 添加阴影 context.shadowColor = config.shadowColor; context.shadowBlur = 10; context.shadowOffsetX = 0; context.shadowOffsetY = 2; // 绘制文本 context.fillStyle = config.textColor; context.font = `${config.fontSize}px ${config.fontFamily}`; context.textBaseline = 'middle'; lines.forEach((line, i) => { const y = config.padding + (i + 0.5) * lineHeight; context.fillText(line, config.padding, y); }); } // 显示通知 function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; padding: 12px 24px; background: ${type === 'success' ? '#4caf50' : type === 'warning' ? '#ff9800' : '#f44336'}; color: white; border-radius: 4px; font-size: 14px; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.2); animation: fadeInOut 3s ease-in-out; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 3000); } // 主要事件处理函数 async function handleKeyPress(event) { if (!(event.altKey && event.key.toLowerCase() === 'i')) return; const selection = getSelectedText(); if (!selection) { showNotification('请先选中文本!', 'warning'); return; } try { const context = document.createElement('canvas').getContext('2d'); context.font = `${config.fontSize}px ${config.fontFamily}`; const lines = selection.split('\n').flatMap(line => wrapText(context, line, config.maxWidth) ); const { canvas, context: finalContext, lineHeight } = setupCanvas(lines); drawImage(canvas, finalContext, lines, lineHeight); const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); await navigator.clipboard.write([ new ClipboardItem({ 'image/png': blob }) ]); showNotification('图片已复制到剪贴板!', 'success'); } catch (error) { console.error('转换失败:', error); showNotification('转换失败,请检查权限或浏览器兼容性。', 'error'); } } // 注册事件监听器 document.addEventListener('keydown', handleKeyPress); // 添加样式 const style = document.createElement('style'); style.textContent = ` @keyframes fadeInOut { 0% { opacity: 0; transform: translateY(-20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } `; document.head.appendChild(style); })();// ==UserScript== // @name 一键文本转图片 // @namespace https://iscyclebai.com // @version 1.5 // @description 按下 Alt+I 时将选中文字转为图片并复制到剪贴板 // @author Cycle Bai // @match *://*/* // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; // 配置选项 const config = { fontSize: 16, fontFamily: 'Arial, "Microsoft YaHei", sans-serif', padding: 20, maxWidth: 800, lineHeight: 1.5, backgroundColor: '#ffffff', textColor: '#333333', borderRadius: 8, shadowColor: 'rgba(0, 0, 0, 0.1)', }; // 获取选中的文本 function getSelectedText() { const activeElement = document.activeElement; const selection = window.getSelection().toString().trim(); if (selection) return selection; if (activeElement.tagName === 'TEXTAREA' || activeElement.tagName === 'INPUT') { return activeElement.value.substring( activeElement.selectionStart, activeElement.selectionEnd ).trim(); } return ''; } // 优化的文本换行处理 function wrapText(context, text, maxWidth) { const characters = Array.from(text); let lines = []; let currentLine = ''; for (let char of characters) { const testLine = currentLine + char; const metrics = context.measureText(testLine); if (metrics.width > maxWidth - (config.padding * 2)) { lines.push(currentLine); currentLine = char; } else { currentLine = testLine; } } if (currentLine) { lines.push(currentLine); } return lines; } // 创建并配置画布 function setupCanvas(lines) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); // 设置字体 context.font = `${config.fontSize}px ${config.fontFamily}`; // 计算画布尺寸 const lineHeight = config.fontSize * config.lineHeight; const width = config.maxWidth; const height = lines.length * lineHeight + (config.padding * 2); // 设置画布尺寸(考虑设备像素比以提高清晰度) const scale = window.devicePixelRatio || 1; canvas.width = width * scale; canvas.height = height * scale; canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; // 缩放上下文以匹配设备像素比 context.scale(scale, scale); return { canvas, context, lineHeight }; } // 绘制图片 function drawImage(canvas, context, lines, lineHeight) { // 绘制背景 context.fillStyle = config.backgroundColor; context.fillRect(0, 0, canvas.width, canvas.height); // 添加圆角 context.beginPath(); context.roundRect(0, 0, canvas.width, canvas.height, config.borderRadius); context.clip(); // 添加阴影 context.shadowColor = config.shadowColor; context.shadowBlur = 10; context.shadowOffsetX = 0; context.shadowOffsetY = 2; // 绘制文本 context.fillStyle = config.textColor; context.font = `${config.fontSize}px ${config.fontFamily}`; context.textBaseline = 'middle'; lines.forEach((line, i) => { const y = config.padding + (i + 0.5) * lineHeight; context.fillText(line, config.padding, y); }); } // 显示通知 function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; padding: 12px 24px; background: ${type === 'success' ? '#4caf50' : type === 'warning' ? '#ff9800' : '#f44336'}; color: white; border-radius: 4px; font-size: 14px; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.2); animation: fadeInOut 3s ease-in-out; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 3000); } // 主要事件处理函数 async function handleKeyPress(event) { if (!(event.altKey && event.key.toLowerCase() === 'i')) return; const selection = getSelectedText(); if (!selection) { showNotification('请先选中文本!', 'warning'); return; } try { const context = document.createElement('canvas').getContext('2d'); context.font = `${config.fontSize}px ${config.fontFamily}`; const lines = selection.split('\n').flatMap(line => wrapText(context, line, config.maxWidth) ); const { canvas, context: finalContext, lineHeight } = setupCanvas(lines); drawImage(canvas, finalContext, lines, lineHeight); const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); await navigator.clipboard.write([ new ClipboardItem({ 'image/png': blob }) ]); showNotification('图片已复制到剪贴板!', 'success'); } catch (error) { console.error('转换失败:', error); showNotification('转换失败,请检查权限或浏览器兼容性。', 'error'); } } // 注册事件监听器 document.addEventListener('keydown', handleKeyPress); // 添加样式 const style = document.createElement('style'); style.textContent = ` @keyframes fadeInOut { 0% { opacity: 0; transform: translateY(-20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } `; document.head.appendChild(style); })();