Home Java javaTutorial Android implements QR code generation based on google Zxing

Android implements QR code generation based on google Zxing

Jan 07, 2017 am 10:42 AM

The recent project has used the generation and recognition of QR codes. I have not been exposed to this before. Then I searched online and found that there are many resources in this area, especially the encapsulation of QR codes by Google Zxing, which has been implemented. Not bad, you can quote it directly. After downloading their source code, I only made a few changes, that is, adding the function of long press recognition to the demo. Although there are demos of long press recognition on the Internet, many of them cannot be downloaded. Run it, then summarize it and add it to the demo below.
Let’s introduce the main class of this Demo

public class BarCodeTestActivity extends Activity { 
   
private TextView resultTextView; 
private EditText qrStrEditText; 
private ImageView qrImgImageView; 
private String time; 
 private File file = null; 
 @Override
 public void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.main);   
  resultTextView = (TextView) this.findViewById(R.id.tv_scan_result); 
  qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string); 
  qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image); 
    
  Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode); 
  scanBarCodeButton.setOnClickListener(new OnClickListener() { 
  
@Override
public void onClick(View v) { 
//打开扫描界面扫描条形码或二维码 
Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class); 
startActivityForResult(openCameraIntent, 0); 
} 
}); 
qrImgImageView.setOnLongClickListener(new OnLongClickListener() { 
  
@Override
public boolean onLongClick(View v) { 
// 长按识别二维码 
  
 saveCurrentImage(); 
return true; 
} 
});   
  Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode); 
  generateQRCodeButton.setOnClickListener(new OnClickListener() { 
  
@Override
public void onClick(View v) { 
try { 
String contentString = qrStrEditText.getText().toString(); 
if (!contentString.equals("")) { 
//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350) 
Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350); 
qrImgImageView.setImageBitmap(qrCodeBitmap); 
}else { 
//提示文本不能是空的 
Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show(); 
} 
  
} catch (WriterException e) { 
// TODO Auto-generated catch block 
e.printStackTrace(); 
} 
} 
}); 
 } 
  
 //这种方法状态栏是空白,显示不了状态栏的信息 
 private void saveCurrentImage() 
 { 
  //获取当前屏幕的大小 
  int width = getWindow().getDecorView().getRootView().getWidth(); 
  int height = getWindow().getDecorView().getRootView().getHeight(); 
  //生成相同大小的图片 
  Bitmap temBitmap = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 ); 
  //找到当前页面的根布局 
  View view = getWindow().getDecorView().getRootView(); 
  //设置缓存 
  view.setDrawingCacheEnabled(true); 
  view.buildDrawingCache(); 
  //从缓存中获取当前屏幕的图片,创建一个DrawingCache的拷贝,因为DrawingCache得到的位图在禁用后会被回收 
  temBitmap = view.getDrawingCache(); 
  SimpleDateFormat df = new SimpleDateFormat("yyyymmddhhmmss"); 
  time = df.format(new Date()); 
  if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ 
   file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/screen",time + ".png"); 
   if(!file.exists()){ 
    file.getParentFile().mkdirs(); 
    try { 
     file.createNewFile(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
   } 
   FileOutputStream fos = null; 
   try { 
    fos = new FileOutputStream(file); 
    temBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); 
    fos.flush(); 
    fos.close(); 
   } catch (FileNotFoundException e) { 
    e.printStackTrace(); 
   } catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
   } 
   new Thread(new Runnable() { 
    @Override
    public void run() { 
     String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/screen/" + time + ".png"; 
     final Result result = parseQRcodeBitmap(path); 
     runOnUiThread(new Runnable() { 
      public void run() { 
      if(null!=result){ 
      resultTextView.setText(result.toString()); 
      }else{ 
       Toast.makeText(BarCodeTestActivity.this, "无法识别", Toast.LENGTH_LONG).show(); 
      } 
      } 
     }); 
    } 
   }).start(); 
   //禁用DrawingCahce否则会影响性能 ,而且不禁止会导致每次截图到保存的是缓存的位图 
   view.setDrawingCacheEnabled(false); 
  } 
 } 
   
 //解析二维码图片,返回结果封装在Result对象中 
 private com.google.zxing.Result parseQRcodeBitmap(String bitmapPath){ 
  //解析转换类型UTF-8 
  Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>(); 
  hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); 
  //获取到待解析的图片 
  BitmapFactory.Options options = new BitmapFactory.Options();  
  //如果我们把inJustDecodeBounds设为true,那么BitmapFactory.decodeFile(String path, Options opt) 
  //并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你 
  options.inJustDecodeBounds = true; 
  //此时的bitmap是null,这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了 
  Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options); 
  //我们现在想取出来的图片的边长(二维码图片是正方形的)设置为400像素 
  /** 
   options.outHeight = 400; 
   options.outWidth = 400; 
   options.inJustDecodeBounds = false; 
   bitmap = BitmapFactory.decodeFile(bitmapPath, options); 
  */
  //以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性 
  options.inSampleSize = options.outHeight / 400; 
  if(options.inSampleSize <= 0){ 
   options.inSampleSize = 1; //防止其值小于或等于0 
  } 
  /** 
   * 辅助节约内存设置 
   * 
   * options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默认是Bitmap.Config.ARGB_8888 
   * options.inPurgeable = true; 
   * options.inInputShareable = true; 
   */
  options.inJustDecodeBounds = false; 
  bitmap = BitmapFactory.decodeFile(bitmapPath, options);  
  //新建一个RGBLuminanceSource对象,将bitmap图片传给此对象 
  RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap); 
  //将图片转换成二进制图片 
  BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource)); 
  //初始化解析对象 
  QRCodeReader reader = new QRCodeReader(); 
  //开始解析 
  Result result = null; 
  try { 
   result = reader.decode(binaryBitmap, hints); 
  } catch (Exception e) { 
   // TODO: handle exception 
  } 
    
  return result; 
 } 
  
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
super.onActivityResult(requestCode, resultCode, data); 
//处理扫描结果(在界面上显示) 
if (resultCode == RESULT_OK) { 
Bundle bundle = data.getExtras(); 
String scanResult = bundle.getString("result"); 
resultTextView.setText(scanResult); 
} 
} 
}
Copy after login

