自己的第一個也是唯一一個開源專案,因為平時比較懶,很少做宣傳,今天剛好突破160個star,發到園子裡推薦給大家,算是慶祝一下,哈。
如果你也喜歡這個專案,記得幫忙star哦~
專案地址:https://gitee.com/opensourcechen/image-combiner
一. 新手介紹
1.1 專案背景
最近公司上了不少傳播方面的需求,免不了合成各種營銷圖片,圖片合成本身並不是什麼高深的技術,但用底層api去搞確實繁瑣,於是抽時間封裝了一個小工具,初衷是解放生產力,後來發現挺好使,那就開源吧,花了一個整天重新整理了一下程式碼,作為自己從業十年第一個開源專案(打破零記錄,哈哈),希望能夠幫助到需要的小夥伴~
1.2 ImageCombiner能夠做什麼?
ImageCombiner是一個專門用於圖片合成的工具,沒有很複雜的功能,簡單實用,從實際業務場景出發,提供簡單的介面,幾行程式碼即可實現圖片拼合(當然用於合成水印也可以),素材上支援圖片和文字兩種,支援定位、縮放、旋轉、圓角、透明度、顏色、字型、字號、刪除線、居中繪製、文字自動換行等特性,足夠覆蓋圖片合成的日常需求
1.3 先看一下效果
1.4 UML
1.5 ImageCombiner怎麼使用
ImageCombiner使用起來相當簡單,主要的類只用一個,new一個ImageCombiner物件,指定背景圖片和輸出格式,然後加入各種素材元素,設定元素的位置、大小和效果(如圓角、顏色、透明度等),呼叫combine()方法即可。combine()方法直接返回BufferedImage物件,也可以呼叫getCombinedImageStream()獲得流,方便上傳oss等後續操作,或者呼叫save()方法儲存到本地,除錯的時候比較方便。
1.6 版本要求
專案不依賴任何框架,完全基於JDK本身編寫,沒有各種花裡胡哨的東西,效能還是相當不錯的。
二. 示例程式碼
2.1 安裝
注意:合成圖片若包含文字的話,開發機和伺服器要先安裝相應的字型,否則看不出效果,預設使用的字型為“阿里巴巴普惠體”(見font目錄)
在專案中加入以下依賴:
<dependency>
<groupId>com.freeway</groupId>
<artifactId>image-combiner</artifactId>
<version>1.1.3</version>
</dependency>
最新版本為1.1.3,目前還沒有上傳中央倉庫(比較麻煩),請先自行deploy到自己的私庫
2.2 最簡單的例子
public void simpleDemo() throws Exception { //合成器(指定背景圖和輸出格式,整個圖片的寬高和相關計算依賴於背景圖,所以背景圖的大小是個基準) ImageCombiner combiner = new ImageCombiner("http://xxx.com/image/bg.jpg", OutputFormat.JPG); //加圖片元素 combiner.addImageElement("http://xxx.com/image/product.png", 0, 300); //加文字元素 combiner.addTextElement("週末大放送", 60, 100, 960); //執行圖片合併 combiner.combine(); //可以獲取流(並上傳oss等) InputStream is = combiner.getCombinedImageStream(); //也可以儲存到本地 combiner.save("d://image.jpg");
2.3 完整示例
public void demo() throws Exception { //圖片元素可以是Url,也可以是BufferImage物件 String bgImageUrl = "http://xxx.com/image/bg.jpg"; //背景圖 String qrCodeUrl = "http://xxx.com/image/qrCode.png"; //二維碼 String productImageUrl = "http://xxx.com/image/product.jpg"; //商品圖 BufferedImage waterMark = ImageIO.read(new URL("https://xxx.com/image/waterMark.jpg")); //水印圖 BufferedImage avatar = ImageIO.read(new URL("https://xxx.com/image/avatar.jpg")); //頭像 String title = "# 最愛的家居"; //標題文字 String content = "蘇格拉底說:“如果沒有那個桌子,可能就沒有那個水壺”"; //內容文字 //建立合成器(指定背景圖和輸出格式,整個圖片的寬高和相關計算依賴於背景圖,所以背景圖的大小是個基準) ImageCombiner combiner = new ImageCombiner(bgImageUrl, OutputFormat.JPG); //設定背景高斯模糊(毛玻璃效果) combiner.setBackgroundBlur(30); //標題(預設字型為阿里普惠、黑色,也可以自己指定Font物件) combiner.addTextElement(title, 0, 150, 1400) .setCenter(true) //居中繪製(會忽略x座標,改為自動計算) .setAlpha(.8f); //透明度(0.0~1.0) .setRotate(45); //旋轉(0~360) .setColor(Color.Red) //顏色 //內容(設定文字自動換行,需要指定最大寬度(超出則換行)、最大行數(超出則丟棄)、行高) combiner.addTextElement(content, "微軟雅黑", 40, 150, 1480) .setStrikeThrough(true) //刪除線 .setAutoBreakLine(837, 2, 60); //自動換行 //商品圖(設定座標、寬高和縮放模式,若按寬度縮放,則高度按比例自動計算) combiner.addImageElement(productImageUrl, 0, 160, 837, 0, ZoomMode.Width) .setCenter(true); //居中繪製(會忽略x座標,改為自動計算) .setRoundCorner(46) //設定圓角 //頭像(圓角設定一定的大小,可以把頭像變成圓的) combiner.addImageElement(avatar, 200, 1200) .setRoundCorner(200); //圓角 //水印(設定透明度,0.0~1.0) combiner.addImageElement(waterMark, 630, 1200) .setAlpha(.8f); //透明度(0.0~1.0) .setRotate(45); //旋轉(0~360) .setBlur(20); //高斯模糊(1~100)_ //二維碼(強制按指定寬度、高度縮放) combiner.addImageElement(qrCodeUrl, 138, 1707, 186, 186, ZoomMode.WidthHeight); //價格(元素物件也可以直接new,然後手動加入待繪製列表) TextElement textPrice = new TextElement("¥1290", 60, 230, 1300); textPrice.setColor(Color.red); //紅色 textPrice.setStrikeThrough(true); //刪除線 combiner.addElement(textPrice); //加入待繪製集合 //執行圖片合併 combiner.combine(); //可以獲取流(並上傳oss等) InputStream is = combiner.getCombinedImageStream(); //也可以儲存到本地 combiner.save("d://image.jpg"); }
2.4 小技巧
實際需求中,經常會在一段固定文案裡,填充寬度不定的文字或數字(如使用者暱稱、價格等),那中間待填充的空白部分留多少合適呢? 在這個場景下,我們一般會把一行文案拆分成多段,構建多個TextElement,共同拼成一句話,後一個TextElement的x座標, 通過動態計算前一個TextElement的實際寬度後,累加得來。
以下例子中,我們以“您出征XX,共在前線戰鬥了XX天!”這行為例, 由於兩個XX都是呼叫時傳進來的引數,實際繪製寬度不固定,所以我們把這一行切分成5段,用5個TextElement動態計算位置,然後拼接起來。
public void dynamicWidthDemoTest() throws Exception { String bg = "http://xxx.com/image/bg.jpg"; ImageCombiner combiner = new ImageCombiner(bg, OutputFormat.JPG); String str1 = "您出征"; String str2 = "某城市"; //外部傳參,內容不定,寬度也不定 String str3 = ",共在前線戰鬥了"; String str4 = "365"; //外部傳參,內容不定,寬度也不定 String str5 = "天!"; int fontSize = 60; int xxxFontSize = 80; int offsetX = 20; //通過計算前一個元素的實際寬度,並累加這個偏移量,得到後一個元素正確的x座標值 int y = 300; //第一段 TextElement element1 = combiner.addTextElement(str1, fontSize, offsetX, y); offsetX += combiner.computeTextWidth(element1); //計算寬度,並累加偏移量 //第二段(內容不定,寬度也不定) TextElement element2 = combiner.addTextElement(str2, xxxFontSize, offsetX, y) .setColor(Color.red); offsetX += combiner.computeTextWidth(element2); //第三段 TextElement element3 = combiner.addTextElement(str3, fontSize, offsetX, y); offsetX += combiner.computeTextWidth(element3); //第四段(內容不定,寬度也不定) TextElement element4 = combiner.addTextElement(str4, xxxFontSize, offsetX, y) .setColor(Color.red); offsetX += combiner.computeTextWidth(element4); //第五段 combiner.addTextElement(str5, fontSize, offsetX, y); combiner.combine(); combiner.save("d://demo.jpg"); }
實際執行效果
動態計算高度也是同樣的原理,比方要把價格顯示在商品描述下面,但商品描述不定有多少行,那此時價格元素的y座標就是不確定的,可以通過呼叫combiner.computeTextLineHeight(textElement)方法,得到上一個元素的高度,累加計算後續元素的y座標。
2.5 程式碼截圖
2.6 元素支援的特性
具體ImageElement
和TextElement
物件支援的特性如下表:
元素型別 | 特性 | 相關方法 |
---|---|---|
ImageElement |
圖片 | setImage() ,setImgUrl() |
ImageElement |
位置 | setX() ,setY() |
ImageElement |
縮放 | setWidth() ,setHeight() ,ZoomMode |
ImageElement |
旋轉 | setRotate() |
ImageElement |
圓角 | setRoundCorner() |
ImageElement |
居中繪製 | setCenter() |
ImageElement |
透明度 | setAlpha() |
ImageElement |
高斯模糊 | setBlur() |
----------------- | ||
TextElement |
文字 | setText() |
TextElement |
位置 | setX() ,setY() |
TextElement |
居中繪製 | setCenter() |
TextElement |
旋轉 | setRotate() |
TextElement |
透明度 | setAlpha() |
TextElement |
顏色 | setColor() |
TextElement |
字型 | setFont() |
TextElement |
字號 | setFont() |
TextElement |
刪除線 | setStrikeThrough() |
TextElement |
自動換行 | setAutoBreakLine() |
2.7 後續計劃
作者日常需求中已經夠用了,各位小夥伴如果有額外的需求可以考慮再進一步擴充,如增加旋轉、毛玻璃、藝術字等特效,歡迎加群交流
2.8 更新日誌
v1.0.0
- 基本功能完善
v1.1.0
- 修復一些小bug
- 開放文字寬度、高度計算等方法,方便外部動態計算元素位置
- 文字和圖片元素支援旋轉
v1.1.1
- 背景和圖片元素支援高斯模糊(毛玻璃效果)
v1.1.2
- 修復一個ImageElement建構函式bug
v1.1.3
- 修復背景圖為png時,合成後背景圖透明部分變黑的問題
- 整理了下測試方法
三. 聯絡作者
QQ群:706993679
四. 專案協議
The MIT-996 License (MIT)
Copyright (c) 2020 Zhaoqing Chen