Compare commits

...

3 Commits

Author SHA1 Message Date
浪子 16e91b835e 0.7.2 2025-05-16 13:45:33 +08:00
浪子 9671712412 0.7.2 2025-05-16 13:43:59 +08:00
浪子 4df85ae062 0.7.2 2025-05-16 11:56:31 +08:00
6 changed files with 180 additions and 18 deletions

View File

@ -6,6 +6,8 @@
## 更新日志 & 预览
### 0.7.2
- 优化页面加载速度,自动裁切封面,并压缩为`webp`格式,并保存在主题目录`assets`-`images`-`covers`下,使用前必须开启`php`的`GD拓展`和主题目录的写入权限
### 0.7.1

View File

@ -17,7 +17,7 @@
is_single = false;
post_id = 0;
is_archive = false;
VERSION = "0.7.1";
VERSION = "0.7.2";
constructor() {
super();
this.initCopyright();
@ -46,7 +46,7 @@
}
initCopyright() {
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa &nbsp;<br>Made with<a href="https://www.imsun.org" target="_blank">jkjoy</a> / version ${this.VERSION}
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa &nbsp;<br>Made with&nbsp;<a href="https://www.imsun.org" target="_blank">老孙博客</a> / version ${this.VERSION}
</div>`;
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
document.querySelector(".icon--copryrights").addEventListener("click", () => {

View File

@ -24,23 +24,23 @@ function themeConfig($form) {
$form->addInput($mastodonurl);
$showProfile = new Typecho_Widget_Helper_Form_Element_Radio('showProfile',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否在文章页面显示作者信息'), _t('选择“是”将在文章页面包含显示作者信息。'));
'0', _t('是否在文章页面显示作者信息'), _t('选择"是"将在文章页面包含显示作者信息。'));
$form->addInput($showProfile);
$showcate = new Typecho_Widget_Helper_Form_Element_Radio('showcate',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否在文章页面显示文章分类'), _t('选择“是”将在文章页面显示文章的分类信息。'));
'0', _t('是否在文章页面显示文章分类'), _t('选择"是"将在文章页面显示文章的分类信息。'));
$form->addInput($showcate);
$showrelated = new Typecho_Widget_Helper_Form_Element_Radio('showrelated',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否显示相关文章'), _t('选择“是”将在文章页面显示相关文章。'));
'0', _t('是否显示相关文章'), _t('选择"是"将在文章页面显示相关文章。'));
$form->addInput($showrelated);
$showshare = new Typecho_Widget_Helper_Form_Element_Radio('showshare',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否显示复制链接'), _t('选择“是”将在文章页面显示复制链接。'));
'0', _t('是否显示复制链接'), _t('选择"是"将在文章页面显示复制链接。'));
$form->addInput($showshare);
$showtime = new Typecho_Widget_Helper_Form_Element_Radio('showtime',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否显示页面加载时间'), _t('选择“是”将在页脚显示加载时间。'));
'0', _t('是否显示页面加载时间'), _t('选择"是"将在页脚显示加载时间。'));
$form->addInput($showtime);
$loadmore = new Typecho_Widget_Helper_Form_Element_Radio('loadmore',
array('0'=> _t('加载更多'), '1'=> _t('页码模式')),
@ -111,6 +111,17 @@ $options = Typecho_Widget::widget('Widget_Options');
$gravatarPrefix = empty($options->cnavatar) ? 'https://cravatar.cn/avatar/' : $options->cnavatar;
define('__TYPECHO_GRAVATAR_PREFIX__', $gravatarPrefix);
// 初始化主题
function init_theme() {
// 检查并创建封面图片目录
$coversDir = dirname(__FILE__) . '/assets/images/covers';
if (!is_dir($coversDir)) {
@mkdir($coversDir, 0755, true);
}
}
// 在主题加载时执行初始化
init_theme();
/**
* 页面加载时间
*/
@ -138,6 +149,19 @@ function timer_start() {
*/
function img_postthumb($cid) {
$db = Typecho_Db::get();
// 首先检查是否设置了自定义封面
$cover = $db->fetchRow($db->select('str_value')
->from('table.fields')
->where('cid = ?', $cid)
->where('name = ?', 'cover'));
// 如果找到自定义封面,直接返回
if ($cover && !empty($cover['str_value'])) {
return $cover['str_value'];
}
// 否则尝试从文章内容中获取第一张图片
$rs = $db->fetchRow($db->select('table.contents.text')
->from('table.contents')
->where('table.contents.cid=?', $cid)
@ -168,8 +192,11 @@ function getPermalinkFromCoid($coid) {
* 图片灯箱
*/
class ImageStructureProcessor {
public static function processContent($content, $widget) {
// 首先检查内容是否为空
public static function processContent($content, $widget, $lastResult = null) {
// 首先应用之前的过滤器结果
$content = empty($lastResult) ? $content : $lastResult;
// 检查内容是否为空
if (empty($content) || !is_string($content)) {
return $content;
}
@ -236,15 +263,130 @@ class ImageStructureProcessor {
} catch (Exception $e) {
// 记录错误但返回原始内容
error_log('Image processing error: ' . $e->getMessage());
return $content;
// 如果发生错误,返回上一个过滤器结果或原始内容
return empty($lastResult) ? $content : $lastResult;
}
}
return $content;
}
}
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
return ImageStructureProcessor::processContent($content, $widget);
};
// u6ce8u91cau6389u8fd9u884cuff0cu9632u6b62u8986u76d6u8fd9u4e2au94a9u5b50u7684u5176u4ed6u6ce8u518c
// Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
// return ImageStructureProcessor::processContent($content, $widget);
// };
/**
* 处理图片为封面图裁剪为5:3最大宽度500px转换为webp
*
* @param string $imageUrl 原始图片URL
* @return string 处理后的图片URL
*/
function process_cover_image($imageUrl) {
// 检查GD库是否可用
if (!function_exists('imagecreatetruecolor')) {
return $imageUrl; // 如果GD库不可用返回原图
}
// 分析URL
$parsed = parse_url($imageUrl);
// 如果图片是外部链接,需要下载
$isExternalUrl = !empty($parsed['host']) && $parsed['host'] !== $_SERVER['HTTP_HOST'];
// 生成唯一的文件名使用MD5哈希
$filename = md5($imageUrl) . '.webp';
// 处理后图片的保存路径
$themeDir = dirname(__FILE__);
$savePath = $themeDir . '/assets/images/covers/' . $filename;
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
// 如果缓存文件已存在,直接返回
if (file_exists($savePath)) {
return $webPath;
}
// 获取原始图片内容
if ($isExternalUrl) {
// 外部图片,需要下载
$imageContent = @file_get_contents($imageUrl);
if (!$imageContent) {
return $imageUrl; // 无法下载,返回原图
}
} else {
// 本地图片
$localPath = $_SERVER['DOCUMENT_ROOT'] . $parsed['path'];
if (!file_exists($localPath)) {
return $imageUrl; // 无法找到本地文件,返回原图
}
$imageContent = @file_get_contents($localPath);
}
// 创建图像资源
$originalImage = @imagecreatefromstring($imageContent);
if (!$originalImage) {
return $imageUrl; // 无法创建图像资源,返回原图
}
// 获取原始图片尺寸
$originalWidth = imagesx($originalImage);
$originalHeight = imagesy($originalImage);
// 计算目标尺寸5:3比例最大宽度500px
$targetWidth = min(500, $originalWidth);
$targetHeight = intval($targetWidth * 3 / 5);
// 计算裁剪坐标(居中裁剪)
$cropX = 0;
$cropY = 0;
$cropWidth = $originalWidth;
$cropHeight = $originalHeight;
// 计算比例
$originalRatio = $originalWidth / $originalHeight;
$targetRatio = 5 / 3;
if ($originalRatio > $targetRatio) {
// 原图过宽,需要裁剪宽度
$cropWidth = intval($originalHeight * $targetRatio);
$cropX = intval(($originalWidth - $cropWidth) / 2);
} else {
// 原图过高,需要裁剪高度
$cropHeight = intval($originalWidth / $targetRatio);
$cropY = intval(($originalHeight - $cropHeight) / 2);
}
// 创建目标图像
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
// 裁剪并调整大小
imagecopyresampled(
$targetImage,
$originalImage,
0, 0,
$cropX, $cropY,
$targetWidth, $targetHeight,
$cropWidth, $cropHeight
);
// 保存为webp格式
if (!function_exists('imagewebp')) {
// 如果不支持webp保存为png
$filename = md5($imageUrl) . '.png';
$savePath = $themeDir . '/assets/images/covers/' . $filename;
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
imagepng($targetImage, $savePath, 9); // 9是最高压缩质量
} else {
// 保存为webp
imagewebp($targetImage, $savePath, 80); // 80是质量参数
}
// 释放资源
imagedestroy($originalImage);
imagedestroy($targetImage);
return $webPath;
}
/**
* *获取文章卡片
@ -297,6 +439,9 @@ function get_article_info($atts) {
$imageToDisplay = img_postthumb($post['cid']);
if (empty($imageToDisplay)) {
$imageToDisplay = $default_thumbnail;
} else {
// 处理封面图片
$imageToDisplay = process_cover_image($imageToDisplay);
}
// 构建输出
$output = '<div class="graph--mixtapeEmbed">';
@ -315,11 +460,16 @@ class ContentFilter
{
// 首先运行之前的过滤器结果
$content = empty($lastResult) ? $content : $lastResult;
// 处理图片灯箱
$content = ImageStructureProcessor::processContent($content, $widget, $content);
// 然后处理我们的文章短代码
$content = preg_replace_callback('/\[article\s+([^\]]+)\]/', function($matches) {
$atts = self::parse_atts($matches[1]);
return get_article_info($atts);
}, $content);
return $content;
}
// 解析短代码属性
@ -377,8 +527,11 @@ EOF;
}
}
// 注册编辑器按钮钩子
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
// 避免重复注册,在最后执行
if (!Typecho_Plugin::exists('Widget_Abstract_Contents', 'editor')) {
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
}
/**
* 评论者认证等级 + 身份
@ -455,8 +608,11 @@ function commentApprove($widget, $email = NULL)
* 修改附件插入功能
*/
// 添加批量插入按钮的JavaScript
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
// 避免重复注册,使用条件判断
if (!Typecho_Plugin::exists('admin/write-post.php', 'bottom')) {
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
}
class MyHelper {
public static function addBatchInsertButton() {

View File

@ -3,7 +3,7 @@
* 一款单栏主题. 移植自HUGO主题 Farallon 原作者 bigfa
* @package Farallon
* @author 老孙
* @version 0.7.1
* @version 0.7.2
* @link https://www.imsun.org
*/
if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>

View File

@ -75,6 +75,7 @@
$cover = $this->fields->cover;
$imageToDisplay = !empty($cover) ? $cover : $firstImage;
if($imageToDisplay):
$imageToDisplay = process_cover_image($imageToDisplay);
?>
<a href="<?php $this->permalink() ?>" class="cover--link">
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>

View File

@ -12,6 +12,9 @@
if (empty($imageToDisplay)) {
$imageToDisplay = $firstImage;
}
if (!empty($imageToDisplay) && $imageToDisplay != $default_thumbnail) {
$imageToDisplay = process_cover_image($imageToDisplay);
}
?>
<article class="post--card" id="loadpost" itemscope itemtype="http://schema.org/Article">
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>