Then press and hold to recognize the QR code and call the RGBLuminanceSource class

public class RGBLuminanceSource extends LuminanceSource { 
private byte bitmapPixels[]; 
  
protected RGBLuminanceSource(Bitmap bitmap) { 
super(bitmap.getWidth(), bitmap.getHeight()); 
  
// 首先,要取得该图片的像素数组内容 
int[] data = new int[bitmap.getWidth() * bitmap.getHeight()]; 
this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()]; 
bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight()); 
  
// 将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容 
for (int i = 0; i < data.length; i++) { 
this.bitmapPixels[i] = (byte) data[i]; 
} 
} 
  
@Override
public byte[] getMatrix() { 
// 返回我们生成好的像素数据 
return bitmapPixels; 
} 
  
  
@Override
public byte[] getRow(int y, byte[] row) { 
// 这里要得到指定行的像素数据 
System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth()); 
return row; 
} 
}
Copy after login

The camera recognizes the QR code and calls the CaptureActivity class

public class CaptureActivity extends Activity implements Callback { 
  
private CaptureActivityHandler handler; 
private ViewfinderView viewfinderView; 
private boolean hasSurface; 
private Vector<BarcodeFormat> decodeFormats; 
private String characterSet; 
private InactivityTimer inactivityTimer; 
private MediaPlayer mediaPlayer; 
private boolean playBeep; 
private static final float BEEP_VOLUME = 0.10f; 
private boolean vibrate; 
private Button cancelScanButton; 
  
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.camera); 
  
CameraManager.init(getApplication()); 
viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); 
cancelScanButton = (Button) this.findViewById(R.id.btn_cancel_scan); 
hasSurface = false; 
inactivityTimer = new InactivityTimer(this); 
} 
  
