基于Golang和Docker图像无损压缩方案

基于Golang和Docker图像无损压缩方案

本项目已经开源到了Github上:composeImage,如果对你有帮助欢迎Star!

前言

笔者的NAS中存有大量的高清图片,这些图片占据的大量的空间,导致笔者的存储空间吃紧,同时文件空间太大不利于传输和分享,只能一个人存到本地太不够意思了。

因此我必须想出一种高效的方式来压缩图片,使其便于存储和发送,这时候我就想到了使用webp这种格式

笔者之前很喜欢用Python,因为它简单易用,但是这次要处理大约4万张图片,Python的性能确实不太够。这时候我想到了Golang,它同样简单易用,而且性能优异,还可以进行静态编译,我何乐而不为呢?

具体实现

首先我们要明确需求:

  • 能实现jpgpng格式的自动转换
  • 能监控文件夹,如果监测到文件夹内存在文件变动则自动继续转换
  • 重启后对已经转换过的文件不再继续转换,自动跳过
  • 性能尽量要好,使用高并发,多线程

之后我们就可以按照上面的需求开始写了,实际上写的过程很简单,我是直接丢给GPT进行写的,但是在这过程中存在一个问题,笔者是ARM Mac用户,而NAS是基于x86的,那么就必须使用交叉编译或者在NAS上重新搭建Golang环境。显然后者更加麻烦而且臃肿,我果断选择交叉编译——好了,第一个坑来了,我第一次使用的是来自Golang官方的golang.org/x/image/webp,直接运行的时候出现报错,显示导入错误,但是我仔细检查后觉得没有错误,就使用第三方github.com/chai2010/webp 库,完美运行。

但到正式交叉编译的时候又傻眼了,显示缺少对于的gcc编译器。。。我直接裂开,后来我想到可以在容器内进行编译,再使用一个基础容器进行封装就好了

容器化

首先要先在容器内进行编译,在这里我们直接使用一个基于Golang的容器,由于这个基础镜像所占空间比较大,我们使用alpine作为承载容器运行这个编译后的二进制文件

其中有一个坑就是,编译出来的文件需要一些依赖项,必须将其补齐才能正常运行

在docker中我们指定了两个文件夹来作为输入和输出文件夹

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
# 使用官方的Go镜像作为基础镜像
FROM golang:1.20 AS builder

# 设置工作目录
WORKDIR /app

# 复制当前目录内容到工作目录
COPY . .

# 下载依赖
RUN go mod download

# 编译Go程序
RUN go build -o composeImage .

# 使用一个更小的基础镜像来运行编译后的二进制文件
FROM alpine:latest

# 安装运行二进制文件所需的依赖项
RUN apk add --no-cache libc6-compat

# 设置工作目录
WORKDIR /app

# 从构建阶段复制编译后的二进制文件
COPY --from=builder /app/composeImage .

# 设置执行权限
RUN chmod +x composeImage

# 运行程序
CMD ["./composeImage", "-input", "/input", "-output", "/output", "-quality", "90", "-workers", "4"]

使用

Go

1
2
git clone https://github.com/Aicnal/composeImage.git
go mod download

请不要直接使用Go run...进行运行,你必须提供输入和输出目录,压缩质量和线程数量
在正式使用之前请先进行编译:

1
go build go build -o composeImage .

之后再指定相关目录

1
./composeImage -input /input -output /output -quality 90 -workers 4

Docker

直接进行Docker构建

1
docker build -t image-compressor:latest .
1
docker run -v $(pwd)/input:/input -v $(pwd)/output:/output image-compressor:latest

或者你可以使用docker-compose.yaml进行统一管理

1
2
3
4
5
6
7
8
9
version: '3.8'

services:
image-compressor:
image: image-compressor:latest
volumes:
- ./input:/input
- ./output:/output
restart: always