安卓使用ZXing生成二维码

32

在进行 Android 编程时,我尝试生成 QR 码时遇到了一些问题。这是我按照的教程。当我点击生成按钮时,我调用了这个方法:

private void generateQR(){
    String qrInputText = "test";

    //Find screen size
    WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE);
    Display display = manager.getDefaultDisplay();
    Point point = new Point();
    display.getSize(point);
    int width = point.x;
    int height = point.y;
    int smallerDimension = width < height ? width : height;
    smallerDimension = smallerDimension * 3/4;

    //Encode with a QR Code image
    QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(
        qrInputText, 
        null, 
        Contents.Type.TEXT,  
        BarcodeFormat.QR_CODE.toString(), 
        smallerDimension
    );
    try {
        Bitmap bitmap = qrCodeEncoder.encodeAsBitmap();
        ImageView myImage = (ImageView) findViewById(R.id.ivImage);
        myImage.setImageBitmap(bitmap);
    } catch (WriterException e) {
        e.printStackTrace();
    }
}

对于QRCodeEncoder和Contents类,我遵循了教程中的方法。然而,当我点击生成时,出现了以下错误信息:

01-30 16:37:03.093: I/dalvikvm(1069): Could not find method com.google.zxing.BarcodeFormat.valueOf, referenced from method com.example.qrcodescan.QRCodeEncoder.encodeContents
01-30 16:37:03.093: W/dalvikvm(1069): VFY: unable to resolve static method 338: Lcom/google/zxing/BarcodeFormat;.valueOf (Ljava/lang/String;)Lcom/google/zxing/BarcodeFormat;
01-30 16:37:03.093: D/dalvikvm(1069): VFY: replacing opcode 0x71 at 0x0005
01-30 16:37:03.093: W/dalvikvm(1069): VFY: unable to resolve static field 287 (QR_CODE) in Lcom/google/zxing/BarcodeFormat;
01-30 16:37:03.093: D/dalvikvm(1069): VFY: replacing opcode 0x62 at 0x0011
01-30 16:37:03.093: W/dalvikvm(1069): VFY: unable to resolve static field 287 (QR_CODE) in Lcom/google/zxing/BarcodeFormat;
01-30 16:37:03.093: D/dalvikvm(1069): VFY: replacing opcode 0x62 at 0x0015
01-30 16:37:03.093: W/dalvikvm(1069): VFY: unable to resolve static field 294 (CHARACTER_SET) in Lcom/google/zxing/EncodeHintType;
01-30 16:37:03.093: D/dalvikvm(1069): VFY: replacing opcode 0x62 at 0x0018
01-30 16:37:03.093: E/dalvikvm(1069): Could not find class 'com.google.zxing.MultiFormatWriter', referenced from method com.example.qrcodescan.QRCodeEncoder.encodeAsBitmap
01-30 16:37:03.093: W/dalvikvm(1069): VFY: unable to resolve new-instance 150 (Lcom/google/zxing/MultiFormatWriter;) in Lcom/example/qrcodescan/QRCodeEncoder;
01-30 16:37:03.093: D/dalvikvm(1069): VFY: replacing opcode 0x22 at 0x001d
01-30 16:37:03.093: D/dalvikvm(1069): DexOpt: unable to opt direct call 0x0159 at 0x1f in Lcom/example/qrcodescan/QRCodeEncoder;.encodeAsBitmap
01-30 16:37:03.093: D/AndroidRuntime(1069): Shutting down VM
01-30 16:37:03.093: W/dalvikvm(1069): threadid=1: thread exiting with uncaught exception (group=0x40c341f8)
01-30 16:37:03.101: E/AndroidRuntime(1069): FATAL EXCEPTION: main
01-30 16:37:03.101: E/AndroidRuntime(1069): java.lang.NoClassDefFoundError: com.google.zxing.BarcodeFormat
01-30 16:37:03.101: E/AndroidRuntime(1069):     at com.example.qrcodescan.MainActivity.generateQR(MainActivity.java:95)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at com.example.qrcodescan.MainActivity.access$0(MainActivity.java:77)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at com.example.qrcodescan.MainActivity$2.onClick(MainActivity.java:54)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.view.View.performClick(View.java:3620)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.view.View$PerformClick.run(View.java:14292)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.os.Handler.handleCallback(Handler.java:605)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.os.Handler.dispatchMessage(Handler.java:92)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.os.Looper.loop(Looper.java:137)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at android.app.ActivityThread.main(ActivityThread.java:4512)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at java.lang.reflect.Method.invokeNative(Native Method)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at java.lang.reflect.Method.invoke(Method.java:511)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:982)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)
01-30 16:37:03.101: E/AndroidRuntime(1069):     at dalvik.system.NativeStart.main(Native Method)

