当前位置: 首页 > news >正文

Canvas 动态高度文本图片生成器

先看效果图

上代码:

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Canvas 动态高度文本图片生成器</title><style>body {font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;margin: 0;padding: 20px;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);min-height: 100vh;display: flex;flex-direction: column;align-items: center;}.container {background: white;border-radius: 15px;padding: 30px;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);max-width: 800px;width: 100%;margin-bottom: 30px;}h1 {text-align: center;color: #333;margin-bottom: 30px;font-weight: 300;}.input-area {margin-bottom: 20px;}textarea {width: 100%;height: 120px;padding: 15px;border: 2px solid #e2e8f0;border-radius: 8px;font-size: 16px;resize: vertical;font-family: inherit;box-sizing: border-box;}textarea:focus {outline: none;border-color: #667eea;box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);}.controls {display: flex;gap: 15px;margin-bottom: 20px;flex-wrap: wrap;}button {padding: 12px 24px;border: none;border-radius: 8px;background: #667eea;color: white;cursor: pointer;transition: all 0.3s ease;font-size: 14px;font-weight: 500;}button:hover {background: #5a67d8;transform: translateY(-1px);}button:active {transform: translateY(0);}.preview-area {text-align: center;margin-top: 30px;}.preview-container {display: inline-block;border: 2px dashed #cbd5e0;border-radius: 10px;padding: 20px;background: #f8fafc;margin-bottom: 20px;}.info {margin-top: 15px;padding: 15px;background: #edf2f7;border-radius: 8px;font-size: 14px;color: #4a5568;}.download-btn {background: #48bb78;margin-top: 15px;}.download-btn:hover {background: #38a169;}</style></head><body><div class="container"><h1>Canvas 动态高度文本图片生成器</h1><div class="input-area"><textareaid="textInput"placeholder="请输入要生成图片的文本内容..."oninput="debouncedCalculateAndPreview()">
这是一个示例文本,用于演示Canvas动态高度文本渲染功能。当文本内容超过固定宽度时,会自动换行并计算所需高度。</textarea></div><div class="controls"><button onclick="calculateAndPreview()">立即生成</button><button onclick="changeFontSize('increase')">增大字体</button><button onclick="changeFontSize('decrease')">减小字体</button><button onclick="changeLineHeight('increase')">增加行距</button><button onclick="changeLineHeight('decrease')">减少行距</button><button onclick="toggleTheme()">切换主题</button></div><div class="preview-area"><div class="preview-container"><canvas id="previewCanvas"></canvas></div><div class="info" id="sizeInfo">图片尺寸: 0px × 0px | 行数: 0</div><button class="download-btn" onclick="downloadImage()">下载图片</button></div></div><script>// 配置参数const config = {fixedWidth: 400, // 固定宽度fontSize: 16, // 字体大小lineHeight: 1.5, // 行高倍数padding: 20, // 内边距fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",textColor: "#2d3748", // 文字颜色backgroundColor: "#ffffff", // 背景颜色borderColor: "#e2e8f0", // 边框颜色};// Canvas 相关变量let canvas = document.getElementById("previewCanvas");let ctx = canvas.getContext("2d");let currentText = "";// 防抖函数function debounce(func, wait) {let timeout;return function executedFunction(...args) {const later = () => {clearTimeout(timeout);func(...args);};clearTimeout(timeout);timeout = setTimeout(later, wait);};}// 设置防抖的预览函数const debouncedCalculateAndPreview = debounce(calculateAndPreview, 300);// 计算文本换行和高度function calculateTextDimensions(text, maxWidth) {// 设置字体以测量文本ctx.font = `${config.fontSize}px ${config.fontFamily}`;const words = text.split("");const lines = [];let currentLine = words[0];let maxLineWidth = 0;// 文本换行算法for (let i = 1; i < words.length; i++) {const testLine = currentLine + words[i];const metrics = ctx.measureText(testLine);const testWidth = metrics.width;if (testWidth > maxWidth && currentLine !== "") {// 当前行已满,添加到行数组lines.push(currentLine);maxLineWidth = Math.max(maxLineWidth,ctx.measureText(currentLine).width);currentLine = words[i];} else {currentLine = testLine;}}// 添加最后一行lines.push(currentLine);maxLineWidth = Math.max(maxLineWidth,ctx.measureText(currentLine).width);console.log("maxLineWidth",maxLineWidth,ctx.measureText(currentLine).width);// 计算总高度const lineHeight = config.fontSize * config.lineHeight;const totalHeight = lines.length * lineHeight + config.padding * 2;return {lines: lines,lineCount: lines.length,totalHeight: totalHeight,maxLineWidth: maxLineWidth,lineHeight: lineHeight,};}// 计算并预览图片function calculateAndPreview() {const text = document.getElementById("textInput").value.trim();currentText = text;if (!text) {canvas.width = config.fixedWidth;canvas.height = 100;ctx.clearRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = config.backgroundColor;ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = "#a0aec0";ctx.font = `${config.fontSize}px ${config.fontFamily}`;ctx.textAlign = "center";ctx.fillText("请输入文本内容", canvas.width / 2, 50);updateSizeInfo(0, 0, 0);return;}// 计算文本尺寸const dimensions = calculateTextDimensions(text,config.fixedWidth - config.padding * 2);// 设置Canvas尺寸canvas.width = config.fixedWidth;canvas.height = dimensions.totalHeight;// 绘制背景ctx.fillStyle = config.backgroundColor;ctx.fillRect(0, 0, canvas.width, canvas.height);// 绘制边框ctx.strokeStyle = config.borderColor;ctx.lineWidth = 1;ctx.strokeRect(0, 0, canvas.width, canvas.height);// 绘制文本ctx.fillStyle = config.textColor;ctx.font = `${config.fontSize}px ${config.fontFamily}`;ctx.textBaseline = "middle";ctx.textAlign = "left";const startY = config.padding + dimensions.lineHeight / 2;dimensions.lines.forEach((line, index) => {const y = startY + index * dimensions.lineHeight;console.log(line, config.padding, y);ctx.fillText(line, config.padding, y);});// 更新尺寸信息updateSizeInfo(canvas.width, canvas.height, dimensions.lineCount);}// 更新尺寸信息显示function updateSizeInfo(width, height, lineCount) {document.getElementById("sizeInfo").textContent = `图片尺寸: ${width}px × ${height}px | 行数: ${lineCount} | 字体: ${config.fontSize}px`;}// 改变字体大小function changeFontSize(action) {if (action === "increase") {config.fontSize = Math.min(config.fontSize + 2, 32);} else {config.fontSize = Math.max(config.fontSize - 2, 12);}calculateAndPreview();}// 改变行高function changeLineHeight(action) {if (action === "increase") {config.lineHeight = Math.min(config.lineHeight + 0.1, 2.5);} else {config.lineHeight = Math.max(config.lineHeight - 0.1, 1.2);}calculateAndPreview();}// 切换主题function toggleTheme() {if (config.backgroundColor === "#ffffff") {// 切换到暗色主题config.backgroundColor = "#2d3748";config.textColor = "#e2e8f0";config.borderColor = "#4a5568";} else {// 切换到亮色主题config.backgroundColor = "#ffffff";config.textColor = "#2d3748";config.borderColor = "#e2e8f0";}calculateAndPreview();}// 下载图片function downloadImage() {if (!currentText) {alert("请先输入文本内容");return;}const link = document.createElement("a");link.download = `text-image-${new Date().getTime()}.png`;link.href = canvas.toDataURL("image/png");link.click();}// 初始化function init() {// 设置初始字体ctx.font = `${config.fontSize}px ${config.fontFamily}`;// 初始渲染calculateAndPreview();// 添加键盘快捷键document.addEventListener("keydown", (e) => {if (e.ctrlKey && e.key === "Enter") {calculateAndPreview();}});}// 页面加载完成后初始化window.addEventListener("load", init);</script></body>
</html>

http://www.dtcms.com/a/349921.html

相关文章:

  • Linux 详谈Ext系列⽂件系统(一)
  • 嵌入式(ARM方向)面试常见问题及解答
  • 【ARM】MDK在debug模式下断点的类型
  • blazor 学习笔记--vscode debug
  • C++11(Linux/GCC)字节序工具
  • 2025年09月计算机二级Python选择题每日一练——第七期
  • 栈指针(Stack Pointer)是什么?
  • 设置密钥连接服务器
  • 【基础-单选】向服务器提交表单数据,以下哪种请求方式比较合适
  • Linux 离线安装lrzsz(rz、sz上传下载小插件)
  • 什么是高防服务器?如何进行防御?
  • UE5多人MOBA+GAS 54、用户登录和会话创建请求
  • 矩阵系统源代码开发,支持OEM贴牌
  • 深入解析ffmpeg.dll:电脑中的关键组件及其相关问题解决​
  • 【龙泽科技】汽车车身测量与校正仿真教学软件【赛欧+SHARK】
  • 8851定期复盘代码实现设计模式的于芬应用
  • 中国计算机学会(CCF)推荐学术会议-B(计算机图形学与多媒体):DCC 2026
  • 《信息检索与论文写作》实验报告一 EI数据库检索
  • Allegro约束管理器设置详细教程
  • JUC之volatile关键字
  • 高通平台wifi--p2p issue
  • KubeBlocks for Redis的5种网络模式
  • Linux文件归档工具tar
  • 基于SpringBoot+Vue的社区二手交易系统(WebSocket实时通讯、Echarts图形化分析、协同过滤算法)
  • 3-3〔OSCP ◈ 研记〕❘ WEB应用攻击▸WEB应用安全评估工具
  • nacos管理配置
  • Go语言内存管理深度解析:堆栈分配与逃逸分析的艺术
  • 深度学习篇---ResNet家族
  • Matlab高光谱遥感、数据处理与混合像元分解实践技术应用
  • Mysql系列--8、索引