Android realizes the generation of two dimensional code based on google Zxing

  • 2021-07-22 11:19:13
  • OfStack

Recent projects have used the generation and recognition of 2D codes, I didn't touch this piece before, Then I searched the Internet, I found that there are many resources in this field. In particular, google Zxing encapsulation of 2-D code, the implementation has been good, can be taken directly to reference, after downloading their source code, only a few changes have been made, that is, the function of long press identification has been added in Demo. Although there are Demo with long press identification on the Internet, many downloads can't run, and then summarized 1, added in the following Demo.
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) { 
//打开扫描界面扫描条形码或2维码 
Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class); 
startActivityForResult(openCameraIntent, 0); 
} 
}); 
qrImgImageView.setOnLongClickListener(new OnLongClickListener() { 
 
@Override 
public boolean onLongClick(View v) { 
// 长按识别2维码 
 
 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("")) { 
//根据字符串生成2维码图片并显示在界面上,第2个参数为图片的大小(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(); 
  //从缓存中获取当前屏幕的图片,创建1个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); 
  } 
 } 
  
 //解析2维码图片,返回结果封装在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) 
  //并不会真的返回1个Bitmap给你,它仅仅会把它的宽,高取回来给你 
  options.inJustDecodeBounds = true; 
  //此时的bitmap是null,这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了 
  Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options); 
  //我们现在想取出来的图片的边长(2维码图片是正方形的)设置为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);  
  //新建1个RGBLuminanceSource对象,将bitmap图片传给此对象 
  RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap); 
  //将图片转换成2进制图片 
  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); 
} 
} 
} 

Then the class RGBLuminanceSource is called by pressing the identification 2-dimensional code for a long time


public class RGBLuminanceSource extends LuminanceSource { 
private byte bitmapPixels[]; 
 
protected RGBLuminanceSource(Bitmap bitmap) { 
super(bitmap.getWidth(), bitmap.getHeight()); 
 
//  First, you want to get the contents of the pixel array of the picture  
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()); 
 
//  Will int Array is converted to byte Array, that is, take the blue value part of the pixel value as the discrimination content  
for (int i = 0; i < data.length; i++) { 
this.bitmapPixels[i] = (byte) data[i]; 
} 
} 
 
@Override 
public byte[] getMatrix() { 
//  Return the pixel data we generated  
return bitmapPixels; 
} 
 
 
@Override 
public byte[] getRow(int y, byte[] row) { 
//  Here you want to get the pixel data of the specified row  
System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth()); 
return row; 
} 
} 

Camera recognition 2D code calls the class CaptureActivity


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("")) { 
// Scan failed  
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); 
} 
}; 
 
 
} 

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>

For more information, please download demo to see for yourself. Demo solves the phenomenon that 2-dimensional code is stretched when decoding in vertical beat.
However, I encountered a problem is 2-dimensional code scanning frame after the size, scanning sensitivity reduced, I want to know friends to give guidance
If you are interested, you can download Demo to see 1: google Zxing realizes the generation of 2-dimensional code


Related articles: