zoukankan      html  css  js  c++  java
  • 人生就要挑战新难度——记zxing的深化

      首先,我们来看看zxing一些基本介绍。

      ZXing是一个开放源码的,用Java实现的多种格式的1D(注1d条码主要常见的条码)

      

      /2D条码(主要是二维码)

      

      图像处理库,它包含了联系到其他语言的端口。Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。该项目可实现的条形码编码和解码。我们目前支持以下格式:

      UPC-A,UPC-E
      EAN-8,EAN-13
      39码
      93码
      代码128
      创新及科技基金
      库德巴
      RSS-14(所有的变体
      RSS扩展(大多数变体)
      QR码
      数据矩阵
      阿兹台克人('测试版'质量)
      PDF 417('阿尔法'的质量)
      Zxing库的主要部分支持以下几个功能:核心代码的使用、适用于J2SE客户端的版本、适用于Android客户端的版本(即BarcodeScanner)、Android的集成(通过Intent支持和BarcodeScanner的集成)等。
      在android下生成二维码
      http://code.google.com/p/zxing/downloads/list下载zxing压缩包(我用的Zxing-1.7),解压后将core/src和javase/src中的com文件夹整体复制到你的java工程中,这两个包里面包含java所用的java源码。
      相应的源代码如下: 
    package com.easyoa.test;
    
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Hashtable;
    
    import javax.imageio.ImageIO;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.DecodeHintType;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.Reader;
    import com.google.zxing.ReaderException;
    import com.google.zxing.Result;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.ByteMatrix;
    import com.google.zxing.common.HybridBinarizer;
    
    public class Test {
       private static final int BLACK = 0xff000000;
       private static final int WHITE = 0xFFFFFFFF;
     /**
      * @param args
      */
     public static void main(String[] args) {
      Test test=new Test();
      test.encode();
     test.decode();
     }
     //编码
     /**
      * 在编码时需要将com.google.zxing.qrcode.encoder.Encoder.java中的
      *  static final String DEFAULT_BYTE_MODE_ENCODING = "ISO8859-1";修改为UTF-8,否则中文编译后解析不了
      */
     public void encode(){
      try { 
       String str = "姓名:曾驰文,性别:男,年龄:27,籍贯:湖南长沙,";// 二维码内容 
       String path = "D://test.png"; 
       ByteMatrix byteMatrix; 
       byteMatrix= new MultiFormatWriter().encode(str, BarcodeFormat.QR_CODE, 200, 200);
       File file = new File(path); 
          writeToFile(byteMatrix, "png", file); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      }
     }
     public static void writeToFile(ByteMatrix matrix, String format, File file)
     throws IOException {
    BufferedImage image = toBufferedImage(matrix);
    ImageIO.write(image, format, file);
    }
     public static BufferedImage toBufferedImage(ByteMatrix matrix) {
         int width = matrix.getWidth();
         int height = matrix.getHeight();
         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
         for (int x = 0; x < width; x++) {
           for (int y = 0; y < height; y++) {
             image.setRGB(x, y, matrix.get(x, y) == 0 ? BLACK:WHITE);
           }
         }
         return image;
       }
     //解码
     public void decode(){
      try{
       Reader reader = new MultiFormatReader(); 
       String imgPath = "D://test.png"; 
       File file = new File(imgPath); 
       BufferedImage image; 
       try { 
        image = ImageIO.read(file); 
        if (image == null) { 
        System.out.println("Could not decode image"); 
        } 
        LuminanceSource source = new BufferedImageLuminanceSource(image); 
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 
        Result result; 
        Hashtable hints= new Hashtable(); 
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); 
        //解码设置编码方式为:utf-8,
        result = new MultiFormatReader().decode(bitmap,hints); 
        String resultStr = result.getText(); 
        System.out.println("解析后内容:"+resultStr);
    
       } catch (IOException ioe) { 
        System.out.println(ioe.toString()); 
       } catch (ReaderException re) { 
        System.out.println(re.toString()); 
       }
    
      }catch(Exception ex){
       System.out.println(ex.toString());
      }
     }
    
    }

      通过代码,我们可以得出下列的结论:

      为了更好的生成相应的二维码,我们需要将相应的二维码内容转换成相应的流对象,将流对象转换成相应的图片,这图片是不同部分变成黑白的图片。

      相应的解析的结果是:姓名:曾驰文,性别:男,年龄:27,籍贯:湖南长沙,

      解析二维码

      下面是 二维码从图片解析内容的分析与实现

      解码的流程大致分成以下几个步骤:

      1:获取摄像头byte[] data
      2:对数据进行解析
      在zxing客户端源码中
      PreviewCallback 摄像头回调 data就是出自这里
      PlanarYUVLuminanceSource 继承与LuminanceSource不同的数据原 YUV RGB  
      RGBLuminanceSource
      AutoFocusCallback  自动对焦。不能自动对焦的手机zxing就不能发威了(这个处理相应的摄像头的过程中,在android系统下,由于是调用硬件设备,往往系统调度无法处理,从而实现后退键反映不及时的结果)
      CameraManager  摄像头管理类。打开,关闭
      DecodeThread   线程管理主要利用到了CountDownLatch
      DecodeHandler  数据传输中枢。我理解DecodeThread控制线程,DecodeHandler发送数据
      DecodeFormatManager  这个配置解码格式。一维码,二维码等
      CaptureActivityHandler 这个是解码与avtivity中介。解码成功,失败都用她回调
      ViewfinderView  我们看到的扫描框,搞花样就从她入手
          同样,我们来看看源代码:

      

    public class DecodeImageHandler {
        private static final String TAG = DecodeImageHandler.class.getSimpleName();
        // 解码格式
        private MultiFormatReader multiFormatReader;
        private static final String ISO88591 = "ISO8859_1";
     
        // private Context mContext;
     
        public DecodeImageHandler(Context context) {
            // 解码的参数
            Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(2);
            // 能解析的编码类型 和 解析时使用的编码。
            Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();
            decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
            decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
            decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
            hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
            hints.put(DecodeHintType.CHARACTER_SET, ISO88591);
            init(context, hints);
     
        }
     
        public DecodeImageHandler(Context context, Hashtable<DecodeHintType, Object> hints) {
            init(context, hints);
        }
     
        private void init(Context context, Hashtable<DecodeHintType, Object> hints) {
            multiFormatReader = new MultiFormatReader();
            multiFormatReader.setHints(hints);
            // mContext = context;
        }
     
        public Result decode(Bitmap bitmap) {
            // 首先,要取得该图片的像素数组内容
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            //--------------------------------------------------
            //rgb模式
            int[] data = new int[width * height];
            bitmap.getPixels(data, 0, width, 0, 0, width, height);
            Result rgbResult = rgbModeDecode(data, width, height);
            if (rgbResult != null) {
                data = null;
                return rgbResult;
            }
     
            //----------------------------------------------------
            //yuv
            byte[] bitmapPixels = new byte[width * height];
            bitmap.getPixels(data, 0, width, 0, 0, width, height);
            // 将int数组转换为byte数组
            for (int i = 0; i < data.length; i++) {
                bitmapPixels[i] = (byte) data[i];
            }
            //        ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
            Result yuvResult = yuvModeDecode(bitmapPixels, width, height);
            bitmapPixels = null;
            return yuvResult;
        }
     
        //    public Result decode(String path) throws IOException {
        //        // 解析图片高和宽
        //        BitmapFactory.Options options = new BitmapFactory.Options();
        //        options.inJustDecodeBounds = true;
        //        BitmapFactory.decodeFile(path, options);
        //
        //        //从图片直接获取byte[]
        //        File file = new File(path);
        //        FileInputStream is = new FileInputStream(file);
        //        ByteArrayOutputStream os = new ByteArrayOutputStream();
        //        int len = -1;
        //        byte[] buf = new byte[512];
        //        while ((len = is.read(buf)) != -1) {
        //            os.write(buf, 0, len);
        //        }
        //        //关闭流
        //        try {
        //            is.close();
        //        } finally {
        //            if (is != null) {
        //                is.close();
        //            }
        //        }
        //
        //        //解析
        //        return decode(os.toByteArray(), options.outWidth, options.outHeight);
        //    }
     
        public Result rgbModeDecode(int[] data, int width, int height) {
            Result rawResult = null;
            RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            try {
                rawResult = multiFormatReader.decodeWithState(bitmap);
            } catch (ReaderException re) {
                // continue
            } finally {
                multiFormatReader.reset();
            }
     
            //转换乱码
            if (rawResult != null) {
                return converResult(rawResult);
            }
            return rawResult;
        }
     
        public Result yuvModeDecode(byte[] data, int width, int height) {
            Result rawResult = null;
            PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            try {
                rawResult = multiFormatReader.decodeWithState(bitmap);
            } catch (ReaderException re) {
                // continue
            } finally {
                multiFormatReader.reset();
            }
     
            //转换乱码
            if (rawResult != null) {
                return converResult(rawResult);
            }
            return rawResult;
        }
     
        /**
         * 使用ISO88591进行解码,然后通过ISO88591在进行转换乱码
         */
        private Result converResult(Result rawResult) {
            //复制一个Result,并转码
            String str = rawResult.getText();
            String converText = null;
            try {
                converText = BarcodeUtils.converStr(str, ISO88591);
            } catch (UnsupportedEncodingException e) {
                Logger.getInstance(TAG).debug(e.toString());
            }
     
            //        FIXME 转化失败--》1:结果置空
            //                     --》2:把未解码的内容返回
            if (converText != null) {
                return serResultText(rawResult, converText);
            } else {
                return rawResult;
            }
        }
     
        private Result serResultText(Result rawResult, String converText) {
            Result resultResult = new Result(converText, rawResult.getRawBytes(), rawResult.getResultPoints(),
                    rawResult.getBarcodeFormat(), System.currentTimeMillis());
            resultResult.putAllMetadata(rawResult.getResultMetadata());
            return resultResult;
        }
     
    }

      我们可以看出:

      ①指定相应的系统的参数来解码byte数组中的内容。

      ②这样数组往往会出现乱码,我们需要经过crc等等的编码格式的校正。

      ③把相应的文字赋值给对话框。

      这就是我对zxing的理解。

  • 相关阅读:
    401. Binary Watch
    46. Permutations
    61. Rotate List
    142. Linked List Cycle II
    86. Partition List
    234. Palindrome Linked List
    19. Remove Nth Node From End of List
    141. Linked List Cycle
    524. Longest Word in Dictionary through Deleting
    android ListView详解
  • 原文地址:https://www.cnblogs.com/manuosex/p/3665373.html
Copyright © 2011-2022 走看看