diff --git a/app/common/tools/PhoneImage.php b/app/common/tools/PhoneImage.php index 0988831..3735497 100644 --- a/app/common/tools/PhoneImage.php +++ b/app/common/tools/PhoneImage.php @@ -19,6 +19,7 @@ class PhoneImage implements PostOutputManagerInterface 'fontSize' => ['type' => 'number', 'default' => 14, 'min' => 10, 'max' => 24], 'watermark' => ['type' => 'text', 'default' => ''], 'pageAlignments' => ['type' => 'json', 'default' => '{}'], + 'fontScale' => ['type' => 'number', 'default' => 1, 'min' => 0.5, 'max' => 2.0], ]; } @@ -38,6 +39,12 @@ class PhoneImage implements PostOutputManagerInterface return false; } } + if (isset($config['fontScale'])) { + $scale = floatval($config['fontScale']); + if ($scale < 0.5 || $scale > 2.0) { + return false; + } + } // watermark 是文本类型,无需特殊验证 // pageAlignments 是 JSON 类型,存储时由框架自动序列化 diff --git a/public/static/css/phone-image-templates.css b/public/static/css/phone-image-templates.css index 4481255..d4535da 100644 --- a/public/static/css/phone-image-templates.css +++ b/public/static/css/phone-image-templates.css @@ -11,11 +11,13 @@ /* --- CSS Custom Properties (小红书经典风格) --- */ :root { + /* 字号缩放 */ + --pi-font-scale: 1; /* 字号 */ - --pi-font-size-base: 14px; - --pi-font-size-title: 26px; - --pi-font-size-subtitle: 16px; - --pi-font-size-small: 12px; + --pi-font-size-base: calc(14px * var(--pi-font-scale, 1)); + --pi-font-size-title: calc(26px * var(--pi-font-scale, 1)); + --pi-font-size-subtitle: calc(16px * var(--pi-font-scale, 1)); + --pi-font-size-small: calc(12px * var(--pi-font-scale, 1)); /* 行高 */ --pi-line-height: 1.8; /* 间距 */ @@ -66,7 +68,7 @@ position: absolute; bottom: 60px; right: 20px; - font-size: 12px; + font-size: calc(12px * var(--pi-font-scale, 1)); color: rgba(0, 0, 0, 0.3); pointer-events: none; white-space: nowrap; @@ -105,7 +107,7 @@ } .page-cover .cover-title { - font-size: 28px; + font-size: calc(28px * var(--pi-font-scale, 1)); font-weight: normal; letter-spacing: 2px; line-height: 1.5; @@ -163,7 +165,7 @@ } .page-cover.no-cover-image .cover-no-img-title { - font-size: 36px; + font-size: calc(36px * var(--pi-font-scale, 1)); font-weight: bold; line-height: 1.4; color: var(--pi-color-text); @@ -220,7 +222,7 @@ } .page-header .page-title { - font-size: 20px; + font-size: calc(20px * var(--pi-font-scale, 1)); font-weight: normal; letter-spacing: 1px; color: #666; @@ -250,7 +252,7 @@ .page-content h2 { font-weight: normal; - font-size: 18px; + font-size: calc(18px * var(--pi-font-scale, 1)); letter-spacing: 1px; margin-top: 24px; margin-bottom: 12px; @@ -259,28 +261,28 @@ .page-content h3 { font-weight: normal; - font-size: 16px; + font-size: calc(16px * var(--pi-font-scale, 1)); margin-top: 20px; margin-bottom: 10px; color: #555; } .page-content h4 { - font-size: 14px; + font-size: calc(14px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: var(--pi-spacing-sm); margin-bottom: 5px; } .page-content h5 { - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: var(--pi-spacing-sm); margin-bottom: 5px; } .page-content h6 { - font-size: 12px; + font-size: calc(12px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: var(--pi-spacing-sm); margin-bottom: 5px; @@ -310,7 +312,7 @@ border-top: none; padding-top: 0; margin-top: var(--pi-spacing-sm); - font-size: 11px; + font-size: calc(11px * var(--pi-font-scale, 1)); color: #bbb; display: flex; justify-content: space-between; @@ -330,7 +332,7 @@ .page-summary .summary-title { font-weight: normal; letter-spacing: 2px; - font-size: 22px; + font-size: calc(22px * var(--pi-font-scale, 1)); margin-bottom: var(--pi-spacing); color: var(--pi-color-text); } @@ -447,7 +449,7 @@ border-radius: 50%; background: var(--pi-color-accent); color: #fff; - font-size: 14px; + font-size: calc(14px * var(--pi-font-scale, 1)); line-height: 20px; text-align: center; border: none; @@ -473,7 +475,7 @@ } .page-break-marker .break-marker-label { - font-size: 12px; + font-size: calc(12px * var(--pi-font-scale, 1)); color: #ff4d4f; user-select: none; } @@ -488,7 +490,7 @@ border-radius: 50%; background: #ff4d4f; color: #fff; - font-size: 14px; + font-size: calc(14px * var(--pi-font-scale, 1)); line-height: 20px; text-align: center; border: none; @@ -529,7 +531,7 @@ .preview-thumb-page-num { display: block; text-align: center; - font-size: 12px; + font-size: calc(12px * var(--pi-font-scale, 1)); color: #999; margin-top: 6px; } @@ -547,7 +549,7 @@ display: flex; align-items: center; justify-content: center; - font-size: 14px; + font-size: calc(14px * var(--pi-font-scale, 1)); color: #666; user-select: none; border: none; @@ -576,7 +578,7 @@ ============================================ */ /* 表格美化样式(html2canvas兼容) */ -.page-content table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13px; } +.page-content table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: calc(13px * var(--pi-font-scale, 1)); } .page-content th { background-color: #f0f0f0; font-weight: bold; padding: 8px 10px; border: 1px solid #ddd; text-align: left; } .page-content td { padding: 8px 10px; border: 1px solid #ddd; } .page-content tr:nth-child(even) td { background-color: #f9f9f9; } @@ -587,14 +589,14 @@ border-radius: 4px; padding: 12px; overflow-x: auto; - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); line-height: 1.6; margin: 10px 0; } .content-flow code { font-family: 'Courier New', Consolas, monospace; - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); } .content-flow pre code { @@ -604,7 +606,7 @@ } /* 中间栏表格样式 */ -.content-flow-block table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13px; } +.content-flow-block table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: calc(13px * var(--pi-font-scale, 1)); } .content-flow-block th { background-color: #f0f0f0; font-weight: bold; padding: 8px 10px; border: 1px solid #ddd; text-align: left; } .content-flow-block td { padding: 8px 10px; border: 1px solid #ddd; } .content-flow-block tr:nth-child(even) td { background-color: #f9f9f9; } @@ -785,7 +787,7 @@ body > .page-header-right .layui-btn:not(.layui-btn-primary):not(.layui-btn-norm /* 预览区标题字号 */ #render-preview h1 { - font-size: 22px; + font-size: calc(22px * var(--pi-font-scale, 1)); font-weight: bold; letter-spacing: 1px; margin-top: 24px; @@ -795,7 +797,7 @@ body > .page-header-right .layui-btn:not(.layui-btn-primary):not(.layui-btn-norm #render-preview h2 { font-weight: normal; - font-size: 18px; + font-size: calc(18px * var(--pi-font-scale, 1)); letter-spacing: 1px; margin-top: 24px; margin-bottom: 12px; @@ -803,27 +805,27 @@ body > .page-header-right .layui-btn:not(.layui-btn-primary):not(.layui-btn-norm #render-preview h3 { font-weight: normal; - font-size: 16px; + font-size: calc(16px * var(--pi-font-scale, 1)); margin-top: 20px; margin-bottom: 10px; } #render-preview h4 { - font-size: 14px; + font-size: calc(14px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: 10px; margin-bottom: 5px; } #render-preview h5 { - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: 10px; margin-bottom: 5px; } #render-preview h6 { - font-size: 12px; + font-size: calc(12px * var(--pi-font-scale, 1)); font-weight: bold; margin-top: 10px; margin-bottom: 5px; @@ -850,7 +852,7 @@ body > .page-header-right .layui-btn:not(.layui-btn-primary):not(.layui-btn-norm width: 100%; border-collapse: collapse; margin: 10px 0; - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); } #render-preview th { @@ -877,14 +879,14 @@ body > .page-header-right .layui-btn:not(.layui-btn-primary):not(.layui-btn-norm border-radius: 4px; padding: 12px; overflow-x: auto; - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); line-height: 1.6; margin: 10px 0; } #render-preview code { font-family: 'Courier New', Consolas, monospace; - font-size: 13px; + font-size: calc(13px * var(--pi-font-scale, 1)); } #render-preview pre code { diff --git a/public/static/js/phone-image.js b/public/static/js/phone-image.js index 019a41a..5a78546 100644 --- a/public/static/js/phone-image.js +++ b/public/static/js/phone-image.js @@ -19,7 +19,8 @@ var PhoneImageEngine = (function () { xiaohongshu: { width: 540, height: 720 }, douyin: { width: 540, height: 960 } }, - contentPadding: 20 + contentPadding: 20, + fontScale: 1 }; // ===== 文章数据 ===== @@ -71,6 +72,15 @@ var PhoneImageEngine = (function () { if (userConfig) { $.extend(config, userConfig); } + applyFontScale(); + } + + /** + * 应用字号缩放到CSS变量 + */ + function applyFontScale() { + var scale = config.fontScale || 1; + document.documentElement.style.setProperty('--pi-font-scale', scale); } /** @@ -656,7 +666,7 @@ var PhoneImageEngine = (function () { } // 按句子拆分:句号、问号、叹号、换行(兼容不支持 lookbehind 的浏览器) - var effectiveFontSize = 14; + var effectiveFontSize = 14 * (config.fontScale || 1); var parts = text.split(/([。!?\n])/); var sentences = []; var current = ''; @@ -1269,6 +1279,7 @@ var PhoneImageEngine = (function () { config: { size: saveConfig.size || config.size, watermark: saveConfig.watermark || config.watermark, + fontScale: config.fontScale || 1, pageAlignments: config.pageAlignments || {} }, content_html: saveConfig.content_html || postData.content_html @@ -1488,6 +1499,7 @@ var PhoneImageEngine = (function () { if (newConfig) { $.extend(config, newConfig); } + applyFontScale(); } }; })(); diff --git a/view/admin/post/phone_image.html b/view/admin/post/phone_image.html index ad298bb..4f8b080 100644 --- a/view/admin/post/phone_image.html +++ b/view/admin/post/phone_image.html @@ -165,7 +165,15 @@