天天看點

Java操作圖檔工具類

1、多個圖檔合成

2、生成不帶logo的二維碼

3、讀取圖檔二維碼資訊

4、生成帶logo的二維碼

5、圖檔壓縮

6、文字水印到圖檔

7、圖檔水印到圖檔

9、解決圖檔紅色問題 ,JDK中提供的Image

package com.hlj.util.QRcode;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * 作者 :HealerJean
 * 日期 :2018/10/29  下午4:31.
 * 類描述:
 */
public class QrCodeUtils {


    /**
     *
     * 1、 輸出圖檔到本地目錄
     * @param buffImg 圖檔
     * @param savePath 本地目錄的路徑
     */
    public static void  saveImageToLocalDir(BufferedImage buffImg, String savePath) {
        try {
            ImageIO.write(buffImg, "jpg", new File(savePath));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }



    /**
     *
     * 2、 方法描述: 多個圖檔合成
     * exImage 底圖
     * innerImage 嵌入的圖檔
     * x 坐标x
     * y 坐标y
     * innerImageWedith 嵌入圖檔的長度
     * innerImageHeight 嵌入圖檔的寬度
     */
    public  static BufferedImage imageAndImages(BufferedImage exImage, BufferedImage innerImage, int x, int y, int innerImageWedith, int innerImageHeight, float alpha) throws IOException {
        Graphics2D g2d = exImage.createGraphics();
        // 在圖形和圖像中實作混合和透明效果
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        // 繪制
        g2d.drawImage(innerImage, x, y, innerImageWedith, innerImageHeight, null);
        g2d.dispose();// 釋放圖形上下文使用的系統資源
        return exImage;
    }

    /**
     * 2、測試 多個圖檔合成
     */
    @Test
    public void testimageAndImages(){

        String sourceFilePath = "/Users/healerjean/Desktop/origin.jpeg";
        String innerImageFilePath = "/Users/healerjean/Desktop/img.jpeg";
        // 建構疊加層
        BufferedImage buffImg = null;
        try {
            buffImg = imageAndImages(ImageIO.read(new File(sourceFilePath)), ImageIO.read(new File(innerImageFilePath)),238, 588,210 ,208, 1.0f);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 輸出水印圖檔
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(buffImg, saveFilePath);
    }


    /**
     * 3、不帶logo的二維碼
     *
     * @param text 二維碼内容
     * @param width 二維碼寬度
     * @param height 長度
     * @param whiteSize 白邊大小
     * @return
     */
    public static BufferedImage writeQRImg(String text,int width,int height,int whiteSize){
        // 配置參數
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 字元編碼
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 容錯級别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        // 設定空白邊距的寬度
        hints.put(EncodeHintType.MARGIN, whiteSize); // 預設是4

        // 1、生成二維碼
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        // 2、擷取二維碼寬高
        int codeWidth = bitMatrix.getWidth();
        int codeHeight = bitMatrix.getHeight();

        // 3、将二維碼放入緩沖流
        BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < codeWidth; i++) {
            for (int j = 0; j < codeHeight; j++) {
                // 4、循環将二維碼内容定入圖檔
                //判斷 BitMatrix 是否存在像素  二維碼填充顔色 黑色  0XFF000000 白色 :0xFF是補碼 0XFFFFFFFF
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0XFF000000 : 0XFFFFFFFF);
            }
        }

        return image ;
    }

    /**
     * 3、測試 不帶logo的二維碼
     * @throws Exception
     */
    @Test
    public void testWriteQRImg(){
        String text = "http://blog.healerjean.top";
        BufferedImage  noLogoImage = writeQRImg(text,200,200, 4 );
        //存儲到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(noLogoImage, saveFilePath);
    }





    /**
     *  4、 讀取二維碼的檔案裡面的資訊
     */
    public static String readQRImg(BufferedImage image) throws Exception {

        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
        // 字元編碼
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 對圖像進行解碼
        return result.getText();
    }

    /**
     * 4、測試 讀取二維碼資訊
     * @throws Exception
     */
    @Test
    public void testReadQRImg() throws Exception{
        //讀取二維碼資訊
        String filePath = "/Users/healerjean/Desktop/new.png";
        BufferedImage image = ImageIO.read(new File(filePath));
        String info =readQRImg(image);
        System.out.println(info);
    }



