为 Next 主题添加相册功能

在博客中记录你的回忆,过程是如此的艰难 QAQ

前提准备

  1. 你需要 python,以及下载python的插件工具pip
  2. 一个码云账号或者github账号。

创建相册文件夹(远程)

在你的码云或者github账号下新建一个仓库,名字任意,但是记住一定要是公开的仓库,否则博客中无法正常显示。并在改仓库中新建两个文件夹photomini_photo

photo文件夹中存放的是照片原图,而mini_photo中存放的是照片的略缩图

照片的命名方式请按照yyyy-MM-dd_图片描述.png/jpg的格式,方便管理以及程序对照片进行处理

对照片进行处理

在本地博客的上级目录中存放本地相册,在博客/source文件夹中新建photos目录

1
git clone  你的git仓库

这里我们采用python脚本对照片进行处理,将脚本放在本地相册文件夹中

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#coding: utf-8
from PIL import Image
import os
import sys
import json
from datetime import datetime
from ImageProcess import Graphics
# 定义压缩比,数值越大,压缩越小
SIZE_normal = 1.0
SIZE_small = 1.5
SIZE_more_small = 2.0
SIZE_more_small_small = 3.0


def make_directory(directory):
"""创建目录"""
os.makedirs(directory)

def directory_exists(directory):
"""判断目录是否存在"""
if os.path.exists(directory):
return True
else:
return False

def list_img_file(directory):
"""列出目录下所有文件,并筛选出图片文件列表返回"""
old_list = sorted(os.listdir(directory), reverse=True)
print(old_list)
new_list = []
for filename in old_list:
name, fileformat = filename.split(".")
if fileformat.lower() == "jpg" or fileformat.lower() == "png" or fileformat.lower() == "gif" or fileformat.lower() == "jpeg":
new_list.append(filename)
# print new_list
return new_list


def print_help():
print("""
This program helps compress many image files
you can choose which scale you want to compress your img(jpg/png/etc)
1) normal compress(4M to 1M around)
2) small compress(4M to 500K around)
3) smaller compress(4M to 300K around)
""")

def compress(choose, des_dir, src_dir, file_list):
"""压缩算法,img.thumbnail对图片进行压缩,

参数
-----------
choose: str
选择压缩的比例,有4个选项,越大压缩后的图片越小
"""
if choose == '1':
scale = SIZE_normal
if choose == '2':
scale = SIZE_small
if choose == '3':
scale = SIZE_more_small
if choose == '4':
scale = SIZE_more_small_small
for infile in file_list:
img = Image.open(src_dir+infile)
# size_of_file = os.path.getsize(infile)
w, h = img.size
img.thumbnail((int(w/scale), int(h/scale)))
img.save(des_dir + infile)
def compress_photo():
'''调用压缩图片的函数
'''
src_dir, des_dir = "photos/", "min_photos/"

if directory_exists(src_dir):
if not directory_exists(src_dir):
make_directory(src_dir)
# business logic
file_list_src = list_img_file(src_dir)
if directory_exists(des_dir):
if not directory_exists(des_dir):
make_directory(des_dir)
file_list_des = list_img_file(des_dir)
# print file_list
'''如果已经压缩了,就不再压缩'''
for i in range(len(file_list_des)):
if file_list_des[i] in file_list_src:
file_list_src.remove(file_list_des[i])
compress('4', des_dir, src_dir, file_list_src)

def handle_photo():
'''根据图片的文件名处理成需要的json格式的数据

-----------
最后将data.json文件存到博客的source/photos文件夹下
'''
src_dir, des_dir = "photos/", "min_photos/"
file_list = list_img_file(src_dir)
print(file_list)
list_info = []
for i in range(len(file_list)):
filename = file_list[i]
date_str, info = filename.split("_")
info, _ = info.split(".")
date = datetime.strptime(date_str, "%Y-%m-%d")
year_month = date_str[0:7]
if i == 0: # 处理第一个文件
new_dict = {"date": year_month, "arr":{'year': date.year,
'month': date.month,
'link': [filename],
'text': [info],
'type': ['image']
}
}
list_info.append(new_dict)
elif year_month != list_info[-1]['date']: # 不是最后的一个日期,就新建一个dict
new_dict = {"date": year_month, "arr":{'year': date.year,
'month': date.month,
'link': [filename],
'text': [info],
'type': ['image']
}
}
list_info.append(new_dict)
else: # 同一个日期
list_info[-1]['arr']['link'].append(filename)
list_info[-1]['arr']['text'].append(info)
list_info[-1]['arr']['type'].append('image')
list_info.reverse() # 翻转
tmp = bubbleYear(list_info)
bubble(tmp)
final_dict = {"list": list_info}
with open("../hexoBlog/source/photos/data.json","w") as fp:
json.dump(final_dict, fp)

