package com.xzx.gc.common.utils.image; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.Result; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; import net.coobird.thumbnailator.Thumbnails; import org.apache.commons.lang3.StringUtils; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.swing.*; import java.awt.*; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Hashtable; import java.util.Iterator; public class QrCodeBaseUtils { private static final String CHARSET = "utf-8"; // 二维码001尺寸 private static final int QRCODE_SIZE = 172; // 二维码002尺寸 private static final int QRCODES_OTHER_SIZE = 200; // LOGO宽度 private static final int WIDTH = 50; // LOGO高度 private static final int HEIGHT = 50; /** * 删除二维码白边 * * @param bitMatrix * @return */ public static BitMatrix deleteWhite(BitMatrix bitMatrix) { int[] rec = bitMatrix.getEnclosingRectangle(); int resWidth = rec[2] + 1; int resHeight = rec[3] + 1; BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); resMatrix.clear(); for (int i = 0; i < resWidth; i++) { for (int j = 0; j < resHeight; j++) { if (bitMatrix.get(i + rec[0], j + rec[1])) { resMatrix.set(i, j); } } } return resMatrix; } /* * 插入LOGO * * @param source 二维码图片 * * @param imgPath LOGO图片地址 * * @param needCompress 是否压缩 * * @param frame 是否去白边 * * @param type * * @throws Exception */ @SuppressWarnings("unused") private static void insertImage(BufferedImage source, String imgPath, boolean needCompress, boolean frame, int type) throws Exception { BufferedImage logoBufferedImage = null; if (StringUtils.isNotBlank(imgPath)) { if (imgPath.startsWith("http")) { logoBufferedImage = ImageIO.read(new URL(imgPath)); } else { logoBufferedImage = ImageIO.read(new File(imgPath)); } } if (logoBufferedImage == null) { return; } int width = 0; int height = 0; if (imgPath.endsWith("/132")) { width = 132; height = 132; } else { width = logoBufferedImage.getWidth(); height = logoBufferedImage.getHeight(); } // 压缩LOGO if (needCompress) { if (width > WIDTH) { width = WIDTH; } if (height > HEIGHT) { height = HEIGHT; } if (imgPath.startsWith("http")) { logoBufferedImage = Thumbnails.of(new URL(imgPath)).size(width, height).asBufferedImage(); } else { logoBufferedImage = Thumbnails.of(imgPath).size(width, height).asBufferedImage(); } } // 插入LOGO Graphics2D graph = source.createGraphics(); int x = 0; int y = 0; if (frame) { x = (QRCODE_SIZE - width - 39) / 2; y = (QRCODE_SIZE - height - 39) / 2; } else { if (type == 0) { x = (QRCODE_SIZE - width) / 2; y = (QRCODE_SIZE - height) / 2; } else if (type == 1) { x = (QRCODES_OTHER_SIZE - width) / 2; y = (QRCODES_OTHER_SIZE - height) / 2; } } graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graph.drawImage(logoBufferedImage, x, y, width, height, null); // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小 Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8); // 边框 // 默认情况下,Graphics // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等 graph.setStroke(new BasicStroke(3f)); graph.draw(shape); graph.dispose(); } /** * 解析二维码 * * @param file * 二维码图片 * @return * @throws Exception */ public static String decode(File file) throws Exception { BufferedImage image; image = ImageIO.read(file); if (image == null) { return null; } BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Result result; Hashtable hints = new Hashtable(); hints.put(DecodeHintType.CHARACTER_SET, CHARSET); result = new MultiFormatReader().decode(bitmap, hints); String resultStr = result.getText(); return resultStr; } /** * 解析二维码 * * @param path * 二维码图片地址 * @return * @throws Exception */ public static String decode(String path) throws Exception { return decode(new File(path)); } /** * * compressPicByQuality 压缩图片,通过压缩图片质量,保持原图大小 * * @param bufferImage * @param quality * :0-1 * @return */ public static byte[] compressPicByQuality(BufferedImage bufferImage, float quality) { byte[] inByte = null; try { if (bufferImage == null) { return null; } // 得到指定Format图片的writer // 得到迭代器 Iterator iter = ImageIO.getImageWritersByFormatName("jpeg"); // 得到writer ImageWriter writer = (ImageWriter)iter.next(); // 得到指定writer的输出参数设置(ImageWriteParam ) ImageWriteParam iwp = writer.getDefaultWriteParam(); // 设置可否压缩 iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置压缩质量参数 iwp.setCompressionQuality(quality); iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED); ColorModel colorModel = ColorModel.getRGBdefault(); // 指定压缩时使用的色彩模式 iwp.setDestinationType( new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16))); // 开始打包图片,写入byte[] ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); IIOImage iIamge = new IIOImage(bufferImage, null, null); // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream)); writer.write(null, iIamge, iwp); inByte = byteArrayOutputStream.toByteArray(); } catch (IOException e) { System.out.println("write errro"); e.printStackTrace(); } return inByte; } /** * image File 转 BufferedImage 直接使用 ImageIO 可能会使图片染红。 * * @param imaPath * @return * @throws Exception */ public static BufferedImage imageToBufferedImage(String imaPath) throws Exception { if (StringUtils.isNotBlank(imaPath)) { Image src = null; BufferedImage img = null; if (imaPath.startsWith("http")) { src = Toolkit.getDefaultToolkit().getImage(new URL(imaPath)); } else { src = Toolkit.getDefaultToolkit().getImage(imaPath); } if (src != null) { img = toBufferedImage(src); } return img; } else { return null; } } /** * image File 转 BufferedImage 直接使用 ImageIO 可能会使图片染红。 * * @param url * @return * @throws Exception */ public static BufferedImage imageToBufferedImage(URL url) throws Exception { Image src = Toolkit.getDefaultToolkit().getImage(url); BufferedImage img = null; if (src != null) { img = toBufferedImage(src); } return img; } /** * image File 转 BufferedImage 的依赖函数 * * @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; } /* * 插入LOGO * * @param source 二维码图片 * * @param imgUrl LOGOURL * * @param needCompress 是否压缩 * * @param frame 是否去白边 * * @param type * * @throws Exception */ public static void insertImage(BufferedImage source, URL imgUrl, boolean needCompress, boolean frame, int qrCodeSize) throws Exception { if (qrCodeSize == 0) { qrCodeSize = QRCODE_SIZE; } BufferedImage logoBufferedImage = ImageIO.read(imgUrl); if (logoBufferedImage == null) { return; } int width = 0; int height = 0; width = logoBufferedImage.getWidth(); height = logoBufferedImage.getHeight(); if (needCompress) { if (qrCodeSize == 136) { if (width > 33) { width = 33; } if (height > 33) { height = 33; } } else { if (width > WIDTH) { width = WIDTH; } if (height > HEIGHT) { height = HEIGHT; } } logoBufferedImage = Thumbnails.of(imgUrl).size(width, height).asBufferedImage(); } // 插入LOGO Graphics2D graph = source.createGraphics(); int x = 0; int y = 0; if (frame) { x = (QRCODE_SIZE - width - 39) / 2; y = (QRCODE_SIZE - height - 39) / 2; } else { x = (qrCodeSize - width) / 2; y = (qrCodeSize - height) / 2; } graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graph.drawImage(logoBufferedImage, x, y, width, height, null); // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小 Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8); // 边框 // 默认情况下,Graphics // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等 graph.setStroke(new BasicStroke(3f)); graph.draw(shape); graph.dispose(); } /* * 插入LOGO * * @param source 二维码图片 * * @param imgFile LOGO-图片(File) * * @param needCompress 是否压缩 * * @param frame 是否去白边 * * @param type * * @throws Exception */ public static void insertImage(BufferedImage source, File imgFile, boolean needCompress, boolean frame, int qrCodeSize) throws Exception { BufferedImage logoBufferedImage = null; logoBufferedImage = ImageIO.read(imgFile); if (logoBufferedImage == null) { return; } int width = logoBufferedImage.getWidth(); int height = logoBufferedImage.getHeight(); // 压缩LOGO if (needCompress) { if (needCompress) { if (qrCodeSize == 136) { if (width > 33) { width = 33; } if (height > 33) { height = 33; } } else { if (width > WIDTH) { width = WIDTH; } if (height > HEIGHT) { height = HEIGHT; } } logoBufferedImage = Thumbnails.of(imgFile).size(width, height).asBufferedImage(); } } // 插入LOGO Graphics2D graph = source.createGraphics(); int x = 0; int y = 0; if (frame) { x = (QRCODE_SIZE - width - 39) / 2; y = (QRCODE_SIZE - height - 39) / 2; } else { if (qrCodeSize == 0) { qrCodeSize = QRCODE_SIZE; } x = (qrCodeSize - width) / 2; y = (qrCodeSize - height) / 2; } graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graph.drawImage(logoBufferedImage, x, y, width, height, null); // logoBufferedImage 是 logo对象 xy 是gs两个边的距离,width height 是 logo的大小 Shape shape = new RoundRectangle2D.Float(x, y, width, height, 8, 8); // 边框 // 默认情况下,Graphics // 绘图类使用的笔画属性是粗细为1个像素的正方形,而Java2D的Graphics2D类可以调用setStroke()方法设置笔画的属性,如改变线条的粗细、虚实和定义线段端点的形状、风格等 graph.setStroke(new BasicStroke(3f)); graph.draw(shape); graph.dispose(); } }