java实现二维码([带]logo)的绘制和解析(zxing by google)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集

二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。

--百度百科

注:遇到问题:

①:二维码logo图片加入为黑白色,已经解决(测试代码中)。

②:二维码背景色和显示颜色色差大,扫描快,但如果显示颜色设置为黑色外其他颜色,可能无法扫描。

使用到的jar包zxing.jar,源码twodimensioncode,颜色转换:java实现颜色Color对象和16进制之间的转换

1:绘制二维码:

package com.tsxs.tools.twodimensioncode;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.EnumMap;

import javax.imageio.ImageIO;

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;
/**
 * 通过google的zxing实现二维码(加入logo图片)
 * @author tskk
 * @version 2015-6-26 13:30:20
 * */
public final class EncodeImgZxing { 
	//二维码颜色
	private static final int BLACK = 0xFF000000;//0xFFFF0000,红色
	//二维码背景色
	private static final int WHITE = 0xFFFFFFFF;//0xFF0000FF,蓝色
	//注:二维码颜色色差大,扫描快,但如果"BLACK'设置为黑色外其他颜色,可能无法扫描
	//二维码图片宽度
	private static final int width = 300;
	//二维码图片高度
	private static final int height = 300;
	//二维码格式参数
	private static final EnumMap<EncodeHintType, Object> hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
	static{
		/*二维码的纠错级别(排错率),4个级别:
		 L (7%)、
		 M (15%)、
		 Q (25%)、
		 H (30%)(最高H)
		 纠错信息同样存储在二维码中,纠错级别越高,纠错信息占用的空间越多,那么能存储的有用讯息就越少;共有四级;
		 选择M,扫描速度快。
		 */
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		// 二维码边界空白大小 1,2,3,4 (4为默认,最大)
		hints.put(EncodeHintType.MARGIN, 1);
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.MAX_SIZE, 350);
		hints.put(EncodeHintType.MIN_SIZE, 150);
	}
	/**
	 * 绘制二维码
	 * @param contents 二维码内容  
	 * @return image 二维码图片
	 * */
	public static BufferedImage encodeImg(String contents){
		BufferedImage image = null;
		try{
			BitMatrix matrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
			image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			int width = matrix.getWidth();
			int height = matrix.getHeight();
			for(int x = 0; x < width; x++){
				for(int y =0;y < height; y++){
					image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
				}
			}
		}catch(Exception e){
			System.out.println("生成二维码失败"+e.getMessage());
		}
		return image;
	}
	
	/**
	 * 二维码输出到文件
	 * 	@param contents 二维码内容
	 * @param format 图片格式
	 * @param file 输出文件
	 * */
	public static void writeToFile(String contents,String format,File file){
		BufferedImage image = encodeImg(contents);
		try {
			ImageIO.write(image, format, file);
		} catch (IOException e) {
			System.out.println("二维码写入文件失败"+e.getMessage());
		}
	}
	/**
	 * 二维码流式输出
	 * 	@param contents 二维码内容
	 * @param format 图片格式
	 * @param stream 输出流
	 * */
	public static void writeToStream(String contents,String format,OutputStream stream){
		BufferedImage image = encodeImg(contents);
		try {
			ImageIO.write(image, format, stream);
		} catch (IOException e) {
			System.out.println("二维码写入流失败"+e.getMessage());
		}
	}
}

2:测试代码:

package com.tsxs.test;

import java.io.File;

import org.junit.Test;

import com.tsxs.tools.twodimensioncode.DecodeImgZxing;
import com.tsxs.tools.twodimensioncode.EncodeImgZingLogo;
import com.tsxs.tools.twodimensioncode.EncodeImgZxing;

public class EncodeImgZingLogoTest {

	@Test
	public void testWriteToFile() {
		String contents = "http://blog.csdn.net/typa01_kk";
		String format = "jpeg"; //***此处如果格式为"gif",则logo图片为黑色,其他格式ok
		//生成二维码
		File logoImg = new File("D:"+File.separator+"logo.jpg");
		File img = new File("D:"+File.separator+"csdn.jpg");
		EncodeImgZxing.writeToFile(contents, format, img);
//		//添加logo图片
		File img1 = new File("D:"+File.separator+"csdnlogo.jpg");
		EncodeImgZingLogo.writeToFile(img, logoImg, format, img1);
		
		//解析二维码
		String content = DecodeImgZxing.decodeImg(img);
		System.out.println("1:"+content);
		//带logo
		String content1 = DecodeImgZxing.decodeImg(img1);
		System.out.println("2:"+content1);
	}

}

效果图为:img1:(H 1) img2(M 4) img3(color change ,无法扫描,红色改为黑色,可扫描,速度慢)

