Java 二维码QRCode生成与解析

2024-07-14 1854阅读

QR Code

QR码(Quick Response Code,快速矩阵图码)是二维码的一种,于1994年由日本汽车零组件大厂电装公司的原昌宏发明。QR码使用四种标准化编码模式(数字、字母数字、字节(二进制)和日文(Shift_JIS))来存储数据。QR码原创于日本,现已在世界各国广泛运用于手机读码操作。QR码比普通条形码具有快速读取和更大的存储资料容量,也无需要像一维条码般在扫描时需要直线对准扫描仪,应用范围包括产品跟踪、物品识别、文档管理、库存营销等等。

QR码最大资料容量(对于版本40)
数字最多7,089字符
字母最多4,296字符
二进制数(8 bit)最多2,953 字节
日文汉字/片假名最多1,817字符(采用Shift JIS)
中文汉字最多984字符(采用UTF-8)
最多1,800字符(采用BIG5/GB2312)
错误修正容量
L等级可修正7%的字码
M等级可修正15%的字码
Q等级可修正25%的字码
H等级可修正30%的字码

对于我们来说QR码并不陌生,不管是网购剁手,还是日常面对面交易或信息交互,都有它的身影。

Java实现QR码生成和解析

Maven引用zxing

通过修改pom.xml文件,引入zxing核心com.google.zxing.core及其javase扩展com.google.zxing.javase两个依赖。写这篇文章的时候使用的是3.5.3版本。

  
    ...
    3.5.3
    ...
  
  
    ...
    
    
      com.google.zxing
      core
      ${zxing.version}
    
    
    
      com.google.zxing
      javase
      ${zxing.version}
    
    ...
  

若Maven编译报错:[ERROR] 不再支持源选项 5。请使用 7 或更高版本。[ERROR] 不再支持目标选项 5。请使用 7 或更高版本。加上源和目标编译器设置:

    17
    17

以maven-archetype-quickstart脚手架搭建的maven项目为例,完整的pom.xml如下:

  4.0.0
  org.humbunklung
  quick-response-code
  1.0-SNAPSHOT
  
    
      
        org.apache.maven.plugins
        maven-compiler-plugin
        3.8.0
        
          8
          8
        
      
    
  
  jar
  quick-response-code
  http://maven.apache.org
  
    UTF-8
    17
    17
    3.5.3
  
  
    
      junit
      junit
      3.8.1
      test
    
    
    
      com.google.zxing
      core
      ${zxing.version}
    
    
    
      com.google.zxing
      javase
      ${zxing.version}
    
  

QR码图片生成

