文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android之 Zxing二维码详解

2023-09-22 08:35

关注

一 简介

1 ZXing

目前Android扫描二维码,条形码主要用google官方的工具Zxing,支持扫码,相册解码,生成带logo的二维码等功能 

Zxing github 示例地址:https://github.com/zxing/zxing

2 ZBar

由于zxing是基于java编写的,扫码速度和解析上可能没那么快,但大部分场合足够用。也有基于c/c++的库zbar,需要编译通过才能用,下面是官网,有兴趣的可以编译试试:

ZBar官网:http://zbar.sourceforge.net/
ZBar GitHub地址:https://github.com/ZBar/ZBar

3  华为ScanKit

目前体验最好的华为统一扫码SDK,基本可以做到秒扫和快速识别,支持多码识别和二维码生成。但该服务必须在华为开发者联盟平台注册应用,配置包名和服务json

https://gitee.com/hms-core/hms-scan-demo华为官方demo示例 gitee地址:https://gitee.com/hms-core/hms-scan-demo

二 Zxing使用

1 依赖远程zxing库

dependencies {  //zxing的core库  implementation "com.google.zxing:core:3.5.1"   //zxing  implementation "com.google.zxing:zxing-parent:3.5.1"  //zxing  implementation 'com.journeyapps:zxing-android-embedded:4.1.0'}

或直接使用下面库,目前识别比较快的Zxing库

implementation 'com.journeyapps:zxing-android-embedded:4.3.0'

2 添加权限

3 调用SDK的扫码页面并返回结果

private void goScan(){    Intent intent = new Intent(MainActivity.this, CaptureActivity.class);    startActivityForResult(intent, REQUEST_CODE_SCAN);}
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    super.onActivityResult(requestCode, resultCode, data);    // 扫描二维码/条码回传    if (requestCode == REQUEST_CODE_SCAN && resultCode == RESULT_OK) {        if (data != null) {            //返回的文本内容            String content = data.getStringExtra(DECODED_CONTENT_KEY);            //返回的BitMap图像            Bitmap bitmap = data.getParcelableExtra(DECODED_BITMAP_KEY);        }    }}

三 自定义扫码页面

1 效果图

e3936b2bcaef40839606b0b9af31702c.png

2 activity_scan.xml

                                                                                                                                                                                                                                                                                             

3 ScanActivity.java

public class ScanActivity extends BaseActivity {    private DecoratedBarcodeView decoratedBarcodeView;       @Override    protected int getLayoutId() {        return R.layout.activity_scan;    }    @Override    public void initData() {        decoratedBarcodeView = new DecoratedBarcodeView(this);        decoratedBarcodeView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));        decoratedBarcodeView.setStatusText("");        decoratedBarcodeView.getViewFinder().setVisibility(View.GONE);        decoratedBarcodeView.getCameraSettings().setAutoFocusEnabled(true);        mDataBinding.vScanLayout.removeAllViews();        mDataBinding.vScanLayout.addView(decoratedBarcodeView);        checkCameraPermission();           }    public final int REQUEST_CAMERA_PERMISSION = 1;    private String cameraPermission = Manifest.permission.CAMERA;    private void checkCameraPermission() {        //检查是否有相机权限        if (ContextCompat.checkSelfPermission(this, cameraPermission) != PackageManager.PERMISSION_GRANTED) {            //没权限,请求权限            ActivityCompat.requestPermissions(this, new String[]{cameraPermission},                    REQUEST_CAMERA_PERMISSION);        } else {            //有权限            scanLaunch();        }    }    //权限请求回调    @Override    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case REQUEST_CAMERA_PERMISSION:                if (grantResults != null && grantResults.length > 0                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    //用户同意权限                    scanLaunch();                } else {                    // 权限被用户拒绝了,可以提示用户,关闭界面等等。                    Toast.makeText(this, "拒绝权限,请去设置里面手动开启权限", Toast.LENGTH_SHORT).show();                }                break;        }    }        private void scanLaunch() {        Collection formats = Arrays.asList(BarcodeFormat.QR_CODE, BarcodeFormat.CODE_39);        decoratedBarcodeView.getBarcodeView().setDecoderFactory(new DefaultDecoderFactory(formats));        decoratedBarcodeView.initializeFromIntent(getIntent());        decoratedBarcodeView.decodeContinuous(callback);        startScanAnimal();    }    private BarcodeCallback callback = new BarcodeCallback() {        @Override        public void barcodeResult(BarcodeResult result) {            String originalValue = result.getText();            if (TextUtils.isEmpty(originalValue)) {                // Prevent duplicate scans                return;            }            toResult(originalValue);        }        @Override        public void possibleResultPoints(List resultPoints) {        }    };    private void toResult(String originalValue) {        Intent intent=new Intent(mContext,ScanResultActivity.class);        intent.putExtra("result",originalValue);        startActivity(intent);    }    @Override    protected void onResume() {        super.onResume();        decoratedBarcodeView.resume();    }    @Override    protected void onPause() {        super.onPause();        decoratedBarcodeView.pause();    }    @Override    protected void onDestroy() {        super.onDestroy();        if (animation != null) {            animation.cancel();        }    }    //扫码线动画    private Animation animation;    private void startScanAnimal() {        animation = new TranslateAnimation(0, 0, 0, StatuesBarUtils.getScreenWidth(this) - StatuesBarUtils.dp2px(this, 100));        animation.setDuration(2000);        animation.setRepeatCount(Animation.INFINITE);//动画的反复次数        animation.setFillAfter(true);//设置为true,动画转化结束后被应用        //animation.setRepeatMode(ObjectAnimator.RESTART);//重复模式        animation.setInterpolator(new LinearInterpolator());        mDataBinding.scanLine.startAnimation(animation);//開始动画    }}

四 相册选区图片解析二维码

1 选择相册图片

private void setPictureScanOperation() {        imgBtn = findViewById(R.id.img_btn);        imgBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {               Intent pickIntent = new Intent(Intent.ACTION_PICK,                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);                pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image    public static Bitmap getDecodeAbleBitmap(String picturePath) {        try {            BitmapFactory.Options options = new BitmapFactory.Options();            options.inJustDecodeBounds = true;            BitmapFactory.decodeFile(picturePath, options);            int sampleSize = options.outHeight / 400;            if (sampleSize <= 0) {                sampleSize = 1;            }            options.inSampleSize = sampleSize;            options.inJustDecodeBounds = false;            return BitmapFactory.decodeFile(picturePath, options);        } catch (Exception e) {            e.printStackTrace();            return null;        }    }

3  解析二维码图片

     public static String syncDecodeQRCode(Bitmap bitmap) {        Result result;        RGBLuminanceSource source = null;        try {            int width = bitmap.getWidth();            int height = bitmap.getHeight();            int[] pixels = new int[width * height];            bitmap.getPixels(pixels, 0, width, 0, 0, width, height);            source = new RGBLuminanceSource(width, height, pixels);            result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), new EnumMap<>(DecodeHintType.class));            return result.getText();        } catch (Exception e) {            e.printStackTrace();            if (source != null) {                try {                    result = new MultiFormatReader().decode(new BinaryBitmap(new GlobalHistogramBinarizer(source)), new EnumMap<>(DecodeHintType.class));                    return result.getText();                } catch (Throwable e2) {                    e2.printStackTrace();                }            }            return null;        }    }

五 生成二维码

1 支持修改边框颜色大小,二维码颜色大小,背景颜色,logo样式和圆角

2 activity_qrcode_style_xml

