虽然我部署了Lsky 来管理图床,但我的小服务器硬盘只有50G空间,图片还是得处理下再存储比较好,顺便还用python打包了一个转换压缩图片为webp的exe工具
下载文件:百度网盘链接
提取码:abcd

需求与解决方案

  • 图片格式转换和压缩存储
  • 尽可能降低响应时间
    ·
  • 使用Redis当作消息队列,用作脚本和Lsky之间的通信
  • 使用Python Pillow库编写脚本处理转换压缩图片

思路

PS:下面代码仅作示例,非可直接执行代码。

在 Laravel 中配置 Redis 队列:

Lsky开源版本composer.json没有redis需要自己安装 Redis 驱动,配置 .env,

composer require predis/predis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

在任务中发送消息:

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Redis;

class ProcessPythonTask implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $data;

    public function __construct($data)
    {
        $this->data = $data;
    }

    public function handle()
    {
        Redis::rpush('python_tasks', json_encode($this->data));
    }
}
在 Python 中消费消息:
import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

while True:
    task = r.blpop('python_tasks', timeout=0)
    if task:
        data = json.loads(task[1])
        print("Received task:", data)
在 Laravel 中分发任务:
// 每当上传成功一个图片就把这个图片信息添加到redis
ProcessPythonTask::dispatch(['message' => 'Hello from Laravel!']);
Python与Mysql通信:
import pymysql

# 创建数据库连接
conn = pymysql.connect(
    host='localhost',  # 主机地址
    user='root',       # 用户名
    password='password',  # 密码
    database='test_db'    # 数据库名
)

# 创建游标对象
cursor = conn.cursor()

# 执行 SQL 查询
cursor.execute("SELECT * FROM your_table")

# 获取查询结果
result = cursor.fetchall()
for row in result:
    print(row)

# 关闭连接
cursor.close()
conn.close()
Python实现图片转换:
# 省略代码.....
failed_images = []  # 用于记录转换失败的图片
compression_type = ["无损","自动","有损"]
output_format  = "WEBP"   
def process_images(image,quality=80): 
  try:
    with Image.open(image['path']) as img:
      if compression_type == "无损":
          img.save(image['path'], output_format.upper(), lossless=True)
      elif compression_type == "自动":
          img.save(image['path'], output_format.upper())
      else:
          img.save(image['path'], output_format.upper(), quality=quality)
     
    except Exception as e:
      failed_images.append(image)
      logging.error(f"处理图片 {image['origin_name']} 时发生错误: {e}", exc_info=True)
    
def record_db(insert_data,update_data):
  try:
    conn.start_transaction()
    # 记录转换压缩失败图片到数据库,这个表要自己建
    insert_query = "INSERT INTO your_table (name, age) VALUES (%s, %s)"
    cursor.executemany(insert_query, insert_data)
  
    # 更改转换成功的图片数据
    update_query = "UPDATE your_table SET age = %s WHERE name = %s"
    cursor.executemany(update_query, update_data)
    conn.commit()  # 提交事务
  except Exception as e:
    logging.error(f"记录转换失败图片 {image['origin_name']} 时发生错误: {e}", exc_info=True)
    conn.rollback()  # 回滚事务
    os.remove(update_data['new_path'])
  finally:
    # 关闭连接
    cursor.close()
    conn.close()
    # 删除原图
    os.remove(update_data['old_path'])
# 省略代码...