原文链接
前言
有自己机房的公司一般都有一套存储系统用于存储公司的图片、视频、音频、文件等数据,常见的存储系统有以NAS、FASTDFS为代表的传统文件存储,和以Minio为代表的对象存储系统,随着云服务的兴起很多公司逐渐将数据迁移到以阿里云OSS为代表的云对象存储,OSS的好处是不但解决了数据的存储还自带的很多文件的处理功能,如图片的缩放、打水印、裁剪等功能,例如我们要获获取一张宽为200大小的图片只需要在原图后面增加?x-oss-process=image/resize,w_200
这个参数就可以了,处理图片确实非常方便。
https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,w_200。
传统的NAS、FASTDFS只有存储功能,没有文件处理能力的,我们可以使用图片处理软件给它加上类似的图片处理功能。常用的图片处理软件有Imagemagick
、GraphicsMagick
、OpenCV
对应的JAVA操作库为im4java
、JMagick
、Javacv
。用上这些图片处理软件再配置Nginx+Lua
或者OpenResty
就可以让你的传统NAS
存储也也有像OSS
一样的图片处理能力。
ImageMagick、GraphicsMagick的安装
ImageMagick官网下载
官网下载地址:https://imagemagick.org/script/download.php
以windows为例,下载ImageMagick-7.1.1-15-Q16-HDRI-x64-dll.exe ,然后下一步、下一步安装就好了,安装完成后输入magick -version
检查是否安装成功:
PS C:\Users\Administrator> magick -version
Version: ImageMagick 7.1.1-15 Q16-HDRI x64 a0a5f3d:20230730 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenCL OpenMP(2.0)
Delegates (built-in): bzlib cairo flif freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193532217)
GraphicsMagick官网下载
GraphicsMagick
最初源于ImageMagick5.5.2
(2002年11月),但从那时起就完全独立于ImageMagick
项目。自从ImageMagick
的fork以来,许多作者使用开放的开发模型进行了许多改进(参见新闻),但没有破坏API或实用程序操作。下载地址:
http://www.graphicsmagick.org/download.html
安装完成后输出gm
检测是否安装成功。
C:\Users\Administrator>gm
GraphicsMagick 1.3.40 2023-01-14 Q16 http://www.GraphicsMagick.org/
Copyright (C) 2002-2023 GraphicsMagick Group.
Additional copyrights and licenses apply to this software.
See http://www.GraphicsMagick.org/www/Copyright.html for details.
Usage: gm command [options ...]
JAVA操作
JAVA操作GraphicsMagick
可以使用im4java
引入POM依赖im4java
<dependency>
<groupId>org.im4java</groupId>
<artifactId>im4java</artifactId>
<version>1.4.0</version>
</dependency>
im4java
官网地址:
https://im4java.sourceforge.net
im4java
源码地址:im4java download | SourceForge.net
JAVA操作ImageMagick
可以使用JMagick
,引入POM依赖:
<dependency>
<groupId>jmagick</groupId>
<artifactId>jmagick</artifactId>
<version>6.6.9</version>
</dependency>
JMagick
官网地址:www.jmagick.org
JMagick
源码地址:JMagick download | SourceForge.net
图片信息获取
命令获取图片信息
magick identify .\1.jpg
.\1.jpg PNG 1920x1080 1920x1080+0+0 8-bit sRGB 1.31707MiB 0.000u 0:00.000
//格式化输出
magick identify -format '%W,%H,%B,%f,%m' .\1.jpg
1920,1080,1381050,1.jpg,PNG
JAVA获取图片信息
@Test
public void info() throws IOException, InterruptedException, IM4JavaException {
String iImageDir = "C:\\Users\\Administrator\\Desktop\\img\\1.jpg";
IMOperation operation = new IMOperation();
//格式化输出
//operation.format("%W,%H,%B,%f,%m");
operation.addImage(iImageDir);
IdentifyCmd indentity = new IdentifyCmd();
ArrayListOutputConsumer output = new ArrayListOutputConsumer();
indentity.setOutputConsumer(output);
indentity.run(operation);
ArrayList<String> cmdOutput = output.getOutput();
String line = cmdOutput.get(0);
System.out.println(line);
//C:\Users\Administrator\Desktop\img\1.jpg PNG 1920x1080 1920x1080+0+0 8-bit sRGB 1.31707MiB 0.000u 0:00.000
}
注意事项
-
如果运行代码报
org.im4java.core.CommandException: java.io.IOException: Cannot run program "identify": CreateProcess error=2, 系统找不到指定的文件。
是因为刚安装软件,系统没找到命令,重启电脑后就可以解决。 -
可以使用
-format '%W,%H,%B,%f,%m'
来格式化图片信息的输出 ,具体的格式化参数有很多,详细可以参考官方文档,你想要的图片信息应该都是有的。https://imagemagick.org/script/escape.phps
图片缩放
命令图片缩放
magick .\1.jpg -resize 200x100 1_w200h100.jpg
magick identify -format '%W,%H,%B,%f,%m' .\1_w200h100.jpg
输出:
178,100,8003,1_w200h100.jpg,JPEG
JAVA图片缩放
@Test
public void resizeImg() throws IOException, InterruptedException, IM4JavaException {
String srcImagePath = "C:\\Users\\Administrator\\Desktop\\img\\1.jpg";
Integer width = 200;
Integer height = 100;
String newImagePath = "C:\\Users\\Administrator\\Desktop\\img\\1_w200h100.jpg";
IMOperation op = new IMOperation();
op.addImage(srcImagePath);
op.resize(width, height);
op.addImage(newImagePath);
ImageCommand convert = new ConvertCmd();
convert.run(op);
}
注意事项
这里我们使用 -resize 200x100
想生成一张200x100
的图片,结果输出图片是178x100
,因为原始图片为1920x1080
为了保持图片宽高比例,做了等比例缩放,防止图片变形。
图片打水印
命令图片打水印
magick composite -geometry '200x200+100+50' -gravity 'center' .\avatar.png .\1.jpg 1_avater.jpg
JAVA图片打水印
@Test
public void testaddImgWatermark() throws Exception {
String srcImagePath="D://img/1.jpg";
String destImagePath="D://img/1_avater.jpg";
String waterImgPath="D://img/avatar.png";
IMOperation op = new IMOperation();
//水印大小
op.geometry(1000,1000,1000,500);
// 水印图片位置NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
op.gravity("NorthEast");
// 水印透明度
op.dissolve(100);
// 水印
op.addImage(waterImgPath);
// 原图
op.addImage(srcImagePath);
// 目标
op.addImage(destImagePath);
ImageCommand cmd = new CompositeCmd();
cmd.run(op);
}
注意事项
-geometry '200x200+100+50'
中的200x200
是设置水印图片的大小,+200+50
设置水印图片相对于gravity
的位置-gravity 'center'
是给定水印的相对原图的位置,支持NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
,这个参数和阿里OSS加水印的也是一样的。
最终打出水印的效果如下:
图片裁剪
命令图片裁剪
magick convert -gravity 'center' .\1_avater.jpg -crop 200x200+100+50 1_cut.jpg
JAVA图片裁剪
@Test
public void testCrop() throws Exception {
String srcImagePath="D://img//1.jpg";
String destImagePath="D://img/1_cut.jpg";
IMOperation op = new IMOperation();
op.gravity("center");
op.addImage(srcImagePath);
op.crop( 200,200,100,50);
op.addImage(destImagePath);
ImageCommand cmd = new ConvertCmd();
cmd.run(op, srcImagePath, destImagePath);
}
最张裁剪效果:
注意事项
-crop 200x200+100+50
结合-gravity 'center'
刚好可以把我们打上的水印裁剪出来;- 裁剪出的图片在左右两边还是有一点红色边框,这个可能是计算有一两个像素误差。
图片加参数自动处理
有了以上的图片处理命令之后想要实现OSS ?x-oss-process=image/resize,w_200
这样加参数处理图片可以使用Nginx+Lua
来实现,集成了Lua
模块的Nginx
项目OpenResty
例如我们原始图片地址:
http://127.0.0.1/img/1.jpg
自动缩放图片尺寸:
http://127.0.0.1/img/1_400x400.jpg
- 下载安装 OpenResty - Download
- 下载安装LUA Release Lua for Windows v5.1.5-52 Released · rjpcomputing/luaforwindows · GitHub
Nginx配置引入Lua:
http {
lua_package_path 'D:\software\openresty\lualib\\?.lua;;';
lua_package_cpath 'D:\software\openresty\lualib\\?.so;;';
}
Nginx配置文件中可以写成这样:
location ~ '/img/(\d+)_(\d+)x(\d+).jpg$' {
root D:/img;
set $img_root "D:/img/img";
set $fileName ngx.arg[1];
set $width ngx.arg[2];
set $height ngx.arg[3];
set $origin "${img_root}/${fileName}.jpg" ;
set $file "${img_root}/${fileName}_${width}x${height}.jpg";
if (!-f $file) {
rewrite_by_lua '
local command = "magick "..ngx.var.origin.." -resize "..ngx.var.width.."x" ..ngx.var.height.." "..ngx.var.file;
os.execute(command);
';
}
}
当访问(http://127.0.0.1/img/1_400x400.jpg时可动态生成对应尺寸图片,类似OSS的功能:
生成的文件,当然我们还可以使用Lua+Redis
缓存这里生成的文件,如果有CDN
还可以配置CDN
缓存这些文件,下次就可以从CDN
缓存直接取对应尺寸的图片了,减少服务器处理图片的性能消耗。很多大厂不将这种图片处理下沉到CDN
边缘节点,利用离用户最近CDN
节点完成图片数据的处理,减少数据回源,从而减少中心服务器的性能消耗。
当然这个只是使用Nginx+Lua+GraphicsMagick
来实现简单的图片裁剪功能,如果要实现阿里OSS图片处理要比这个复杂的多,不仅要解决大量文件存储高可要和自动扩容问题,还要解决高并发下图片裁剪的性能问题,们只是通过这个案例了解图片自动缩放的基本原理,原理看起来比较简单,想要做的好而且还要给全国那么多企业用,要保持高可用、高性能就比较有难度了。
总结
本文主要介绍了常用图片处理软件ImageMagick
的使用,并通过命令和JAVA
代码演示图片信息的获取、缩放、打水印、裁剪功能,在最后通过OpenResty+Lua
实现类似OSS
的自动图片缩放功能。