html5+css3+canvas长文转长图工具支持换行

发布于:2025-08-03 ⋅ 阅读:(9) ⋅ 点赞:(0)

朋友圈神器长文转图片工具支持自动换行

效果见图,体验见左下角原文链接,原名微博长文转长图工具。

朋友圈(微博)分享文章工具,图文人必备。

另:不依赖服务器,可以自行保存网页局域网浏览器打开使用。

 


<!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>