Java生成二维码增加logo或备注信息

Java生成二维码后,带logo图片时,需要在新生成的二维码图片中,画对应的logo;带备注信息时,需要先准备一张画布,将画布分为二维码信息和备注信息两部分,一部分画二维码信息,一部分写备注信息。

二维码带logo图片

想做个类似支付宝或微信收款码这样的二维码,二维码中间有用户的图像logo

使用谷歌zxing技术来实现

先看代码,代码中有详细注释

	/**
	   * 生成二维码
	   * 二维码中内嵌图片logo
	 * @param content 二维码携带内容信息
	 * @param width 二维码宽/高
	 * @param picFormat 二维码图片格式
	 * @param logoImgPath 内嵌logo图片路径
	 * @param needCompress logo图片是否压缩
	 * @return 二维码字节数组
	 */
	public static byte[] generateQRcodeByte(String content, int width, String picFormat, 
			String logoImgPath, boolean needCompress) {
		
		// 编码提示信息,设置二维码纠错级别、编码字符、边框等信息
		Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, 1);
        
		byte[] codeBytes = null;
		try {
			// 构造二维字节矩阵,将二位字节矩阵渲染为二维缓存图片
			BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, width, hints);
			BufferedImage sourceImg = toBufferedImage(bitMatrix);
			
			// 读取logo图片,并判断logo图片的宽高必须相等
			Image logoImg = ImageIO.read(new File(logoImgPath));
	        int logoWidth = logoImg.getWidth(null);
	        int logoHeight = logoImg.getHeight(null);
	        if (logoWidth != logoHeight) {
	        	return codeBytes;
	        }
	        
	        // 对logo图片实施压缩
	        // 若logo图片宽高大于二维码宽高,必须对logo图片进行压缩
	        // 否则,过大的照片会撑爆二维码,生成的二维码只能看到部分的logo图片信息
	        if (needCompress) { 
	            if (logoWidth > LOGO_WIDTH && logoHeight > LOGO_HEIGHT) {
	            	logoWidth = LOGO_WIDTH;
	            	logoHeight = LOGO_HEIGHT;
	            }
	            
	            // 创建缩微版本的logo图片
	            Image image = logoImg.getScaledInstance(logoWidth, logoHeight,
	                    Image.SCALE_SMOOTH);
	            BufferedImage tag = new BufferedImage(logoWidth, logoHeight,
	                    BufferedImage.TYPE_INT_RGB);
	            
	            // 绘制缩微版logo图片,并将新的logo图片赋给原logo图片变量
	            Graphics g = tag.getGraphics();
	            g.drawImage(image, 0, 0, null);
	            g.dispose();
	            logoImg = image;
	        }
	        
	        // 在原二维码中计算位置,插入新的logo图片
	        Graphics2D graph = sourceImg.createGraphics();
	        int x = (QRCODE_SIZE - logoWidth) / 2;
	        int y = (QRCODE_SIZE - logoHeight) / 2;
	        graph.drawImage(logoImg, x, y, logoWidth, logoWidth, null);
	        Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoWidth, 6, 6);
	        graph.setStroke(new BasicStroke(3f));
	        graph.draw(shape);
	        graph.dispose();
	        
			// 定义输出流,将二维缓存图片写到指定输出流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(sourceImg, picFormat, out);
            
            // 将输出流转换为字节数组
            codeBytes = out.toByteArray();

		} catch (WriterException | IOException e) {
			e.printStackTrace();
		}
		return codeBytes;
	}

toBufferedImage( ) 方法与上篇博文相同,这里不再贴代码了。

二维码中内嵌logo图片时,需要先生成二维码图片,然后再将logo图片画到二维码中间,其它的与普通二维码无异。

二维码带备注信息

经常会看到共享单车的二维码下面有一个单车的编号,那么这个带编号的二维码怎么用Java生成呢?

正常生成一个二维码,然后新画一张画布,画布分两块内容,一块画二维码,一块写备注信息就可以啦。

先看看代码实现

	/**
	 * 生成二维码
	 * 带有备注信息字样
	 * 二维码的宽高受备注信息字体大小影响,这里没有抽取公共参数
	 * @throws WriterException
	 * @throws IOException
	 */
	public static void generateQRcodeRemark() throws IOException, WriterException {

		// 创建输出画布,由于有备注信息,这里个二维码宽高不等
		// 通常情况下,建议设置宽高相等
		BufferedImage logoReamarkImage = new BufferedImage(300, 325, BufferedImage.TYPE_INT_RGB);
		Graphics graphics = logoReamarkImage.getGraphics();
		graphics.setColor(Color.WHITE);
		graphics.fillRect(0, 0, 300, 325);
		graphics.dispose();

		// 设置二维码纠错信息
		HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		hints.put(EncodeHintType.MARGIN, 0);
		
		// 定义二维码位图矩阵
		BitMatrix m = new MultiFormatWriter().encode(CONTENT, BarcodeFormat.QR_CODE, 300, 300,
				hints);
		BufferedImage imageNew = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < 300; x++) {
			for (int y = 0; y < 300; y++) {
				imageNew.setRGB(x, y, m.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
			}
		}

		// 将生成的二维码转化为像素数组,并将数组写到画布logoReamarkImage上
		int[] imageNewArray = new int[300 * 300];
		imageNewArray = imageNew.getRGB(0, 0, 300, 300, imageNewArray, 0, 300);
		logoReamarkImage.setRGB(0, 0, 300, 300, imageNewArray, 0, 300);
		
		// 设置二维码备注信息
		Graphics graphicsText = logoReamarkImage.createGraphics();
		graphicsText.setColor(Color.black);
		graphicsText.setFont(new Font(null, Font.PLAIN, 18));
		graphicsText.drawString("二维码备注", 100, 320);
		graphicsText.dispose();

		// 定义输出流,将二维缓存图片写到指定输出流
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ImageIO.write(logoReamarkImage, "jpg", out);

		// 二维码图片最终输出
		String path = "D:\\DEV_ENV" + File.separator + "image" + File.separator + sf.format(new Date());
		File pathDir = new File(path);
		if (!pathDir.exists()) {
			pathDir.mkdirs();
		}

		File pathFile = new File(path + File.separator + "qrcodeRemark.jpg");
		byte[] fileIo = out.toByteArray();
		try {
			OutputStream os = new FileOutputStream(pathFile);
			os.write(fileIo);
			os.flush();
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

内容都在代码和注释中了,关键点在于将二维码转化为数组,并重新写到画布上

		// 将生成的二维码转化为像素数组,并将数组写到画布logoReamarkImage上
		int[] imageNewArray = new int[300 * 300];
		imageNewArray = imageNew.getRGB(0, 0, 300, 300, imageNewArray, 0, 300);
		logoReamarkImage.setRGB(0, 0, 300, 300, imageNewArray, 0, 300);

执行代码,可以生成二维码

猜你喜欢

转载自blog.csdn.net/magi1201/article/details/87972749