老规矩,先上效果图:
说到二维码,对于开发人员来说那这张图片就在熟悉不过了
什么?不熟悉?那好吧,我来讲一下吧…(了解二维码原理的大佬请略过…)
基础知识
首先,我们先说一下二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)*4 + 21(V是版本号) 最高Version 40,(40-1)*4+21 = 177,所以最高是177 x 177 的正方形。
那么,二维码上面那些图案又代表什么呢?
请接着看~(标黄的地方大家自己对应上图看)
定位图案
- Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。
- Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。
Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。
功能性数据
- Format Information存在于所有的尺寸中,用于存放一些格式化数据的。
- Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。
数据码和纠错码
除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。
关于数据编码我这里就不讲了,一个字,麻烦,我们还是来说说怎么写出好看的二维码吧~结果请看下回分晓…哈哈,言归正传,代码还有30秒到达战场!
画二维码图
Position Detection Pattern
首先,先把Position Detection图案画在三个角上。(无论Version如何,这个图案的尺寸就是这么大)
Alignment Pattern
然后,再把Alignment图案画上(无论Version如何,这个图案的尺寸就是这么大)
Timing Pattern
接下来是Timing Pattern的线(这个不用多说了)
Format Information
再接下来是Formation Information,下图中的蓝色部分。
Format Information是一个15个bits的信息,每一个bit的位置如下图所示:(注意图中的Dark Module,那是永远出现的)
最后就是错误码和掩码了,这个比较简单,就不说了。
好了,说了这么多,那么show your code,不对,是my code…
public class QRCodeUtil {
private static final byte BYTE_EPT = 0;
private static final byte BYTE_DTA = 1;
private static final byte BYTE_POS = 2;
private static final byte BYTE_AGN = 3;
private static final byte BYTE_TMG = 4;
private static final byte BYTE_PTC = 5;
private static final float DEFAULT_DTA_DOT_SCALE = 0.3F;
private static final float DEFAULT_LOGO_SCALE = 0.2F;
private static final int DEFAULT_SIZE = 800;
private static final int DEFAULT_MARGIN = 20;
private static final int DEFAULT_LOGO_MARGIN = 10;
private static final int DEFAULT_LOGO_RADIUS = 8;
private static final int DEFAULT_BINARIZING_THRESHOLD = 128;
private float mAgnX;
private float mAgnY;
private float mPosX;
private float mPosY;
private Bitmap create(String contents, int size, int margin, float dataDotScale, int colorDark, int colorLight, int startColor, int endColor, Bitmap backgroundImage, boolean whiteMargin, boolean autoColor, boolean binarize, int binarizeThreshold, boolean roundedDataDots, Bitmap logoImage, int logoMargin, int logoCornerRadius, float logoScale) throws IllegalArgumentException {
if (contents == null) {
throw (new IllegalArgumentException("Error: contents is empty. (contents.isEmpty())"));
} else {
CharSequence var17 = (CharSequence) contents;
if (var17.length() == 0) {
throw (new IllegalArgumentException("Error: contents is empty. (contents.isEmpty())"));
} else if (size < 0) {
throw (new IllegalArgumentException("Error: a negative size is given. (size < 0)"));
} else if (margin < 0) {
throw (new IllegalArgumentException("Error: a negative margin is given. (margin < 0)"));
} else if (size - 2 * margin <= 0) {
throw (new IllegalArgumentException("Error: there is no space left for the QRCode. (size - 2 * margin <= 0)"));
} else {
ByteMatrix byteMatrix = this.getBitMatrix(contents);
int var10000 = size - 2 * margin;
if (var10000 < byteMatrix.getWidth()) {
throw (new IllegalArgumentException("Error: there is no space left for the QRCode. (size - 2 * margin < " + byteMatrix.getWidth() + ")"));
} else if (dataDotScale >= (float) 0 && dataDotScale <= (float) 1) {
return this.render(byteMatrix, size - 2 * margin, margin, dataDotScale, colorDark, colorLight, startColor, endColor, backgroundImage, whiteMargin, autoColor, binarize, binarizeThreshold, roundedDataDots, logoImage, logoMargin, logoCornerRadius, logoScale);
} else {
throw (new IllegalArgumentException("Error: an illegal data dot scale is given. (dataDotScale < 0 || dataDotScale > 1)"));
}
}
}
}
private final Bitmap render(ByteMatrix byteMatrix, int innerRenderedSize, int margin, float dataDotScale, int colorDark, int colorLight, int startColor, int endColor, Bitmap backgroundImage, boolean whiteMargin, boolean autoColor, boolean binarize, int binarizeThreshold, boolean roundedDataDots, Bitmap logoImage, int logoMargin, int logoCornerRadius, float logoScale) {
int nCount = byteMatrix.getWidth();
float nWidth = (float) innerRenderedSize / (float) nCount;
float nHeight = (float) innerRenderedSize / (float) nCount;
Bitmap backgroundImageScaled = Bitmap.createBitmap(innerRenderedSize + (whiteMargin ? 0 : margin * 2), innerRenderedSize + (whiteMargin ? 0 : margin * 2), Config.ARGB_8888);
if (backgroundImage != null) {
this.scaleBi