我已经在libs文件夹下添加了core.jar。有什么想法吗?谢谢。


你是否在代码上运行了Proguard? - Flaxie
@Flaxie 没有,但为什么? - user2531590
你将jar包添加到构建路径里了吗? - G_V
如果在调试模式下可以正常工作,但是在gradle文件中设置了“minifyEnabled true”,则发布版本将被混淆并且类的名称将会改变。 - Flaxie
但是我找不到 build.gradle 文件。 - user2531590
显示剩余10条评论
5个回答

75

我已经更新了我的Github上的小型演示项目和下面的回答,以适应2022年:

screenshot

将ZXing库添加到您的app/build.gradle文件中:
implementation 'com.google.zxing:core:3.4.1'

然后在你的MainActivity.java中使用以下函数将字符串生成为QR码图片:

Bitmap encodeAsBitmap(String str) throws WriterException {
    QRCodeWriter writer = new QRCodeWriter();
    BitMatrix bitMatrix = writer.encode(str, BarcodeFormat.QR_CODE, 400, 400);

    int w = bitMatrix.getWidth();
    int h = bitMatrix.getHeight();
    int[] pixels = new int[w * h];
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            pixels[y * w + x] = bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE;
        }
    }

    Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
    return bitmap;
}

1
用于扫描:如果您检测到Amazon、Blackberry或Cyanogen设备上都缺少Google Play且未安装条形码扫描器应用程序,则可以手动将用户重定向到替代的“应用商店”。仅用于生成QR码:我不知道-请自行尝试并在此处报告。 - Alexander Farber
2
奇怪的是,正如您在我的屏幕截图中所看到的那样,我也使用了模拟器,但它从未询问过我关于Google Play的问题。 - Alexander Farber
1
警告无法长时间显示。它只在屏幕上出现了一瞬间,所以用户根本没有足够的时间来阅读它。我不得不截屏才能读到文本,因为它只在屏幕上停留了不到一秒钟。但是无论如何,它似乎可以在没有GooglePlayServices的情况下正常工作。 - Sakiboy
4
我们真的需要从BitMatrix中复制粘贴创建位图的代码吗?在zxing库中难道没有实用程序方法来完成这个吗? - ernazm
1
完美!有用的答案。 - Nininea
显示剩余4条评论

9
public static int white = 0xFFFFFFFF;
public static int black = 0xFF000000;
public final static int WIDTH = 500;


try
    {
        Bitmap bmp =  encodeAsBitmap("Life is a bitch");
        imgView.setImageBitmap(bmp);
    } catch (Exception e) {
        e.printStackTrace();
    }


Bitmap encodeAsBitmap(String str) throws WriterException {
    BitMatrix result;
    Bitmap bitmap=null;
    try
    {
        result = new MultiFormatWriter().encode(str,
                BarcodeFormat.QR_CODE, WIDTH, WIDTH, null);

        int w = result.getWidth();
        int h = result.getHeight();
        int[] pixels = new int[w * h];
        for (int y = 0; y < h; y++) {
            int offset = y * w;
            for (int x = 0; x < w; x++) {
                pixels[offset + x] = result.get(x, y) ? black:white;
            }
        }
        bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, 0, WIDTH, 0, 0, w, h);
    } catch (Exception iae) {
        iae.printStackTrace();
        return null;
    }
    return bitmap;
}

8

ZXing库可以在这里提供帮助。

源自:生成QRCode Android示例

添加依赖项