 5.3 核心生成二维码源码,QRCodeEncoder.java

public class QRCodeEncoder {    public static final Map HINTS = new EnumMap<>(EncodeHintType.class);    static {        HINTS.put(EncodeHintType.CHARACTER_SET, "utf-8");        HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);        HINTS.put(EncodeHintType.MARGIN, 0);    }    private QRCodeEncoder() {    }        public static Bitmap syncEncodeQRCode(String content, int size) {        return syncEncodeQRCode(content, size, Color.BLACK, Color.WHITE, null);    }        public static Bitmap syncEncodeQRCode(String content, int size, int foregroundColor) {        return syncEncodeQRCode(content, size, foregroundColor, Color.WHITE, null);    }        public static Bitmap syncEncodeQRCode(String content, int size, int foregroundColor, Bitmap logo) {        return syncEncodeQRCode(content, size, foregroundColor, Color.WHITE, logo);    }        public static Bitmap syncEncodeQRCode(String content, int size, int foregroundColor, int backgroundColor, Bitmap logo) {        try {            BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, HINTS);            int[] pixels = new int[size * size];            for (int y = 0; y < size; y++) {                for (int x = 0; x < size; x++) {                    if (matrix.get(x, y)) {                        pixels[y * size + x] = foregroundColor;                    } else {                        pixels[y * size + x] = backgroundColor;                    }                }            }            Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);            bitmap.setPixels(pixels, 0, size, 0, 0, size, size);            return addLogoToQRCode(bitmap, logo);        } catch (Exception e) {            e.printStackTrace();            return null;        }    }        public static Bitmap syncEncodeQRCode(String content, int size, int foregroundColor, int backgroundColor, Bitmap logo ,int border , int borderColor) {        int borderWidth= (int) dp2px(MyApp.getInstance(),4);        size-=borderWidth*2;        try {            BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, HINTS);            int[] pixels = new int[size * size];            for (int y = 0; y < size; y++) {                for (int x = 0; x < size; x++) {                    if (matrix.get(x, y)) {                        pixels[y * size + x] = foregroundColor;                    } else {                        pixels[y * size + x] = backgroundColor;                    }                }            }            Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);            bitmap.setPixels(pixels, 0, size, 0, 0, size, size);            if(bitmap!=null){                bitmap=addLogoToQRCode(bitmap, logo);            }            bitmap=addBorderToQRCode(bitmap,backgroundColor ,border,borderColor);            return bitmap;        } catch (Exception e) {            e.printStackTrace();            return null;        }    }        private static Bitmap addBorderToQRCode(Bitmap src, int backgroundColor, int border , int borderColor) {        if (src == null) {            return src;        }        if(borderColor==0){            borderColor=Color.parseColor("#63C99B");        }        int srcWidth = src.getWidth();        int srcHeight = src.getHeight();        int borderWidth= (int) dp2px(MyApp.getInstance(),4);        Bitmap bitmap = Bitmap.createBitmap(srcWidth+borderWidth, srcHeight+borderWidth, Bitmap.Config.ARGB_8888);        try {            Canvas canvas = new Canvas(bitmap);            canvas.drawColor(backgroundColor);            if(border!=0){                Paint paintRect = new Paint();                paintRect.setColor(borderColor);                paintRect.setStrokeWidth(borderWidth);                if(border==1){                    paintRect.setPathEffect(new DashPathEffect(new float[]{8, 8}, 0)); // 设置虚线样式                }                paintRect.setStyle(Paint.Style.STROKE);                canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paintRect);            }            canvas.drawBitmap(src, borderWidth/2f, borderWidth/2f, null);            canvas.save();            canvas.restore();        } catch (Exception e) {            e.printStackTrace();            bitmap = null;        }        return bitmap;    }        private static Bitmap addLogoToQRCode(Bitmap src, Bitmap logo) {        if (src == null || logo == null) {            return src;        }        int srcWidth = src.getWidth();        int srcHeight = src.getHeight();        int logoWidth = logo.getWidth();        int logoHeight = logo.getHeight();        float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;        Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);        try {            Canvas canvas = new Canvas(bitmap);            canvas.drawBitmap(src, 0, 0, null);            canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);            canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);            canvas.save();            canvas.restore();        } catch (Exception e) {            e.printStackTrace();            bitmap = null;        }        return bitmap;    }        public static Bitmap syncEncodeBarcode(String content, int width, int height, int textSize) {        if (TextUtils.isEmpty(content)) {            return null;        }        Map hints = new HashMap<>();        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);        hints.put(EncodeHintType.MARGIN, 0);        try {            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, width, height, hints);            int[] pixels = new int[width * height];            for (int y = 0; y < height; y++) {                for (int x = 0; x < width; x++) {                    if (bitMatrix.get(x, y)) {                        pixels[y * width + x] = 0xff000000;                    } else {                        pixels[y * width + x] = 0xffffffff;                    }                }            }            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);            if (textSize > 0) {                bitmap = showContent(bitmap, content, textSize);            }            return bitmap;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }        private static Bitmap showContent(Bitmap barcodeBitmap, String content, int textSize) {        if (TextUtils.isEmpty(content) || null == barcodeBitmap) {            return null;        }        Paint paint = new Paint();        paint.setColor(Color.BLACK);        paint.setAntiAlias(true);        paint.setStyle(Paint.Style.FILL);        paint.setTextSize(textSize);        paint.setTextAlign(Paint.Align.CENTER);        int textWidth = (int) paint.measureText(content);        Paint.FontMetrics fm = paint.getFontMetrics();        int textHeight = (int) (fm.bottom - fm.top);        float scaleRateX = barcodeBitmap.getWidth() * 1.0f / textWidth;        if (scaleRateX < 1) {            paint.setTextScaleX(scaleRateX);        }        int baseLine = barcodeBitmap.getHeight() + textHeight;        Bitmap bitmap = Bitmap.createBitmap(barcodeBitmap.getWidth(), barcodeBitmap.getHeight() + 2 * textHeight, Bitmap.Config.ARGB_4444);        Canvas canvas = new Canvas();        canvas.drawColor(Color.WHITE);        canvas.setBitmap(bitmap);        canvas.drawBitmap(barcodeBitmap, 0, 0, null);        canvas.drawText(content, barcodeBitmap.getWidth() / 2, baseLine, paint);        canvas.save();        canvas.restore();        return bitmap;    }    public static float dp2px(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return dpValue * scale + 0.5f;    }}

4 异步调用QRCodeEncoder生成二维码

