Android zxing扫码截彩色图

不得不说这个过程看上去简单,实际上写到我差不多一个星期的时间,由于超出预定时间,此功能被放弃,出于对技术的追求,于是继续写,终于被我弄出来。
其实两种方法的本质都是通过byte[]data获取数据,通过camera获取长宽。扫码过程中主要由两种途径:
1.camera.takePicture(自己写回调,灵活性相对高,推荐)
2.camera.setPreviewCallback(最终通过handler传递到DecodeHandler里面的decode())

说说思路-方法1:拍照

1.使用camera拍照

2.把拍照的data格式转换进行保存

听上去很简单吧?那我们试一下。
我的手机是mi5x,看看效果:
预览效果:
这里写图片描述
拍摄图片:
这里写图片描述
takePicture回调:

public void takePicture(final TakePictureCallback callback){
    if (camera != null && previewing) {
      camera.takePicture(null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
          byte[] rotatedData = new byte[data.length];
          Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
          Matrix matrix = new Matrix();
          matrix.setRotate(90);
          int width = bitmap.getWidth();
          int height = bitmap.getHeight();

          bitmap = createBitmap(bitmap, 0, 0, width, height, matrix, true);
          File file = new File(Environment.getExternalStorageDirectory() + File.separator + "mCamera", "b.jpg");
          saveBitmap(file.getAbsolutePath(), bitmap);
          if(callback!=null)
            callback.callback();
        }
      });
    }
  }

这个效果看的我n脸懵逼,摄像头怎么了?怎么拍摄的照片不完整?随后换了其他手机,如华为,vivo又不会有这样的问题,拍摄图片显示正常。几经周折,终于在不断尝试下找到解决办法:
摄像头初始化setPreviewSize前,要使用setPictureSize:

Camera.Parameters parameters = camera.getParameters();
    List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
    int position =0;
    if(supportedPreviewSizes.size()>2){
      position=supportedPreviewSizes.size()/2+1;//supportedPreviewSizes.get();
    }else {
      position=supportedPreviewSizes.size()/2;
    }

    int width = supportedPreviewSizes.get(position).width;
    int height = supportedPreviewSizes.get(position).height;
    Log.d(TAG, "Setting preview size: " + cameraResolution);
    parameters.setPictureSize(width,height);
    camera.setDisplayOrientation(90);
    cameraResolution.x=width;
    cameraResolution.y=height;
    parameters.setPreviewSize(width,height);
    setFlash(parameters);
    setZoom(parameters);
    //setSharpness(parameters);
    camera.setParameters(parameters);

估计setPictureSize就是实际拍摄的大小了,没有设置就会按照默认的来,小米这里可能又挖坑了。
另:实测发现vivo手机等加入setPictureSize后可能会在解码旋转图片过程中出现ArrayIndexOutOfBoundsException问题,如果碰到可能需要识别手机型号,小米才进行setPictureSize,其他手机采用默认【这方面可能需要查更多的资料,现在找到的信息有限】。

java.lang.ArrayIndexOutOfBoundsException: length=4147200; index=4913280

说说思路-方法2:扫码解码后直接保存

zxing的DecoderHandler里面有一个decode()方法用于解码,里面可以拿到data和长宽,可以直接在此处保存。

步骤1:使用传过来的原始长宽以及data

步骤2:进行解码保存在文件中

使用renderCroppedGreyscaleBitmap,图变灰:

public Bitmap renderCroppedGreyscaleBitmap() {
    int width = getWidth();
    int height = getHeight();
    int[] pixels = new int[width * height];
    byte[] yuv = yuvData;
    int inputOffset = top * dataWidth + left;

    for (int y = 0; y < height; y++) {
      int outputOffset = y * width;
      for (int x = 0; x < width; x++) {
        int grey = yuv[inputOffset + x] & 0xff;
        pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
      }
      inputOffset += dataWidth;
    }

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

成功变成黑白照。
这里写图片描述

另外说说为什么用原始长宽和data。在zxing解码这个部分,我们通常会看到这样一段代码:

Result rawResult = null;
    //modify here
    byte[] rotatedData = new byte[data.length];
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++)
            rotatedData[x * height + height - y - 1] = data[x + y * width];
    }
    int tmp = width; // Here we are swapping, that's the difference to #11
    width = height;
    height = tmp;

这是解码前做的准备,简单的说就是把图片进行了一下翻转,但如果是截图,请不要直接使用这个rotateData以及转换之后的长宽,否则效果如下:

这里写图片描述
【这张图本身也很奇怪,用手机看是全的,用电脑看下面变灰色】

由上面两个结果得出的结论是:

1.保存时候图片先不要旋转

2.不要使用renderCroppedGreyscaleBitmap()进行图片保存

于是用了原始参数,是这样传的:

source.renderCroppedGreyscaleBitmap2(data,height,width,file.getAbsolutePath());

内部如下:

public void renderCroppedGreyscaleBitmap2(final byte[] data, int width, int height, String path) {
    FileOutputStream outStream = null;
    try {
      YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21,width,height,null);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      yuvimage.compressToJpeg(new Rect(0,0,width,height), 100, baos);

      outStream = new FileOutputStream(path);
      outStream.write(baos.toByteArray());
      outStream.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
    }

  }

得到图片:

这里写图片描述
可以看到是彩色的,选择的方式上面有贴出,建议新开线程来处理,这里再贴一下:
路径获取bitmap:

FileInputStream fis = new FileInputStream(path);
Bitmap bitmap  = BitmapFactory.decodeStream(fis);

旋转:

Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
          Matrix matrix = new Matrix();
          matrix.setRotate(90);
          int width = bitmap.getWidth();
          int height = bitmap.getHeight();

          bitmap = createBitmap(bitmap, 0, 0, width, height, matrix, true);

保存:

public static String saveBitmap(String dir, Bitmap b) {
    try {
      File f = new File(dir);

      if (f.exists()) {
        f.delete();
      }
      f.createNewFile();
      FileOutputStream fout = new FileOutputStream(f);
      BufferedOutputStream bos = new BufferedOutputStream(fout);
      b.compress(Bitmap.CompressFormat.JPEG, 100, bos);
      bos.flush();
      bos.close();
      return dir;
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "";
  }

猜你喜欢

转载自blog.csdn.net/yu_duan_hun/article/details/80480179