@Override
protected void onResume() { 
super.onResume(); 
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); 
SurfaceHolder surfaceHolder = surfaceView.getHolder(); 
if (hasSurface) { 
initCamera(surfaceHolder); 
} else { 
surfaceHolder.addCallback(this); 
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 
decodeFormats = null; 
characterSet = null; 
  
  
playBeep = true; 
AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE); 
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { 
playBeep = false; 
} 
initBeepSound(); 
vibrate = true; 
  
//quit the scan view 
cancelScanButton.setOnClickListener(new OnClickListener() { 
  
@Override
public void onClick(View v) { 
CaptureActivity.this.finish(); 
} 
}); 
} 
  
@Override
protected void onPause() { 
super.onPause(); 
if (handler != null) { 
handler.quitSynchronously(); 
handler = null; 
} 
CameraManager.get().closeDriver(); 
} 
  
@Override
protected void onDestroy() { 
inactivityTimer.shutdown(); 
super.onDestroy(); 
} 
  
/** 
* Handler scan result 
* @param result 
* @param barcode 
*/
public void handleDecode(Result result, Bitmap barcode) { 
inactivityTimer.onActivity(); 
playBeepSoundAndVibrate(); 
String resultString = result.getText(); 
//FIXME 
if (resultString.equals("")) { 
//扫描失败 
Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show(); 
}else { 
// System.out.println("Result:"+resultString); 
Intent resultIntent = new Intent(); 
Bundle bundle = new Bundle(); 
bundle.putString("result", resultString); 
resultIntent.putExtras(bundle); 
this.setResult(RESULT_OK, resultIntent); 
} 
CaptureActivity.this.finish(); 
} 
  
private void initCamera(SurfaceHolder surfaceHolder) { 
try { 
CameraManager.get().openDriver(surfaceHolder); 
} catch (IOException ioe) { 
return; 
} catch (RuntimeException e) { 
return; 
} 
if (handler == null) { 
handler = new CaptureActivityHandler(this, decodeFormats, 
characterSet); 
} 
} 
  
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, 
int height) { 
  
} 
  
@Override
public void surfaceCreated(SurfaceHolder holder) { 
if (!hasSurface) { 
hasSurface = true; 
initCamera(holder); 
} 
  
} 
  
@Override
public void surfaceDestroyed(SurfaceHolder holder) { 
hasSurface = false; 
} 
public ViewfinderView getViewfinderView() { 
return viewfinderView; 
}  
public Handler getHandler() { 
return handler; 
}  
public void drawViewfinder() { 
viewfinderView.drawViewfinder(); 
} 
private void initBeepSound() { 
if (playBeep && mediaPlayer == null) { 
// The volume on STREAM_SYSTEM is not adjustable, and users found it 
// too loud, 
// so we now play on the music stream. 
setVolumeControlStream(AudioManager.STREAM_MUSIC); 
mediaPlayer = new MediaPlayer(); 
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mediaPlayer.setOnCompletionListener(beepListener); 
  
AssetFileDescriptor file = getResources().openRawResourceFd( 
R.raw.beep); 
try { 
mediaPlayer.setDataSource(file.getFileDescriptor(), 
file.getStartOffset(), file.getLength()); 
file.close(); 
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); 
mediaPlayer.prepare(); 
} catch (IOException e) { 
mediaPlayer = null; 
} 
} 
} 
  
private static final long VIBRATE_DURATION = 200L;  
private void playBeepSoundAndVibrate() { 
if (playBeep && mediaPlayer != null) { 
mediaPlayer.start(); 
} 
if (vibrate) { 
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); 
vibrator.vibrate(VIBRATE_DURATION); 
} 
} 
  
/** 
* When the beep has finished playing, rewind to queue up another one. 
*/
private final OnCompletionListener beepListener = new OnCompletionListener() { 
public void onCompletion(MediaPlayer mediaPlayer) { 
mediaPlayer.seekTo(0); 
} 
}; 
  
  
}
Copy after login