QR码编码,通过zxing的MultiFormatWriter的encode方法完成,将需要编码的内容按照用户设置的参数形成比特矩阵。

    /**
     * 按照自定义内容、宽度、高度、纠错等级、字符集、编剧创建QR码比特矩阵。
     *
     * @param content 二维码内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @param errCorrLevel 纠错等级,可以是L, M, Q, H
     * @param charSet 字符集
     * @param margin 边距
     * @return BitMatrix 二维码比特矩阵
     * @throws WriterException
     */
    public static BitMatrix createQRCodeBitMatrix(String content, int width, int height,
   ErrorCorrectionLevel errCorrLevel,
   String charSet, int margin) throws WriterException {
        if (width 
            width = DEFAULT_QR_CODE_WIDTH;
        }
        if (height 
            height = DEFAULT_QR_CODE_HEIGHT;
        }
        Map
        if (imageFormat == null || imageFormat.equals("")){
            imageFormat = DEFAULT_FORMAT_NAME;
        }
        BitMatrix bitMatrix = createQRCodeBitMatrix(content, width, height, errCorrLevel, charSet, margin);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, os);
        return os.toByteArray();
    }
    /**
     * 创建二维码,返回base64字节流
     *
     * @param content 二维码里的内容
     * @param imageFormat 图片后缀名
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return byte[] base64字节数组
     */
    public static byte[] createQRCodeBase64Bytes(String content , String imageFormat , int width , int height)
            throws WriterException, IOException {
        byte[] bytes = createQRCode(content , imageFormat , width, height);
        return Base64.getEncoder().encode(bytes);
    }  
    /**
     * 创建二维码,返回base64字符串
     *
     * @param content 二维码里的内容
     * @param imageFormat 图片后缀名
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return String base64字符串
     */
    public static String createQRCodeBase64(String content , String imageFormat , int width , int height,
                                            String encoding) throws WriterException, IOException {
        return new String(createQRCodeBase64Bytes(content, imageFormat, width, height), encoding);
    }      

        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(onColor, offColor);
        return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
    }

        if (imageFormat == null || imageFormat.equals("")){
            imageFormat = DEFAULT_FORMAT_NAME;
        }
        BufferedImage bufferedImage = encodeQRCode(content, onColor, offColor,
                width, height, errorCorrectionLevel, charSet, margin);
        ImageIO.write(bufferedImage, imageFormat, new File(imagePath));
    }

        // 当前目录
        String currentDirectory = System.getProperty("user.dir");
        // 获取当前时间并设置格式,用于生成的文件名
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 输出目录
        String output = String.format("%s/data/%s.png", currentDirectory, now.format(dateTimeFormatter));
        String imagePath = new File(output).toPath().toString();
        try {
            QRCodeHelper.encodeQRCode(DEFAULT_TEST_CONTENT, imagePath, "png", 0xff5683ed, 0xffffffff,
                    500, 500, ErrorCorrectionLevel.H, "UTF-8", 2);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (WriterException e) {
            e.printStackTrace();
        }
    }

        if (image == null) return "";
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Hashtable
        BufferedImage clone = deepCopy(bufferedImage); // 深复制BufferedImage避免污染原图
        Graphics2D graphics = clone.createGraphics();
        // 读取logo图片文件
        BufferedImage logo = ImageIO.read(logoFile);
        // 开始绘制图片
        graphics.drawImage(logo, xPos, yPos, logoWidth, logoHeight, null);
        graphics.setStroke(new BasicStroke(strokeWidth, strokeCap, strokeJoin));
        graphics.setColor(Color.white);
        // 绘制圆角矩形
        graphics.drawRoundRect(xPos, yPos, logoWidth, logoHeight, arcWidth, arcHeight);
        graphics.dispose();
        clone.flush();
        return clone;
    }
    /**
     * 在QR码图像中央加入一个1/5大小的LOGO
     * @param bufferedImage QR码图像
     * @param logoFile LOGO文件
     * @param strokeWidth LOGO圆角笔宽
     * @param strokeCap
     * @param strokeJoin
     * @param arcWidth 圆角宽,0则不圆
     * @param arcHeight 圆角高,0则不圆
     * @return
     * @throws IOException
     */
    public static BufferedImage addLogoToBufferedImage(BufferedImage bufferedImage, File logoFile,
        float strokeWidth, int strokeCap, int strokeJoin,
        int arcWidth, int arcHeight)
            throws IOException {
        int matrixWidth = bufferedImage.getWidth();
        int matrixHeight = bufferedImage.getHeight();
        // 读取logo图片文件
        BufferedImage logo = ImageIO.read(logoFile);
        int logoWidth = logo.getWidth();
        int logoHeight = logo.getHeight();
        //  计算logo放置位置
        int x = matrixWidth  / 5*2;
        int y = matrixHeight / 5*2;
        int width = matrixWidth / 5;
        int height = matrixHeight / 5;
        return addLogoToBufferedImage(bufferedImage, logoFile, x, y, width, height,
                strokeWidth, strokeCap, strokeJoin, arcWidth, arcHeight);
    }

        // 当前目录
        String currentDirectory = System.getProperty("user.dir");
        // 获取当前时间并设置格式,用于生成的文件名
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 输出目录
        String output = String.format("%s/data/%s.png", currentDirectory, now.format(dateTimeFormatter));
        String imagePath = new File(output).toPath().toString();
        File logoFile = new File(String.format("%s/data/logo.jpg", currentDirectory));
        try {
            BufferedImage qr = QRCodeHelper.encodeQRCode(DEFAULT_TEST_CONTENT, 0xff5683ed, 0xffffffff,
                    500, 500, ErrorCorrectionLevel.H, "UTF-8", 2);
            BufferedImage qrWithLogo = QRCodeHelper.addLogoToBufferedImage(qr, logoFile, 5.0F,
                    1, 1, 20, 20);
            ImageIO.write(qr, "png", new File(imagePath));
            ImageIO.write(qrWithLogo, "png",
                    new File(imagePath.replace(".png", "-logo.png")));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (WriterException e) {
            e.printStackTrace();
        }
    }

        BufferedImage scaledOverlay = scaleOverlay(qrcode, overlay,overlayToQRCodeRatio);
        Integer deltaHeight = qrcode.getHeight() - scaledOverlay.getHeight();
        Integer deltaWidth  = qrcode.getWidth()  - scaledOverlay.getWidth();
        BufferedImage combined = new BufferedImage(qrcode.getWidth(), qrcode.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = (Graphics2D)combined.getGraphics();
        g2.drawImage(qrcode, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, overlayTransparency));
        g2.drawImage(scaledOverlay, Math.round(deltaWidth/2), Math.round(deltaHeight/2), null);
        return combined;
    }
    /**
     * 按比例调整LOGO
     *
     * @param qrcode
     * @param overlay
     * @param overlayToQRCodeRatio
     * @return
     */
    private static BufferedImage scaleOverlay(BufferedImage qrcode, BufferedImage overlay, float overlayToQRCodeRatio) {
        Integer scaledWidth = Math.round(qrcode.getWidth() * overlayToQRCodeRatio);
        Integer scaledHeight = Math.round(qrcode.getHeight() * overlayToQRCodeRatio);
        BufferedImage imageBuff = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics g = imageBuff.createGraphics();
        g.drawImage(overlay.getScaledInstance(scaledWidth, scaledHeight, BufferedImage.SCALE_SMOOTH),
                0, 0, new Color(0,0,0), null);
        g.dispose();
        return imageBuff;
    }

        // 当前目录
        String currentDirectory = System.getProperty("user.dir");
        // 获取当前时间并设置格式,用于生成的文件名
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 输出目录
        String output = String.format("%s/data/%s.png", currentDirectory, now.format(dateTimeFormatter));
        String imagePath = new File(output).toPath().toString();
        File logoFile = new File(String.format("%s/data/logo.jpg", currentDirectory));
        try {
            BufferedImage qr = QRCodeHelper.encodeQRCode(DEFAULT_TEST_CONTENT, 0xff5683ed, 0xffffffff,
                    500, 500, ErrorCorrectionLevel.H, "UTF-8", 2);
            BufferedImage qrWithLogo = QRCodeHelper.getQRCodeWithOverlay(qr, ImageIO.read(logoFile),
                    0.8F, 0.1F);
            ImageIO.write(qr, "png", new File(imagePath));
            ImageIO.write(qrWithLogo, "png",
                    new File(imagePath.replace(".png", "-logo.png")));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (WriterException e) {
            e.printStackTrace();
        }
    }

    // 默认编码方式
    private static final String DEFAULT_CHAR_SET = "UTF-8";
    // 默认二维码图片格式
    private static final String DEFAULT_FORMAT_NAME = "PNG";
    // 默认二维码宽度
    private static final int DEFAULT_QR_CODE_WIDTH = 300;
    // 默认二维码高度
    private static final int DEFAULT_QR_CODE_HEIGHT = 300;
    public static BitMatrix createBitMatrix(String content) throws  WriterException {
        return createBitMatrix(content, DEFAULT_QR_CODE_WIDTH, DEFAULT_QR_CODE_WIDTH);
    }
    /**
     * 创建BitMatrix比特矩阵
     *
     * @param content 二维码里的内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return com.google.zxing.common.BitMatrix 二维码比特矩阵
     * @throws WriterException
     */
    public static BitMatrix createBitMatrix(String content , int width , int height) throws WriterException {
        if (width 
            width = DEFAULT_QR_CODE_WIDTH;
        }
        if (height 
            height = DEFAULT_QR_CODE_HEIGHT;
        }
        Map
        if (width 
            width = DEFAULT_QR_CODE_WIDTH;
        }
        if (height 
            height = DEFAULT_QR_CODE_HEIGHT;
        }
        Map
        if (imageFormat == null || imageFormat.equals("")){
            imageFormat = DEFAULT_FORMAT_NAME;
        }
        BitMatrix bitMatrix = createBitMatrix(content , width, height);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, os);
        return os.toByteArray();
    }
    /**
     * 创建二维码,返回字节数组
     *
     * @param content 二维码内容
     * @param imageFormat 二维码图像格式
     * @param width 宽度
     * @param height 高度
     * @param errCorrLevel 纠错等级
     * @param charSet 字符集
     * @param margin 边距
     * @return byte[]
     * @throws WriterException
     * @throws IOException
     */
    public static byte[] createQRCode(String content, String imageFormat, int width, int height,
                                      ErrorCorrectionLevel errCorrLevel, String charSet, int margin)
            throws WriterException, IOException {
        if (imageFormat == null || imageFormat.equals("")){
            imageFormat = DEFAULT_FORMAT_NAME;
        }
        BitMatrix bitMatrix = createQRCodeBitMatrix(content, width, height, errCorrLevel, charSet, margin);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, os);
        return os.toByteArray();
    }
    /**
     * 创建二维码,返回base64字节流
     *
     * @param content 二维码里的内容
     * @param imageFormat 图片后缀名
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return byte[] base64字节数组
     */
    public static byte[] createQRCodeBase64Bytes(String content , String imageFormat , int width , int height)
            throws WriterException, IOException {
        byte[] bytes = createQRCode(content , imageFormat , width, height);
        return Base64.getEncoder().encode(bytes);
    }
    /**
     * 创建二维码,返回base64字符串
     *
     * @param content 二维码里的内容
     * @param imageFormat 图片后缀名
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return String base64字符串
     */
    public static String createQRCodeBase64(String content , String imageFormat , int width , int height,
                                            String encoding) throws WriterException, IOException {
        return new String(createQRCodeBase64Bytes(content, imageFormat, width, height), encoding);
    }
    /**
     * 转换为BufferedImage
     *
     * @param bitMatrix 比特矩阵
     * @param onColor 条码颜色
     * @param offColor 背景颜色
     * @return java.awt.image.BufferedImage
     */
    public static BufferedImage toBufferedImage(BitMatrix bitMatrix, int onColor, int offColor) {
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(onColor, offColor);
        return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
    }
    /**
     * 转换为BufferedImage
     *
     * @param bitMatrix 比特矩阵
     * @return java.awt.image.BufferedImage
     */
    public static BufferedImage toBufferedImage(BitMatrix bitMatrix) {
//        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig();    // 无参数为白底黑码
        return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
    }
    /**
     * QR码编码
     *
     * @param content 编码内容
     * @param onColor 二维码颜色
     * @param offColor 背景颜色
     * @param width 宽度
     * @param height 高度
     * @param errCorrLevel 纠错等级
     * @param charSet 字符集
     * @param margin 边距
     * @return BufferedImage
     * @throws WriterException
     */
    public static BufferedImage encodeQRCode(String content, int onColor, int offColor, int width, int height,
                                             ErrorCorrectionLevel errCorrLevel, String charSet, int margin)
            throws WriterException {
        BitMatrix bitMatrix = createQRCodeBitMatrix(content, width, height, errCorrLevel, charSet, margin);
        return toBufferedImage(bitMatrix, onColor, offColor);
    }
    /**
     * QR码编码
     *
     * @param content 编码内容
     * @param width 宽度
     * @param height 高度
     * @return BufferedImage
     * @throws WriterException
     */
    public static BufferedImage encodeQRCode(String content, int width, int height) throws WriterException {
        BitMatrix bitMatrix = createBitMatrix(content, width, height);
        return toBufferedImage(bitMatrix);
    }
    /**
     * QR码编码
     *
     * @param content 要编码的内容
     * @return BufferedImage
     * @throws WriterException
     */
    public static BufferedImage encodeQRCode(String content) throws WriterException {
        return toBufferedImage(createBitMatrix(content));
    }
    /**
     * 根据内容和设置生成二维码图片到指定路径
     *
     * @param content 二维码里的内容
     * @param imagePath 生成图片路径
     * @param imageFormat 图片格式
     * @param onColor 二维码颜色
     * @param offColor 背景颜色
     * @param width 二维码宽度
     * @param height 二维码高度
     * @param errorCorrectionLevel 纠错等级
     * @param charSet 字符集
     * @param margin 边距
     * @throws WriterException
     * @throws IOException
     */
    public static void encodeQRCode(String content, String imagePath,
                                    String imageFormat, int onColor, int offColor, int width, int height,
                                    ErrorCorrectionLevel errorCorrectionLevel, String charSet, int margin)
            throws WriterException, IOException {
        if (imageFormat == null || imageFormat.equals("")){
            imageFormat = DEFAULT_FORMAT_NAME;
        }
        BufferedImage bufferedImage = encodeQRCode(content, onColor, offColor,
                width, height, errorCorrectionLevel, charSet, margin);
        ImageIO.write(bufferedImage, imageFormat, new File(imagePath));
    }
    /**
     * 解码二维码
     *
     * @param image 二维码BufferedImage
     * @return java.lang.String
     */
    public static String decodeQRCode(BufferedImage image) throws Exception {
        if (image == null) return "";
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Hashtable
        BufferedImage clone = deepCopy(bufferedImage); // 深复制BufferedImage避免污染原图
        Graphics2D graphics = clone.createGraphics();
        // 读取logo图片文件
        BufferedImage logo = ImageIO.read(logoFile);
        // 开始绘制图片
        graphics.drawImage(logo, xPos, yPos, logoWidth, logoHeight, null);
        graphics.setStroke(new BasicStroke(strokeWidth, strokeCap, strokeJoin));
        graphics.setColor(Color.white);
        // 绘制圆角矩形
        graphics.drawRoundRect(xPos, yPos, logoWidth, logoHeight, arcWidth, arcHeight);
        graphics.dispose();
        clone.flush();
        return clone;
    }
    /**
     * 在QR码图像中央加入一个1/5大小的LOGO
     * @param bufferedImage QR码图像
     * @param logoFile LOGO文件
     * @param strokeWidth LOGO圆角笔宽
     * @param strokeCap
     * @param strokeJoin
     * @param arcWidth 圆角宽,0则不圆
     * @param arcHeight 圆角高,0则不圆
     * @return
     * @throws IOException
     */
    public static BufferedImage addLogoToBufferedImage(BufferedImage bufferedImage, File logoFile,
        float strokeWidth, int strokeCap, int strokeJoin,
        int arcWidth, int arcHeight)
            throws IOException {
        int matrixWidth = bufferedImage.getWidth();
        int matrixHeight = bufferedImage.getHeight();
        // 读取logo图片文件
        BufferedImage logo = ImageIO.read(logoFile);
        int logoWidth = logo.getWidth();
        int logoHeight = logo.getHeight();
        //  计算logo放置位置
        int x = matrixWidth  / 5*2;
        int y = matrixHeight / 5*2;
        int width = matrixWidth / 5;
        int height = matrixHeight / 5;
        return addLogoToBufferedImage(bufferedImage, logoFile, x, y, width, height,
                strokeWidth, strokeCap, strokeJoin, arcWidth, arcHeight);
    }
    /**
     * 给BufferedImage添加LOGO,该方法选择自网络,修改了原来按引用传递带来的副作用(会改变原来的BufferedImage)。
     *
     * @deprecated
     * @param bufferedImage
     * @param logoFile
     * @return
     * @throws IOException
     */
    public static BufferedImage addLogoToBufferedImage(BufferedImage bufferedImage, File logoFile)
            throws IOException {
        BufferedImage clone = deepCopy(bufferedImage); // 深复制BufferedImage避免污染原图
        Graphics2D graphics = clone.createGraphics();
        int matrixWidth = clone.getWidth();
        int matrixHeight = clone.getHeight();
        // 读取logo图片文件
        BufferedImage logo = ImageIO.read(logoFile);
        int logoWidth = logo.getWidth();
        int logoHeight = logo.getHeight();
        //  计算logo放置位置
        int x = clone.getWidth()  / 5*2;
        int y = clone.getHeight() / 5*2;
        int width = matrixWidth / 5;
        int height = matrixHeight / 5;
        // 开始绘制图片
        graphics.drawImage(logo, x, y, width, height, null);
        graphics.setStroke(new BasicStroke(5.0F, 1, 1));
        graphics.setColor(Color.white);
        graphics.drawRoundRect(x, y, width, height, 15, 15);
        graphics.dispose();
        clone.flush();
        return clone;
    }
    /**
     * 给QR码的BufferedImage添加可透明的LOGO
     *
     * @param qrcode
     * @param overlay
     * @param overlayToQRCodeRatio
     * @param overlayTransparency
     * @return
     */
    public static BufferedImage getQRCodeWithOverlay(BufferedImage qrcode, BufferedImage overlay,
      float overlayToQRCodeRatio, float overlayTransparency) {
        BufferedImage scaledOverlay = scaleOverlay(qrcode, overlay,overlayToQRCodeRatio);
        Integer deltaHeight = qrcode.getHeight() - scaledOverlay.getHeight();
        Integer deltaWidth  = qrcode.getWidth()  - scaledOverlay.getWidth();
        BufferedImage combined = new BufferedImage(qrcode.getWidth(), qrcode.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = (Graphics2D)combined.getGraphics();
        g2.drawImage(qrcode, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, overlayTransparency));
        g2.drawImage(scaledOverlay, Math.round(deltaWidth/2), Math.round(deltaHeight/2), null);
        return combined;
    }
    /**
     * 按比例调整LOGO
     *
     * @param qrcode
     * @param overlay
     * @param overlayToQRCodeRatio
     * @return
     */
    private static BufferedImage scaleOverlay(BufferedImage qrcode, BufferedImage overlay, float overlayToQRCodeRatio) {
        Integer scaledWidth = Math.round(qrcode.getWidth() * overlayToQRCodeRatio);
        Integer scaledHeight = Math.round(qrcode.getHeight() * overlayToQRCodeRatio);
        BufferedImage imageBuff = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics g = imageBuff.createGraphics();
        g.drawImage(overlay.getScaledInstance(scaledWidth, scaledHeight, BufferedImage.SCALE_SMOOTH),
                0, 0, new Color(0,0,0), null);
        g.dispose();
        return imageBuff;
    }
    /**
     * BufferedImage 深复制
     * @param bi
     * @return
     */
    private static BufferedImage deepCopy(BufferedImage bi) {
        ColorModel cm = bi.getColorModel();
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster());
        return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }
}
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]