摘要:本文介绍了 Typora 中的图片,使用 opencv 转换图片格式为 webp,再使用 Python 脚本上传至 Minio 对象存储,以及 Docker 部署 Minio 和 Nginx 反向代理 Minio。

1、环境

  • 服务器 - Ubuntu

    • Docker 环境
    • Minio
    • Nginx
  • 客户端 - Windows

    • python 3.x 环境
    • typora 软件

2、Minio 部署

(1) 服务器部署 Minio

创建 docker compose 文件。

1
2
3
mkdir -p /root/docker_data/minio/
cd /root/docker_data/minio/
vi compose.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3.8'
services:
minio:
image: minio/minio
hostname: "minio"
ports:
- 9000:9000 # api 端口
- 9001:9001 # 控制台端口
environment:
MINIO_ACCESS_KEY: admin #管理后台用户名
MINIO_SECRET_KEY: Ad1234min_123 #管理后台密码,最小8个字符
volumes:
- /root/docker_data/minio/data:/data #映射当前目录下的data目录至容器内/data目录
- /root/docker_data/minio/config:/root/.minio/ #映射配置目录
command: server --console-address ':9001' /data #指定容器中的目录 /data
privileged: true
restart: always

(2) 配置 nginx 反向代理

需要配置2个反向代理

  • 代理1:代理控制台 9001 端口,用于web界面控制
  • 代理2:代理 api 9000 端口 ,用于资源访问
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
# / 匹配默认控制端
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
chunked_transfer_encoding off;
proxy_pass http://127.0.0.1:9001;
}

# 匹配存储桶资源,blog 为存储桶名称
location ^~ /blog {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_ssl_server_name off;
}

# 全部配置文件参考
server {
listen 80 ;
listen 443 ssl http2 ;
server_name oss.yyds.space;
index index.php index.html index.htm default.php default.htm default.html;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
access_log /www/sites/oss.yyds.space/log/access.log main;
error_log /www/sites/oss.yyds.space/log/error.log;
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}
root /www/sites/oss.yyds.space/index;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
ssl_certificate /www/sites/oss.yyds.space/ssl/fullchain.pem;
ssl_certificate_key /www/sites/oss.yyds.space/ssl/privkey.pem;
ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;
proxy_set_header X-Forwarded-Proto https;
ssl_stapling on;
ssl_stapling_verify on;
include /www/sites/oss.yyds.space/proxy/*.conf;
}

(3) web 配置 minio

1)访问 minio 控制端

访问 https://oss.yyds.space , 进行控制端登陆,用户名和密码配置在 compose.yaml 中。

image-20240720111106222

2)创建存储桶

创建存储桶,这里创建示例名称为 blog

image-20240720112113625

3)修改访问策略

MinIO 默认创建桶的权限是private私有的,也就是桶内的文件是不允许外界直接访问的,在此更改选项为 public ,就可以实现通过:地址/桶名称/文件名直接访问

image-20240720120223116

4)上传测试图片

上传本地图片 tx.png ,并进行访问测试 https://oss.yyds.space/blog/tx.png,访问成功则,搭建基本完成。

image-20240720114854708

5)获取 Access Key

创建 Access key 并记录到本地,后续脚本需要使用到。

image-20240720133401570

3、Typora 上传图片到 Minio

(1) 配置上传脚本

本文使用 python 脚本进行图片格式转换为webp,并上传到 Minio,Python环境建议使用 3.x,此处不介绍 Python 环境的安装。

1)安装 Python 第三方库

1
2
python -m pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple
python -m pip install minio opencv-python opencv-python-headless numpy

2)配置脚本

在本地创建脚本,示例在 D:\Typora\upload_script\upload.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
81
82
import sys
import datetime
import cv2
import os
import random
import requests
import io
import numpy as np
from minio import Minio
from pathlib import Path


# 配置以下内容
minio_domain = "oss.yyds.space"
minio_domain_port = "9000"
minio_access_key = "access_key"
minio_secret_key = "secret_key"
# 存储桶名称
bucket_name = "blog"
# 存储桶子文件夹名称
bucket_name_dir_name = "img"

# 获取minio客户端连接
minio_client = Minio(
f"{minio_domain}:{minio_domain_port}",
minio_access_key,
minio_secret_key,
secure=False,
)

# 如果存储桶不存在,则创建
if not minio_client.bucket_exists(bucket_name):
minio_client.make_bucket(bucket_name)


# 判断上传的图片是否为网络图片
def is_url(path_str):
return path_str.lower().startswith("http://") or path_str.lower().startswith(
"https://"
)


# 获取图片参数
images = sys.argv[1:]

# 处理并上传每一张照片
for image_path in images:
# 生成图片文件名,使用年月日时分秒+2位随机数
current_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
file_name = "{}{}{}".format(current_time, random.randint(10, 99), ".webp")

# 如果是网络图片则需要下载再进行格式转换,如果是本地图片,则无需下载直接进行格式转换。
if is_url(image_path):
response = requests.get(image_path)
if response.status_code == 200:
img_bytes = io.BytesIO(response.content)
img_array = np.frombuffer(img_bytes.read(), np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
else:
print(f"Failed to download image from URL: {image_path}")
continue
else:
img = cv2.imread(image_path)
if img is None:
print(f"Unable to read local image file: {image_path}")
continue
# 图片格式转换为WebP
webp_image = cv2.imencode(".webp", img)[1]

# 写入临时WebP文件
temp_image_path = f"{current_time}.webp"
with open(temp_image_path, "wb") as f:
f.write(bytearray(webp_image))

# 文件存储桶下子路径拼接
remote_full_path_name = "{}/{}".format(bucket_name_dir_name, file_name)
# 上传文件
minio_client.fput_object(bucket_name, remote_full_path_name, temp_image_path)
# 删除临时WebP文件
os.remove(temp_image_path)
# 打印文件路径
print("https://{}/{}/{}".format(minio_domain, bucket_name, remote_full_path_name))

(2) 配置 Typora 图片上传

Typora 导航到路径【文件】-> 【偏好设置】-> 【图像】,进行以下设置,上传服务选择 Custom Command,命令填写 Python 脚本路径 , 点击图片上传选项进行验证

image-20240720134415559

出现验证成功,到此Typora 图片格式转换并上传环境搭建完成,点击 ok 退出。

image-20240727131405997