    /**
     *   5、 生成帶logo的二維碼
     *
     *
     * @param text 二維碼内容
     * @param text 二維碼内容
     * @param width 二維碼寬度
     * @param height 長度
     * @param whiteSize 白邊大小
     * @param logo LOGO圖檔
     * @return
     * @throws Exception
     */
    public static BufferedImage createLogoQRImg(String text,int width,int height, int whiteSize,BufferedImage logo) throws Exception {
        // 配置參數
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 字元編碼
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 容錯級别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        // 設定空白邊距的寬度
        hints.put(EncodeHintType.MARGIN, whiteSize); // 預設是4

        // 1、生成二維碼
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        // 2、擷取二維碼寬高
        int codeWidth = bitMatrix.getWidth();
        int codeHeight = bitMatrix.getHeight();

        // 3、将二維碼放入緩沖流
        BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < codeWidth; i++) {
            for (int j = 0; j < codeHeight; j++) {
                // 4、循環将二維碼内容定入圖檔
                //判斷 BitMatrix 是否存在像素  二維碼填充顔色 黑色  0XFF000000 白色 :0xFF是補碼 0XFFFFFFFF
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0XFF000000 : 0XFFFFFFFF);
            }
        }

            //在原來基礎上,再添加一個圖檔
            Graphics2D g = image.createGraphics();
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ?
                    (image.getWidth() * 2 / 10) : logo.getWidth(null);
            int heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ?
                    (image.getHeight() * 2 / 10) : logo.getHeight(null);

            //設定在圖檔中間
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;

            // 開始繪制圖檔
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);

            //繪制圓角矩形
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);

            //邊框寬度
            g.setStroke(new BasicStroke(2));

            //邊框顔色
            g.setColor(Color.WHITE);
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();
            return image;
    }




    /**
     * 5、測試 帶logo的二維碼
     * @throws Exception
     */
    @Test
    public void testWriteQRImgWithLogo() throws Exception{
        String text = "http://blog.healerjean.top";
        String logoPath = "/Users/healerjean/Desktop/logo.png";
        BufferedImage logo = ImageIO.read(new File(logoPath));
        BufferedImage  logoImage = createLogoQRImg(text,200,200, 1 ,logo);

        //存儲到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(logoImage, saveFilePath);
    }


    /**
     * 6/ 指定圖檔寬度和高度和壓縮比例對圖檔進行壓縮
     * @param widthdist 壓縮後圖檔的寬度
     * @param heightdist 壓縮後圖檔的高度
     * @param rate 壓縮的比例 ,可以設定為null
     */
    public static BufferedImage reduceImg(BufferedImage bufferedImage, int widthdist, int heightdist, Float rate) {
        try {

            // 如果比例不為空則說明是按比例壓縮
            if (rate != null && rate > 0) {
                //獲得源圖檔的寬高存入數組中
                int results[] = { 0, 0 };
                results[0] =bufferedImage.getWidth(null); // 得到源圖檔寬
                results[1] =bufferedImage.getHeight(null);// 得到源圖檔高

                if (results == null || results[0] == 0 || results[1] == 0) {
                    return null;
                } else {
                    //按比例縮放或擴大圖檔大小,将浮點型轉為整型
                    widthdist = (int) (results[0] * rate);
                    heightdist = (int) (results[1] * rate);
                }
            }
            // 開始讀取檔案并進行壓縮
            Image src = (Image) bufferedImage;
            // 構造一個類型為預定義圖像類型之一的 BufferedImage
            BufferedImage tag = new BufferedImage((int) widthdist, (int) heightdist, BufferedImage.TYPE_INT_RGB);
            //繪制圖像  getScaledInstance表示建立此圖像的縮放版本,傳回一個新的縮放版本Image,按指定的width,height呈現圖像
            //Image.SCALE_SMOOTH,選擇圖像平滑度比縮放速度具有更高優先級的圖像縮放算法。
            tag.getGraphics().drawImage(src.getScaledInstance(widthdist, heightdist, Image.SCALE_SMOOTH), 0, 0, null);

            return tag;
        } catch (Exception ef) {
            ef.printStackTrace();
        }
        return  null;
    }

    /**
     * 6 測試
     * @throws IOException
     */
    @Test
    public void testReduceImg() throws IOException {
        String reducePath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(reducePath));
        BufferedImage  reduceImg = reduceImg(originImage,200,200, null );

        //存儲到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(reduceImg, saveFilePath);
    }


    /**
     *  7、 添加文字水印
     * @param image 需要加水印的檔案
     * @param waterText 水印文本
     * @param moreMark  是否是多個水印 true多個水印   /false 或不寫,一個水印
     * @return
     */
    public static BufferedImage textWaterMark(BufferedImage image,String waterText, boolean... moreMark) {

            //字型樣式
            int FONT_STYLE = Font.BOLD;
            //字型大小
            int FONT_SIZE = 50;
            //字型顔色
            Color FONT_COLOR = Color.black;
            //字型顔色
            String FONT_NAME = "微軟雅黑";
            //透明度
            float ALPHA = 0.3F;

            //多圖的情況下,水印的間距
            Integer MORE_MARK_DISTANCE = 100;

            //計算原始圖檔寬度長度
            int width = image.getWidth();
            int height = image.getHeight();
            //建立圖檔緩存對象
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //建立java繪圖工具對象
            Graphics2D graphics2d = bufferedImage.createGraphics();
            //參數主要是,原圖,坐标,寬高
            graphics2d.drawImage(image, 0, 0, width, height, null);

            //使用繪圖工具将水印繪制到圖檔上
            //計算文字水印寬高值
            int waterWidth = FONT_SIZE*getTextLength(waterText);
            int waterHeight = FONT_SIZE;
            //水印透明設定
            graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
            graphics2d.setFont(new Font(FONT_NAME, FONT_STYLE, FONT_SIZE));
            graphics2d.setColor(FONT_COLOR);

            if(moreMark!= null && moreMark.length >0 && moreMark[0]){
                //設定旋轉 , 後面兩個參數表示的是圍繞那個坐标
                graphics2d.rotate(Math.toRadians(-30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);

                int x = -width/2;
                int y = -height/2;

                while(x < width*1.5){
                    y = -height/2;
                    while(y < height*1.5){
                        graphics2d.drawString(waterText, x, y);
                        //水印的間距
                        y+=waterHeight+MORE_MARK_DISTANCE;
                    }
                    x+=waterWidth+MORE_MARK_DISTANCE;
                }
            }else{
                graphics2d.drawString(waterText, width-waterWidth, height);
            }

            //寫圖檔
            graphics2d.dispose();
            return  bufferedImage;
    }
    /**
     * 計算水印文本長度
     *
     * 中文長度即文本長度 2、英文長度為文本長度二分之一
     * @param text
     * @return
     */
    private static int getTextLength(String text){
        //水印文字長度
        int length = text.length();

        for (int i = 0; i < text.length(); i++) {
            String s =String.valueOf(text.charAt(i));
            if (s.getBytes().length>1) {
                length++;
            }
        }
        length = length%2==0?length/2:length/2+1;
        return length;
    }

    @Test
    public void testTextWaterMark() throws IOException {
        String originPath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(originPath));
        BufferedImage newImage = textWaterMark(originImage,"healerjean",true);

        //存儲到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(newImage, saveFilePath);
    }





    /**
     * 8、 添加圖檔水印
     * @param srcFile 需要家水印的檔案路徑
     * @return
     */
    public static BufferedImage imageWaterMark(BufferedImage image,BufferedImage imageLogo, boolean... moreMark) {
        //字型樣式
        int FONT_STYLE = Font.BOLD;
        //字型大小
        int FONT_SIZE = 50;
        //字型顔色
        Color FONT_COLOR = Color.black;
        //字型顔色
        String FONT_NAME = "微軟雅黑";
        //透明度
        float ALPHA = 0.3F;
        //多圖的情況下,水印的間距
        Integer MORE_MARK_DISTANCE = 100;

        int X = 636;
        int Y = 763;
            //計算原始圖檔寬度長度
            int width = image.getWidth(null);
            int height = image.getHeight(null);
            //建立圖檔緩存對象
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //建立java繪圖工具對象
            Graphics2D graphics2d = bufferedImage.createGraphics();
            //參數主要是,原圖,坐标,寬高
            graphics2d.drawImage(image, 0, 0, width, height, null);
            graphics2d.setFont(new Font(FONT_NAME, FONT_STYLE, FONT_SIZE));
            graphics2d.setColor(FONT_COLOR);

            //水印圖檔路徑
            int widthLogo = imageLogo.getWidth(null);
            int heightLogo = imageLogo.getHeight(null);
            int widthDiff = width-widthLogo;
            int heightDiff = height-heightLogo;
            //水印坐标設定
            if (X > widthDiff) {
                X = widthDiff;
            }
            if (Y > heightDiff) {
                Y = heightDiff;
            }
            //水印透明設定
            graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));

            if(moreMark!= null && moreMark.length >0 && moreMark[0]){
                graphics2d.rotate(Math.toRadians(-30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);

                int x = -width/2;
                int y = -height/2;

                while(x < width*1.5){
                    y = -height/2;
                    while(y < height*1.5){
                        graphics2d.drawImage(imageLogo, x, y, null);
                        y+=heightLogo+MORE_MARK_DISTANCE;
                    }
                    x+=widthLogo+MORE_MARK_DISTANCE;
                }
            }else{
                graphics2d.drawImage(imageLogo, X, Y, null);
            }

            graphics2d.dispose();

            return  bufferedImage;

    }




    @Test
    public void testImageWaterMark() throws IOException {
        String originPath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(originPath));


        String logoPath = "/Users/healerjean/Desktop/origin.jpeg";
        BufferedImage logoImage = ImageIO.read(new File(logoPath));

        BufferedImage newImage = imageWaterMark(originImage,logoImage,true);

        //存儲到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(newImage, saveFilePath);
    }


    /**
     *  9、解決圖檔紅色問題 ,JDK中提供的Image
     //如果是file
     Image src=Toolkit.getDefaultToolkit().getImage(file.getPath());


     如果是url
     URL url = new URL(wechat_erweimaTmail);
     java.awt.Image imageTookittitle = Toolkit.getDefaultToolkit().createImage(url);
     BufferedImage titleLab = ImageUtils.toBufferedImage(imageTookittitle);

     * @param image
     * @return
     */
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null),
                    image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null),
                    image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }

}