contentEx = array('ImageCaptionWatermark_Plugin', 'parseContent'); Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('ImageCaptionWatermark_Plugin', 'parseContent'); Typecho_Plugin::factory('Widget_Archive')->footer = array('ImageCaptionWatermark_Plugin', 'addFooter'); return '插件已激活,请到设置页面配置参数。'; } /** * 禁用插件 */ public static function deactivate() { return '插件已禁用'; } /** * 插件配置面板 */ public static function config(Typecho_Widget_Helper_Form $form) { // 标题设置部分 $titleEnable = new Typecho_Widget_Helper_Form_Element_Radio( 'titleEnable', array('1' => '开启', '0' => '关闭'), '1', '启用图片标题', '是否自动为文章中的图片添加标题' ); $form->addInput($titleEnable); $titlePosition = new Typecho_Widget_Helper_Form_Element_Select( 'titlePosition', array( 'bottom-center' => '底部居中', 'bottom-right' => '右下角', 'bottom-left' => '左下角', 'top-center' => '顶部居中', 'top-right' => '右上角', 'top-left' => '左上角' ), 'bottom-center', '标题显示位置', '标题在图片上的显示位置' ); $form->addInput($titlePosition); $titleMinWidth = new Typecho_Widget_Helper_Form_Element_Text( 'titleMinWidth', NULL, '300', '标题最小图片宽度', '页面显示宽度大于此值(像素)的图片才显示标题' ); $titleMinWidth->input->setAttribute('style', 'width: 120px;'); $form->addInput($titleMinWidth->addRule('isInteger', '请输入整数')); // 新增:标题最小高度 $titleMinHeight = new Typecho_Widget_Helper_Form_Element_Text( 'titleMinHeight', NULL, '300', '标题最小图片高度', '页面显示高度大于此值(像素)的图片才显示标题' ); $titleMinHeight->input->setAttribute('style', 'width: 120px;'); $form->addInput($titleMinHeight->addRule('isInteger', '请输入整数')); $titleChineseOnly = new Typecho_Widget_Helper_Form_Element_Radio( 'titleChineseOnly', array('1' => '开启', '0' => '关闭'), '1', '仅显示中文标题', '开启:如果图片alt/title中没有中文,则不显示标题
关闭:显示所有标题' ); $form->addInput($titleChineseOnly); $titleColor = new Typecho_Widget_Helper_Form_Element_Text( 'titleColor', NULL, '#FFFFFF', '标题文字颜色', '标题文字的颜色' ); $titleColor->input->setAttribute('style', 'width: 150px;'); $form->addInput($titleColor); $titleBgColor = new Typecho_Widget_Helper_Form_Element_Text( 'titleBgColor', NULL, 'rgba(0,0,0,0.85)', '标题背景颜色', '标题背景的颜色' ); $titleBgColor->input->setAttribute('style', 'width: 150px;'); $form->addInput($titleBgColor); // 新增:标题背景透明度 $titleBgOpacity = new Typecho_Widget_Helper_Form_Element_Text( 'titleBgOpacity', NULL, '0.85', '标题背景透明度', '0-1之间,1为不透明' ); $titleBgOpacity->input->setAttribute('style', 'width: 100px;'); $titleBgOpacity->input->setAttribute('placeholder', '0.0-1.0'); $form->addInput($titleBgOpacity); // 修改:标题显示分类 $titleIncludeCategories = new Typecho_Widget_Helper_Form_Element_Text( 'titleIncludeCategories', NULL, '', '标题显示分类', '仅在此分类下的文章显示图片标题,留空表示所有分类都显示
多个分类用逗号间隔,如:技术,生活' ); $titleIncludeCategories->input->setAttribute('style', 'width: 300px;'); $form->addInput($titleIncludeCategories); $titleFontSize = new Typecho_Widget_Helper_Form_Element_Text( 'titleFontSize', NULL, '14', '标题字体大小', '标题文字的大小(像素)' ); $titleFontSize->input->setAttribute('style', 'width: 120px;'); $form->addInput($titleFontSize->addRule('isInteger', '请输入整数')); $titlePadding = new Typecho_Widget_Helper_Form_Element_Text( 'titlePadding', NULL, '8px 15px', '标题内边距', '标题的内边距,格式:上下 左右' ); $titlePadding->input->setAttribute('style', 'width: 150px;'); $form->addInput($titlePadding); // 新增:是否跳过横排组内的图片标题 $skipFlexGroupTitles = new Typecho_Widget_Helper_Form_Element_Radio( 'skipFlexGroupTitles', array('1' => '跳过', '0' => '不跳过'), '1', '跳过横排组内的图片标题', '开启:在横排图片组(flex-group)中不显示单张图片的标题,只显示组标题
关闭:同时显示组标题和单图标题' ); $form->addInput($skipFlexGroupTitles); // 水印设置部分 $watermarkEnable = new Typecho_Widget_Helper_Form_Element_Radio( 'watermarkEnable', array('1' => '开启', '0' => '关闭'), '1', '启用图片水印', '是否自动为文章中的图片添加水印' ); $form->addInput($watermarkEnable); $watermarkText = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkText', NULL, 'SHITOUCUO.COM', '水印文字内容', '水印文字的内容' ); $watermarkText->input->setAttribute('style', 'width: 300px;'); $form->addInput($watermarkText); $watermarkPosition = new Typecho_Widget_Helper_Form_Element_Select( 'watermarkPosition', array( 'top-left' => '左上角', 'top-center' => '顶部居中', 'top-right' => '右上角', 'center' => '正中央', 'bottom-left' => '左下角', 'bottom-center' => '底部居中', 'bottom-right' => '右下角' ), 'top-center', '水印显示位置', '避免与标题重叠,建议使用顶部位置' ); $form->addInput($watermarkPosition); $watermarkMinWidth = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkMinWidth', NULL, '200', '水印最小图片宽度', '页面显示宽度大于此值(像素)的图片才添加水印' ); $watermarkMinWidth->input->setAttribute('style', 'width: 120px;'); $form->addInput($watermarkMinWidth->addRule('isInteger', '请输入整数')); // 新增:水印最小高度 $watermarkMinHeight = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkMinHeight', NULL, '500', '水印最小图片高度', '页面显示高度大于此值(像素)的图片才添加水印' ); $watermarkMinHeight->input->setAttribute('style', 'width: 120px;'); $form->addInput($watermarkMinHeight->addRule('isInteger', '请输入整数')); // 修改:水印显示分类 $watermarkIncludeCategories = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkIncludeCategories', NULL, '', '水印显示分类', '仅在此分类下的文章显示图片水印,留空表示所有分类都显示
多个分类用逗号间隔,如:技术,生活' ); $watermarkIncludeCategories->input->setAttribute('style', 'width: 300px;'); $form->addInput($watermarkIncludeCategories); $watermarkOpacity = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkOpacity', NULL, '0.7', '水印透明度', '0-1之间,1为不透明' ); $watermarkOpacity->input->setAttribute('style', 'width: 100px;'); $watermarkOpacity->input->setAttribute('placeholder', '0.0-1.0'); $form->addInput($watermarkOpacity); $watermarkFontSize = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkFontSize', NULL, '24', '水印字体大小', '文字水印的字体大小(像素)' ); $watermarkFontSize->input->setAttribute('style', 'width: 100px;'); $form->addInput($watermarkFontSize->addRule('isInteger', '请输入整数')); $watermarkFontColor = new Typecho_Widget_Helper_Form_Element_Text( 'watermarkFontColor', NULL, 'rgba(255,255,255,0.9)', '水印文字颜色', '文字水印的颜色' ); $watermarkFontColor->input->setAttribute('style', 'width: 150px;'); $form->addInput($watermarkFontColor); // 性能设置部分 $batchSize = new Typecho_Widget_Helper_Form_Element_Text( 'batchSize', NULL, '10', '批量处理数量', '每次同时处理的图片数量,减少一次性处理压力' ); $batchSize->input->setAttribute('style', 'width: 120px;'); $form->addInput($batchSize->addRule('isInteger', '请输入整数')); $processDelay = new Typecho_Widget_Helper_Form_Element_Text( 'processDelay', NULL, '100', '处理延迟(ms)', '图片加载后延迟处理的时间(毫秒)' ); $processDelay->input->setAttribute('style', 'width: 120px;'); $form->addInput($processDelay->addRule('isInteger', '请输入整数')); $debugMode = new Typecho_Widget_Helper_Form_Element_Radio( 'debugMode', array('1' => '开启', '0' => '关闭'), '0', '调试模式', '开启后在控制台显示处理信息(调试完成后建议关闭)' ); $form->addInput($debugMode); } /** * 个人用户配置面板 */ public static function personalConfig(Typecho_Widget_Helper_Form $form) { // 不需要个人配置 } /** * 处理文章内容 */ public static function parseContent($content, $widget, $lastResult) { $content = empty($lastResult) ? $content : $lastResult; if ($widget instanceof Widget_Archive) { $content = self::parseImages($content, $widget); } return $content; } /** * 解析图片并添加标题和水印 */ private static function parseImages($text, $widget) { $options = Helper::options(); $config = $options->plugin('ImageCaptionWatermark'); if (!$config) { return $text; } // 获取当前文章分类 $currentCategories = array(); if ($widget->categories && is_array($widget->categories)) { foreach ($widget->categories as $category) { if (isset($category['name'])) { $currentCategories[] = $category['name']; } } } // 处理显示分类设置 $titleIncludeCategories = array(); if (!empty($config->titleIncludeCategories) && trim($config->titleIncludeCategories) !== '') { $titleIncludeCategories = array_map('trim', explode(',', $config->titleIncludeCategories)); } $watermarkIncludeCategories = array(); if (!empty($config->watermarkIncludeCategories) && trim($config->watermarkIncludeCategories) !== '') { $watermarkIncludeCategories = array_map('trim', explode(',', $config->watermarkIncludeCategories)); } // 检查当前分类是否在显示列表中 $isTitleIncluded = true; // 默认显示,除非设置了显示分类且当前分类不在其中 $isWatermarkIncluded = true; // 默认显示,除非设置了显示分类且当前分类不在其中 // 如果设置了显示分类,则检查当前分类是否在其中 if (!empty($titleIncludeCategories)) { $isTitleIncluded = false; foreach ($currentCategories as $category) { if (in_array($category, $titleIncludeCategories)) { $isTitleIncluded = true; break; } } } if (!empty($watermarkIncludeCategories)) { $isWatermarkIncluded = false; foreach ($currentCategories as $category) { if (in_array($category, $watermarkIncludeCategories)) { $isWatermarkIncluded = true; break; } } } // 匹配图片标签 $text = preg_replace_callback('/]*>/i', function($matches) use ($config, $isTitleIncluded, $isWatermarkIncluded) { $imgTag = $matches[0]; // 跳过特定图片 if (preg_match('/class=["\'][^"\']*(no-watermark|no-caption)[^"\']*["\']/i', $imgTag)) { return $imgTag; } // 检查图片是否在横排组中(通过父元素判断) $skipTitle = false; if ($config->skipFlexGroupTitles == '1') { // 检查img标签周围是否有flexphoto-group的迹象 if (strpos($imgTag, 'no-title') !== false || preg_match('/class=["\'][^"\']*no-title[^"\']*["\']/i', $imgTag)) { $skipTitle = true; } } $newTag = $imgTag; // 获取图片URL $imgUrl = ''; if (preg_match('/src=["\']([^"\']+)["\']/', $imgTag, $srcMatch)) { $imgUrl = $srcMatch[1]; } // 获取标题(从alt或title属性) $caption = ''; $hasChinese = false; if (!$skipTitle) { // 只有需要显示标题时才处理 if (preg_match('/alt=["\']([^"\']*)["\']/', $imgTag, $altMatch)) { $caption = $altMatch[1]; $hasChinese = self::hasChineseText($caption); } elseif (preg_match('/title=["\']([^"\']*)["\']/', $imgTag, $titleMatch)) { $caption = $titleMatch[1]; $hasChinese = self::hasChineseText($caption); } } // 如果开启了仅显示中文标题,且没有中文,则清空标题 if ($config->titleChineseOnly == '1' && !$hasChinese) { $caption = ''; } else { // 提取中文部分 $caption = self::extractChineseText($caption); } // 添加水印数据属性(如果当前分类在显示列表中) $watermarkData = ''; if ($isWatermarkIncluded && $config->watermarkEnable == '1' && !empty($config->watermarkText)) { $watermarkClass = 'icw-watermark'; $watermarkData = ' data-watermark="' . htmlspecialchars($config->watermarkText) . '"'; $watermarkData .= ' data-watermark-position="' . htmlspecialchars($config->watermarkPosition) . '"'; $watermarkData .= ' data-watermark-minwidth="' . intval($config->watermarkMinWidth) . '"'; $watermarkData .= ' data-watermark-minheight="' . intval($config->watermarkMinHeight) . '"'; $newTag = preg_replace('/titleEnable == '1' && !empty($caption) && !empty($imgUrl)) || ($isWatermarkIncluded && $config->watermarkEnable == '1' && !empty($imgUrl))) { $wrapperClass = 'icw-wrapper'; // 添加标题数据(如果当前分类在显示列表中且需要显示标题) $titleData = ''; if (!$skipTitle && $isTitleIncluded && $config->titleEnable == '1' && !empty($caption)) { $titleData .= ' data-caption="' . htmlspecialchars($caption) . '"'; $titleData .= ' data-position="' . htmlspecialchars($config->titlePosition) . '"'; $titleData .= ' data-minwidth="' . intval($config->titleMinWidth) . '"'; $titleData .= ' data-minheight="' . intval($config->titleMinHeight) . '"'; $titleData .= ' data-chinese-only="' . $config->titleChineseOnly . '"'; if ($isWatermarkIncluded && $config->watermarkEnable == '1') { $wrapperClass .= ' icw-has-both'; } else { $wrapperClass .= ' icw-title-only'; } } elseif ($isWatermarkIncluded && $config->watermarkEnable == '1') { $wrapperClass .= ' icw-watermark-only'; } // 如果是横排组内的图片,添加特殊标记 if ($skipTitle) { $wrapperClass .= ' icw-in-flexgroup'; } $newTag = '
' . $newTag . '
'; } return $newTag; }, $text); return $text; } /** * 检查是否包含中文字符 */ private static function hasChineseText($text) { return preg_match('/[\x{4e00}-\x{9fa5}]/u', $text); } /** * 提取中文字符 */ private static function extractChineseText($text) { preg_match_all('/[\x{4e00}-\x{9fa5}\x{3000}-\x{303F}\x{FF00}-\x{FFEF}]+/u', $text, $matches); if (!empty($matches[0])) { return trim(implode('', $matches[0])); } return $text; } /** * 添加页脚脚本和样式(前台) */ public static function addFooter() { $options = Helper::options(); $config = $options->plugin('ImageCaptionWatermark'); if (!$config) { return; } $debugMode = $config->debugMode == '1' ? 'true' : 'false'; $batchSize = intval($config->batchSize) ?: 10; $processDelay = intval($config->processDelay) ?: 100; $skipFlexGroupTitles = $config->skipFlexGroupTitles == '1' ? 'true' : 'false'; // 输出CSS样式 echo ''; // 输出JavaScript - 修改以支持跳过横排组标题 echo ''; } }