當前位置 博文首頁 > 推土機2019:ImageCombiner - Java服務端圖片合成工具,好用!

    推土機2019:ImageCombiner - Java服務端圖片合成工具,好用!

    作者:推土機2019 時間:2021-02-20 16:36

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

     

    自己的第一個也是唯一一個開源項目,因為平時比較懶,很少做宣傳,今天剛好突破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);   //圓角
    
        //水。ㄔO置透明度,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

    bk
推土機2019:ImageCombiner - Java服務端圖片合成工具,好用! 萊布尼茨:【從零開始擼一個App】Fragment和導航中的使用 等不到的口琴:億級流量架構之資源隔離思路與方法 TOP生物信息:一文學會常規轉錄組分析 Twittytop:我的2020之路 我愛睡蓮:keepalived-1.3.5+MHA部署mysql集群 程序員養成日記:mysql一張表到底能存多少數據? 等你歸去來:java線程池趣味事:這不是線程池 Linyiwei:C++算法代碼――Tuna Linux中執行shell腳本的4種方法總結 Flutter深色模式適配的實現 Python合并Excel表(多sheet)的實現 MacBook m1芯片采用miniforge安裝python3.9的方法示例 mybatis-plus動態表名的實現示例 MyBatis limit分頁設置的實現 詳解Nginx1.19 php8.0 源碼編譯安裝 php如何將字符串轉utf8格式 linux如何更改php版本號 php地域時間怎么去設置 實戰分析:為什么你網站的收錄及效益一直不見提升 HTTPS優缺點和原理解析:我們的網站該不該做HTTPS? Visual Studio Code上添加小程序自動補全插件的操作方法 intellij idea設置統一JavaDoc模板的方法詳解 Hadoop 使用IntelliJ IDEA 進行遠程調試代碼的配置方法 PyCharm配置KBEngine快速處理代碼提示沖突、配置命令問題 SpringBoot對Controller進行單元測試的實現代碼 附亂碼解決方案 iPhone6做“大”營銷 品牌營銷也需投機取巧 如何區分PHP中intval()與(int) use關鍵字在PHP中的百態人生 詳解php中函數的引用傳遞和返回 (附代碼)
国产av欧美av亚韩av_欧美 日产 国产 首页_婷婷五月色中文字幕的