Skip to content

Typora 配合 minio 实现图片存储

摘要:本文介绍了 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 文件。

bash
mkdir -p /root/docker_data/minio/
cd /root/docker_data/minio/
vi compose.yaml
dockerfile
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 端口 ,用于资源访问
nginx
# / 匹配默认控制端
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 第三方库

bash
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 配置以下脚本

python
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