生成帶 LOGO 的二維碼

通過 生成二維碼之 Java (Google zxing) 篇 我們可以實(shí)現(xiàn)簡單二維碼的生成, 但是二維碼顯示卻過于單調(diào), 本文變講述如何利用 thumbnailator 為我們的二維碼添加 LOGO

thumbnailator 是一個縮略圖工具類庫, 但它除了能縮略圖片外, 還提供裁剪, 旋轉(zhuǎn), 水印等功能, 此次我們便借助它的水印 API 實(shí)現(xiàn)以上需求

項(xiàng)目環(huán)境

<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>

操作步驟

  1. 準(zhǔn)備一張二維碼圖片, 一張 logo 圖片

    String qrCodeFilePath = "src/qrCode.jpg";
    String logoFilePath = "src/logo.jpg";
    
src/qrCode.png, 內(nèi)容為 1

src/logo.png
  1. 根據(jù)文件路徑生成一個圖片構(gòu)造對象( Thumbnails.of() 方法還可以接收 BufferedImage,InputStream,URL,String 的可變參數(shù)類型)

    Thumbnails.Builder<File> builder = Thumbnails.of(new File(qrCodeFilePath));
    
  2. 創(chuàng)建一個水印對象, 水印對象需要三個參數(shù) Position position, BufferedImage watermarkImg,float opacity, 其中 Position 是水印的坐標(biāo),BufferedImage 是水印圖片,opacity 是不透明度, 值為 [0-1] 之間, 1 代表不透明.

    BufferedImage bufferedImage = ImageIO.read(new File(logoFilePath));
    //Positions 實(shí)現(xiàn)了 Position 并提供九個坐標(biāo), 分別是 上左, 上中, 上右, 中左, 中中, 中右, 下左, 下中, 下右 我們使用正中的位置
    Watermark watermark = new Watermark(Positions.CENTER, bufferedImage, 1F);
    
  3. 為二維碼設(shè)置水印, 并設(shè)置縮略比例為 1(即不壓縮), 輸出到一個新文件中(outputFormat() 為指定輸出格式, 如: jpg,png)

    builder.watermark(watermark).scale(1F).toFile(new File("src/logoQrCode.png"));
    
  4. 生成后的二維碼


    src/logoQrCode.png

通過以上方法我們能夠簡單的為二維碼添加 LOGO, 但是實(shí)際使用時遠(yuǎn)沒有這樣簡單, 有以下幾個問題

  1. logo 圖片的尺寸可能并不固定, 可能有大有小, 這樣就會導(dǎo)致 logo 在二維碼中太小或太大
    這時我們可以在創(chuàng)建 BufferedImage 時將原圖壓縮 / 放大至指定尺寸, 也可以使用二維碼的尺寸乘以一定比例

    //forceSize(int width, int height) 指將圖片強(qiáng)制壓縮為指定寬高, 如不強(qiáng)制, 可使用 size(int width, int height)
    BufferedImage bufferedImage = Thumbnails.of(new File(logoFilePath)).forceSize(120, 120).asBufferedImage();
    
  2. 二維碼圖片, logo 圖片可能不是一個圖片文件, 同時生成好之后的圖片希望直接輸出在頁面上
    Thumbnails.of() 可以接收 BufferedImage,InputStream,URL,String,File 的可變 (** 批量處理需要 **) 參數(shù)類型
    ImageIO.read() 可以接收 File,ImageInputStream,InputStream,URL 參數(shù)類型
    以下為 SpringMVC 動態(tài)生成帶 LOGO 二維碼示例,QRCodeUtil.toBufferedImage() 具體實(shí)現(xiàn)請看 生成二維碼之 Java (Google zxing) 篇

    /**
     * @param content 二維碼內(nèi)容
     * @param logoUrl logo 鏈接
     */
    @RequestMapping(value = "/qrcode")
    public void qrcode(String content, String logoUrl, @RequestParam(defaultValue = "300") int width, @RequestParam(defaultValue = "300") int height,HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            // 根據(jù) QRCodeUtil.toBufferedImage() 返回的 BufferedImage 創(chuàng)建圖片構(gòu)件對象
            Thumbnails.Builder<BufferedImage> builder = Thumbnails.of(QRCodeUtil.toBufferedImage(content, width, height));
            // 將 logo 的尺寸設(shè)置為二維碼的 30% 大小, 可以自己根據(jù)需求調(diào)節(jié)
            BufferedImage logoImage = Thumbnails.of(new URL(logoUrl)).forceSize((int) (width * 0.3), (int) (height * 0.3)).asBufferedImage();
            // 設(shè)置水印位置(居中), 水印圖片 BufferedImage, 不透明度(1F 代表不透明)
            builder.watermark(Positions.CENTER, logoImage, 1F).scale(1F);
            // 此處需指定圖片格式, 否者報 Output format not specified 錯誤
            builder.outputFormat("png").toOutputStream(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 返回一個 BufferedImage 對象
     * @param content 二維碼內(nèi)容
     * @param width   寬
     * @param height  高
     */
    public static BufferedImage toBufferedImage(String content, int width, int height) throws WriterException, IOException {
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }
    

拓展思考

以上案例可知 thumbnailator 水印功能的強(qiáng)大. 然而除了實(shí)現(xiàn)以上案例外, 我們也可以根據(jù)水印功能實(shí)現(xiàn)另外一種需求.
比如公司現(xiàn)在有一個推廣需求, 讓用戶為我們的產(chǎn)品進(jìn)行宣傳, 達(dá)到多少次就進(jìn)行獎勵. 傳統(tǒng)的實(shí)現(xiàn)方式是一段文字再配上一個專屬鏈接. 但是此方式往往太過單調(diào), 枯燥. 這個時候如果我們讓設(shè)計提供一張內(nèi)容豐富, 帶有二維碼的宣傳圖片, 然后根據(jù)專屬鏈接生成二維碼與宣傳圖片進(jìn)行組合. 這時用戶就有了一張自己的專屬宣傳圖片. 此時通過直接宣傳專屬圖片往往會比文字加鏈接有著更好的效果.
注: 此功能在圖片合成時需要對二維碼的位置進(jìn)行定位, 此時可使用 Position 的實(shí)現(xiàn)類 Coordinate 完成
使用如下:

//Coordinate 存在一個 Coordinate(int x, int y) 構(gòu)造函數(shù), x 為水印距離底圖左邊的像素, y 為上邊
BufferedImage bufferedImage = ImageIO.read(new File(logoFilePath));
Watermark watermark = new Watermark(new Coordinate(100, 100), bufferedImage, 1F);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容