def cut_photo():
"""裁剪算法

----------
调用Graphics类中的裁剪算法,将src_dir目录下的文件进行裁剪(裁剪成正方形)
"""
src_dir = "photos/"
if directory_exists(src_dir):
if not directory_exists(src_dir):
make_directory(src_dir)
# business logic
file_list = list_img_file(src_dir)
# print file_list
if file_list:
print_help()
for infile in file_list:
img = Image.open(src_dir+infile)
img = img.convert('RGB')
Graphics(infile=src_dir+infile, outfile=src_dir + infile).cut_by_ratio()
else:
pass
else:
print("source directory not exist!")



def git_operation():
'''
git 命令行函数,将仓库提交

----------
需要安装git命令行工具,并且添加到环境变量中
'''
os.system('git add --all')
os.system('git commit -m "add photos"')
os.system('git push origin master')


def bubble(bubbleList):
listLength = len(bubbleList)
while listLength > 0:
for i in range(listLength - 1): # 这个循环负责设置冒泡排序进行的次数
# print(bubbleList[i])
for j in range(listLength-i-1): # j为列表下标
if(bubbleList[j].get('arr').get('year') == bubbleList[j+1].get('arr').get('year')):
if bubbleList[j].get('arr').get('month') < bubbleList[j+1].get('arr').get('month'):

bubbleList[j], bubbleList[j+1] = bubbleList[j+1], bubbleList[j]
return bubbleList


# for i in range(listLength - 1):
# if(bubbleList[i].get('arr').get('year') == bubbleList[i+1].get('arr').get('year')):
# if bubbleList[i].get('arr').get('month') > bubbleList[i+1].get('arr').get('month'):
# bubbleList[i] = bubbleList[i] + bubbleList[i+1]
# bubbleList[i+1] = bubbleList[i] - bubbleList[i+1]
# bubbleList[i] = bubbleList[i] - bubbleList[i+1]
# listLength -= 1

def bubbleYear(bubbleList):
listLength = len(bubbleList)
while listLength > 0:
for i in range(listLength - 1):
for j in range(listLength-i-1):
if bubbleList[j].get('arr').get('year') < bubbleList[j+1].get('arr').get('year'):

bubbleList[j], bubbleList[j+1] = bubbleList[j+1], bubbleList[j]
# print(bubbleList)
return bubbleList


if __name__ == "__main__":
cut_photo() # 裁剪图片,裁剪成正方形,去中间部分
compress_photo() # 压缩图片,并保存到mini_photos文件夹下
git_operation() # 提交到github仓库
handle_photo() # 将文件处理成json格式,存到博客仓库中

其中文件中的内容进行修改,将../hexoBlog/source/photos/data.json 改为你自己的本地博客地址
还需要一个额外的python脚本ImageProcess.py(上网搜了好久都没有,后面找到了源代码赶紧保存了下来)

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
# coding=utf-8  
from PIL import Image
import shutil
import os

class Graphics:
''' 图片处理类

参数
-------
infile: 输入文件路径
outfile: 输出文件路径
'''
def __init__(self, infile, outfile):
self.infile = infile
self.outfile = outfile

def fixed_size(self, width, height):
"""按照固定尺寸处理图片"""
im = Image.open(self.infile)
out = im.resize((width, height),Image.ANTIALIAS)
out.save(self.outfile)


def resize_by_width(self, w_divide_h):
"""按照宽度进行所需比例缩放"""
im = Image.open(self.infile)
(x, y) = im.size
x_s = x
y_s = x/w_divide_h
out = im.resize((x_s, y_s), Image.ANTIALIAS)
out.save(self.outfile)


def resize_by_height(self, w_divide_h):
"""按照高度进行所需比例缩放"""
im = Image.open(self.infile)
(x, y) = im.size
x_s = y*w_divide_h
y_s = y
out = im.resize((x_s, y_s), Image.ANTIALIAS)
out.save(self.outfile)


def resize_by_size(self, size):
"""按照生成图片文件大小进行处理 (单位 KB)"""
size *= 1024
im = Image.open(self.infile)
size_tmp = os.path.getsize(self.infile)
q = 100
while size_tmp > size and q > 0:
print (q)
out = im.resize(im.size, Image.ANTIALIAS)
out.save(self.outfile, quality=q)
size_tmp = os.path.getsize(self.outfile)
q -= 5
if q == 100:
shutil.copy(self.infile, self.outfile)