3:二维码绘制logo(二维码和logo图片合并绘制,图片尽量为方形,有利扫描和显示)

package com.tsxs.tools.twodimensioncode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.imageio.ImageIO;
/**
 * 通过google的zxing实现二维码(加入logo图片)
 * @author tskk
 * @version 2015-6-28 13:30:20
 * */
public final class EncodeImgZingLogo {
	/**
	 * 二维码绘制logo
	 * @param twodimensioncodeImg 二维码图片文件
	 * @param logoImg logo图片文件
	 * */
	public static BufferedImage encodeImgLogo(File twodimensioncodeImg,File logoImg){
		BufferedImage twodimensioncode = null;
		try{
			if(!twodimensioncodeImg.isFile() || !logoImg.isFile()){
				System.out.println("输入非图片");
				return null;
			}
			//读取二维码图片
			twodimensioncode = ImageIO.read(twodimensioncodeImg);
			//获取画笔
			Graphics2D g = twodimensioncode.createGraphics();
			//读取logo图片
			BufferedImage logo = ImageIO.read(logoImg);
			//设置二维码大小,太大,会覆盖二维码,此处20%
			int logoWidth = logo.getWidth(null) > twodimensioncode.getWidth()*2 /10 ? (twodimensioncode.getWidth()*2 /10) : logo.getWidth(null);
			int logoHeight = logo.getHeight(null) > twodimensioncode.getHeight()*2 /10 ? (twodimensioncode.getHeight()*2 /10) : logo.getHeight(null);
			//设置logo图片放置位置
			//中心
			int x = (twodimensioncode.getWidth() - logoWidth) / 2;
			int y = (twodimensioncode.getHeight() - logoHeight) / 2;
			//右下角,15为调整值
//			int x = twodimensioncode.getWidth()  - logoWidth-15;
//			int y = twodimensioncode.getHeight() - logoHeight-15;
			//开始合并绘制图片
			g.drawImage(logo, x, y, logoWidth, logoHeight, null);
			g.drawRoundRect(x, y, logoWidth, logoHeight, 15 ,15);
			//logo边框大小
			g.setStroke(new BasicStroke(2));
			//logo边框颜色
			g.setColor(Color.WHITE);
			g.drawRect(x, y, logoWidth, logoHeight);
			g.dispose();
			logo.flush();
			twodimensioncode.flush();
		}catch(Exception e){
			System.out.println("二维码绘制logo失败");
		}
		return twodimensioncode;
	}
	
	/**
	 * 二维码输出到文件
	 * @param twodimensioncodeImg 二维码图片文件
	 * @param logoImg logo图片文件
	 * @param format 图片格式
	 * @param file 输出文件
	 * */
	public static void writeToFile(File twodimensioncodeImg,File logoImg,String format,File file){
		BufferedImage image = encodeImgLogo(twodimensioncodeImg, logoImg);
		try {
			ImageIO.write(image, format, file);
		} catch (IOException e) {
			System.out.println("二维码写入文件失败"+e.getMessage());
		}
	}
	/**
	 * 二维码流式输出
	 * @param twodimensioncodeImg 二维码图片文件
	 * @param logoImg logo图片文件
	 * @param format 图片格式
	 * @param stream 输出流
	 * */
	public static void writeToStream(File twodimensioncodeImg,File logoImg,String format,OutputStream stream){
		BufferedImage image = encodeImgLogo(twodimensioncodeImg, logoImg);
		try {
			ImageIO.write(image, format, stream);
		} catch (IOException e) {
			System.out.println("二维码写入流失败"+e.getMessage());
		}
	}
}

使用上测试代码产生二维码为:

4:二维码内容解析:

package com.tsxs.tools.twodimensioncode;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.EnumMap;

import javax.imageio.ImageIO;

import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
/**
 * 通过google的zxing解析二维码
 * @author tskk
 * @version 2015-6-26 13:30:20
 * 注:此代码,不能解析:L纠错级别带logo和H级别的解析
 * */
public final class DecodeImgZxing {
	//二维码格式参数
	private static final EnumMap<DecodeHintType, Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
	static{
		hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
	}
	/**
	 * 解析二维码,使用google的zxing
	 * @param imgPath 二维码路径
	 * @return content 二维码内容
	 * */
	public static String decodeImg(File imgFile){
		String content = null;
		if(!imgFile.isFile()){
			System.out.println("输入非文件");
			return null;
		}
		try {
			BufferedImage image = ImageIO.read(imgFile);
			LuminanceSource source = new BufferedImageLuminanceSource(image);
			Binarizer binarizer = new HybridBinarizer(source);
			BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
			MultiFormatReader reader = new MultiFormatReader();
			Result result = reader.decode(binaryBitmap, hints);
			content = result.getText();
//			System.out.println("二维码结果:"+":"+result.toString()+","+result.getBarcodeFormat()+","+result.getText());
		} catch (NotFoundException e) {
			System.out.println("二维码解析NotFoundException");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("二维码解析IOException");
			e.printStackTrace();
		}
		return content;
	}
}