compile 'com.google.zxing:core:3.2.1'

这里是将字符串转换为QR图像的方法。
private Bitmap TextToImageEncode(String Value) throws WriterException {
        BitMatrix bitMatrix;
        try {
            bitMatrix = new MultiFormatWriter().encode(
                    Value,
                    BarcodeFormat.DATA_MATRIX.QR_CODE,
                    QRcodeWidth, QRcodeWidth, null
            );
 
        } catch (IllegalArgumentException Illegalargumentexception) {
 
            return null;
        }
        int bitMatrixWidth = bitMatrix.getWidth();
 
        int bitMatrixHeight = bitMatrix.getHeight();
 
        int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
 
        for (int y = 0; y < bitMatrixHeight; y++) {
            int offset = y * bitMatrixWidth;
 
            for (int x = 0; x < bitMatrixWidth; x++) {
 
                pixels[offset + x] = bitMatrix.get(x, y) ?
                        getResources().getColor(R.color.black):getResources().getColor(R.color.white);
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_4444);
 
        bitmap.setPixels(pixels, 0, 500, 0, 0, bitMatrixWidth, bitMatrixHeight);
        return bitmap;
    }

保存生成的二维码图片

 public String saveImage(Bitmap myBitmap) {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
        File wallpaperDirectory = new File(
                Environment.getExternalStorageDirectory() + IMAGE_DIRECTORY);
        // have the object build the directory structure, if needed.
 
        if (!wallpaperDirectory.exists()) {
            Log.d("dirrrrrr", "" + wallpaperDirectory.mkdirs());
            wallpaperDirectory.mkdirs();
        }
 
        try {
            File f = new File(wallpaperDirectory, Calendar.getInstance()
                    .getTimeInMillis() + ".jpg");
            f.createNewFile();   //give read write permission
            FileOutputStream fo = new FileOutputStream(f);
            fo.write(bytes.toByteArray());
            MediaScannerConnection.scanFile(this,
                    new String[]{f.getPath()},
                    new String[]{"image/jpeg"}, null);
            fo.close();
            Log.d("TAG", "File Saved::--->" + f.getAbsolutePath());
 
            return f.getAbsolutePath();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return "";
 
    }

这段代码运行非常缓慢:getResources().getColor(R.color.black):getResources().getColor(R.color.white); 需要替换为 - colorBlack:colorWhite,在 for 语句之外定义 colorBlackcolorWhite。同时,也许更快的方法是将所有位图填充为白色,并只放置黑色像素。 - w201

2

以下代码对我有效:

...
String QRcode = "...";
new generateQrcode(qrcodeImageview).execute(QRcode);
...
private class generateQrcode extends AsyncTask<String, Void, Bitmap> {
        public final static int WIDTH = 400;
        ImageView bmImage;

        public generateQrcode(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {
            String Value = urls[0];
            com.google.zxing.Writer writer = new QRCodeWriter();
            Bitmap bitmap = null;
            BitMatrix bitMatrix = null;
            try {
                bitMatrix = writer.encode(Value, com.google.zxing.BarcodeFormat.QR_CODE, WIDTH, WIDTH,
                        ImmutableMap.of(EncodeHintType.MARGIN, 1));
                bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
                for (int i = 0; i < 400; i++) {
                    for (int j = 0; j < 400; j++) {
                        bitmap.setPixel(i, j, bitMatrix.get(i, j) ? Color.BLACK
                                : Color.WHITE);
                    }
                }
            } catch (WriterException e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }

1
如果你能提供诸如“这段代码为什么有用?”和“它与OP的代码有何不同?”这样的信息,那么它将真正改善你的答案。这样可以传达关于解决方案本身的知识。基本上是教授钓鱼的技巧,而不是直接喂鱼 ;) - Mong Zhu
找不到ImmutableMap类。 - Shomu

0
使用这个会更容易。 添加依赖项:
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'

并轻松获取位图:

try {
       val qrCodeBitmap = BarcodeEncoder().encodeBitmap("your qr code data here", BarcodeFormat.QR_CODE, 400, 400)
} catch (e: Exception) {

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接