def cut_by_ratio(self):
""" 按照图片长宽进行分割

------------
取中间的部分,裁剪成正方形
"""
im = Image.open(self.infile)
(x, y) = im.size
if x > y:
region = (int(x/2-y/2), 0, int(x/2+y/2), y)
#裁切图片
crop_img = im.crop(region)
#保存裁切后的图片
crop_img.save(self.outfile)
elif x < y:
region = (0, int(y/2-x/2), x, int(y/2+x/2))
#裁切图片
crop_img = im.crop(region)
#保存裁切后的图片
crop_img.save(self.outfile)

在运行之前还需要安装python插件

1
pip install Pillow

将这两个文件都放在照片的文件夹里,运行脚本

1
python imageDeal.py

执行完后重新git到远程仓库

如果提示缺少什么库,请自行使用pip安装即可

上面两个文件若是出错,可以到我的码云中下载

运行完成后会在你的博客目录/source/photos中出现data.json

修改 Next 主题中的配置

增加相册 style

在 next 主题目录next/layout下面增加 photo.swig 页面

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
{% extends '_layout.swig' %}
{% import '_macro/post-collapse.swig' as post_template %}
{% import '_macro/sidebar.swig' as sidebar_template %}

{% block title %}{{ page.title }} | {{ config.title }}{% endblock %}

{% block content %}

{#################}
{### Photo BLOCK ###}
{#################}
<div class="post-block photo">

<div id="posts" class="posts-collapse">

</div>

</div>

{#####################}
{### END Photo BLOCK ###}
{#####################}

{% include '_partials/pagination.swig' %}
{% endblock %}

{% block sidebar %}
{{ sidebar_template.render(false) }}
{% endblock %}

生成相册页面

生成相册页面和生成分类和标签页面一样

1
hexo new page photos

修改博客/source/photos/index.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<link rel="stylesheet" href="./ins.css">
<link rel="stylesheet" href="./photoswipe.css">
<link rel="stylesheet" href="./default-skin/default-skin.css">

<div class="photos-btn-wrap">
<a class="photos-btn active" href="javascript:void(0)">照片美如画</a>
</div>
<div class="instagram itemscope">
http://localhost:4000/mrxun" target="_blank" class="open-ins">图片正在加载中…
</div>

<script>
(function() {
var loadScript = function(path) {
var $script = document.createElement('script')
document.getElementsByTagName('body')[0].appendChild($script)
$script.setAttribute('src', path)
}
setTimeout(function() {
loadScript('./ins.js')
}, 0)
})()
</script>

将其中的网址http://localhost:4000/mrxun换成你自己的域名

另外还需要三个css,以及js

photoswipe.css
ins.css
default-skin/default-skin.css(新建文件夹后在放入css文件)
ins.js

这些文件我也放在码云

添加查看相册插件 photoswipe

/theme/next/source/js中添加photoswipe.min.jsphotoswipe-ui-default.min.js,这两个文件可以在github上下载

/theme/next/layout/_scripts/pages/post-details.swig 中插入以下两行(没有的话直接新建即可)

1
2
<script src="{{ url_for(theme.js) }}/src/photoswipe.min.js?v={{ theme.version }}"></script>
<script src="{{ url_for(theme.js) }}/src/photoswipe-ui-default.min.js?v={{ theme.version }}"></script>

/theme/next/layout/_layout.swighead标签中添加下面几行

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
{% if page.type === "photos" %}
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<div class="pswp__bg"></div>
<div class="pswp__scroll-wrap">
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title="Share"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
{% endif %}

至此相册查看插件 photoswipe 已经配置完毕

总结

我们回顾以下整个流程

  1. 远程仓库 photos
  2. 本地文件夹,从远程仓库 git clone
  3. 博客中新建photos 页面
  4. 执行python脚本处理照片
  5. 重新提交到github码云
  6. 修改博客/source/photos中的index.md,以及添加cssjs文件
  7. 修改主题/layout文件夹中的一些文件
  8. 主题/source/js文件夹中添加js文件

主要参考的文章:https://lovexinforever.github.io/
十分感谢,并且其他添加相册的方法全部失效
原博的顺序以及文件已经非常不全面,我将过程重新梳理,所有需要的插件全部上传到码云,供大家使用