 private void updateQrcode(){        new GenerateQrcodeTask().execute(content);    }    public class GenerateQrcodeTask extends AsyncTask {        @Override        protected Bitmap doInBackground(String... strings) {            Bitmap logoBitmap=null;            if(logo!=0){                logoBitmap = BitmapFactory.decodeResource(getResources(), logo);            }            int borderColor22=TextUtils.isEmpty(borderColor)?0:Color.parseColor(borderColor);            return QRCodeEncoder.syncEncodeQRCode(strings[0], (int) StatuesBarUtils.dp2px(mContext, 300f), Color.parseColor(qianColor),Color.parseColor(beinColor),logoBitmap, border , borderColor22);        }        @Override        protected void onPostExecute(Bitmap bitmap) {            super.onPostExecute(bitmap);            qrBitmap=bitmap;            if (bitmap != null) {                mDataBinding.vImage.setImageBitmap(qrBitmap);            } else {                Toast.makeText(mContext, "生成維碼失敗", Toast.LENGTH_SHORT).show();            }        }    }

5 保存二维码,FileUtil.java工具类

public class FileUtil {    public static String saveToImage(Bitmap bitmap) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {            return MediaStore.Images.Media.insertImage(MyApp.getInstance().getContentResolver(), bitmap, "", "");        } else {            try {                File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "qrcode");                if (!dir.exists()) {                    dir.mkdirs();                }                File picFile = new File(dir, System.currentTimeMillis() + ".png");                FileOutputStream fos = new FileOutputStream(picFile);                bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);                fos.flush();                fos.close();                return picFile.getAbsolutePath();            } catch (Exception e) {                e.printStackTrace();            }        }        return null;    }

