关于汉信码的识别方法

如果你只是想识别汉信码,可以试试这两个:


最近接触到了汉信码这种二维码,于是想着做个小工具出来玩玩。汉信码的生成可以借助 zint 这个库来生成,但识别就有点费劲了,在网上找了一圈找也没找到任何相关信息。好在功夫不负有心人,最终另辟蹊径还是找到了解决办法。

汉信码识别Java版

  1. IDcode 里有安卓版sdk可识别汉信码,版本略老,是 armv5 的版本…

  2. 将sdk中的 libs/armeabi/libhxcode.so 复制出来,添加到自己项目中 jniLib 库中(注意 abiFilters 应配置为 armeabi),然后通过 jni 方式来调用。下面是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 代码仅供学习交流,请勿用于非法用途
// HxDecode.java
package com.hxcode;

import java.io.UnsupportedEncodingException;

public class HxDecode
{
static
{
System.loadLibrary("hxcode");
}

private static native int preprocessImg(byte[] grayImg, int width, int height, byte[] binaryData);
private static native int DeCodeCsbyte(byte[] binaryData, int length, byte[] decodebytes);

//主函数识别汉信码,接收图像的灰度像素数据,图像宽高
public static String decode(byte[] data, int width, int height) {
String rawResult = null;
byte[] binaryData = new byte[189 * 189];

//这一步 preprocessImg 处理图片,根据灰度图像生成01矩阵,返回的是汉信码的列宽
int iwidth = HxDecode.preprocessImg(data, width, height, binaryData);

//列宽介于 23 和 189 之间表示汉信码识别成功
if (iwidth >= 23 && iwidth <= 189) {
byte[] decodebytes = new byte[4 * 1024]; //汉信码最多容纳 3262 个字节的信息

// DeCodeCsbyte 读出矩阵中包含的字节信息,返回的是字节总长度
iwidth = HxDecode.DeCodeCsbyte(binaryData, iwidth, decodebytes);

//接下来是将字节信息转换为中文
if (iwidth > 0) {
try {
if (HxDecode.isUTF8(decodebytes, 0, iwidth)) {
rawResult = new String(decodebytes, 0, iwidth, "UTF-8");
} else {
rawResult = new String(decodebytes, 0, iwidth, "GBK");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return rawResult;
}

private static boolean isUTF8(byte[] data, int start, int end) {
boolean canBeUTF8 = true;
for (int i = start; i < end; i++) {
int value = data[i] & 0xFF;
if (value >= 0xC0 && value <= 0xDF) {//两字节情况
i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}
} else if (value >= 0xE0 && value <= 0xEF) { //三字节情况
i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}
} else if (value >= 0xF0 && value <= 0xF7) { //四字节情况
i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}
} else if (value >= 0xF8 && value <= 0xFB) { //五字节情况
i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}
} else if (value >= 0xFC && value <= 0xFD) { //六字节情况
i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}

i++;
value = data[i] & 0xFF;
if (value >= 0x80 && value <= 0xBF) {
} else {return false;}
}
}
return canBeUTF8;
}
}

Tips:借助 libhybris 可以在 ARM Linux 上调用安卓动态链接库,性能和可拓展性会更好。
可以参考下这篇文章:在ARM Linux上使用libhybris调用安卓动态链接库

汉信码识别网页版

由于很多时候需要在电脑上识别汉信码,所以这里提供了网页版。地址如下:


关于汉信码的识别方法
https://blog.itfox.net/posts/关于汉信码的识别方法.html
作者
blog.itfox.net
发布于
2023年2月3日
许可协议