原文鏈接
前言
有自己機房的公司一般都有一套存儲系統用于存儲公司的圖片、視頻、音頻、文件等數據,常見的存儲系統有以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獲取圖片信息
@Testpublic 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圖片縮放
@Testpublic 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圖片打水印
@Testpublic 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, SouthEastop.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圖片裁剪
@Testpublic 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
的自動圖片縮放功能。