The following is the main layout mian file

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@android:color/white"
 android:orientation="vertical" > 
  
  
 <Button
  android:id="@+id/btn_scan_barcode"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_marginTop="30dp"
  android:text="Open camera" /> 
   
 <LinearLayout
  android:orientation="horizontal"
  android:layout_marginTop="10dp"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"> 
    
  <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textColor="@android:color/black"
  android:textSize="18sp"
  android:text="Scan result:" /> 
    
  <TextView
  android:id="@+id/tv_scan_result"
  android:layout_width="fill_parent"
  android:textSize="18sp"
  android:textColor="@android:color/black"
  android:layout_height="wrap_content" /> 
 </LinearLayout> 
   
 <EditText
  android:id="@+id/et_qr_string"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_marginTop="30dp"
  android:hint="Input the text"/> 
   
 <Button
  android:id="@+id/btn_add_qrcode"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="Generate QRcode" /> 
   
 <ImageView
  android:id="@+id/iv_qr_image"
  android:layout_width="250dp"
  android:layout_height="250dp"
  android:scaleType="fitXY"
  android:layout_marginTop="10dp"
  android:layout_gravity="center"/> 
  
  
</LinearLayout>
Copy after login

For detailed information, please download the demo and see for yourself. The demo solves the problem of the QR code being stretched during vertical decoding.

However, I encountered a problem. After the scanning frame of the QR code is enlarged, the scanning sensitivity is reduced. I hope friends who know can give me some guidance.

The above is the entire content of this article. I hope It will be helpful to everyone's learning, and I hope everyone will support the PHP Chinese website.

For more Android-based QR code generation based on google Zxing, please pay attention to the PHP Chinese website!


Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to restrict access to specific interfaces of nested H5 pages through OAuth2.0's scope mechanism? How to restrict access to specific interfaces of nested H5 pages through OAuth2.0's scope mechanism? Apr 19, 2025 pm 02:30 PM

How to use OAuth2.0's access_token to achieve control of interface access permissions? In the application of OAuth2.0, how to ensure that the...

In back-end development, how to distinguish the responsibilities of the service layer and the dao layer? In back-end development, how to distinguish the responsibilities of the service layer and the dao layer? Apr 19, 2025 pm 01:51 PM

Discussing the hierarchical architecture in back-end development. In back-end development, hierarchical architecture is a common design pattern, usually including controller, service and dao three layers...

In Java remote debugging, how to correctly obtain constant values ​​on remote servers? In Java remote debugging, how to correctly obtain constant values ​​on remote servers? Apr 19, 2025 pm 01:54 PM

Questions and Answers about constant acquisition in Java Remote Debugging When using Java for remote debugging, many developers may encounter some difficult phenomena. It...

How to choose Java project management tools when learning back-end development? How to choose Java project management tools when learning back-end development? Apr 19, 2025 pm 02:15 PM

Confused with choosing Java project management tools for beginners. For those who are just beginning to learn backend development, choosing the right project management tools is crucial...

Ultimate consistency in distributed systems: how to apply and how to compensate for data inconsistencies? Ultimate consistency in distributed systems: how to apply and how to compensate for data inconsistencies? Apr 19, 2025 pm 02:24 PM

Exploring the application of ultimate consistency in distributed systems Distributed transaction processing has always been a problem in distributed system architecture. To solve the problem...

How to convert names to numbers to implement sorting within groups? How to convert names to numbers to implement sorting within groups? Apr 19, 2025 pm 01:57 PM

How to convert names to numbers to implement sorting within groups? When sorting users in groups, it is often necessary to convert the user's name into numbers so that it can be different...

Why does the Python script not be found when submitting a PyFlink job on YARN? Why does the Python script not be found when submitting a PyFlink job on YARN? Apr 19, 2025 pm 02:06 PM

Analysis of the reason why Python script cannot be found when submitting a PyFlink job on YARN When you try to submit a PyFlink job through YARN, you may encounter...

How to dynamically modify the savePath parameter of @Excel annotation in easypoi when project starts in Java? How to dynamically modify the savePath parameter of @Excel annotation in easypoi when project starts in Java? Apr 19, 2025 pm 02:09 PM

How to dynamically configure the parameters of entity class annotations in Java During the development process, we often encounter the need to dynamically configure the annotation parameters according to different environments...

See all articles