问题:
目录
近期有网友做了一个系统,实现文档的拍照扫描,打印的文档上面有一个条码,但通过拍照设备拍照上传后发现无法识读其中的条码,网友也使用了zxing进行后台扫码,也自己用zxing制作了一个android的扫描程序,可正常扫码,经过沟通,取得设备扫描图如下图所示:
分析定位:
虽然知道zxing是扫码工具,但不常用,所以也是无法直接下手,包在哪里都不知道,只好请求度娘和古哥,一通操作下来,发现在线生成的code没有问题,可以扫描识读
但这个扫描的文档就是不行,但手机可以扫。
于是只取其中一部分(Windows的画图工具,将其他部分删除,只留下下面部分),还是无法识读:
放大(直接用画图工具,将图片放大)了之后再试,可以了:
得出结论:图片放大就可以了,告诉网友解决方案,图片放大就可以了
验证结论:经过放大确实解决了(具体过程为详细沟通)
反转:
虽然好像解决了,但经过测试,发现无法识读到准确的条码,因为图片上还有一个二维码,整个图片放大后,总是识读到这个二维码,但这个不是需要的。
修正:
条码定点扫描,那么位置应该也是相对固定的,我们应该将条码抠出来再识读,于是固定识别区域,并将其固定放大2倍,测试后可以准确识读。
再反转完善
既然可以指定区域识读条码,那么做个通用的,先固定区域抠图,再识读,但因为放大多少才能扫描到不清楚,那么就多做几次循环,就3次,相应的从1-3倍数进行图片放大。
修好后发现竟然不需要放大就可以准确识读了。。。。。。。。。
解决实现
入口类 app.java
package qrcodescanner;
public class app {
/**
* 主程序入口
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
BarcodeDecoder decoder = new BarcodeDecoder();
String s = decoder.decode("D:\\1.jpg", 304, 192, 580, 319);
System.out.println("S=" + s);
}
}
功能类BarcodeDecoder.java
package qrcodescanner;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Hashtable;
import javax.imageio.ImageIO;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import net.coobird.thumbnailator.Thumbnails;
/**
* @author Zhengjie
* 条码解码
*/
public class BarcodeDecoder {
/**
* zxing 解码条码
* @param file 文件名
* @return
*/
public String decode(File file) throws Exception {
BufferedImage image;
image = ImageIO.read(file);
if (image == null) {
return null;
}
return decode(image);
}
/**
* zxing 解码条码
* @param image
* @return
*/
public String decode(BufferedImage image) throws Exception {
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result;
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
result = new MultiFormatReader().decode(bitmap, hints);
String resultStr = result.getText();
return resultStr;
}
/**
* 解码barcode
* @param f 文件名
* @param left 左上角坐标 x
* @param top 左上角坐标 y
* @param right 右下角坐标x
* @param bottom 右下角坐标 y
* @return
* @throws Exception
*/
public String decode(String f, int left, int top, int right, int bottom) throws Exception {
BufferedImage imgIn = ImageIO.read(new File(f));
BufferedImage imgOut = new BufferedImage(right - left, bottom - top, imgIn.getType());
Graphics2D gr = imgOut.createGraphics();
gr.drawImage(imgIn, 0, 0, right - left, bottom - top, left, top , right, bottom, null);
String sBarcode = "";
int iRetry = 1;
while (true) {
try {
// 条码输出文件名
String sOutFile = f + ".barcode." + iRetry + ".jpg";
// 放大每次加1倍
Thumbnails.of(imgOut).size((right - left) * iRetry, (bottom - top) * iRetry).toFile(sOutFile);
sBarcode = decode(new File(sOutFile));
System.out.println("解码" + iRetry + "次成功:" + sBarcode);
break;
} catch (Exception e) {
System.out.println("解码" + iRetry + "次出错:" + e.toString());
} finally {
if (iRetry ++ > 3) break;
}
}
return sBarcode;
}
}
maven pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.diri</groupId>
<artifactId>qrcodescanner</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
</dependencies>
</project>
总结与反思
初步以为是图片压缩了,导致分辨率的问题,后来发现其实不是,而是没找到准确的位置,为什么Android的识读没问题,就是手机扫码时,是对着条码扫的,但为定位抠图的图片,是整个图片扫的,处理的过程完全不同,但一开始却想当然的以为相同。