ZXing之生成条形码

一 前言

在前面学习了二维码的解码及生产,两篇文章总结如下:
  • ZXing之二维码解析图片资源
  • ZXing之生成二维码
接下来就让我们来看看条形码的生成方式。在正式开始之前先来了来了解一个东西,因为在绘制条形码的内容的时候会用到,那就是drawText绘制,小的时候我们都适用过四线格写过英语单词,其实android 系统在进行文本绘制的时候就是这种格式,其格式如下:
ZXing之生成条形码_第1张图片
Android 系统在绘制文本的时候需要找到一个轴,这个轴就是上面红色的线(基线),也就是四线格的第三条线,在它上下还有四条线分别是top、ascent、decent、bottom ,如下(图片源自于网络) :
ZXing之生成条形码_第2张图片
它们的意义分别是:
  • ascent: 系统建议的,绘制单个字符时,字符应当的最高高度所在线
  • descent:系统建议的,绘制单个字符时,字符应当的最低高度所在线
  • top: 可绘制的最高高度所在线
  • bottom: 可绘制的最低高度所在线
这个几个参数在Paint内部类FontMetrics中,好接下来进入主题。

二 条形码生成实现

条形码的生成步骤和二维码基本是相同的:
1 设置参数
//配置参数
Map hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 容错级别 这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
MultiFormatWriter writer = new MultiFormatWriter();
说明,在设置容错级别时最好设置为最好级别,编码格式设置为国际通用的"utf-8"。
2 把数据转换为Matrix
// 图像数据转换,使用了矩阵转换 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, widthPix, heightPix, hints);
3 根据上面生成的BitMatrix把像素点都为黑白色
            int[] pixels = new int[widthPix * heightPix];
//             下面这里按照二维码的算法,逐个生成二维码的图片,
            // 两个for循环是图片横列扫描的结果
            for (int y = 0; y < heightPix; y++) {
                for (int x = 0; x < widthPix; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * widthPix + x] = 0xff000000; // 黑色
                    } else {
                        pixels[y * widthPix + x] = 0xffffffff;// 白色
                    }
                }
            }
4 生成位图Bitmap(图片)
Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
5 如果允许接下来就是绘制文本
Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);//设置填充样式
        paint.setTextSize(20);
//        paint.setTextAlign(Paint.Align.CENTER);
        Paint.FontMetrics fm = paint.getFontMetrics();
        //测量字符串的宽度
        int textWidth = (int) paint.measureText(content);
        //绘制字符串矩形区域的高度
        int textHeight = (int) (fm.bottom - fm.top);
        // x 轴的缩放比率
        float scaleRateX = bCBitmap.getWidth() / textWidth;
        paint.setTextScaleX(scaleRateX);
        //绘制文本的基线
        int baseLine = bCBitmap.getHeight() + textHeight;
        //创建一个图层,然后在这个图层上绘制bCBitmap、content
        Bitmap  bitmap = Bitmap.createBitmap(bCBitmap.getWidth(),bCBitmap.getHeight() + 2 * textHeight,Bitmap.Config.ARGB_4444);
        Canvas canvas = new Canvas();
        canvas.drawColor(Color.WHITE);
        canvas.setBitmap(bitmap);
        canvas.drawBitmap(bCBitmap, 0, 0, null);
        canvas.drawText(content,0,baseLine,paint);
        canvas.save(Canvas.ALL_SAVE_FLAG);
        canvas.restore();
说明,这部分感觉还是比较难,下面就是详细分析下,在得到条形码的Bitmap(即bCBitmap)后,接下来就是把文本和条形码绘制到一起,绘制过程我们可以分为两部分,第一先绘制条形码的Bitmap,第二绘制文本,绘制条形码的Bitmap很简单,在这之前首先要创建一个新的图层,这个图层的宽度就是条形码图形的宽度,通过bCBitmap.getWidth()获取,那么高度呢,首先要有条形码图形的高度,即通过bCBitmap.getHeight()来获取,再加上文本绘制区域的高度,其值可以通过上面所述bottom线 - top线得到,如下:
Paint.FontMetrics fm = paint.getFontMetrics();
//绘制字符串矩形区域的高度
int textHeight = (int) (fm.bottom - fm.top);
那么创建新的图层代码如下 :
//创建一个图层,然后在这个图层上绘制bCBitmap、content
Bitmap bitmap = Bitmap.createBitmap(bCBitmap.getWidth(),bCBitmap.getHeight() +
2 * textHeight,Bitmap.Config.ARGB_4444);
说明下,为了不使文本与条形码图像间距过于紧密,我加上了2倍文本绘制区域的高度。
         如果仅仅这样处理的话,会发现绘制的文本左对齐,右边空了一截没有内容,看起来很不爽,我们知道Paint有个方法setTextScaleX可以
