优缺点

  • 优点:本地处理无需搭建服务器、不需要改动原文件
  • 缺点:拥有大量文章时可能会影响博客生成速度(我文章较少没有感觉),不适用动态资源的图片如:随机图API

参考

参考

安装

1
npm i hexo-naokuo-image-color --save

启用

  • _config.anzhiyu.yml
1
2
3
4
5
6
7
8
# 主色调相关配置
mainTone:
enable: true # true or false 文章是否启用获取图片主色调
mode: api # cdn/api/both/local cdn模式为图片url+imageAve参数获取主色调,api模式为请求API获取主色调,both模式会先请求cdn参数,无法获取的情况下将请求API获取,可以在文章内配置main_color: '#3e5658',使用十六进制颜色,则不会请求both/cdn/api获取主色调,而是直接使用配置的颜色
# 项目地址:https://github.com/anzhiyu-c/img2color-go
api: # mode为api时可填写
cover_change: true # 整篇文章跟随cover修改主色调
# log: false # 默认输出日志信息,为 false 时关闭日志输出

其他

  • 问:为什么不把生成后的文章主色调插入到文章的Front Matter中。
  • 答:考虑到文章封面随时可能更换,主色调也要随之变化,还要写一个判断文章封面是否更换就觉得太麻烦;不过我参考hexo-abbrlink写了一个(文章封面更换时需删除原有主色调配置也重新获取对应文章封面主色调)
  • 已制作beta版,经测试可用。(由于这会改动文章,使用时请备份源码)
1
npm install --save hexo-naokuo-image-color@beta
  • _config.yml
1
2
3
4
5
# 图片主色调提取
imageColor:
enable: true
api_url: https://imgcolor.naokuo.top/api?img= # (尽量自己搭建)主色调提取API接口链接,项目:https://github.com/yife68/img2color-go
# log: false # 默认输出日志信息,为 false 时关闭日志输出
  • 源码
源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
'use strict';

const node_fetch = require("node-fetch");
const logger = require('hexo-log').default();
const fs = require('hexo-fs');
const frontMatter = require('hexo-front-matter');

hexo.extend.filter.register('before_post_render', async function (Posts) {
const config = hexo.config.imageColor || hexo.theme.config.imageColor

// 存在自定义文章主色调 或 没有文章封面 或 配置没有开启时跳出
if (!Posts.cover || Posts.main_color || !config.enable) return;

try {
// 获取图片主色调API
const color_API = config.api_url;
// 获取文章封面图片路径
const imageUrl = Posts.cover;
// 获取图片主色调链接拼接
const dominantColor = color_API + imageUrl;
let adjustedColor;

// 发起一个 GET 请求
await node_fetch(dominantColor)
.then(response => {
// 检查响应状态码是否正常
if (!response.ok) return;

// 如果需要JSON格式的数据,则解析响应体
return response.json();
})
.then(data => {
// 将颜色转换为HEX格式
const ImgColorHex = colorHex(data.RGB);
adjustedColor = ImgColorHex;

// 默认输出日志信息
if (!config.log == true) {
logger.info(`文章《${Posts.title}》的主色调:${adjustedColor}`);
}

// 将主题色添加到文章数据中
Posts.main_color = adjustedColor;

// 只有在处理.md文件时更新Front Matter和源文件
if (/\.md$/.test(Posts.source)) {
// 解析原始Front Matter
const parsedPost = frontMatter.parse(Posts.raw);

// 添加新的主色调属性
parsedPost.main_color = adjustedColor;

// 重新生成包含新主色调的Front Matter的Markdown内容
const processedPostStr = frontMatter.stringify(parsedPost);
const updatedContent = '---\n' + processedPostStr;

// 更新源文件
fs.writeFile(Posts.full_source, updatedContent, 'utf-8');
}
})
.catch(error => {
logger.error(`提取文章《${Posts.title}》封面图像的主题颜色时出错: ${error}`);
});
} catch (error) {
logger.error(`提取文章《${Posts.title}》封面图像的主题颜色时出错: ${error}`);
}

return Posts;
});

//RGB颜色转化为16进制颜色
const colorHex = str => {
const hexRegex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;

if (/^(rgb|RGB)/.test(str)) {
const aColor = str.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
return aColor.reduce((acc, val) => {
const hex = Number(val).toString(16).padStart(2, "0");
return acc + hex;
}, "#");
}

if (hexRegex.test(str)) {
if (str.length === 4) {
return Array.from(str.slice(1)).reduce((acc, val) => acc + val + val, "#");
}
return str;
}

return str;
};