 异步调用FileUtil,保存二维码

public class SaveBitmapTask extends AsyncTask {        @Override        protected String doInBackground(Bitmap... bitmaps) {            return FileUtil.saveToImage(bitmaps[0]);        }        @Override        protected void onPostExecute(String result) {            super.onPostExecute(result);            if (result != null) {                Intent intent = new Intent(mContext, QrBarcodeEditResultActivity.class);                intent.putExtra("filePath", result);                startActivity(intent);            } else {                Toast.makeText(mContext, "保存二維碼失敗", Toast.LENGTH_SHORT).show();            }        }    }

6 核心源码解析,我们知道bitmap是一个保存所有像素内容的容器,那二维码原理即是把内容解析到每一个像素里面。如下

  public static Bitmap syncEncodeQRCode(String content, int size, int foregroundColor, int backgroundColor, Bitmap logo ,int border , int borderColor) {int borderWidth= (int) dp2px(MyApp.getInstance(),4);size-=borderWidth*2;try {//内容解析到字节矩阵BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, HINTS);//设置宽高像素数组int[] pixels = new int[size * size];//遍历记录图片每个像素信息for (int y = 0; y < size; y++) {for (int x = 0; x < size; x++) {if (matrix.get(x, y)) {pixels[y * size + x] = foregroundColor;} else {pixels[y * size + x] = backgroundColor;}}}//创建bitmap,设置像素数组Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, size, 0, 0, size, size);if(bitmap!=null){bitmap=addLogoToQRCode(bitmap, logo);}//添加logobitmap=addBorderToQRCode(bitmap,backgroundColor ,border,borderColor);return bitmap;} catch (Exception e) {e.printStackTrace();return null;}}

 

来源地址:https://blog.csdn.net/qq_29848853/article/details/131057600

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