使用文本在x坐标上缩放,那么缩放多少呢?我们可以先测量文本在绘制区域所需的宽度,实现代码如下:
//测量字符串的宽度
int textWidth = (int) paint.measureText(content);
而,条形码图形的宽度,可以通过bCBitmap.getWidth()获取,条形码图形的宽度/文本在绘制区域所需的宽度就是文本在x坐标上缩放比,实现代码如下:
// x 轴的缩放比率
float scaleRateX = bCBitmap.getWidth() / textWidth;
这样以来就比刚刚的图像好看多了。
效果图如下:
ZXing之生成条形码_第3张图片
    /**
     * 绘制条形码
     * @param content 要生成条形码包含的内容
     * @param widthPix 条形码的宽度
     * @param heightPix 条形码的高度
     * @param isShowContent  否则显示条形码包含的内容
     * @return 返回生成条形的位图
     */
    public static Bitmap createBarcode( String content, int widthPix, int heightPix, boolean isShowContent) {
        if (TextUtils.isEmpty(content)){
            return null;
        }
        //配置参数
        Map hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 容错级别 这里选择最高H级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        MultiFormatWriter writer = new MultiFormatWriter();

        try {
            // 图像数据转换,使用了矩阵转换 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
            BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, widthPix, heightPix, hints);
            int[] pixels = new int[widthPix * heightPix];
//             下面这里按照二维码的算法,逐个生成二维码的图片,
            // 两个for循环是图片横列扫描的结果
            for (int y = 0; y < heightPix; y++) {
                for (int x = 0; x < widthPix; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * widthPix + x] = 0xff000000; // 黑色
                    } else {
                        pixels[y * widthPix + x] = 0xffffffff;// 白色
                    }
                }
            }
            Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
            if (isShowContent){
                bitmap = showContent(bitmap,content);
            }
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 显示条形的内容
     * @param bCBitmap 已生成的条形码的位图
     * @param content  条形码包含的内容
     * @return 返回生成的新位图,它是 方法{@link #createQRCode(String, int, int, Bitmap)}返回的位图与新绘制文本content的组合
     */
    private static Bitmap showContent(Bitmap bCBitmap , String content){
        if (TextUtils.isEmpty(content) || null == bCBitmap){
            return null;
        }
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);//设置填充样式
        paint.setTextSize(20);
//        paint.setTextAlign(Paint.Align.CENTER);
        //测量字符串的宽度
        int textWidth = (int) paint.measureText(content);
        Paint.FontMetrics fm = paint.getFontMetrics();
        //绘制字符串矩形区域的高度
        int textHeight = (int) (fm.bottom - fm.top);
        // x 轴的缩放比率
        float scaleRateX = bCBitmap.getWidth() / textWidth;
        paint.setTextScaleX(scaleRateX);
        //绘制文本的基线
        int baseLine = bCBitmap.getHeight() + textHeight;
        //创建一个图层,然后在这个图层上绘制bCBitmap、content
        Bitmap  bitmap = Bitmap.createBitmap(bCBitmap.getWidth(),bCBitmap.getHeight() + 2 * textHeight,Bitmap.Config.ARGB_4444);
        Canvas canvas = new Canvas();
        canvas.drawColor(Color.WHITE);
        canvas.setBitmap(bitmap);
        canvas.drawBitmap(bCBitmap, 0, 0, null);
        canvas.drawText(content,bCBitmap.getWidth() / 10,baseLine,paint);
        canvas.save(Canvas.ALL_SAVE_FLAG);
        canvas.restore();
        return bitmap;
    }
完整的代码工具类
参考
1 《 Paint测量绘制文本
http://blog.csdn.net/zhoumushui/article/details/51008264

你可能感兴趣的:(二维码/条形码)