使用测试代码,测试结果:

1:http://blog.csdn.net/typa01_kk
2:http://blog.csdn.net/typa01_kk

目录
打赏
0
0
0
0
4
分享
相关文章
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
70 0
|
18天前
|
深入解析java正则表达式
本文深入解析Java正则表达式的应用,从基础概念到实际开发技巧全面展开。正则表达式是一种强大的文本处理工具,广泛应用于格式验证、搜索替换等场景。Java通过`Pattern`和`Matcher`类支持正则表达式,`Pattern.compile()`方法将正则字符串编译为高效模式对象。文章详细介绍了核心类的功能、常用正则语法及实际案例(如邮箱和电话号码验证)。掌握这些内容,可显著提升文本处理能力,满足多种开发需求。
49 1
重学Java基础篇—ThreadLocal深度解析与最佳实践
ThreadLocal 是一种实现线程隔离的机制,为每个线程创建独立变量副本,适用于数据库连接管理、用户会话信息存储等场景。
88 5
重学Java基础篇—类的生命周期深度解析
本文全面解析了Java类的生命周期,涵盖加载、验证、准备、解析、初始化、使用及卸载七个关键阶段。通过分阶段执行机制详解(如加载阶段的触发条件与技术实现),结合方法调用机制、内存回收保护等使用阶段特性,以及卸载条件和特殊场景处理,帮助开发者深入理解JVM运作原理。同时,文章探讨了性能优化建议、典型异常处理及新一代JVM特性(如元空间与模块化系统)。总结中强调安全优先、延迟加载与动态扩展的设计思想,并提供开发建议与进阶方向,助力解决性能调优、内存泄漏排查及框架设计等问题。
49 5
Java机器学习实战:基于DJL框架的手写数字识别全解析
在人工智能蓬勃发展的今天,Python凭借丰富的生态库(如TensorFlow、PyTorch)成为AI开发的首选语言。但Java作为企业级应用的基石,其在生产环境部署、性能优化和工程化方面的优势不容忽视。DJL(Deep Java Library)的出现完美填补了Java在深度学习领域的空白,它提供了一套统一的API,允许开发者无缝对接主流深度学习框架,将AI模型高效部署到Java生态中。本文将通过手写数字识别的完整流程,深入解析DJL框架的核心机制与应用实践。
94 3
|
18天前
|
Java Lambda 表达式:以 Foo 接口为例深入解析
本文深入解析了 Java 8 中 Lambda 表达式的用法及其背后的函数式接口原理,以 `Foo` 接口为例,展示了如何通过简洁的 Lambda 表达式替代传统匿名类实现。文章从 Lambda 基本语法、函数式接口定义到实际应用层层递进,并探讨默认方法与静态方法的扩展性,最后总结常见误区与关键点,助你高效优化代码!
39 0
|
1月前
|
重学Java基础篇—Java Object类常用方法深度解析
Java中,Object类作为所有类的超类,提供了多个核心方法以支持对象的基本行为。其中,`toString()`用于对象的字符串表示,重写时应包含关键信息;`equals()`与`hashCode()`需成对重写,确保对象等价判断的一致性;`getClass()`用于运行时类型识别;`clone()`实现对象复制,需区分浅拷贝与深拷贝;`wait()/notify()`支持线程协作。此外,`finalize()`已过时,建议使用更安全的资源管理方式。合理运用这些方法,并遵循最佳实践,可提升代码质量与健壮性。
58 1
|
1月前
|
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
90 5
深潜数据海洋:Java文件读写全面解析与实战指南
通过本文的详细解析与实战示例,您可以系统地掌握Java中各种文件读写操作,从基本的读写到高效的NIO操作,再到文件复制、移动和删除。希望这些内容能够帮助您在实际项目中处理文件数据,提高开发效率和代码质量。
66 4
Java中Log级别和解析
日志级别定义了日志信息的重要程度,从低到高依次为:TRACE(详细调试)、DEBUG(开发调试)、INFO(一般信息)、WARN(潜在问题)、ERROR(错误信息)和FATAL(严重错误)。开发人员可根据需要设置不同的日志级别,以控制日志输出量,避免影响性能或干扰问题排查。日志框架如Log4j 2由Logger、Appender和Layout组成,通过配置文件指定日志级别、输出目标和格式。

推荐镜像

更多
下一篇
oss创建bucket