package com.xzx.gc.common.utils.image; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import net.coobird.thumbnailator.Thumbnails; import org.apache.commons.lang3.StringUtils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; /** * QrCodeBaseUtils2 * * @author Angzk * @date 2019年8月7日 */ public final class QrCodeGraphicsUtils { private static final String CHARSET = "utf-8"; private static final int QRCODE_SIZE = 172; /** * 生成二维码 * * @param linkUrl * 二维码地址 * @param hasFrame * 是否删除白边 * @param logoStatus * 是否插入logo * @param logoPath * logoPath * @param logoNeedCompress * 是否压缩 logo * @throws Exception */ public static BufferedImage createQrCode(String linkUrl, boolean hasFrame, boolean logoStatus, String logoPath, boolean logoNeedCompress, int qrCodeSize) throws Exception { Hashtable hints = new Hashtable(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); hints.put(EncodeHintType.CHARACTER_SET, CHARSET); hints.put(EncodeHintType.MARGIN, 1); if (qrCodeSize == 0) { qrCodeSize = QRCODE_SIZE; } BitMatrix bitMatrix = new MultiFormatWriter().encode(linkUrl, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hints); // 删除白边 if (hasFrame) { bitMatrix = QrCodeBaseUtils.deleteWhite(bitMatrix); } int width = bitMatrix.getWidth(); int height = bitMatrix.getHeight(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); } } if (logoStatus) { URL avatarUrl = null; File avatarFile = null; if (StringUtils.isNotBlank(logoPath)) { if (logoPath.startsWith("http")) { avatarUrl = new URL(logoPath); QrCodeBaseUtils.insertImage(image, avatarUrl, logoNeedCompress, hasFrame, qrCodeSize); } else { avatarFile = new File(logoPath); QrCodeBaseUtils.insertImage(image, avatarFile, logoNeedCompress, hasFrame, qrCodeSize); } } } return image; } public static Graphics2D drawAvatar(Graphics2D graphics, String avatarUrl, BufferedImage bufferImage, int x, int y) throws Exception { // 绘制头像 。 BufferedImage logoBufferImage = null; if (avatarUrl.startsWith("http")) { logoBufferImage = Thumbnails.of(new URL(avatarUrl)).size(70, 70).asBufferedImage(); } else { logoBufferImage = Thumbnails.of(new File(avatarUrl)).size(70, 70).asBufferedImage(); } // int height2 = logoBufferImage.getHeight(); // 图片变圆 // int border = 2; // Ellipse2D.Double shapeEll = // new Ellipse2D.Double(x + border, y + border, height2 - border * 2, height2 - border * 2); // // 抗锯齿 // graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // graphics.setClip(shapeEll); // 绘制头像 graphics.drawImage(logoBufferImage, x, y, null); // 为了防止 头像圆角之后锯齿问题。需要在头像周围画一个白框覆盖即可。 // graphics = bufferImage.createGraphics(); // graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // int border2 = 2; // Stroke s = new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); // graphics.setStroke(s); // graphics.setColor(Color.WHITE); // 绘制头像边框 // graphics.drawOval(x + border, y + border, height2 - border2 * 2, height2 - border2 * 2); return graphics; } /** * * @param bufferImage * 画布对象 * @param scale * 缩放 * @param outFormat * 输出格式 * @param outPutQuality * 输出品质 * @param pngPath * 输出路径 * @throws Exception */ public static void savePic(BufferedImage bufferImage, int scale, String outFormat, double outPutQuality, String pngPath) throws Exception { File file = new File(pngPath); // 自定义压缩. byte[] picByQuality = QrCodeBaseUtils.compressPicByQuality(bufferImage, 1f); ByteArrayInputStream in = new ByteArrayInputStream(picByQuality); BufferedImage qualityBufferImage = ImageIO.read(in); // Google 工具包 写出文件 Thumbnails.of(qualityBufferImage).scale(scale).outputFormat(outFormat).outputQuality(outPutQuality) .toFile(file); } /** * 绘制海报文字 * * @param graphics * @param text * @param width * @param height */ public static Graphics2D drawText(Graphics2D graphics, String text, int width, int height, Color color) { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.setPaint(new Color(0, 0, 0, 64)); graphics.drawString(text, width, height); // graphics.setPaint(color); // 绘制 商品价格 graphics.drawString(text, width, height); return graphics; } /** * 绘制海报文字(换行) * * @param graphics * 画笔 * @param text * 文本 * @param width * 位置:x * @param height 位置:y * @param lineHeight * 单行行高 * @param linewidth * 单行行宽 * @param color * 文本颜色 * @param limitLineNum * 限制行数 * @return */ public static int drawTextNewLine(Graphics2D graphics, String text, int width, int height, int lineHeight, int linewidth, Color color, int textSize, int limitLineNum, int backgroundWidth) { Font font = new Font("微软雅黑", Font.PLAIN, textSize); graphics.setFont(font); graphics.setPaint(color); FontRenderContext frc = graphics.getFontRenderContext(); graphics.getFontRenderContext(); Rectangle2D stringBounds = font.getStringBounds(text, frc); double fontWidth = stringBounds.getWidth(); List lineList = new ArrayList(); int lineCharCountSub = 0; // 不满一行 if (fontWidth <= linewidth) { lineList.add(text); width = (backgroundWidth - Double.valueOf(fontWidth).intValue()) / 2; } else { width = (backgroundWidth - linewidth) / 2; // 输出文本宽度,这里就以画布宽度作为文本宽度测试 int textWidth = linewidth; // 文本长度是文本框长度的倍数 double bs = fontWidth / textWidth; // 每行大概字数 int lineCharCount = (int)Math.ceil(text.length() / bs); lineCharCountSub = lineCharCount; int beginIndex = 0; while (beginIndex < text.length()) { int endIndex = beginIndex + lineCharCount; if (endIndex >= text.length()) { endIndex = text.length(); } String lineStr = text.substring(beginIndex, endIndex); Rectangle2D tempStringBounds = font.getStringBounds(lineStr, frc); int tzzs = 1; while (tempStringBounds.getWidth() > textWidth) { lineStr = lineStr.substring(0, lineStr.length() - tzzs); tempStringBounds = font.getStringBounds(lineStr, frc); } lineList.add(lineStr); beginIndex = beginIndex + lineStr.length(); } } // Color.BLACK 。字体颜色 graphics.setPaint(color); if (lineHeight == 0) { lineHeight = 35; } int lineNum = lineList.size(); if (limitLineNum != 0 && lineNum > limitLineNum) { lineNum = limitLineNum; } // 绘制 换行文字 for (int i = 0; i < lineNum; i++) { String lineStr = lineList.get(i); if (lineNum >= 2 && i == lineNum - 1) { if (lineStr.length() >= lineCharCountSub - 3) { lineStr = lineStr.substring(0, lineStr.length() - 2) + "..."; } } graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); } return lineNum; } /** * 绘制海报文字(换行) * * @param graphics * 画笔 * @param text * 文本 * @param width * 位置:x * @param height 位置:y * @param lineHeight * 单行行高 * @param linewidth * 单行行宽 * @param color * 文本颜色 * @param limitLineNum * 限制行数 * @return */ public static int drawRightTextNewLine(Graphics2D graphics, String text, int width, int height, int lineHeight, int linewidth, Color color, int textSize, int limitLineNum, int backgroundWidth) { Font font = new Font("微软雅黑", Font.PLAIN, textSize); graphics.setFont(font); graphics.setPaint(color); FontRenderContext frc = graphics.getFontRenderContext(); graphics.getFontRenderContext(); Rectangle2D stringBounds = font.getStringBounds(text, frc); double fontWidth = stringBounds.getWidth(); List lineList = new ArrayList(); int lineCharCountSub = 0; // 不满一行 if (fontWidth <= linewidth) { lineList.add(text); width = (backgroundWidth - Double.valueOf(fontWidth).intValue()) / 2 + backgroundWidth / 2 + 57; } else { width = (backgroundWidth - linewidth) / 2 + backgroundWidth / 2 + 57; // 输出文本宽度,这里就以画布宽度作为文本宽度测试 int textWidth = linewidth; // 文本长度是文本框长度的倍数 double bs = fontWidth / textWidth; // 每行大概字数 int lineCharCount = (int)Math.ceil(text.length() / bs); lineCharCountSub = lineCharCount; int beginIndex = 0; while (beginIndex < text.length()) { int endIndex = beginIndex + lineCharCount; if (endIndex >= text.length()) { endIndex = text.length(); } String lineStr = text.substring(beginIndex, endIndex); Rectangle2D tempStringBounds = font.getStringBounds(lineStr, frc); int tzzs = 1; while (tempStringBounds.getWidth() > textWidth) { lineStr = lineStr.substring(0, lineStr.length() - tzzs); tempStringBounds = font.getStringBounds(lineStr, frc); } lineList.add(lineStr); beginIndex = beginIndex + lineStr.length(); } } // Color.BLACK 。字体颜色 graphics.setPaint(color); if (lineHeight == 0) { lineHeight = 35; } int lineNum = lineList.size(); if (limitLineNum != 0 && lineNum > limitLineNum) { lineNum = limitLineNum; } // 绘制 换行文字 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int i = 0; i < lineNum; i++) { String lineStr = lineList.get(i); if (lineNum >= 2 && i == lineNum - 1) { if (lineStr.length() >= lineCharCountSub - 3) { lineStr = lineStr.substring(0, lineStr.length() - 2) + "..."; } } graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); } return lineNum; } /** * 绘制海报文字(换行) * * @param graphics * 画笔 * @param text * 文本 * @param width * 位置:x * @param height 位置:y * @param lineHeight * 单行行高 * @param linewidth * 单行行宽 * @param color * 文本颜色 * @param limitLineNum * 限制行数 * @return */ public static int drawTextNewLine(Graphics2D graphics, String text, int width, int height, int lineHeight, int linewidth, Color color, int textSize, int limitLineNum) { Font font = new Font("微软雅黑", Font.PLAIN, textSize); graphics.setFont(font); graphics.setPaint(color); FontRenderContext frc = graphics.getFontRenderContext(); graphics.getFontRenderContext(); Rectangle2D stringBounds = font.getStringBounds(text, frc); double fontWidth = stringBounds.getWidth(); List lineList = new ArrayList(); int lineCharCountSub = 0; // 不满一行 if (fontWidth <= linewidth) { lineList.add(text); } else { // 输出文本宽度,这里就以画布宽度作为文本宽度测试 int textWidth = linewidth; // 文本长度是文本框长度的倍数 double bs = fontWidth / textWidth; // 每行大概字数 int lineCharCount = (int)Math.ceil(text.length() / bs); lineCharCountSub = lineCharCount; int beginIndex = 0; while (beginIndex < text.length()) { int endIndex = beginIndex + lineCharCount; if (endIndex >= text.length()) { endIndex = text.length(); } String lineStr = text.substring(beginIndex, endIndex); Rectangle2D tempStringBounds = font.getStringBounds(lineStr, frc); int tzzs = 1; while (tempStringBounds.getWidth() > textWidth) { lineStr = lineStr.substring(0, lineStr.length() - tzzs); tempStringBounds = font.getStringBounds(lineStr, frc); } lineList.add(lineStr); beginIndex = beginIndex + lineStr.length(); } } // Color.BLACK 。字体颜色 graphics.setPaint(color); if (lineHeight == 0) { lineHeight = 35; } int lineNum = lineList.size(); if (limitLineNum != 0 && lineNum > limitLineNum) { lineNum = limitLineNum; } // 绘制 换行文字 for (int i = 0; i < lineNum; i++) { String lineStr = lineList.get(i); if (lineNum >= 2 && i == lineNum - 1) { if (lineStr.length() >= lineCharCountSub - 3) { lineStr = lineStr.substring(0, lineStr.length() - 2) + "..."; } } graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); graphics.drawString(lineStr, width, height + (i + 1) * lineHeight); } return lineNum; } }