朋友圈神器长文转图片工具支持自动换行
效果见图,体验见左下角原文链接,原名微博长文转长图工具。
朋友圈(微博)分享文章工具,图文人必备。
另:不依赖服务器,可以自行保存网页局域网浏览器打开使用。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>增强版文章转图片生成器 chalide.cn</title>
<meta name="author" content="yujianyue, 15058593138@qq.com">
<style>
body {
font-family: 'Arial', sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 15px;
}
.form-row {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-bottom: 15px;
}
.form-col {
flex: 1;
min-width: 150px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
font-size: 14px;
}
textarea {
width: 100%;
height: 200px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
resize: vertical;
font-family: inherit;
line-height: 1.5;
}
input, select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
font-family: inherit;
}
.color-input {
display: flex;
gap: 10px;
}
.color-input input[type="color"] {
width: 40px;
height: 40px;
padding: 0;
border: 1px solid #ddd;
}
.color-input input[type="text"] {
flex: 1;
min-width: 100px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
margin: 25px 0;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
flex: 1;
max-width: 200px;
}
button:hover {
background-color: #45a049;
}
.download-btn {
background-color: #2196F3;
}
.download-btn:hover {
background-color: #0b7dda;
}
.image-container {
text-align: center;
margin-top: 30px;
background-color: #f9f9f9;
padding: 15px;
border-radius: 4px;
border: 1px dashed #ddd;
}
.image-preview {
max-width: 100%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.error-message {
color: red;
text-align: center;
margin: 10px 0;
min-height: 20px;
font-size: 14px;
}
.loading {
text-align: center;
margin: 20px 0;
display: none;
color: #666;
}
@media (max-width: 600px) {
.form-col {
min-width: 100%;
}
.btn-group {
flex-direction: column;
align-items: center;
}
button {
max-width: 100%;
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h1>文章转图片生成器</h1>
<form id="text-to-image-form">
<div class="form-group">
<label for="text-content">文章内容:</label>
<textarea id="text-content" name="text" placeholder="请输入要转换的文章内容..." required></textarea>
</div>
<div class="form-row">
<div class="form-col">
<label for="font-select">字体</label>
<select id="font-select" name="font">
<option value="Arial">Arial</option>
<option value="Microsoft YaHei" selected>微软雅黑</option>
<option value="SimSun">宋体</option>
<option value="SimHei">黑体</option>
<option value="KaiTi">楷体</option>
</select>
</div>
<div class="form-col">
<label for="font-size">字体大小 (px)</label>
<input type="number" id="font-size" name="font_size" min="12" max="72" value="18">
</div>
<div class="form-col">
<label for="line-height">行高 (倍数)</label>
<input type="number" id="line-height" name="line_height" min="1" max="3" step="0.1" value="1.5">
</div>
</div>
<div class="form-row">
<div class="form-col">
<label for="text-color">文字颜色</label>
<div class="color-input">
<input type="color" id="text-color-picker" value="#333333">
<input type="text" id="text-color" name="text_color" value="#333333" placeholder="#333333">
</div>
</div>
<div class="form-col">
<label for="bg-color">背景颜色</label>
<div class="color-input">
<input type="color" id="bg-color-picker" value="#FFFFFF">
<input type="text" id="bg-color" name="bg_color" value="#FFFFFF" placeholder="#FFFFFF">
</div>
</div>
<div class="form-col">
<label for="padding">内边距 (px)</label>
<input type="number" id="padding" name="padding" min="0" max="100" value="30">
</div>
</div>
<div class="btn-group">
<button type="submit">生成图片</button>
<button type="button" id="download-btn" class="download-btn" style="display: none;">下载图片</button>
</div>
<div class="error-message" id="error-message"></div>
<div class="loading" id="loading">生成中,请稍候...</div>
</form>
<div class="image-container" id="image-container">
<p>生成的图片将显示在这里</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取DOM元素
const textContent = document.getElementById('text-content');
const fontSelect = document.getElementById('font-select');
const fontSizeInput = document.getElementById('font-size');
const textColorPicker = document.getElementById('text-color-picker');
const textColorInput = document.getElementById('text-color');
const bgColorPicker = document.getElementById('bg-color-picker');
const bgColorInput = document.getElementById('bg-color');
const lineHeightInput = document.getElementById('line-height');
const paddingInput = document.getElementById('padding');
const errorMessage = document.getElementById('error-message');
const form = document.getElementById('text-to-image-form');
const loading = document.getElementById('loading');
const imageContainer = document.getElementById('image-container');
const downloadBtn = document.getElementById('download-btn');
// 颜色选择器和输入框同步
textColorPicker.addEventListener('input', function() {
textColorInput.value = this.value;
});
textColorInput.addEventListener('input', function() {
if (/^#[0-9A-F]{6}$/i.test(this.value)) {
textColorPicker.value = this.value;
}
});
bgColorPicker.addEventListener('input', function() {
bgColorInput.value = this.value;
});
bgColorInput.addEventListener('input', function() {
if (/^#[0-9A-F]{6}$/i.test(this.value)) {
bgColorPicker.value = this.value;
}
});
// 表单提交
form.addEventListener('submit', function(e) {
e.preventDefault();
generateImage();
});
// 初始生成一个示例图片
textContent.value = "这是一段示例文本,用于展示文章转图片的功能。\n\n支持自动换行、自定义字体大小和颜色。当一行文本超过指定宽度时,系统会自动将其分割为多行,确保所有内容都能完整显示。\n\n图片宽度固定为728像素,高度会根据内容长度自动调整。您可以输入任意长度的文本,系统会智能处理换行和段落分隔。\n\n此外,除了文本输入区域外,其他所有控制项都采用一行三列的布局,并能够自适应不同屏幕尺寸,提供更好的用户体验。";
generateImage();
// 生成图片函数
function generateImage() {
const text = textContent.value.trim();
if (!text) {
errorMessage.textContent = '请输入文章内容';
return;
}
errorMessage.textContent = '';
loading.style.display = 'block';
imageContainer.innerHTML = '';
downloadBtn.style.display = 'none';
// 使用setTimeout让UI有机会更新加载状态
setTimeout(() => {
try {
// 创建临时canvas测量高度
const measureCanvas = document.createElement('canvas');
const measureCtx = measureCanvas.getContext('2d');
// 设置canvas宽度
const imageWidth = 728;
const padding = parseInt(paddingInput.value);
const contentWidth = imageWidth - padding * 2;
// 设置测量上下文
const fontSize = parseInt(fontSizeInput.value);
const font = fontSelect.value;
measureCtx.font = `${fontSize}px ${font}`;
// 计算行高
const lineHeight = fontSize * parseFloat(lineHeightInput.value);
// 分割文本行为多行(支持段落内自动换行)
const paragraphs = text.split('\n');
const lines = [];
paragraphs.forEach(paragraph => {
if (!paragraph.trim()) {
lines.push(''); // 空行
return;
}
// 将段落分割为适合宽度的行
const words = paragraph.split('');
let currentLine = words[0] || '';
for (let i = 1; i < words.length; i++) {
const word = words[i];
const testLine = currentLine + ' ' + word;
const metrics = measureCtx.measureText(testLine);
if (metrics.width <= contentWidth) {
currentLine = testLine;
} else {
// 如果当前行不为空,先保存当前行
if (currentLine) {
lines.push(currentLine);
}
currentLine = word;
}
}
// 添加最后一行
if (currentLine) {
lines.push(currentLine);
}
});
// 计算总高度
const contentHeight = lines.length * lineHeight;
const imageHeight = contentHeight + padding * 2;
// 创建实际canvas
const canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
const ctx = canvas.getContext('2d');
// 绘制背景
ctx.fillStyle = bgColorInput.value;
ctx.fillRect(0, 0, imageWidth, imageHeight);
// 设置文本样式
ctx.font = `${fontSize}px ${font}`;
ctx.fillStyle = textColorInput.value;
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
// 绘制文本
let y = padding;
lines.forEach(line => {
if (line === '') {
// 空行处理
y += lineHeight;
} else {
ctx.fillText(line, padding, y);
y += lineHeight;
}
});
// 显示图片
const img = new Image();
img.src = canvas.toDataURL('image/png');
img.className = 'image-preview';
img.alt = '生成的图片';
imageContainer.innerHTML = '';
imageContainer.appendChild(img);
// 设置下载链接
downloadBtn.onclick = function() {
const link = document.createElement('a');
link.href = canvas.toDataURL('image/png');
link.download = `article-image-${Date.now()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
downloadBtn.style.display = 'block';
loading.style.display = 'none';
} catch (error) {
console.error('生成图片出错:', error);
errorMessage.textContent = '生成图片时出错: ' + error.message;
loading.style.display = 'none';
}
}, 100);
}
});
</script>
</body>
</html>