// ==UserScript==
// @name 一键文本转图片
// @namespace mailto:[email protected]
// @version 1.5
// @description 按下 Alt+I 时将选中文字转为图片并复制到剪贴板
// @author Cycle Bai
// @license LGPL
// @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);
})();// ==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);
})();