ImageCombiner - Java服務端圖片合成工具,好用!

推土機2019發表於2021-02-20

 

自己的第一個也是唯一一個開源專案,因為平時比較懶,很少做宣傳,今天剛好突破160個star,發到園子裡推薦給大家,算是慶祝一下,哈。

如果你也喜歡這個專案,記得幫忙star哦~

專案地址:https://gitee.com/opensourcechen/image-combiner

 

一. 新手介紹

1.1 專案背景

最近公司上了不少傳播方面的需求,免不了合成各種營銷圖片,圖片合成本身並不是什麼高深的技術,但用底層api去搞確實繁瑣,於是抽時間封裝了一個小工具,初衷是解放生產力,後來發現挺好使,那就開源吧,花了一個整天重新整理了一下程式碼,作為自己從業十年第一個開源專案(打破零記錄,哈哈),希望能夠幫助到需要的小夥伴~

1.2 ImageCombiner能夠做什麼?

ImageCombiner是一個專門用於圖片合成的工具,沒有很複雜的功能,簡單實用,從實際業務場景出發,提供簡單的介面,幾行程式碼即可實現圖片拼合(當然用於合成水印也可以),素材上支援圖片和文字兩種,支援定位、縮放、旋轉、圓角、透明度、顏色、字型、字號、刪除線、居中繪製、文字自動換行等特性,足夠覆蓋圖片合成的日常需求

 

1.3 先看一下效果

avater

1.4 UML

avater

 

 

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動態計算位置,然後拼接起來。

avater

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");
    }

 

實際執行效果

avater

動態計算高度也是同樣的原理,比方要把價格顯示在商品描述下面,但商品描述不定有多少行,那此時價格元素的y座標就是不確定的,可以通過呼叫combiner.computeTextLineHeight(textElement)方法,得到上一個元素的高度,累加計算後續元素的y座標。

2.5 程式碼截圖

avater

2.6 元素支援的特性

具體ImageElementTextElement物件支援的特性如下表:

元素型別特性相關方法
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

郵箱:alexzchen@163.com

四. 專案協議

The MIT-996 License (MIT)

Copyright (c) 2020 Zhaoqing Chen

相關文章