/** * 二维码 工具 * * @author Rubekid * */ public class QRcodeUtils { /** * 默认version */ public static final int DEFAULT_VERSION = 9; /** * 图片类型 png (默认) 比较小 */ public static final String IMAGE_TYPE_PNG = "png"; /** * 图片类型 jpg */ public static final String IMAGE_TYPE_JPEG = "jpg"; /** * 容错率等级 L */ public static final char CORRECT_L = 'L'; /** * 容错率等级 M */ public static final char CORRECT_M = 'M'; /** * 容错率等级 Q */ public static final char CORRECT_Q = 'Q'; /** * 容错率等级 H */ public static final char CORRECT_H = 'H'; /** * 旁白占用比率 */ public static final double PADDING_RATIO = 0.02; /** * 生成二维码 * * @param content * 要生成的内容 * @param size * 要生成的尺寸 * @param versoin * 二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大 * @param ecc * 二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%) * @return * @throws Exception */ public static BufferedImage encode(String content, int size, int version, char ecc) throws Exception { BufferedImage image = null; Qrcode qrcode = new Qrcode(); // 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小 qrcode.setQrcodeErrorCorrect(ecc); qrcode.setQrcodeEncodeMode('B'); // 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大 qrcode.setQrcodeVersion(version); // 获得内容的字节数组,设置编码格式 byte[] contentBytes = content.getBytes("utf-8"); double ratio = 3;// 默认放大三倍 int qrcodeSize = 21 + 4 * (version - 1); if (size > 0) { ratio = (double) size / qrcodeSize; } int intRatio = (int) Math.ceil(ratio); // 旁白 int padding = (int) Math.ceil(qrcodeSize * intRatio * PADDING_RATIO); if (padding < 5) { padding = 5; } // 图片尺寸 int imageSize = qrcodeSize * intRatio + padding * 2; // 图片边长 调整(10的倍数) if (intRatio > ratio) { int newSize = (int) Math.ceil(ratio * imageSize / intRatio); int r = newSize % 10; newSize += 10 - r; int newImageSize = (int) Math.floor(intRatio * newSize / ratio); padding += (newImageSize - imageSize) / 2; imageSize = newImageSize; } else { int r = imageSize % 10; int d = 10 - r; padding += d / 2; imageSize += d; } image = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_RGB); Graphics2D gs = image.createGraphics(); // 设置背景颜色 gs.setBackground(Color.WHITE); gs.clearRect(0, 0, imageSize, imageSize); // 设定图像颜色 BLACK gs.setColor(Color.BLACK); // 输出内容 二维码 if (contentBytes.length > 0 && contentBytes.length < 800) { boolean[][] codeOut = qrcode.calQrcode(contentBytes); for (int i = 0; i < codeOut.length; i++) { for (int j = 0; j < codeOut.length; j++) { if (codeOut[j][i]) { gs.fillRect(j * intRatio + padding, i * intRatio + padding, intRatio, intRatio); } } } } else { throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800]."); } gs.dispose(); image.flush(); if (intRatio > ratio) { image = resize(image, (int) Math.ceil(ratio * imageSize / intRatio)); } return image; } /** * 生成二维码 * * @param content * @param size * @return * @throws Exception */ public static BufferedImage encode(String content, int size) throws Exception { return encode(content, size, DEFAULT_VERSION, CORRECT_Q); } /** * 生成二维码 * * @param content * @param size * @param version * @return */ public static BufferedImage encode(String content, int size, int version) throws Exception { return encode(content, size, version, CORRECT_Q); } /** * 生成二维码 * * @param content * @param size * @param ecc * @return */ public static BufferedImage encode(String content, int size, char ecc) throws Exception { return encode(content, size, DEFAULT_VERSION, ecc); } /** * 生成二维码 * * @param content * @return */ public static BufferedImage encode(String content) throws Exception { return encode(content, 0, DEFAULT_VERSION, CORRECT_Q); } /** * 解析二维码 * * @throws UnsupportedEncodingException * @throws DecodingFailedException */ public static String decode(BufferedImage bufferedImage) throws DecodingFailedException, UnsupportedEncodingException { QRCodeDecoder decoder = new QRCodeDecoder(); return new String(decoder.decode(new MyQRCodeImage(bufferedImage)), "utf-8"); } /** * 下载二维码 * * @param response * @param filename * @param content * @param size * @param imageType * @throws Exception` */ public static void download(HttpServletResponse response, String filename, String content, int size, String imageType, String logoPath) throws Exception { if (size > 2000) { size = 2000; } BufferedImage image = QRcodeUtils.encode(content, size); if(logoPath !=null){ markLogo(image, logoPath); } // 替换占位符 filename = filename.replace("{size}", String.valueOf(image.getWidth())); InputStream inputStream = toInputStream(image, imageType); int length = inputStream.available(); // 设置response response.setContentType("application/x-msdownload"); response.setContentLength(length); response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("gbk"), "iso-8859-1")); // 输出流 byte[] bytes = new byte[1024]; OutputStream outputStream = response.getOutputStream(); while (inputStream.read(bytes) != -1) { outputStream.write(bytes); } outputStream.flush(); } /** * 下载二维码 * @param response * @param filename * @param content * @param size * @param imageType * @throws Exception */ public static void download(HttpServletResponse response, String filename, String content, int size, String imageType) throws Exception { download(response, filename, content, size, imageType, null); } /** * 下载二维码 * * @param response * @param filename * @param content * @param size * @throws Exception */ public static void download(HttpServletResponse response, String filename, String content, int size) throws Exception { download(response, filename, content, size, IMAGE_TYPE_PNG); } /** * 生成二维码文件 * @param destFile * @param content * @param size * @param logoPath * @throws Exception */ public static void createQrcodeFile(File destFile, String content, int size, String logoPath) throws Exception{ if(!destFile.exists() || !destFile.isFile()){ destFile.createNewFile(); } OutputStream outputStream = new FileOutputStream(destFile); BufferedImage image = QRcodeUtils.encode(content, size); if(logoPath !=null){ markLogo(image, logoPath); } InputStream inputStream = toInputStream(image, QRcodeUtils.IMAGE_TYPE_PNG); // 输出流 byte[] bytes = new byte[1024]; while (inputStream.read(bytes) != -1) { outputStream.write(bytes); } inputStream.close(); outputStream.close(); } /** * 生成二维码文件 * @param destFile * @param content * @param size * @throws Exception */ public static void createQrcodeFile(File destFile, String content, int size) throws Exception{ createQrcodeFile(destFile, content, size, null); } /** * logo水印 * @param qrcode * @param logoPath * @throws IOException */ public static void markLogo(BufferedImage qrcode, String logoPath) throws IOException{ File logoFile = new File(logoPath); if(logoFile.exists()){ Graphics2D gs = qrcode.createGraphics(); int width = qrcode.getWidth(); int height = qrcode.getHeight(); Image logo = ImageIO.read(logoFile); int scale = 6; //显示为图片的 1/n; //logo显示大小 int lw = width / scale; int lh = height / scale; int wx = (width - lw) /2; int wy = (height -lh) / 2; gs.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); gs.drawImage(logo, wx, wy, lw, lh, null); // 图片水印文件结束 gs.dispose(); qrcode.flush(); } } /** * 获取内容二维码图片出流 * * @param content * @param size * @param imageType * @return * @throws Exception * InputStream */ public static InputStream getQrcodeImageStream(String content, int size, String imageType, String logoPath) throws Exception { if (size > 2000) { size = 2000; } BufferedImage image = QRcodeUtils.encode(content, size); if(logoPath!=null){ markLogo(image, logoPath); } return toInputStream(image, imageType); } public static InputStream getQrcodeImageStream(String content, int size, String imageType) throws Exception { return getQrcodeImageStream(content, size, imageType, null); } /** * 转成InputStream * @param image * @param imageType * @return * @throws IOException */ private static InputStream toInputStream(BufferedImage image, String imageType) throws IOException{ // BufferedImage 转 InputStream ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ImageOutputStream imageOutput = ImageIO.createImageOutputStream(byteArrayOutputStream); // 生成jpg格式 if (IMAGE_TYPE_JPEG.equals(imageType)) { Iterator<ImageWriter> iterator = ImageIO.getImageWritersByFormatName("jpeg"); ImageWriter imageWriter = iterator.next(); ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam(); imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); imageWriteParam.setCompressionQuality(1); // 设置质量 imageWriter.setOutput(imageOutput); IIOImage iioImage = new IIOImage(image, null, null); imageWriter.write(null, iioImage, imageWriteParam); imageWriter.dispose(); } else { ImageIO.write(image, "png", imageOutput); } return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); } /** * 图片缩放 */ private static BufferedImage resize(BufferedImage image, int size) { int imageSize = (size % 2) > 0 ? (size + 1) : size; BufferedImage bufferedImage = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_RGB); Graphics2D gs = bufferedImage.createGraphics(); gs.setBackground(Color.WHITE); gs.clearRect(0, 0, imageSize, imageSize); gs.setColor(Color.BLACK); gs.fillRect(0, 0, imageSize, imageSize); gs.drawImage(image, 0, 0, size, size, null); gs.dispose(); image.flush(); return bufferedImage; } }